Search code examples
pythonscipymne-python

Why does mne resample method does not sample the data point to point?


My understanding of downsampling is that it is an operation to decrease the sample rate of x by keeping the first sample and then every nth sample after the first. The example provided from the resample method of scipy package clearly illustrated about this operation as depicted the picture which is accessible from the link (https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.resample.html) or as extracted below

enter image description here

In an enlarged view, it is evident that the original data points were resampled point by point.

However, using the mne example of downsampling which accessible via the link : https://mne.tools/dev/auto_examples/preprocessing/plot_resample.html , I notice that the data points were not resampled point by point as illustrated visually below

enter image description here

This given that, mne resample is based on the resample method of scipy package as indicated from mne resample function as shown: https://github.com/mne-tools/mne-python/blob/607fb4613fb5a80dd225132a4a53fe43b8fde0fb/mne/filter.py#L1342

May I know whether this issue is due to the ringing artifacts or due to other problems?

Also, are there remedies to mitigate this problem.

Thanks for any insight. Appreciate it

The same question has been asked in mne discussion repo, but un-answered as of the time of writing


Solution

  • My understanding of downsampling is that it is an operation to decrease the sample rate of x by keeping the first sample and then every nth sample after the first.

    Resampling typically consists of two steps: low-pass filtering to avoid aliasing, then sample rate reduction (subselecting samples from the resulting signal). The low-passing actually changes the values, so the subselection-of-filtered-data step will not necessarily yield points that were "on" the original signal.

    May I know whether this issue is due to the ringing artifacts or due to other problems?

    In this case it's likely due to the (implicit) low-pass filtering in the frequency-domain resampling of the signal. It looks pretty reasonable to me. If you want to play around with it a bit, you can

    1. Call scipy.signal.resample directly on your data and see how closely it matches.
    2. Pad your signal, call scipy.signal.resample, and remove the (now reduced-length) padding -- this is what MNE does internally.
    3. Use scipy.signal.resample_poly directly on your data.
    4. Manually low-pass filter and then directly subselect samples from the low-passed signal, which is what resample_poly does internally.

    Also, scipy.signal.resample does frequency-domain resampling, so implicitly uses a brick-wall filter at Nyquist when downsampling (unless you specify something for the window argument, which gets applied in the frequency domain in addition to the effective brick-wall filter).

    p.s. The answer provided is an extract from the discussion with the folk at mne, namely Eric Larson,Brunner Clemens,Phillip Alday. Credit should be given to them