Filtering epoched data - filter_length(n) longer than signal...

  • MNE version 1.3.1
  • Debian Bullseye

My data were given to me epoched into 1 second epochs, sampled at 500Hz.
I would like to bandpass filter the data 0.2Hz to 50Hz.
I’ve divided the high- and low- pass filtering into separate calls, to no avail.

epochs = mne.read_epochs(file, preload=True)
epochs = epochs.resample(DESIRED_SAMPLE_FREQ)
epochs = epochs.filter(
    l_freq=LOW_FREQ_FILTER,
    l_trans_bandwidth=0.2,
    h_freq=None,
    picks=get_channels(epochs),
    verbose=False,
)

epochs = epochs.filter(
    l_freq=None,
    h_freq=HIGH_FREQ_FILTER,
    picks=get_channels(epochs),
    verbose=False,
)

The error is:

/tmp/ipykernel_1248440/1549853596.py:12: RuntimeWarning: filter_length (8251) is longer than the signal (502), distortion is likely. Reduce filter length or filter a longer signal.

I’ve played around with l_trans_bandwidth from 0.1 to 1Hz, which either prints the error above, or sends the low pass frequency negative and errors.

Is there a way to filter the raw, underlying data in one long chunk?
I.e. in pseudocode:

data = epochs.get_data()
buttery_filter = scipy.signal.butter(4, [0.2, 50], btype="bandpass", output="sos", fs=500)
filtered = signal.sosfilt(buttery_filter, data)
epochs.set_data(filtered) # n.b. Future People(tm) set_data does not exist

I’ve made a good long trek through the docs and Googles, and don’t see a way to do this.
Thanks!

Edit: padding might help, but I don’t see a way to set the amount, just the type using e.g. pad=edge or the like.

Edit2: After more digging and reading the tutorial on filtering, I came up with this. Would appreciate opinions on how valid it is, and how to get the data back “into” the Epochs object. Maybe I don’t need to, but it would seem to ease things like doing ICA, selecting components, etc.

import numpy as np
from numpy.fft import fft, fftfreq
from scipy import signal
import matplotlib.pyplot as plt

from mne.time_frequency.tfr import morlet
from mne.viz import plot_filter, plot_ideal_filter

file = "../data/Epochs/All epochs/file.fif"
set_label = None

head, tail = os.path.split(file)
if set_label is not None:
    label = set_label
else:
    label = tail[0:4].lower()

epochs = mne.read_epochs(file, preload=True)
epochs = epochs.resample(DESIRED_SAMPLE_FREQ)

iir_params = dict(order=8, ftype="butter")
filt = mne.filter.create_filter(
    epochs.get_data(),
    DESIRED_SAMPLE_FREQ,
    l_freq=0.2,
    h_freq=50,
    method="iir",
    iir_params=iir_params,
    verbose=True,
)

flim = (0.01, DESIRED_SAMPLE_FREQ / 2.0)  # frequencies
dlim = (-0.2, 0.2)  # delays
gain = [0.0, 1.0, 1.0, 0.0]
kwargs = dict(flim=flim, dlim=dlim)
plot_filter(
    filt, DESIRED_SAMPLE_FREQ, None, "Butterworth order=8", compensate=True, **kwargs
)
x_steep = signal.sosfiltfilt(filt["sos"], epochs.get_data())

As it turns out, here’s how to do it:

iir_params = dict(order=8, ftype="butter")
filtered = epochs.filter(l_freq=0.2, h_freq=50, picks=None, method='iir', iir_params=iir_params,
                         verbose=None)

I’ll just leave my struggles above for Future People™, if that’s okay.