第4章:肌电信号时域分析:整流、平滑(RMS计算)、积分肌电值(iEMG)、平均振幅(MAV)
好,咱们进入时域分析。这一块是肌电信号处理里最基础、也最常用的手段。说白了,就是把原始信号那些“毛刺”和“抖动”处理成有物理意义的数值。
我刚开始接触肌电时,看着屏幕上那条疯狂跳动的曲线,心里直犯嘀咕:这玩意儿能看出啥?后来才明白,时域分析就是给这条“疯狗”套上缰绳,让它乖乖听话。
4.1 为什么需要整流?
原始肌电信号是交流信号,有正有负。你想想看,如果直接求平均,正负一抵消,结果可能接近零——这显然不能反映肌肉的真实活动强度。
整流,就是把负半周的信号翻到正半周来。有两种方式:
- 半波整流:只保留正半周,负半周直接置零。说实话,这方法用得少,因为会丢掉一半信息。
- 全波整流:把负半周的绝对值取正。这是主流做法。
核心要点:全波整流后的信号,才能进行后续的平滑和积分计算。否则你算出来的平均值会严重偏低。
我在项目中遇到过一位新手,直接用原始信号算RMS,结果数值忽大忽小,完全没法用。我一看,整流这步跳过了。嗯,这是最常见的坑之一。
4.2 平滑与RMS计算
整流后的信号虽然都是正的,但依然很“扎手”。这时候就需要平滑处理。最经典的方法就是均方根(RMS)计算。
RMS的公式很简单:
RMS = sqrt( (1/N) * Σ(x_i²) )
其中 x_i 是窗口内的采样点,N 是窗口长度。
为什么用RMS而不是直接平均?因为RMS对信号中的“爆发”更敏感。肌肉收缩时,信号幅度会突然增大,RMS能更好地捕捉这种变化。
窗口长度怎么选? 我个人习惯用50-100毫秒的滑动窗口。太短了平滑效果差,太长了又会丢失细节。举个例子,采样率1000Hz时,窗口长度取50-100个点比较合适。
小技巧:如果你做实时分析,可以用指数移动平均代替滑动窗口,计算量更小,响应也更快。
4.3 积分肌电值(iEMG)
iEMG,全称是integrated EMG。它计算的是一段时间内整流后信号的面积。说白了,就是曲线下的总面积。
公式:
iEMG = Σ |x_i| * Δt
其中 Δt 是采样间隔。
iEMG反映的是肌肉在某个时间段内的总活动量。比如你让受试者做10秒的等长收缩,iEMG就能告诉你这10秒里肌肉总共“出了多少力”。
应用场景:
- 疲劳分析:随着肌肉疲劳,iEMG会逐渐增大(因为需要更多运动单位参与)
- 康复评估:对比患侧和健侧的iEMG,判断肌肉激活程度
注意:iEMG对信号长度敏感。比较不同时间段的iEMG时,一定要保证时间窗口一致。我曾经吃过这个亏,两个实验的时间窗口差了0.5秒,结果对比完全失真。
4.4 平均振幅(MAV)
MAV,Mean Absolute Value,就是整流后信号的平均值。公式:
MAV = (1/N) * Σ |x_i|
MAV和RMS很像,但计算更简单。它反映的是信号的平均强度。在工程实践中,MAV常用于:
- 手势识别:不同手势的MAV特征差异明显
- 肌肉激活阈值检测:当MAV超过某个阈值时,认为肌肉开始收缩
我个人觉得,MAV比RMS更直观。RMS因为平方再开方,数值会被“放大”,而MAV就是实实在在的平均幅度。
4.5 知识体系总览
下面这张图,把本章的核心逻辑串起来了:
4.6 实战代码示例
下面是一段Python代码,演示了如何计算RMS、iEMG和MAV。我习惯用numpy,效率高,代码也简洁。
import numpy as np
def compute_emg_features(signal, fs):
"""
计算肌电信号的时域特征
signal: 原始EMG信号(一维数组)
fs: 采样率(Hz)
"""
# 1. 全波整流
rectified = np.abs(signal)
# 2. RMS计算(滑动窗口,窗口长度100ms)
window_len = int(0.1 * fs)
rms = np.array([
np.sqrt(np.mean(rectified[i:i+window_len]**2))
for i in range(0, len(rectified) - window_len, window_len//2)
])
# 3. iEMG(每1秒积分一次)
segment_len = fs # 1秒
iemg = np.array([
np.sum(rectified[i:i+segment_len]) / fs
for i in range(0, len(rectified) - segment_len, segment_len)
])
# 4. MAV(每1秒平均一次)
mav = np.array([
np.mean(rectified[i:i+segment_len])
for i in range(0, len(rectified) - segment_len, segment_len)
])
return rms, iemg, mav
# 使用示例
fs = 1000 # 假设采样率1000Hz
signal = np.random.randn(10000) # 模拟10秒信号
rms, iemg, mav = compute_emg_features(signal, fs)
print(f"RMS均值: {np.mean(rms):.3f}")
print(f"iEMG均值: {np.mean(iemg):.3f}")
print(f"MAV均值: {np.mean(mav):.3f}")
避坑指南:我曾经在计算iEMG时忘了除以采样率,结果数值大得离谱。记住,iEMG的单位是mV·s,一定要考虑时间因素。
4.7 三个指标怎么选?
很多新手会问:RMS、iEMG、MAV,到底用哪个?我的建议是:
- 做实时控制(比如假肢):用RMS,因为它对信号变化响应快,平滑效果也好
- 做疲劳分析:用iEMG,它能累积反映肌肉的总工作量
- 做模式识别(手势分类):用MAV,计算简单,特征稳定
当然,实际项目中往往三个都算,然后看哪个特征区分度最好。嗯,数据不会骗人,多试试就知道了。
公众号:蓝海资料掘金营,微信deep3321