Failed to know how to apply a stopband over a passband

:question: If you have a question or issue with MNE-Python, please include the following info:

  • MNE version: 1.7.1
  • operating system: Windows 10

Hi,

I am new to MNE-python and I apologise if this is an elementary question. I am trying to apply a stopband over a passband. I want to achieve this:

Continuous EEG signals were bandpass filtered (standard non-causal two-pass Butterworth filters) between 0.1 and 100 Hz and bandstop filtered (48–52 and 98–102 Hz) to remove line noise at 50 and 100 Hz.

What I planned to do was first do the bandpass filter and then the two bandstop filter. Then I tried to use the following code:

raw_eeg_subj2_bandstop = raw_eeg_subj2.get_data().filter(0.1, 100).filter(52, 48)

or tried to create a bandpass filter like:

stopband1 = mne.filter.create_filter(raw_eeg_subj2.get_data(), 512, 52, 48)

However, they didn’t work and returned the message:

Stop bands are not sufficiently separated.

I was wondering what was wrong and hope to ask about how to achieve 0.1-100Hz without 48-52Hz and 98-102Hz.

Thank you very much! :smiley:

I recommend that you use raw.filter() directly, there should be no need for .get_data(). I’d also apply the three filters sequentially. Furthermore, since you want a Butterworth filter, you should provide the method="iir" argument.

raw_eeg_subj2.filter(0.1, 100, method="iir")

These operations work in place, so after applying the first filter, you can apply the notch filters:

raw_eeg_subj2.filter(52, 48)
raw_eeg_subj2.filter(102, 98)

These two notch filters use the default FIR method, but of course you can change it with the method argument if that’s not what you want. If you still get an error message regarding the stop band, let us know here!

2 Likes

I’m surprised raw.filter let’s you apply a stop band when raw.notch_filter exist :thinking:

1 Like

I haven’t looked at the implementation, but raw.notch_filter() allows you to specify multiple frequencies to filter (e.g. harmonics), so this is very convenient. I would expect that both methods should work, but raw.notch_filter() should probably be preferred in most cases.

1 Like

Hi,

Thank you very much for the answer and for mentioning how to apply a Butterworth filter! I tried both the filter() and notch_filter(). With the notch_filter(), it works:

raw_eeg_subj38_01Hz_notch1 = raw_eeg_subj38_01Hz.copy().notch_filter(freqs = 50, notch_widths = 4)
raw_eeg_subj38_01Hz_notch2 = raw_eeg_subj38_01Hz_notch1.copy().notch_filter(freqs = 100, notch_widths = 4)

and I got the plot:

But with the filter method, I still got the error message like:

Stop bands are not sufficiently separated.

My code was:

raw_eeg_subj38_01Hz_filter1 = raw_eeg_subj38_01Hz.copy().filter(52, 48)

So I can use the notch_filter() which is so helpful, but I am still a little bit confused about why the filter() failed. :joy:

Anyway, thank you very much for the reply!! :smile:

Hi!

Thank you very much for mentioning the notch_filter()! It worked very well with my data! :smile:

To be honest, I don’t know why raw.filter() does not work for a notch filter. In my opinion, it should be possible to use it as well (for example because the documentation includes band stop filters), so it’s maybe because of some parameters not working out (both methods internally dispatch to mne.filter.filter_data()). @larsoner do you have an idea and/or an opinion? If there is really a conceptual issue why notch filters cannot be applied with raw.filter(), there should at the very least be a note in the docs.

1 Like

With the default parameters of raw.filter, you get l_trans_bandwidth and h_trans_bandwidth set to 'auto' which will yield 2 Hz.

Documentation of l_trans_bandwidth:

min(max(l_freq * 0.25, 2), l_freq)

Thus if you change it, it works.
The default for notch_filter is trans_bandwidth=1.

from mne.datasets import sample
from mne.io import read_raw_fif


raw = read_raw_fif(sample.data_path() / "MEG" / "sample" / "sample_audvis_raw.fif")
raw.crop(tmax=30).pick("eeg").load_data()
raw.filter(52, 48, l_trans_bandwidth=1, h_trans_bandwidth=1)
raw.compute_psd().plot()

yields:

Mathieu

3 Likes

Nice, that’s it! Thanks @mscheltienne!

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.