如何使用 Python 正确计算 EEG 频带?

信息处理 频率 Python 脑电图
2021-12-26 08:06:03

所以我正在尝试用 Python 计算 EEG(25 个通道,512 个采样率,248832/通道)波段(alpha、beta、gamma 等)。我设法做到这一点:首先用一个看起来像这样的巴特沃斯滤波器过滤信号:

def butter_bandpass_filter(data, lowcut, highcut, fs, order=2):
    nyq = 0.5 * fs
    low = lowcut /nyq
    high = highcut/nyq
    b, a = butter(order, [low, high], btype='band')
    #print(b,a)
    y = lfilter(b, a, data)
    return y

我使用了滤波器,低设置为 0.1,高设置为 80。然后我计算信号的 fft 并将其存储在 fft1 中,我再次使用胡桃滤波器来提取每个频段的频率,它看起来像这样:

for i in np.arange(n):
    alpha1 = butter_bandpass_filter(fft1[i, :], 8.1, 12.0, 256)
    beta1 = butter_bandpass_filter(fft1[i, :], 16.0, 36.0, 256)
    gamma1 = butter_bandpass_filter(fft1[i, :], 36.1, 80, 256)
    delta1 = butter_bandpass_filter(fft1[i, :], 0.0, 4.0, 256)
    sigma1 = butter_bandpass_filter(fft1[i, :], 12.1, 16.0, 256)
    theta1 = butter_bandpass_filter(fft1[i, :], 4.1, 8.0, 256)
    sumalpha1 = sum(abs(alpha1))
    sumbeta1 = sum(abs(beta1))
    sumgamma1 = sum(abs(gamma1))
    sumdelta1 = sum(abs(delta1))
    sumsigma1 = sum(abs(sigma1))
    sumtheta1 = sum(abs(theta1))
    objects = [sumalpha1, sumbeta1, sumgamma1, sumdelta1, sumsigma1, sumtheta1]
    N = len(objects)
    ra = range(N)
    plt.title(signal_labels[i])
    plt.autoscale
    somestuffneeded = np.arange(6)
    ticks = ['alpha','beta','gamma','delta','sigma','theta']
    plt.xticks(somestuffneeded, ticks)
    plt.bar(ra, objects)
    plt.show()

问题是我对伽玛值很高(它代表了一种高认知活动,这个人显然没有)。第一个通道的结果是: 在此处输入图像描述

谁能指出一个更好的解决方案/对什么是错的有任何想法/可以告诉我什么是错的?我使用的过滤器不正确吗?谢谢!

3个回答

我相信有一种更简单的方法可以使用numpy.fft.rfftand来做到这一点numpy.fft.rfftfreq

在下面的示例中,我在 0.0 和 100.0 之间以 512 Hz 采样了两秒的随机数据。我在下面绘制频带幅度,但如果你想要功率,它只是值的平方。

我认为您看到 Gamma 值过大的原因是您的 gamma 范围比其他范围大得多,并且您正在获取该范围内所有值的总和。如果您要将一组 EEG 的伽马值与另一组(相对安培/功率)进行比较,这很好,但如果您只是查看一组并想比较伽马与阿尔法,则不行。

如果您只想知道此人处于何种 EEG 状态,您可以np.max使用np.mean. 然后哪个波段的最大值会告诉你这个人的状态。

import numpy as np

fs = 512                                # Sampling rate (512 Hz)
data = np.random.uniform(0, 100, 1024)  # 2 sec of data b/w 0.0-100.0

# Get real amplitudes of FFT (only in postive frequencies)
fft_vals = np.absolute(np.fft.rfft(data))

# Get frequencies for amplitudes in Hz
fft_freq = np.fft.rfftfreq(len(data), 1.0/fs)

# Define EEG bands
eeg_bands = {'Delta': (0, 4),
             'Theta': (4, 8),
             'Alpha': (8, 12),
             'Beta': (12, 30),
             'Gamma': (30, 45)}

