4. 数据采集:表面肌电信号(sEMG)的获取与预处理

好,咱们进入实操环节。

前面聊了那么多肌肉协同的理论,说白了,你最终要面对的问题就一个:怎么把信号干净地采回来?

我见过太多人,算法模型搞得花里胡哨,结果数据一塌糊涂,最后全白搭。嗯,这章咱们就把这个地基打牢。

4.1 电极怎么贴?—— 这不是玄学

很多人觉得贴电极片嘛,撕开一贴就行。其实不然。我早期有个项目,采集前臂屈肌群的数据,结果出来的信号全是50Hz工频干扰,后来发现是电极间距太近了。

这里有几个硬指标,你记一下:

  • 电极类型:干电极 vs 湿电极。实验室里我建议用湿电极(Ag/AgCl),信号质量稳定。可穿戴设备才考虑干电极。
  • 电极间距:中心到中心,20mm 是黄金距离。太近容易串扰,太远会丢失局部信息。
  • 放置方向:顺着肌纤维走向。你想想看,肌肉收缩时电信号是沿着纤维方向传播的,你横着贴,信号就弱了。
  • 参考电极:贴在骨性突起处,比如腕部尺骨茎突。那里没有肌肉,信号最干净。

核心原则:皮肤准备比贴电极更重要。用酒精棉擦去油脂和死皮,阻抗降到 5kΩ 以下再开始采集。

4.2 采样率设多少?—— 别浪费存储空间

表面肌电信号的频率范围,一般在 20-500Hz。根据奈奎斯特定理,采样率至少是最高频率的两倍,也就是 1000Hz。

但我个人习惯,1500-2000Hz 是比较舒服的区间。为什么?

  • 1000Hz 勉强够用,但边缘信息容易丢。
  • 超过 2000Hz 就是浪费。你想想看,500Hz 以上的成分基本都是噪声,采回来还得滤掉,何必呢?
应用场景 推荐采样率 说明
基础步态分析 1000 Hz 够用,数据量小
手部精细动作 1500 Hz 需要捕捉快速肌电爆发
运动疲劳研究 2000 Hz 中频成分变化敏感

我的小技巧:如果设备支持,先以 2000Hz 采,后期处理时再降采样到 1000Hz。这样你手里有冗余,心里不慌。

4.3 预处理流程 —— 把垃圾扔掉

原始信号长什么样?说白了就是一堆毛刺,里面混着心电干扰、运动伪迹、工频噪声。你得一步步把它洗干净。

我习惯的流程是这样的:

  1. 去基线漂移:用高通滤波器,截止频率设在 20Hz。低于这个频率的都是身体晃动产生的伪迹。
  2. 陷波滤波器:50Hz(或60Hz,看你在哪个国家)。工频干扰是最大的敌人,必须干掉。
  3. 低通滤波:截止频率 500Hz。高于这个的都是高频噪声,比如设备热噪声。
  4. 全波整流:把负半周翻到正半周。这一步是为了后续提取包络。
  5. 低通平滑:截止频率 5-10Hz。得到的就是所谓的「线性包络」,也就是肌肉激活程度的直观曲线。

注意:滤波顺序不能乱。先高通去漂移,再陷波去工频,最后低通去噪声。我曾经试过先陷波再高通,结果工频干扰被放大了,那叫一个惨。

4.4 代码示例 —— 用 Python 走一遍

光说不练假把式。我给你一段我常用的预处理代码,你拿去就能用:

import numpy as np
import scipy.signal as signal

def preprocess_semg(raw_signal, fs=1500):
    """
    表面肌电信号预处理
    raw_signal: 原始信号 (numpy array)
    fs: 采样率 (Hz)
    """
    # 1. 高通滤波 (去基线漂移)
    b_high, a_high = signal.butter(4, 20/(fs/2), 'high')
    signal_high = signal.filtfilt(b_high, a_high, raw_signal)

    # 2. 陷波滤波 (去50Hz工频)
    b_notch, a_notch = signal.iirnotch(50, 30, fs)
    signal_notch = signal.filtfilt(b_notch, a_notch, signal_high)

    # 3. 低通滤波 (去高频噪声)
    b_low, a_low = signal.butter(4, 500/(fs/2), 'low')
    signal_low = signal.filtfilt(b_low, a_low, signal_notch)

    # 4. 全波整流
    signal_rect = np.abs(signal_low)

    # 5. 低通平滑 (提取包络)
    b_env, a_env = signal.butter(4, 5/(fs/2), 'low')
    envelope = signal.filtfilt(b_env, a_env, signal_rect)

    return envelope

这段代码我用了好几年,基本没出过问题。注意我用了 filtfilt 而不是 lfilter,前者是零相位滤波,不会产生相位偏移。这一点在肌肉协同分析里特别重要——你想想看,如果各通道信号的时间对齐出了问题,那协同模式就全乱了。

4.5 避坑指南 —— 我踩过的雷

嗯,这里我得好好说说。有些坑你不亲自踩一次,光看书是记不住的。

  • 电极线松动:我曾经在采集过程中,被试动了一下,电极线松了。结果出来的信号全是尖峰,我还以为是肌肉痉挛,折腾了两天才发现是接触不良。所以,采集前一定要用胶带固定好线缆。
  • 汗液影响:夏天采集,被试出汗,电极片粘性下降,信号阻抗飙升。我的解决办法是:备一包医用胶带,出汗多的部位额外加固。
  • 不要过度滤波:有些人为了信号好看,把截止频率设得很低,结果把真实的肌电成分也滤掉了。记住,肌肉协同分析需要保留 20-150Hz 的能量分布,这是关键频段。

一句话总结:数据采集和预处理,占整个项目 70% 的工作量。前面做扎实了,后面的分析就是水到渠成的事。

4.6 知识体系总览

下面这张图,是我自己梳理的本章核心逻辑。你一看就明白:

表面肌电信号获取与预处理流程 数据采集 电极贴放 · 采样率设置 信号预处理 滤波 · 整流 · 平滑 线性包络 肌肉激活曲线 采集细节 电极间距 20mm 采样率 1500-2000Hz 皮肤阻抗 < 5kΩ 预处理步骤 ① 高通 20Hz ② 陷波 50Hz ③ 低通 500Hz ④ 全波整流 ⑤ 低通 5-10Hz 输出结果 干净无漂移 无工频干扰 时间对齐 ⚠️ 预处理质量直接决定肌肉协同提取的准确性,这一步省不得

好了,这一章就到这里。数据采回来了,也洗干净了,下一章咱们就可以正式进入肌肉协同的提取环节了。

专注资料整理