Filtering and resampling data

Some artifacts are restricted to certain frequencies and can therefore be fixed by filtering. An artifact that typically affects only some frequencies is due to the power line.

Power-line noise is a noise created by the electrical network. It is composed of sharp peaks at 50Hz (or 60Hz depending on your geographical location). Some peaks may also be present at the harmonic frequencies, i.e. the integer multiples of the power-line frequency, e.g. 100Hz, 150Hz, … (or 120Hz, 180Hz, …).

This tutorial covers some basics of how to filter data in MNE-Python. For more in-depth information about filter design in general and in MNE-Python in particular, check out Background information on filtering.

import numpy as np
import mne
from mne.datasets import sample

data_path = sample.data_path()
raw_fname = data_path + '/MEG/sample/sample_audvis_raw.fif'
proj_fname = data_path + '/MEG/sample/sample_audvis_eog_proj.fif'

tmin, tmax = 0, 20  # use the first 20s of data

# Setup for reading the raw data (save memory by cropping the raw data
# before loading it)
raw = mne.io.read_raw_fif(raw_fname)
raw.crop(tmin, tmax).load_data()
raw.info['bads'] = ['MEG 2443', 'EEG 053']  # bads + 2 more

fmin, fmax = 2, 300  # look at frequencies between 2 and 300Hz
n_fft = 2048  # the FFT size (n_fft). Ideally a power of 2

# Pick a subset of channels (here for speed reasons)
selection = mne.read_selection('Left-temporal')
picks = mne.pick_types(raw.info, meg='mag', eeg=False, eog=False,
                       stim=False, exclude='bads', selection=selection)
raw.plot_psd(area_mode='range', tmax=10.0, picks=picks, average=False)
../../_images/sphx_glr_plot_artifacts_correction_filtering_001.png

Out:

Opening raw data file /home/circleci/mne_data/MNE-sample-data/MEG/sample/sample_audvis_raw.fif...
    Read a total of 3 projection items:
        PCA-v1 (1 x 102)  idle
        PCA-v2 (1 x 102)  idle
        PCA-v3 (1 x 102)  idle
    Range : 25800 ... 192599 =     42.956 ...   320.670 secs
Ready.
Current compensation grade : 0
Reading 0 ... 12012  =      0.000 ...    20.000 secs...
Effective window size : 3.410 (s)

Removing power-line noise with notch filtering

Removing power-line noise can be done with a Notch filter, directly on the Raw object, specifying an array of frequency to be cut off:

raw.notch_filter(np.arange(60, 241, 60), picks=picks, fir_design='firwin')
raw.plot_psd(area_mode='range', tmax=10.0, picks=picks, average=False)
../../_images/sphx_glr_plot_artifacts_correction_filtering_002.png

Out:

Setting up band-stop filter

FIR filter parameters
---------------------
Designing a one-pass, zero-phase, non-causal bandstop filter:
- Windowed time-domain design (firwin) method
- Hamming window with 0.0194 passband ripple and 53 dB stopband attenuation
- Lower transition bandwidth: 0.50 Hz
- Upper transition bandwidth: 0.50 Hz
- Filter length: 3965 samples (6.602 sec)

Effective window size : 3.410 (s)

Removing power-line noise with low-pass filtering

If you’re only interested in low frequencies, below the peaks of power-line noise you can simply low pass filter the data.

# low pass filtering below 50 Hz
raw.filter(None, 50., fir_design='firwin')
raw.plot_psd(area_mode='range', tmax=10.0, picks=picks, average=False)
../../_images/sphx_glr_plot_artifacts_correction_filtering_003.png

Out:

Filtering raw data in 1 contiguous segment
Setting up low-pass filter at 50 Hz

FIR filter parameters
---------------------
Designing a one-pass, zero-phase, non-causal lowpass filter:
- Windowed time-domain design (firwin) method
- Hamming window with 0.0194 passband ripple and 53 dB stopband attenuation
- Upper passband edge: 50.00 Hz
- Upper transition bandwidth: 12.50 Hz (-6 dB cutoff frequency: 56.25 Hz)
- Filter length: 159 samples (0.265 sec)

