Note
Go to the end to download the full example code or to run this example in your browser via JupyterLite or Binder
EEG Artifact removal using ATAR¶
ATAR: Automatic and Tunable Artifact Removal Algorithm
ATAR Algorithm - Automatic and Tunable Artifact Removal Algorithm for EEG Signal.
Apply ATAR on short windows of signal (single channel):
Signal is decomposed in smaller overlapping windows and reconstructed after correcting using overlap-add method.
For more details, check [1]_
Operating Modes
1. Soft Thresholding
\[ \begin{align}\begin{aligned}\lambda_s (w) &= w & \quad \text{if } |w|<\theta_{\gamma}\\ &= \theta_{\alpha} \frac{1 - e^{\alpha w}}{1 + e^{\alpha w}} & \quad \text{otherwise}\end{aligned}\end{align} \]2. Elimination
\[ \begin{align}\begin{aligned}\lambda_e (w) &= w & \quad \text{if } |w| \le \theta_{\alpha}\\ &= 0 & \quad \text{otherwise}\end{aligned}\end{align} \]3. Linear Attenuation
\[ \begin{align}\begin{aligned}\lambda_a (w) &= w & \quad \text{if } |w| \le \theta_{\alpha}\\ &= sgn(w) \theta_{\alpha} \Big( 1 - \frac{|w| - \theta_{\alpha}}{\theta_{\beta}-\theta_{\alpha}} \Big) & \quad \text{if } \theta_{\alpha} < |w| \le \theta_{\beta}\\ &= 0 & \quad \text{otherwise}\end{aligned}\end{align} \]Computing Threshold
\(f_{\beta}(r) = k_2 \cdot exp \Big(-\beta \frac{w_{max}}{k_2} \times \frac{r}{2} \Big)\)
\(\theta_{\alpha} = f_{\beta}(r) \quad \text{if } f_{\beta}(r) \ge k_1\) otherwise \(\theta_{\alpha} = k_1\)
\(\theta_{\gamma} = g_f \times \theta_{\alpha}\) , where a default value for ‘g_f = 0.8’ For Soft-threshold
\(\theta_{\beta} = b_f \times \theta_{\alpha}\) , where a default value for ‘b_f = 2’ For Linear Attenuation
# Importing libraries/spkit
import numpy as np
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore")
import spkit as sp
print('spkit version :', sp.__version__)
spkit version : 0.0.9.7
Load and filter EEG Signal¶
# Load sample EEG Data ( 16 sec, 128 smapling rate, 14 channel)
# Filter signal (with IIR highpass 0.5Hz)
X, fs, ch_names = sp.data.eeg_sample_14ch()
Xf = sp.filter_X(X.copy(),fs=128.0, band=[0.5], btype='highpass',ftype='SOS')
print(Xf.shape)
(2048, 14)
Artifact removal using ATAR: Single Channel
x = Xf[:,0]
xc1 = sp.eeg.ATAR(x,wv='db3', winsize=128, thr_method='ipr',beta=0.1, k1=10, k2=100,OptMode='soft',verbose=1)
xc2 = sp.eeg.ATAR(x,wv='db3', winsize=128, thr_method='ipr',beta=0.1, k1=10, k2=100,OptMode='linAtten',verbose=1)
xc3 = sp.eeg.ATAR(x,wv='db3', winsize=128, thr_method='ipr',beta=0.1, k1=10, k2=100,OptMode='elim',verbose=1)
3%|▓ |2112\65| Mode : soft
6%|▓▓▓ |2112\129| Mode : soft
9%|▓▓▓▓ |2112\193| Mode : soft
12%|▓▓▓▓▓▓ |2112\257| Mode : soft
15%|▓▓▓▓▓▓▓ |2112\321| Mode : soft
18%|▓▓▓▓▓▓▓▓▓ |2112\385| Mode : soft
21%|▓▓▓▓▓▓▓▓▓▓ |2112\449| Mode : soft
24%|▓▓▓▓▓▓▓▓▓▓▓▓ |2112\513| Mode : soft
27%|▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\577| Mode : soft
30%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\641| Mode : soft
33%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\705| Mode : soft
36%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\769| Mode : soft
39%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\833| Mode : soft
42%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\897| Mode : soft
45%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\961| Mode : soft
48%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1025| Mode : soft
51%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1089| Mode : soft
54%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1153| Mode : soft
57%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1217| Mode : soft
60%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1281| Mode : soft
63%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1345| Mode : soft
66%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1409| Mode : soft
69%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1473| Mode : soft
72%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1537| Mode : soft
75%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1601| Mode : soft
78%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1665| Mode : soft
81%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1729| Mode : soft
84%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1793| Mode : soft
87%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1857| Mode : soft
90%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1921| Mode : soft
93%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1985| Mode : soft
97%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\2049| Mode : soft
100%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓|2112\2113| Mode : soft
Done!
3%|▓ |2112\65| Mode : linAtten
6%|▓▓▓ |2112\129| Mode : linAtten
9%|▓▓▓▓ |2112\193| Mode : linAtten
12%|▓▓▓▓▓▓ |2112\257| Mode : linAtten
15%|▓▓▓▓▓▓▓ |2112\321| Mode : linAtten
18%|▓▓▓▓▓▓▓▓▓ |2112\385| Mode : linAtten
21%|▓▓▓▓▓▓▓▓▓▓ |2112\449| Mode : linAtten
24%|▓▓▓▓▓▓▓▓▓▓▓▓ |2112\513| Mode : linAtten
27%|▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\577| Mode : linAtten
30%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\641| Mode : linAtten
33%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\705| Mode : linAtten
36%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\769| Mode : linAtten
39%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\833| Mode : linAtten
42%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\897| Mode : linAtten
45%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\961| Mode : linAtten
48%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1025| Mode : linAtten
51%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1089| Mode : linAtten
54%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1153| Mode : linAtten
57%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1217| Mode : linAtten
60%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1281| Mode : linAtten
63%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1345| Mode : linAtten
66%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1409| Mode : linAtten
69%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1473| Mode : linAtten
72%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1537| Mode : linAtten
75%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1601| Mode : linAtten
78%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1665| Mode : linAtten
81%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1729| Mode : linAtten
84%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1793| Mode : linAtten
87%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1857| Mode : linAtten
90%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1921| Mode : linAtten
93%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1985| Mode : linAtten
97%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\2049| Mode : linAtten
100%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓|2112\2113| Mode : linAtten
Done!
3%|▓ |2112\65| Mode : elim
6%|▓▓▓ |2112\129| Mode : elim
9%|▓▓▓▓ |2112\193| Mode : elim
12%|▓▓▓▓▓▓ |2112\257| Mode : elim
15%|▓▓▓▓▓▓▓ |2112\321| Mode : elim
18%|▓▓▓▓▓▓▓▓▓ |2112\385| Mode : elim
21%|▓▓▓▓▓▓▓▓▓▓ |2112\449| Mode : elim
24%|▓▓▓▓▓▓▓▓▓▓▓▓ |2112\513| Mode : elim
27%|▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\577| Mode : elim
30%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\641| Mode : elim
33%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\705| Mode : elim
36%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\769| Mode : elim
39%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\833| Mode : elim
42%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\897| Mode : elim
45%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\961| Mode : elim
48%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1025| Mode : elim
51%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1089| Mode : elim
54%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1153| Mode : elim
57%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1217| Mode : elim
60%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1281| Mode : elim
63%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1345| Mode : elim
66%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1409| Mode : elim
69%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1473| Mode : elim
72%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1537| Mode : elim
75%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1601| Mode : elim
78%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1665| Mode : elim
81%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1729| Mode : elim
84%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1793| Mode : elim
87%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1857| Mode : elim
90%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1921| Mode : elim
93%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\1985| Mode : elim
97%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ |2112\2049| Mode : elim
100%|▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓|2112\2113| Mode : elim
Done!
Artifact removal using ATAR: Multi-Channel
XR = sp.eeg.ATAR(Xf.copy(),verbose=0)
print(XR.shape)
(2048, 14)
Plots¶
t = np.arange(Xf.shape[0])/fs
plt.figure(figsize=(10,5))
plt.subplot(111)
plt.plot(t,x, label='$x$: raw EEG - single channel')
plt.plot(t,xc1,label=r'$x_{c1}$: Soft Thresholding')
plt.plot(t,xc2,label=r'$x_{c2}$: Linear Attenuation')
plt.plot(t,xc3,label=r'$x_{c3}$: Elimination')
plt.xlim([9,12])
plt.ylim([-200,200])
plt.legend(bbox_to_anchor=(0.5,0.99),ncol=2,fontsize=8)
plt.grid()
plt.title(r'ATAR Algorithm')
plt.xlabel('time (s)')
plt.show()
plt.figure(figsize=(12,8))
plt.subplot(211)
plt.plot(t,XR+np.arange(-7,7)*200)
plt.xlim([t[0],t[-1]])
plt.xlabel('time (sec)')
plt.yticks(np.arange(-7,7)*200,ch_names)
plt.grid()
plt.title('XR: Corrected Signal')
plt.subplot(212)
plt.plot(t,(Xf-XR)+np.arange(-7,7)*200)
plt.xlim([t[0],t[-1]])
plt.xlabel('time (sec)')
plt.yticks(np.arange(-7,7)*200,ch_names)
plt.grid()
plt.title('Xf - XR: Difference (removed signal)')
plt.suptitle('ATAR: Soft Thresholding (default mode)')
plt.tight_layout()
plt.grid()
plt.show()
plt.figure(figsize=(12,5))
plt.plot(t,Xf+np.arange(-7,7)*200)
plt.xlim([t[0],t[-1]])
plt.xlabel('time (sec)')
plt.yticks(np.arange(-7,7)*200,ch_names)
plt.grid()
plt.title('Xf: 14 channel - EEG Signal (filtered)')
plt.tight_layout()
plt.grid()
plt.show()
ATAR: Linear Attenuation Mode¶
XR = sp.eeg.ATAR(Xf.copy(),verbose=0,OptMode='linAtten')
print(XR.shape)
t = np.arange(Xf.shape[0])/fs
plt.figure(figsize=(15,5))
plt.subplot(121)
plt.plot(t,XR+np.arange(-7,7)*200)
plt.xlim([t[0],t[-1]])
plt.xlabel('time (sec)')
plt.yticks(np.arange(-7,7)*200,ch_names)
plt.grid()
plt.title('XR: Corrected Signal')
plt.subplot(122)
plt.plot(t,(Xf-XR)+np.arange(-7,7)*200)
plt.xlim([t[0],t[-1]])
plt.xlabel('time (sec)')
plt.yticks(np.arange(-7,7)*200,ch_names)
plt.grid()
plt.title('Xf - XR: Difference (removed signal)')
plt.suptitle('ATAR: Linear Attenuation Mode')
plt.tight_layout()
plt.show()
(2048, 14)
ATAR - Elimination Mode¶
XR = sp.eeg.ATAR(Xf.copy(),verbose=0,OptMode='elim')
print(XR.shape)
t = np.arange(Xf.shape[0])/fs
plt.figure(figsize=(15,5))
plt.subplot(121)
plt.plot(t,XR+np.arange(-7,7)*200)
plt.xlim([t[0],t[-1]])
plt.xlabel('time (sec)')
plt.yticks(np.arange(-7,7)*200,ch_names)
plt.grid()
plt.title('XR: Corrected Signal')
plt.subplot(122)
plt.plot(t,(Xf-XR)+np.arange(-7,7)*200)
plt.xlim([t[0],t[-1]])
plt.xlabel('time (sec)')
plt.yticks(np.arange(-7,7)*200,ch_names)
plt.grid()
plt.title('Xf - XR: Difference (removed signal)')
plt.suptitle('ATAR: Elimination Mode')
plt.tight_layout()
plt.show()
(2048, 14)
Total running time of the script: (0 minutes 1.528 seconds)
Related examples
ATAR: Automatic and Tunable Artifact Removal Algorithm
EEG Artifact removal using ICA
Independed Principle Component analysis