# Take the mean of the fft amplitude for each EEG band
eeg_band_fft = dict()
for band in eeg_bands:  
    freq_ix = np.where((fft_freq >= eeg_bands[band][0]) & 
                       (fft_freq <= eeg_bands[band][1]))[0]
    eeg_band_fft[band] = np.mean(fft_vals[freq_ix])

# Plot the data (using pandas here cause it's easy)
import pandas as pd
df = pd.DataFrame(columns=['band', 'val'])
df['band'] = eeg_bands.keys()
df['val'] = [eeg_band_fft[band] for band in eeg_bands]
ax = df.plot.bar(x='band', y='val', legend=False)
ax.set_xlabel("EEG band")
ax.set_ylabel("Mean band Amplitude")

在此处输入图像描述

好的,所以对于那些感兴趣的人,我已经使用问题描述中描述的巴特沃斯滤波器计算了脑电图的频带。在脑电图分析课上,我得出的结论是,频带是从脑电图的 fft 计算出来的,这还不够,因为 fft 应该与其共轭相乘!所以这是python中的代码,它计算总功率、相对和绝对频带。

alpha1 = np.zeros((n, g.getNSamples()[0]))
beta1 = np.zeros((n, g.getNSamples()[0]))
gamma1 = np.zeros((n, g.getNSamples()[0]))
delta1 = np.zeros((n, g.getNSamples()[0]))
sigma1 = np.zeros((n, g.getNSamples()[0]))
theta1 = np.zeros((n, g.getNSamples()[0]))
#I only used the channels with the following indexes
for i in [1,5,10,15,18]:
    #note that fft1 is precomputed in another part of the code i used
    ccFFT1 = fft1[i,:]*np.conjugate(fft1[i,:]) 
    #the butterworth filter is used to compute each frequency band according to its featuring freq.
    alpha1 = butter_bandpass_filter(ccFFT1[:], 8.1, 12.0, 512)
    beta1 = butter_bandpass_filter(ccFFT1[:], 16.0, 36.0, 512)
    gamma1 = butter_bandpass_filter(ccFFT1[:], 36.1, 80, 512)
    delta1 = butter_bandpass_filter(ccFFT1[:], 0.0, 4.0, 512)
    sigma1 = butter_bandpass_filter(ccFFT1[:], 12.1, 16.0, 512)
    theta1 = butter_bandpass_filter(ccFFT1[:], 4.1, 8.0, 512)
    #this sums frequencies for each band 
    sumalpha1 = sum(abs(alpha1))
    sumbeta1 = sum(abs(beta1))
    sumgamma1 = sum(abs(gamma1))
    sumdelta1 = sum(abs(delta1))
    sumsigma1 = sum(abs(sigma1))
    sumtheta1 = sum(abs(theta1))
    #compute the total power
    totalPower = sumalpha1+sumbeta1+sumgamma1+sumdelta1+sumsigma1+sumtheta1
    #storing them in objects to plot
    #this computes the relativ power!
    objects = [sumalpha1/totalPower, sumbeta1/totalPower, sumgamma1/totalPower, sumdelta1/totalPower, sumsigma1/totalPower, sumtheta1/totalPower]
    #to plot the absolute power, don't divide each sum through the total power
    N = len(objects)
    ra = range(N)
    plt.title(str(signal_labels[i])+" relativ")
    plt.autoscale
    somestuffneeded = np.arange(6)
    ticks = ['alpha','beta','gamma','delta','sigma','theta']
    plt.xticks(somestuffneeded, ticks)
    plt.bar(ra, objects)
    plt.show()

希望这可以帮助!如果有任何关于使用 python 计算频带的任务,我很高兴回答问题!

我会为此使用 scipy.signal.welch :

def calc_bands_power(x, dt, bands):
    from scipy.signal import welch
    f, psd = welch(x, fs=1. / dt)
    power = {band: np.mean(psd[np.where((f >= lf) & (f <= hf))]) for band, (lf, hf) in bands.items()}
    return power

另外,mne-python是一个很好的脑电图/脑电图分析包,值得一看!