[1]:
from gcpds.utils import loaddb
from matplotlib import pyplot as plt
import numpy as np
from scipy.fftpack import fft, fftfreq, fftshift
from scipy.signal import welch
from datetime import datetime, timedelta

db = loaddb.BCI_CIV_2a('BCI2a_database')
db.load_subject(1)
data, _ = db.get_data()
fs = db.metadata['sampling_rate']
data.shape
[1]:
(273, 22, 1750)

Frequency filters

[2]:
from gcpds.filters import frequency as flt

The input data format use the default trials,channels,time and the value of the sampling frequency in Hertz.

[3]:
print(f"{data.shape} -> (trials,channels,time)")
print(f"{fs} Hz -> Sampling frequency")
(273, 22, 1750) -> (trials,channels,time)
250 Hz -> Sampling frequency

Predefined filters

All predefined filters have the order N=5 (for bandpass) and the quality factor Q=3 (notch).

There are some predefined filters: notch60, band545, band330, band245, band440, band150, band713, band1550 and band550

There is 2 notch filters: notch50 and notch60

[112]:
filtered_data = flt.notch60(data, fs=fs)
data.shape, filtered_data.shape
[112]:
((273, 22, 1750), (273, 22, 1750))

9 EEG common use filters: band545, band330, band245, band440, band150, band713, band1550, band550, band1100

[96]:
flt.band545(data, fs=fs)  # bandpass 5-45 Hz
flt.band1550(data, fs=fs);  # bandpass 15-50 Hz

and 4 EEG waves filters: delta, theta, alpha, beta, mu (an alpha alias).

Filter

Low frequency

High frequency

Order

delta

2 Hz

5 Hz

5

theta

5 Hz

8 Hz

5

alpha, mu

8 Hz

12 Hz

5

beta

13 Hz

30 Hz

5

[97]:
flt.delta(data, fs=fs)  # bandpass for delta waves
flt.alpha(data, fs=fs);  # bandpass for alpha waves
[110]:
plt.figure(figsize=(15, 5), dpi=90)

t = np.arange(data.shape[2]) / fs
plt.plot(t, data[0, 0], alpha=0.5)
plt.plot(t, flt.theta(data, fs=fs)[0, 0])

plt.title('Theta wave')
plt.ylabel('Amplitude')
plt.xlabel('Time [s]')
plt.show()
../_images/notebooks_01-frequency_13_0.png

Recompile predefined filters

In order to change the default order or the quality factor for predefined filters we must re-compile the filters first.

[3]:
flt.compile_filters(N=10, Q=5)
[3]:
flt.band545(data, fs=fs)  # bandpass 5-45 Hz and order N=10
flt.band1550(data, fs=fs)  # bandpass 15-50 Hz and order N=10
flt.notch60(data, fs=fs);  # quality factor Q=5

Custom filters

A custom bandpass, lowpass, hihghpass and notch filter can be defined with GenericButterBand, GenericButterLowPass, GenericButterHighPass and GenericNotch respectively.

[3]:
band880 = flt.GenericButterBand(f0=8, f1=80, N=7)
band880(data, fs=250);

notch55 = flt.GenericNotch(f0=55, Q=5)
notch55(data, fs=250);

low100 = flt.GenericButterLowPass(f0=100, N=5)
low100(data, fs=250);

high100 = flt.GenericButterHighPass(f0=100, N=5)
high100(data, fs=250);

Filters set

In order to apply a set of filters to the same signal, FiltersSet can be defined to reduce the implementation.

[6]:
my_set = flt.FiltersSet(flt.notch60, flt.band545)
my_set(data, fs=250);

Input shape

All filters can work with multidimensional arrays, by default the filter is applied to the index -1, this can be changed with the argument axis.

[12]:
data = np.random.random((10,150,8,100))
flt.notch60(data).shape
[12]:
(10, 150, 8, 100)
[13]:
data = np.random.random((10,150,8,100))
flt.notch60(data, axis=1).shape
[13]:
(10, 150, 8, 100)

Filtering time series

Is possible to use vectors of timestamps, so internally the sampling frequency is calculated, also, is possible to use a vector with the start and the end (in seconds).

[3]:
data = np.random.random(1000)
t = np.linspace(datetime.now().timestamp(), (datetime.now() + timedelta(seconds=15)).timestamp(), 1000)

flt.alpha(data, timestamp=t).shape
[3]:
(1000,)
[6]:
flt.alpha(data, timestamp=[0, 15]).shape  # Start and end in seconds
[6]:
(1000,)

About sample frequency

This filtering approach needs the sampling frequency in every call in order to apply the filter, this feature enables to change dynamically between databases with others characteristics.


References