使用ICA消除EEG信号的眨眼

时间:2018-10-30 19:37:45

标签: python scikit-learn time-series

我是scikit-learn的新手,但我想消除单个EEG通道内的眨眼(噪声峰值)。  我已经在互联网上进行搜索,但只看到有关MNE,PyEEG或其他Python模块的更复杂的读物。我只想要一些简单且仅依赖sklearn的东西。这是我的代码:

video_shader_enable = "true"
input_overlay_hide_in_menu = "false"
xmb_alpha_factor = "39"
menu_shader_pipeline = "0"
custom_viewport_width = "1161"
custom_viewport_height = "981"
custom_viewport_x = "205"
custom_viewport_y = "28"
aspect_ratio_index = "22"
input_overlay_opacity = "0.930000"

Here is the result of the code

我期望的是将两个部分分开,一个更清晰的脑电信号和眨眼。我不知道是什么问题。有人可以伸出援手吗?

2 个答案:

答案 0 :(得分:2)

您是否注意到您的“组件”完全按比例缩放了原始信号并颠倒了?那是因为您获得的组件比信号还多。

您需要执行以下步骤:

  1. 所有个EEG频道输入ICA
  2. 手动删除包含眨眼或其他伪影的组件
  3. 使用逆变换重建

让我们详细看一下步骤2:为什么要手动删除组件? ICA对眨眼一无所知。它基于统计度量将信号分为多个分量。如果幸运的话,其中一些组件看起来就像眨眼一样。

到目前为止,还可以,但是真正的问题是未定义组件的顺序。运行ICA,您可能会发现组件1包含眨眼。再次运行它,它们在组件3中。再次,它们在组件2和5中...

无法预先知道要删除哪些组件以及要删除多少组件。这就是为什么您需要在每次运行时手动将其告知算法。

在看起来像这样的代码中:

# Use all channels - they will contain eye blinks to varying degrees
X = f1ep1_data[:, :]

# run ICA on signal
ica = FastICA(n_components=x.shape[1])  # we want *all* the components
ica.fit(X)

# decompose signal into components
components = ica.fit_transform(X)

# plot components and ask user which components to remove
# ...
remove_indices = [0, 1, 3]  # pretend the user selected components 0, 1, and 3

# "remove" unwanted components by setting them to 0 - simplistic but gets the job done
components[:, remove_indices] = 0

#reconstruct signal
X_restored = ica.inverse_transform(components)

机会是,您对手动步骤不满意。倒霉:)在2013年,没有健壮的自动算法可以标记眨眼组件。我认为这并没有改变,但是如果有什么变化,您会发现它是特定于域的软件包之一,例如MNE或PyEEG。


但是,如果您碰巧有EOG录音,那还是有希望的!存在A fully automated correction method of EOG artifacts in EEG recordings。该方法基于规范相关或回归(我不记得详细信息),但是您需要将EOG信号与EEG一起记录。


我用模拟的“ EEG”数据创建了一个工作示例。 数据包含三个通道:额叶,中央和顶叶。背面的10 Hz alpha活动最强,正面的闪烁状尖峰最强。

希望该示例更好地说明了如何从多通道数据中删除组件。

import numpy as np
import scipy.signal as sps
from sklearn.decomposition import FastICA
import matplotlib.pyplot as plt

np.random.seed(42)

n = 1000
fs = 100
noise = 3

# simulate EEG data with eye blinks
t = np.arange(n)
alpha = np.abs(np.sin(10 * t / fs)) - 0.5
alpha[n//2:] = 0
blink = np.zeros(n)
blink[n//2::200] += -1
blink = sps.lfilter(*sps.butter(2, [1*2/fs, 10*2/fs], 'bandpass'), blink)

frontal = blink * 200 + alpha * 10 + np.random.randn(n) * noise
central = blink * 100 + alpha * 15 + np.random.randn(n) * noise
parietal = blink * 10 + alpha * 25 + np.random.randn(n) * noise

eeg = np.stack([frontal, central, parietal]).T  # shape = (100, 3)

# plot original data
plt.subplot(3, 1, 1)
plt.plot(frontal + 50)
plt.plot(central + 100)
plt.plot(parietal + 150)
plt.yticks([50, 100, 150], ['Fz', 'Cz', 'Pz'])
plt.ylabel('original data')

# decompose EEG and plot components
ica = FastICA(n_components=3)
ica.fit(eeg)
components = ica.transform(eeg)

plt.subplot(3, 1, 2)
plt.plot([[np.nan, np.nan, np.nan]])  # advance the color cycler to give the components a different color :)
plt.plot(components + [0.5, 1.0, 1.5])
plt.yticks([0.5, 1.0, 1.5], ['0', '1', '2'])
plt.ylabel('components')

# looks like component #2 (brown) contains the eye blinks
# let's remove them (hard coded)!
components[:, 2] = 0

# reconstruct EEG without blinks
restored = ica.inverse_transform(components)

plt.subplot(3, 1, 3)
plt.plot(restored + [50, 100, 150])
plt.yticks([50, 100, 150], ['Fz', 'Cz', 'Pz'])
plt.ylabel('cleaned data')

enter image description here

答案 1 :(得分:0)

如果您要处理的是单通道EEG,以下方法可能是一种易于实现的方法:

1)使用简单的基于阈值的峰值检测来检测信号 x 中的闪烁(您可能必须通过查看几个闪烁实例的信号来找出它)。 Neurosky,Muse等设备带有API来检测眨眼。您可以根据需要使用它。

2)拍摄与眨眼相对应的帧( xb )。在其上拟合一条平滑线( xbs )。

3)从眨眼( xb )中减去平滑线( xbs ),并向其添加信号平均值。让我们称之为 xbc

4)在原始信号 x 中用 xbc 代替 xb