Effective window size : 3.410 (s)

High-pass filtering to remove slow drifts

To remove slow drifts, you can high pass.

Warning

In several applications such as event-related potential (ERP) and event-related field (ERF) analysis, high-pass filters with cutoff frequencies greater than 0.1 Hz are usually considered problematic since they significantly change the shape of the resulting averaged waveform (see examples in High-pass problems). In such applications, apply high-pass filters with caution.

raw.filter(1., None, fir_design='firwin')
raw.plot_psd(area_mode='range', tmax=10.0, picks=picks, average=False)
../../_images/sphx_glr_plot_artifacts_correction_filtering_004.png

Out:

Filtering raw data in 1 contiguous segment
Setting up high-pass filter at 1 Hz

FIR filter parameters
---------------------
Designing a one-pass, zero-phase, non-causal highpass filter:
- Windowed time-domain design (firwin) method
- Hamming window with 0.0194 passband ripple and 53 dB stopband attenuation
- Lower passband edge: 1.00
- Lower transition bandwidth: 1.00 Hz (-6 dB cutoff frequency: 0.50 Hz)
- Filter length: 1983 samples (3.302 sec)

Effective window size : 3.410 (s)

To do the low-pass and high-pass filtering in one step you can do a so-called band-pass filter by running the following:

# band-pass filtering in the range 1 Hz - 50 Hz
raw.filter(1, 50., fir_design='firwin')

Out:

Filtering raw data in 1 contiguous segment
Setting up band-pass filter from 1 - 50 Hz

FIR filter parameters
---------------------
Designing a one-pass, zero-phase, non-causal bandpass filter:
- Windowed time-domain design (firwin) method
- Hamming window with 0.0194 passband ripple and 53 dB stopband attenuation
- Lower passband edge: 1.00
- Lower transition bandwidth: 1.00 Hz (-6 dB cutoff frequency: 0.50 Hz)
- Upper passband edge: 50.00 Hz
- Upper transition bandwidth: 12.50 Hz (-6 dB cutoff frequency: 56.25 Hz)
- Filter length: 1983 samples (3.302 sec)

Downsampling and decimation

When performing experiments where timing is critical, a signal with a high sampling rate is desired. However, having a signal with a much higher sampling rate than necessary needlessly consumes memory and slows down computations operating on the data. To avoid that, you can downsample your time series. Since downsampling raw data reduces the timing precision of events, it is recommended only for use in procedures that do not require optimal precision, e.g. computing EOG or ECG projectors on long recordings.

Note

A downsampling operation performs a low-pass (to prevent aliasing) followed by decimation, which selects every \(N^{th}\) sample from the signal. See scipy.signal.resample() and scipy.signal.resample_poly() for examples.

Data resampling can be done with resample methods.

raw.resample(100, npad="auto")  # set sampling frequency to 100Hz
raw.plot_psd(area_mode='range', tmax=10.0, picks=picks, average=True)
../../_images/sphx_glr_plot_artifacts_correction_filtering_005.png

Out:

25 events found
Event IDs: [ 1  2  3  4  5 32]
25 events found
Event IDs: [ 1  2  3  4  5 32]
Effective window size : 10.010 (s)

To avoid this reduction in precision, the suggested pipeline for processing final data to be analyzed is:

  1. low-pass the data with mne.io.Raw.filter().

  2. Extract epochs with mne.Epochs.

  3. Decimate the Epochs object using mne.Epochs.decimate() or the decim argument to the mne.Epochs object.

We also provide the convenience methods mne.Epochs.resample() and mne.Evoked.resample() to downsample or upsample data, but these are less optimal because they will introduce edge artifacts into every epoch, whereas filtering the raw data will only introduce edge artifacts only at the start and end of the recording.

Total running time of the script: ( 0 minutes 5.123 seconds)

Estimated memory usage: 8 MB

Gallery generated by Sphinx-Gallery