filtering Level 1 pf-aliasing-on-downsample

Downsampling without anti-alias filtering

Symptom. High-frequency content folds into the band of interest.

Symptom

After downsampling, a spectral line or a broadband bump appears at a frequency where there was nothing before: a “beta” or “gamma” feature that the original recording did not have; a mains line that has moved (60 Hz becomes 40 Hz after decimation from 500 to 100 Hz); a raised high-frequency floor. The new features are perfectly stable across trials and subjects, because they are arithmetic, not biology, and they scale with whatever high-frequency content the original had — muscle, line noise, harmonics.

Cause

Keeping every n-th sample of a recording (data[::n]) lowers the sampling rate without removing the content above the new Nyquist frequency. That content does not disappear; it aliases, reappearing at the distance from its true frequency to the nearest multiple of the new rate (L1.1: f_alias = |f − round(f / fs) · fs|). Decimating 500 Hz to 100 Hz without filtering moves a 70 Hz component to 30 Hz and a 60 Hz line to 40 Hz. Proper resampling applies an anti-alias low-pass below the new Nyquist frequency before reducing the rate; naive decimation skips it.

Detect

  • Compare PSDs before and after downsampling on the same axes up to the new Nyquist frequency: any feature that is present after and absent before is aliased.
  • Check the code: raw.resample(), scipy.signal.decimate, scipy.signal.resample_poly and scipy.signal.resample filter or band-limit; array slicing does not.
  • Compute where known lines (mains and harmonics) would land under the new rate, and look there.
  • Downsample a synthetic tone above the new Nyquist frequency with the same code path and see whether it survives.

Fix

  • Use a resampling routine that includes the anti-alias filter (raw.resample() in MNE, decimate or resample_poly in SciPy); if you must decimate by hand, low-pass filter below the new Nyquist frequency first, with a transition band that ends below it.
  • Choose the new rate with room for the filter’s transition band above the highest frequency you will analyse.
  • Resample events and annotations with the data (MNE does this for the stimulus channel and annotations), and check that event samples were converted with the same ratio.
  • Remember that the anti-alias filter bounds only the new Nyquist frequency; the usable band is still limited by the hardware bandwidth of the original recording (pf-hardware-bandwidth-ceiling).

Example

Power spectra of one eyes-open resting EEG channel on a log axis. The 500 Hz original shows a sharp 60 Hz mains peak. After keeping every fifth sample without filtering, a peak of similar height appears at 40 Hz. After an anti-alias low-pass and the same decimation, the spectrum below 50 Hz follows the original with no 40 Hz peak.

ds-iowapd sub-001, Oz, 60 s from 160 s at 500 Hz, decimated to 100 Hz by keeping every fifth sample (no filter) and by an anti-alias low-pass plus decimation (scipy.signal.resample_poly); Welch PSD, 2-s Hann segments. Without the filter the 60 Hz mains line folds to |60 − 100| = 40 Hz, inside the new 0–50 Hz band (1.98 µV²/Hz at 40 Hz against 0.09 with the filter). ds-eegbci cannot host this example: at 160 Hz nothing above 80 Hz exists to fold. Generated by data/scripts/make_figures.py (CC0).