第3章 肌电信号预处理:工频干扰与滤波
说实话,刚接触肌电信号那会儿,我最头疼的就是预处理。你想想看,辛辛苦苦贴好电极,让受试者做动作,结果采集出来的信号长这样——一条弯弯曲曲的线,上面还叠着好多毛刺。嗯,这其实不是真正的肌电信号,而是被各种噪声污染过的原始数据。
我习惯把预处理比作「洗菜」。菜买回来不能直接下锅,得先摘掉烂叶子、洗掉泥土。肌电信号也一样,不洗干净,后面的分析全是白搭。今天咱们就重点聊三个最常见的「脏东西」:工频干扰、基线漂移、运动伪影。
核心知识点速览
- 工频干扰 → 50Hz陷波滤波
- 基线漂移 → 高通滤波(截止频率5-20Hz)
- 运动伪影 → 带通滤波(10-500Hz)
3.1 工频干扰与50Hz陷波
工频干扰,说白了就是电网的「嗡嗡声」。在中国,电网频率是50Hz,这个频率会通过空间电磁场耦合到你的电极线和放大器上。我在实验室里遇到过最夸张的一次——信号里50Hz的幅度比肌电本身还大,整个波形看起来就像一条粗毛线。
怎么判断是不是工频干扰?很简单。你让受试者完全放松,肌肉不发力,这时候采集到的信号如果还有明显的50Hz正弦波,那就是工频干扰。我个人的经验是:先检查接地,再考虑滤波。很多时候接地没做好,滤波也救不了。
陷波滤波器的设计,我推荐用IIR滤波器,阶数不要太高,2阶就够了。太高阶会引入相位失真,反而把有用的肌电信号给削了。
# Python示例:50Hz陷波滤波器
from scipy import signal
import numpy as np
# 设计一个2阶50Hz陷波滤波器
fs = 1000 # 采样率1000Hz
f0 = 50.0 # 陷波频率
Q = 30.0 # 品质因数
b, a = signal.iirnotch(f0, Q, fs)
# 应用滤波
filtered_signal = signal.filtfilt(b, a, raw_emg)
我的小技巧:用filtfilt代替lfilter,可以实现零相位延迟。虽然计算量翻倍,但信号不会发生偏移,这对后续的时序分析很重要。
3.2 基线漂移与高通滤波
基线漂移是什么?你让受试者握拳再松开,会发现信号整体在上下浮动,就像海浪一样。这主要是因为电极与皮肤之间的接触阻抗在变化,或者受试者身体有轻微移动。
我曾经犯过一个错误:为了去除基线漂移,直接把高通滤波的截止频率设到了50Hz。结果肌电信号的高频成分也被滤掉了,动作识别准确率直接掉到60%。后来才明白,肌电信号的有效能量集中在20-150Hz,基线漂移的频率通常低于5Hz。所以,高通滤波的截止频率设在5-20Hz之间就足够了。
# Python示例:高通滤波去除基线漂移
from scipy import signal
fs = 1000
cutoff = 10 # 截止频率10Hz
order = 4
# 设计高通滤波器
b, a = signal.butter(order, cutoff, btype='high', fs=fs)
# 应用滤波
emg_no_drift = signal.filtfilt(b, a, emg_after_notch)
注意:高通滤波的截止频率不能太高。如果设到30Hz以上,你会把肌电信号中低频的力信息也滤掉。我见过有人设到100Hz,结果信号看起来干净了,但肌肉发力时的幅度变化也消失了——这等于把婴儿和洗澡水一起倒掉。
3.3 运动伪影与带通滤波
运动伪影,这是最让人头疼的噪声。它来自电极线晃动、肌肉收缩时的机械形变,甚至衣服摩擦。频率范围很宽,从几Hz到几百Hz都有。我刚开始做康复机器人控制时,受试者一抬手,信号里就出现一个巨大的尖峰,控制器直接误判成肌肉痉挛。
处理运动伪影,我建议用带通滤波。把通带设在10-500Hz,既能保留肌电信号的主要能量,又能滤掉低频的运动伪影和高频的电子噪声。注意,500Hz以上的成分基本是噪声,没必要保留。
# Python示例:带通滤波去除运动伪影
from scipy import signal
fs = 1000
lowcut = 10
highcut = 500
order = 4
# 设计带通滤波器
b, a = signal.butter(order, [lowcut, highcut], btype='band', fs=fs)
# 应用滤波
emg_clean = signal.filtfilt(b, a, emg_no_drift)
预处理流程总结
- 原始肌电信号 → 50Hz陷波(去工频)
- 陷波后信号 → 10Hz高通(去基线漂移)
- 高通后信号 → 10-500Hz带通(去运动伪影)
- 输出:干净的肌电信号,可用于后续特征提取
3.4 滤波顺序有讲究吗?
有。我个人习惯先做陷波,再做高通,最后做带通。为什么?因为工频干扰的幅度往往很大,如果先做高通,50Hz的干扰会被放大,后面再陷波效果就差了。你想想看,先去掉最大的噪声,后面的处理会轻松很多。
当然,也有同行喜欢先做带通再做陷波。我试过,效果差不多,但计算量会大一些。嗯,这个没有绝对的对错,你习惯哪种就用哪种。
3.5 避坑指南
我曾经踩过一个坑:用移动平均滤波去基线漂移。移动平均本质上是一个低通滤波器,它会把肌电信号的高频成分也平滑掉。结果信号看起来是平了,但肌肉活动的细节全没了。后来我改用高通滤波,效果立竿见影。
还有一个坑:滤波器的阶数。阶数越高,滤波效果越好,但相位失真也越严重。我建议IIR滤波器不超过4阶,FIR滤波器不超过50阶。超过这个范围,信号延迟会大到无法接受,尤其是在实时控制系统中。
快速检查滤波效果的方法:滤波前后对比频谱图。如果50Hz处有明显的凹陷,说明陷波有效;如果10Hz以下的能量被大幅衰减,说明高通有效;如果10Hz以下和500Hz以上的能量都被衰减,说明带通有效。用眼睛看波形是不够的,一定要看频谱。
3.6 本章知识体系
下面这张图是我自己画的,把本章的核心逻辑串起来了。你看一遍,应该就能记住预处理的全流程。
好了,这一章的内容就到这里。预处理是肌电分析的地基,地基打不牢,后面盖什么楼都会歪。我建议你拿到数据后,先花10分钟做一遍预处理,看看频谱图,确认噪声被去掉了,再开始做特征提取。别急着跳步,这一步省下来的时间,后面会加倍还给你。
公众号:蓝海资料掘金营,微信deep3321