I have EEG data recorded with a sampling rate of 256 Hz. Each recording contains 19 EEG channels. Other channels (like ECG data) are ignored. The recordings of 10 patients are 20 minutes long each, recordings of 2 other patients cover a period of 24 hours each. The long recordings contain sections where the recording device obviousely was turned off, so that flat lines appeared in the recording. I cut those recordings in smaller chunks at these flat-line sections, so that no chunk contains flat lines. But some of the chunks still are longer than 6 hours.

Some recordings are contaminated by 50 Hz mains hum that was not properly filtered out during recording. And in almost all recordings the means value of many channels is far away from 0 mV, so there is a constant voltage added to the channels.

In my research I am interested in short spikes that have a duration of typically 0.3 to 0.5 seconds. These skipes look similar to Morlet wavelets or Ricker wavelets. I want to detect these spikes with methods of machine learning.

To get rid of that 50 Hz main hum and to also eliminate that constant voltage and very low frequencies, I applied a butterworth band pass filter with these parameters:

  • lowcut = 0.3
  • highcut = 25
  • order = 10
  • nyquistFreq = 128
from scipy.signal import butter, sosfilt

low  = lowcut / nyquistFreq
high = highcut / nyquistFreq

sos  = butter(order, [low, high], btype='bandpass', output='sos')

# data is a numpy array containing the samples of one EEG channel
filtered = sosfilt(sos, data)
# filtered is the filtered version of data

The problem that I have now, is that in the resulting signals there is an overshoot signal at the beginning and also at some positions inside the signal where I have no idea why it appears there. But the more severe problem is, that the spikes I'm interested in are hard to see in the filtered signal. Harder than in the original signal. I hoped, that the spikes would appear more prominent in the filtered signal.


  • Is butterworth a good filter for my task? Which other filter would be better?
  • Which parameters should I use?
  • Did I anything wrong in my python code?

Sorry, I have only very rudimentary knowledge about signal processing. This is not the main topic of my profession. (I come from the research fields machine learning, computer science and statistics.)


1 Answer 1


Let me answer your questions first, then go into details


  1. Yes, butterworth is a good filter (see caveats later)
  2. Your parameters are fine.
  3. Your code is doing what you've intended to do.


There are two things you're trying to do here:

  1. Detrending
  2. 50Hz hum filtering
  • The first thing you should be aware of is zero-phase filtering. Scipy has the function sosfiltfilt that performs that. When applying an IIR filter (such as a butterworth), the phase is going to be altered. Zero-phase filtering is a technique that will prevent the phase alteration (if you're doing off-line processing, which I'm assuming you are).

  • For detrending, there are way more robust methods than high-pass filtering (which will give you problems with transients (such as the spikes you're interested in) and actually might remove crucial information below your cut-off frequency. This paper and associated github has robust de-trending methods you might be interested in.
    If, however, you do wish to use a simple high-pass filter, an order 10 Butterworth is overkill. A second order should be enough. You might need to play around with the cut-off, but 0.3 Hz seems reasonable...

  • For 50Hz filtering, I suggest either a second order notch filter, which will remove the frequencies at 50Hz and 50Hz only (of course a little below and above as well). You can also apply a simple low-pass with an appropriate cut-off (25Hz seems reasonable). That is if you don't care about higher frequencies of course.


  • Try de-trending your signals in a more robust way, then apply a notch filter at 50Hz (or a low pass with appropriate cut-off, 25Hz is probably a good value).
  • If you want to go the easier, detrend-by-filtering route, no need for an order 10 bandpass filter: divide the processing in 2 steps: 2nd order high-pass, then notch filter at 50Hz (or, again a low pass with appropriate cut-off).
  • If you're doing all of this offline, use zero-phase filtering!
  • $\begingroup$ Thank you very much. I will try out your suggestions tomorrow. I do not care about frequencies above 15 Hz and I process the data offline. Thank you for the terms "detrending" and "zero-phase filtering"! This will help me searching for more information. $\endgroup$ Sep 12, 2022 at 18:15
  • $\begingroup$ Great, let me know how that goes. $\endgroup$
    – Jdip
    Sep 12, 2022 at 18:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.