0
$\begingroup$

I am trying to plot windows of acquired data from an LSL-compatible system. For the example below, let's consider 1-second window of a 64 channel EEG system. In practice, I use shorter 0.2-window, but the problematic behavior is present also with 1-second window.

The acquired data is a numpy array of shape (samples, channels), thus in this example, with a 512 Hz sampling frequency: (512, 64).

Before plotting the data, it has to be preprocessed with a bandpass filter. Let's consider a [1, 40] Hz bandpass filter:

from scipy.signal import butter

lowcut = 1
highcut = 40
fs = 512

low = lowcut / (0.5 * fs)
high = highcut / (0.5 * fs)
sos = butter(4, [low, high], btype='band', output='sos', fs=fs)

As each window will be plot on the same expanding graph, the initial and final conditions of each window are required. Thus, the zi parameter is passed to scipy.signal.sosfilt() to retrieve the zf final conditions. The system is initialized with a resting state initial condition.

zi = np.zeros((sos.shape[0], 2, n)) # n = 64 - number of channels

To filter the data, I then apply:

data_filtered, zf = sosfilt(sos, data, 0, zi)

I don't see what I am doing wrong, and yet the output is diverging. By the way, I tried order 2, 4 and 6; and it does change the output but still diverge.

Inputted window of 1 channel:

input

Output window of the same channel:

output

After some research, I believe I should not specify the fs parameter to scipy.signal.butter() when passing the cutting frequencies as normalized from 0 to 1, where 1 is the Nyquist frequency. Nevertheless, the output is different but still diverging.

sos = butter(2, [1, 40], btype='band', output='sos', analog=False, fs=fs)

enter image description here

$\endgroup$

1 Answer 1

1
$\begingroup$

Your signal has a massive DC bias so your output is dominated by the step response of the band pass filter. It will eventually get there but it's going to take a really long time.

Initialize your state with zi = -26040*sosfilt_zi(). See my answer to your other question today.

EDIT

On second thought: while you can fix some of this in software, you probably shouldn't. Your DC bias is about 500 times bigger than your actual signal. A bias that large is typically a sign that something went seriously wrong upstream: could be sensor, calibration, analog front end, ADC, digital pre-processing, data acquisition etc.

A large DC bias can cause a lot of trouble. For example:

  1. You are loosing 50dB+ of dynamic range
  2. If the DC bias drifts by even a tiny amount, the effect will swamp or obscure your desired signal.

Instead of filtering I would recommend trying to identify the root cause of the bias and fix (or improve)it. Processing can only do so much: bad_data_in can only lead to bad_data_out. It might be a little less bad , but it's probably still bad.

$\endgroup$
3
  • $\begingroup$ Now it starts to make all sense!! I'll try! $\endgroup$
    – Mathieu
    Commented Jun 4, 2021 at 14:35
  • $\begingroup$ @Mathieu, sorry, I think I gave you bad advice. Please read the edit. Filtering isn't the right answer here, no matter how you do it. $\endgroup$
    – Hilmar
    Commented Jun 4, 2021 at 17:17
  • $\begingroup$ Thank you for the additional thoughts. Unfortunately, I can not do much about the DC bias. The system(s) I am using are EEG systems, which are known to have a very large DC bias always. I don't have access to the companies hardware schematics or software of the amplifiers anyway. However, I got the filtering to work on 3-4 consecutive acquisition windows of 200 ms perfectly. $\endgroup$
    – Mathieu
    Commented Jun 4, 2021 at 17:40

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.