{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n\n# Background information on filtering\n\nHere we give some background information on filtering in general, and how it is\ndone in MNE-Python in particular. Recommended reading for practical\napplications of digital filter design can be found in\nParks & Burrus (1987) :footcite:`ParksBurrus1987`\nand Ifeachor & Jervis (2002) :footcite:`IfeachorJervis2002`,\nand for filtering in an M/EEG context we recommend reading\nWidmann *et al.* (2015) :footcite:`WidmannEtAl2015`.\n\n
This tutorial goes pretty deep into the mathematics of filtering and the\n design decisions that go into choosing a filter. If you just want to know\n how to apply the default filters in MNE-Python to your data, skip this\n tutorial and read `tut-filter-resample` instead (but someday, you\n should come back and read this one too \ud83d\ude42).
Remez and least squares designs have advantages when there are\n \"do not care\" regions in our frequency response. However, we want\n well controlled responses in all frequency regions.\n Frequency-domain construction is good when an arbitrary response\n is desired, but generally less clean (due to sampling issues) than\n a windowed approach for more straightforward filter applications.\n Since our filters (low-pass, high-pass, band-pass, band-stop)\n are fairly simple and we require precise control of all frequency\n regions, we will primarily use and explore windowed FIR design.
Notice that the group delay (which is related to the phase) of\n the IIR filters below are not constant. In the FIR case, we can\n design so-called linear-phase filters that have a constant group\n delay, and thus compensate for the delay (making the filter\n non-causal) if necessary. This cannot be done with IIR filters, as\n they have a non-linear phase (non-constant group delay). As the\n filter order increases, the phase distortion near and in the\n transition band worsens. However, if non-causal (forward-backward)\n filtering can be used, e.g. with :func:`scipy.signal.filtfilt`,\n these phase issues can theoretically be mitigated.
Here we have made use of second-order sections (SOS)\n by using :func:`scipy.signal.sosfilt` and, under the\n hood, :func:`scipy.signal.zpk2sos` when passing the\n ``output='sos'`` keyword argument to\n :func:`scipy.signal.iirfilter`. The filter definitions\n given `above
This simulated signal contains energy not just within the\n pass-band, but also within the transition and stop-bands -- perhaps\n most easily understood because the signal has a non-zero DC value,\n but also because it is a shifted cosine that has been\n *windowed* (here multiplied by a rectangular window), which\n makes the cosine and DC frequencies spread to other frequencies\n (multiplication in time is convolution in frequency, so multiplying\n by a rectangular window in the time domain means convolving a sinc\n function with the impulses at DC and the cosine frequency in the\n frequency domain).
An important thing to keep in mind with these plots is that they\n are for a single simulated sensor. In multi-electrode recordings\n the topology (i.e., spatial pattern) of the pre-stimulus activity\n will leak into the post-stimulus period. This will likely create a\n spatially varying distortion of the time-domain signals, as the\n averaged pre-stimulus spatial pattern gets subtracted from the\n sensor time courses.
For ``fir_design='firwin2'``, the multiplicative factors are\n doubled compared to what is given in\n Ifeachor & Jervis (2002) :footcite:`IfeachorJervis2002`\n (p. 357), as :func:`scipy.signal.firwin2` has a smearing effect\n on the frequency response, which we compensate for by\n increasing the filter length. This is why\n ``fir_desgin='firwin'`` is preferred to ``fir_design='firwin2'``.
In band-pass applications, often a low-pass filter can operate\n effectively with fewer samples than the high-pass filter, so\n it is advisable to apply the high-pass and low-pass separately\n when using ``fir_design='firwin2'``. For design mode\n ``fir_design='firwin'``, there is no need to separate the\n operations, as the lowpass and highpass elements are constructed\n separately to meet the transition band requirements.
If you are using an IIR filter, :func:`mne.filter.create_filter`\n will not print a filter length and transition bandwidth to the log.\n Instead, you can specify the roll-off with the ``iir_params``\n argument or stay with the default, which is a fourth order\n (Butterworth) filter.