简介:这份资源面向运动生物力学、康复工程与人体运动分析方向的学习者和研究者,提供一套用Matlab求解肌肉激活度的完整实现方案。针对表面肌电信号(sEMG)处理中激活度难以量化的问题,资源给出了可直接运行的代码与配套实验数据,帮助读者从原始信号出发得到肌肉激活度曲线。压缩包共5个文件,约135KB,包含2个mat数据文件、2个m脚本文件和1个txt说明文档,分别对应最大自主收缩(MVC)与运动过程中的sEMG数据、主程序及激活度计算函数,结构紧凑、便于快速上手。目前已有3507人学习下载,说明其在同类教程中具有较好的参考价值。读者可借助MVC归一化思路与激活度求解流程,理解从sEMG到肌肉激活程度的完整计算链路,并在此基础上替换自有数据开展实验分析,适合作为课程设计、论文复现或课题预研的起步素材。
1. 从一段“跳动的波形”说起:这套肌肉激活度 Matlab 代码到底能干什么
如果你手头有一份表面肌电信号(sEMG)数据,却卡在“怎么把它变成能写进论文、能放进报告里的肌肉激活度曲线”这一步,那这套肌肉激活度Matlab代码及数据.rar大概率就是你要找的东西。它解决的不是采集问题,而是采集之后最磨人的一段:原始 sEMG 里混着工频干扰、基线漂移、心电串扰,直接画出来就是一团毛刺,谁看谁头大。这套资源把从原始信号到激活度曲线的完整链路打包好了,包含可运行的 Matlab 脚本和配套的示例数据,适合做运动生物力学、康复评估、人机交互方向的学生和工程师。
我见过太多人拿到 sEMG 数据后第一反应是直接做 RMS,结果曲线抖得像心电图,导师一句“这激活度不对”就得返工。这套代码的价值在于,它把滤波、整流、包络、归一化这几步的先后顺序和参数都固定下来了,你照着跑一遍,至少能先得到一个“看起来合理”的结果,再去调细节。它不挑数据来源,只要你的 sEMG 是常见的一维时间序列,采样率别太离谱,基本都能套进去。
2. 肌肉激活度计算的信号链路:从原始 sEMG 到激活曲线的四步拆解
2.1 为什么不能直接对原始信号取绝对值
很多人以为肌肉激活度就是“把信号整流一下再平滑”,这个理解只对了一半。原始 sEMG 是运动单位动作电位在皮肤表面的叠加,频率成分主要集中在 20–500 Hz,但真正跟发力相关的信息藏在幅值包络里。如果你跳过带通滤波直接整流,50 Hz 工频和低频运动伪迹会一起被算进幅值,出来的激活度曲线会莫名其妙地整体抬高,尤其是在静息段,本该接近零的地方却飘着一层“底噪激活”。
常见做法是先做 20–450 Hz 的带通滤波,把工频和大部分运动伪迹挡掉,再做整流和低通包络。这套代码里用的是 Butterworth 带通加全波整流,后面接一个二阶低通提取包络。参数不是拍脑袋定的,带通下限 20 Hz 是为了保留大部分 sEMG 能量,上限 450 Hz 是考虑到多数采集设备在 1000 Hz 采样率下的有效带宽。如果你的采样率只有 500 Hz,上限要相应降到 200 Hz 左右,否则会引入混叠。
2.2 包络提取:低通截止频率怎么选才不“糊”
包络提取的本质是低通滤波,截止频率决定了激活曲线的“跟手程度”。截止频率太高,曲线会保留太多高频波动,看起来毛躁;太低,曲线会滞后于真实发力时刻,做时序分析时对不齐。我一般会从 6 Hz 开始试,如果发现曲线在发力瞬间爬升太慢,就提到 10 Hz;如果静息段还是抖,就降到 3 Hz。这套代码默认给的是 6 Hz,属于比较稳妥的中间值。
这里有个容易翻车的地方:Matlab 的filtfilt是零相位滤波,适合离线分析,但如果你要做实时系统,就得换成filter,并且接受相位延迟。代码里用的是filtfilt,所以它更适合离线处理,别直接搬到实时控制回路里用。另外,滤波器的阶数别贪高,二阶到四阶足够,阶数太高会导致数值不稳定,尤其是采样率低的时候。
2.3 归一化: MVC 不是唯一答案,但最常用
肌肉激活度的绝对值没有跨人、跨次比较的意义,所以必须归一化。最常见的是用最大自主收缩(MVC)时的幅值做基准,把激活度映射到 0–1 之间。这套代码里预留了归一化接口,但示例数据没有附带 MVC 数据,所以默认走的是“峰值归一化”,也就是用整段信号的最大包络值做分母。这样做的好处是省事,坏处是如果测试动作里包含一个特别大的爆发,其他动作的激活度会被压得很低。
如果你要做组间比较,建议自己补一段 MVC 采集,然后把 MVC 包络的均值或峰值填进归一化参数里。代码里那个normalize_mode变量就是干这个的,改成'mvc'再传入基准值就行。别小看这一步,归一化方式选错,后面统计出来的差异可能全是假的。
2.4 示例数据跑通:一次完整的脚本调用
下面这段代码是资源里主脚本的简化版,我把它拆出来方便你对照。假设你的数据是一列时间序列,采样率 1000 Hz,存成emg_data.mat,变量名是emg。
% 加载示例数据 load('emg_data.mat'); % 变量名为 emg,单位 mV fs = 1000; % 采样率,必须和采集时一致 % 第一步:带通滤波 20-450 Hz [b_bp, a_bp] = butter(4, [20 450]/(fs/2), 'bandpass'); emg_filt = filtfilt(b_bp, a_bp, emg); % 第二步:全波整流 emg_rect = abs(emg_filt); % 第三步:低通包络 6 Hz [b_lp, a_lp] = butter(2, 6/(fs/2), 'low'); emg_env = filtfilt(b_lp, a_lp, emg_rect); % 第四步:峰值归一化 emg_activation = emg_env / max(emg_env); % 画图检查 t = (0:length(emg)-1) / fs; plot(t, emg_activation); xlabel('时间 (s)'); ylabel('激活度 (归一化)'); title('肌肉激活度曲线');逻辑说明:butter生成滤波器系数,filtfilt做零相位滤波,避免相位失真。abs做全波整流,把负半周翻上来。低通滤波提取包络,最后除以最大值完成归一化。参数说明:fs必须和采集设备一致,否则所有截止频率都会偏;butter的第一个参数是阶数,带通用 4 阶,低通用 2 阶,这是我在多数 sEMG 数据上试出来的平衡点。如果你发现滤波后信号失真严重,先检查fs有没有填错,这是最常见的翻车点。
3. 把代码套到自己的数据上:文件结构、参数替换与批量处理
3.1 资源包里的文件怎么摆
解压之后,你大概会看到三类文件:主脚本、函数文件、示例数据。主脚本负责串联流程,函数文件里封装了滤波和包络提取,示例数据用来验证环境。我建议你先把示例数据跑一遍,确认 Matlab 能正常出图,再动自己的数据。常见做法是新建一个工作目录,把主脚本和函数文件复制进去,数据单独放一个data文件夹,避免路径混乱。
如果你的 Matlab 版本比较老,比如 2016 之前的,filtfilt的行为可能有细微差别,但基本能用。工具箱方面,这套代码只依赖信号处理工具箱,如果你没装,butter和filtfilt会报错。替代方案是用designfilt或者手写差分方程,但没必要,装个工具箱最省事。
3.2 参数替换清单:采样率、通道名、归一化方式
拿到自己的数据后,别急着跑,先对着下面这张表把该改的地方改掉。我见过太多人直接跑,结果采样率没改,出来的激活度曲线时间轴全是错的。
| 参数 | 代码里的变量名 | 常见取值 | 改错后果 |
|---|---|---|---|
| 采样率 | fs | 1000 / 2000 / 500 | 截止频率偏移,滤波失效 |
| 数据变量名 | emg | 你的实际变量名 | 报错未定义 |
| 带通下限 | 20 | 20–30 Hz | 太低会保留运动伪迹 |
| 带通上限 | 450 | fs/2 的 80%–90% | 太高会混叠 |
| 包络截止 | 6 | 3–10 Hz | 太高毛躁,太低滞后 |
| 归一化模式 | normalize_mode | 'peak'或'mvc' | 组间比较失效 |
改完之后,先跑一段静息数据看看。如果静息段的激活度在 0.05 以下,说明滤波和归一化基本合理;如果静息段飘到 0.2 以上,多半是工频没滤干净,检查一下带通下限是不是设得太低。
3.3 批量处理多个受试者:循环里要注意的坑
如果你有几十个受试者的数据,一个个跑太慢,肯定要写循环。但循环里有个坑:每个受试者的 MVC 可能不同,如果你用峰值归一化,每个人的分母都不一样,最后组间比较会引入额外变异。我一般会先把所有受试者的 MVC 数据单独处理,算出各自的基准值,存成一个数组,再在循环里调用。
% 假设 subj_list 是受试者编号列表 mvc_values = zeros(length(subj_list), 1); for i = 1:length(subj_list) load(['mvc_', num2str(subj_list(i)), '.mat']); % 对 MVC 数据做同样的包络提取 mvc_env = extract_envelope(mvc_data, fs); mvc_values(i) = mean(mvc_env); % 用均值做基准 end % 再处理正式数据 for i = 1:length(subj_list) load(['emg_', num2str(subj_list(i)), '.mat']); emg_env = extract_envelope(emg_data, fs); activation = emg_env / mvc_values(i); save(['activation_', num2str(subj_list(i)), '.mat'], 'activation'); end逻辑说明:先单独算每个受试者的 MVC 基准,再在正式数据里除以对应基准。参数说明:extract_envelope是你自己封装的函数,把滤波、整流、低通三步包进去,这样主循环干净。注意mvc_values用均值还是峰值,取决于你的实验设计,均值更稳,峰值更敏感。别在循环里重复加载滤波器系数,提前算好放外面,能省不少时间。
4. 避坑与排查:肌肉激活度计算里最容易翻车的五个地方
4.1 曲线整体偏高,静息段下不去
现象:跑完代码,静息段激活度在 0.15–0.3 之间,明显不是零。原因:最常见的是工频干扰没滤干净,或者带通下限设得太低,把运动伪迹放进来了。解决:先看原始信号的频谱,确认 50 Hz 附近有没有尖峰;如果有,把带通下限提到 30 Hz 试试,或者在带通前加一个 50 Hz 陷波。另外检查电极有没有贴牢,接触阻抗太大会引入低频漂移。
4.2 发力瞬间曲线爬升太慢,对不齐事件标记
现象:激活度曲线在发力后 200–300 ms 才爬到峰值,跟力台或关节角度对不上。原因:包络低通截止频率太低,或者用了filter而不是filtfilt导致相位延迟。解决:把包络截止提到 10 Hz,确认用的是filtfilt。如果必须用filter,那就得手动补偿延迟,补偿量大概是滤波器阶数的一半除以采样率。我一般直接换filtfilt,省得算。
4.3 不同受试者之间激活度差异巨大
现象:同样的动作,A 的激活度峰值 0.8,B 只有 0.3。原因:归一化方式不统一,或者 MVC 采集不规范。解决:统一用 MVC 归一化,并且确保 MVC 采集时受试者真的用尽全力。如果没法补 MVC,至少用同一动作的峰值归一化,别混用。另外检查电极贴的位置是不是一致,位置差一厘米,幅值能差一倍。
4.4 滤波后信号出现明显畸变
现象:滤波后的波形跟原始信号比,形状完全变了,甚至出现振荡。原因:滤波器阶数太高,或者截止频率设得离奈奎斯特频率太近。解决:带通阶数降到 2 阶,上限别超过 fs/2 的 90%。如果采样率只有 500 Hz,上限设 200 Hz 就够了,别硬撑到 450。数值不稳定的时候,filtfilt会报警告,看到警告别忽略,回去调参数。
4.5 批量处理时内存爆掉
现象:跑几十个文件,Matlab 卡死或者报内存不足。原因:循环里没清变量,或者把大矩阵反复拼接。解决:每次循环结束用clear清掉临时变量,别在循环里save大文件。如果数据量实在大,分批处理,每批 10 个受试者,中间清一次内存。我一般会在循环里加一句clear emg_filt emg_rect emg_env,能省不少内存。
5. 进阶技巧:用激活度曲线做时序对齐与统计检验
5.1 把激活度曲线对齐到事件点
拿到激活度曲线之后,下一步往往是按事件点(比如足底压力触发)切段平均。这里有个细节:切段之前要先做基线校正,把事件前 200 ms 的均值减掉,否则各段的起点不在同一水平。代码里可以这样写:
% 假设 event_idx 是事件点采样索引,pre = 200 ms pre_samples = round(0.2 * fs); baseline = mean(activation(event_idx - pre_samples : event_idx)); activation_corrected = activation - baseline;逻辑说明:用事件前一段的均值做基线,减掉之后各段起点归零。参数说明:pre_samples根据你的事件类型调,足底压力一般 200 ms 够,脑电触发可能要 500 ms。别用整段均值做基线,那样会把真实激活也减掉。
5.2 统计检验前先检查分布
激活度数据往往不服从正态分布,尤其是峰值附近。我一般会先做 Shapiro-Wilk 检验,如果 p < 0.05,就用非参数检验,比如 Wilcoxon 秩和或 Friedman 检验。别直接上 t 检验,不然审稿人一问分布就尴尬。Matlab 里用swtest或者lillietest都行,swtest需要自己下,lillietest自带。
5.3 一个我常用的验证习惯
每次跑完新数据,我都会做一件事:把原始信号、滤波后信号、包络、激活度四条曲线画在同一张图上,从上到下排开。这样一眼就能看出哪一步出了问题。如果滤波后信号跟原始信号幅值差太多,说明滤波器有问题;如果包络跟滤波后信号对不上,说明低通截止频率不对;如果激活度跟包络形状不一致,说明归一化写错了。这个习惯帮我省了无数次返工。
从那以后我每次拿到新的 sEMG 数据,都强制走一遍这个四图检查,确认无误再往下做统计。希望帮到你。
本文还有配套的精品资源,点击获取