运动想象MI:带通滤波的Python实现

运动想象MI:带通滤波的Python实现

  • 0. 引言
  • 1. 代码介绍
    • 1.1 实现方法(1)
    • 1.2 实现方法(2)
  • 2. 函数介绍
  • 3. 滤波函数介绍
  • 4. 总结

0. 引言

在执行运动想象任务时,由于实际采集实验不是在完全屏蔽的环境中进行的,受试者所处的环境复杂容易受到多种外界干扰,因此在对数据集进行处理之前,需要对采集的数据进行8-40Hz带通滤波,保留与运动想象有关的频率带。
除此之外,在对运动想象任务分类时,当前的诸多先进模型一般将采集得到的带通滤波数据根据频率带的不同分为不同组数据,一般以4Hz为一个频率带进行区分,此时也需要带通滤波当前诸多模型大多是多通道、多尺度的CNN模型!!!

然而,网上查找了诸多文献,但是却没有带通滤波的准确的实现。因此,写了这篇文章来介绍如何使用Python实现带通滤波。

实验环境

Python  3.9
scipy   1.11.1

这里给出一个scipy代码的介绍文档:
Scipy介绍文档:https://scipy-cookbook.readthedocs.io/items/ButterworthBandpass.html

1. 代码介绍

为了防止浪费大家的时间,这里先写出了带通滤波的Python实现,后面会进行细致的介绍。

1.1 实现方法(1)

# 例:实现4-32Hz的带通滤波 采样频率为200Hz
from scipy import signal

# 设置需要采样的数据
data = np.ndarray([200, 20, 3840]) 

# 设置采样频率
Fs = 200
# 其中第一个4表示阶数  []里面的分别表示滤波的下限和上限
b, a = signal.butter(4, [4, 32], 'bandpass',fs=Fs) 

# 对上述数据进行带通滤波
data = signal.filtfilt(b, a, data, axis=-1)

通过以上代码,即可实现一个完整的带通滤波程序。大家需要相关操作的可以自行模仿!!!没兴趣往下看的到这里也就可以结束了,下面介绍些相关的内容。

1.2 实现方法(2)

如果不再后面设置fs=Fs,需要按照下面的代码实现带通滤波4-32Hz的功能。

# 例:实现4-32Hz的带通滤波 采样频率为200Hz
from scipy import signal

# 设置需要采样的数据
data = np.ndarray([200, 20, 3840]) 

# 设置采样频率
Fs = 200
# 其中第一个4表示阶数  []里面的分别表示滤波的下限和上限
b, a = signal.butter(4, [4/(Fs/2), 32/(Fs/2)], 'bandpass') 

# 对上述数据进行带通滤波
data = signal.filtfilt(b, a, data, axis=-1)

2. 函数介绍

在上述代码中,引起争议的函数往往是signal.butter()函数,有很多作者直接在[]里面写上4和32,但是最后不给fs赋值!!,这是完全错误的做法! 为了明白为什么会错误,以下对signal.butter()函数进行简单介绍:

signal.butter(N, Wn, btype='low', analog=False, output='ba', fs=None)
# 设计N阶数字或模拟巴特沃斯滤波器并且返回滤波器系数向量,在求出系数后对信号进行滤波时需要用scipy.signal.filtfilt()。
---------------------------------------------------------------------
# 参数
 - N: 滤波器的阶数。对于“bandpass”和“bandstop”滤波器,最终二阶部分(“os”)矩阵的最终阶为“2*N”,其中“N”是所需系统的二阶部分的数量。
 - Wn: array数组。 临界频率。对于低通和高通滤波器,Wn是标量;对于带通滤波器和带阻滤波器,Wn是长度为2的序列, 例如:[4,32]。
     对于Butterworth 滤波器,这是增益下降到通带增益的1/sqrt(2)的点(“-3dB点”)。
     对于数字滤波器,如果没有指定“fs”,则“Wn”单元从0归一化为1,其中1是奈奎斯特频率(因此“Wn“处于半周期/样本,并被定义为2*临界频率/“fs”)。
     对于模拟滤波器,“Wn”是一个角频率(例如rad/s)。
 - btype:'lowpass', 'highpass', 'bandpass', 'bandstop'},可选。滤波器的类型。默认值为“lowpass”。
 - analog: bool,可选。当为True时,返回模拟滤波器,否则返回数字滤波器。
 - output: 'ba''zpk''sos'},可选。
     输出类型:分子/分母('ba')、零点('zpk')或二阶部分('sos')。默认为“ba”表示向后兼容性,但“sos”应用于通用筛选。
 - fs: float, optional。
     数字系统的采样频率。

注意:如果没有指定“fs”,即:如果fs=None,则对于Wn=[low, high],实际带通为 [low*1/2, high*1/2] ,如果指定了fs,即fs=Fs,则对于Wn=[low, high],实际带通为[low/fs, high/fs]
而对于我们要实现的带通滤波而言,一定要带上频率!!!即;最终带通的频率应为频率/采样频率。

3. 滤波函数介绍

在上述代码中,最终实现了Butterworth 带通滤波器。下面简单介绍下Butterworth 带通滤波器。关于Butterworth 带通滤波器更细致的东西大家可以观看博客:什么是巴特沃斯滤波器。

巴特沃斯(Butterworth)滤波器是是电子滤波器的一种,一种具有最大平坦幅度响应低通滤波器,它在通信领域里已有广泛应用,在电测中也具有广泛的用途,可以作检测信号的滤波器。
Butterworth 的传递函数:
运动想象MI:带通滤波的Python实现_第1张图片
Butterworth 的设计:
运动想象MI:带通滤波的Python实现_第2张图片
Butterworth 的算法:

Butterworth 滤波器的幅值响应在通带内具有最大平坦度,并在整体上呈现单调性。这种平滑是以降低滚降陡度为代价的。对于给定滤波器阶数,椭圆和 Chebyshev 滤波器通常提供更陡的滚降

butter 使用一个五步算法:

  1. 它使用函数 buttap 查找低通模拟原型的极点、零点和增益。
  2. 它将极点、零点和增益转换为状态空间形式。
  3. 如果需要,它使用状态空间变换将低通滤波器转换为具有所需频率约束的带通、高通或带阻滤波器。
  4. 对于数字滤波器设计,它使用 bilinear通过具有频率预修正的双线性变换将模拟滤波器转换为数字滤波器。经过仔细调整频率,模拟滤波器和数字滤波器在 Wn 或 w1 和 w2处可具有相同的频率响应幅值。
  5. 根据需要,它将状态空间滤波器转换回其传递函数或零极点增益形式。

4. 总结

到此,有关带通滤波的Python实现就基本讲完了。如果有什么疑问欢迎在评论区提出,对于共性问题可能会后续添加到文章介绍中。

如果觉得这篇文章对你有用,记得点赞、收藏并分享给你的小伙伴们哦。

你可能感兴趣的:(运动想象,脑机接口,python,人工智能,算法,运动想象,脑机接口)