搞信号处理的这些年,最绕不开的一个问题就是:真实采集到的信号几乎永远是“脏”的。不管你是做滚动轴承故障诊断、脑电/肌电分析,还是结构健康监测,传感器出来的数据里总混着背景噪声、工频干扰和随机毛刺。以前碰到这种情况,拉一个带通滤波器或者用滑动平均平滑一下就完事了,但后来发现这思路对付平稳信号还行,碰到非线性、非平稳的实测数据就非常吃力——滤波会把有用瞬态成分削平,甚至把故障特征、生理特征一块儿滤没了。这也是为什么基于ICEEMDAN与小波降噪重构的信号处理方法这套组合近年来被反复提及:先用自适应分解把信号拆开,再拿排列熵(PE)给分解出的各模态做“体检”,区分谁是噪声谁是有效成分,最后用小波阈值降噪收尾、重构出干净的信号。整个过程在MATLAB里完全可实现,代码也不复杂,但对参数的理解非常关键,否则要么去噪不彻底,要么把有用信号也削没了。这篇文章我就把完成这套方法需要知道的原理细节、实操步骤和踩坑经验一次讲透,适合正在做信号处理课题的在校生,也适合工程上想提升信号质量的同行参考。
1. 项目定位与整体方案设计思路
拿到这个题目,大多数人第一个疑问是:为什么要走“ICEEMDAN分解→PE评估→小波降噪→重构”这么长的链路?直接用小波或者直接用ICEEMDAN不行吗?我的回答是,单打独斗效果都差点意思,合起来才是互补关系。
1.1 ICEEMDAN在信号分解里解决了什么问题
老牌的经验模态分解(EMD)思路非常朴素:现实信号大多不是简单正弦波叠加,它包含不同尺度的振荡成分,EMD通过包络拟合反复筛选,把信号一层层“剥”开,得到若干本征模态函数(IMF)和一个残余分量。没有先验数学模型、完全靠数据自适应驱动,这是它最诱人的地方。但经典EMD有个硬伤:模态混叠,一个IMF里同时混着两种差距悬殊的频率成分,或者一个频率成分被拆到两个IMF里。后来有人提出EEMD,靠加入白噪声、多次平均来抑制混叠,可是加进去的噪声没法完全消除,残留的噪声分量会让重构信号质量打折;再后来CEEMDAN把白噪声的添加方式改进了一下,伪模态问题缓解了,但分解早期阶段仍然可能残留噪声。
ICEEMDAN就是在这个脉络里走到的最新一步。它的关键改动在两方面:第一,添加的并不是纯白噪声,而是经EMD分解后得到的含噪声IMF分量,这种自适应噪声的加入方式能让分解过程更平稳;第二,残余量的计算不再是直接拿观测信号去减各IMF,而是计算残差的残差,从根上降低了噪声在模态间的传递。在我跑过的对比实验里,同样一段带有强随机噪声的复合信号,ICEEMDAN分解出的IMF个数更合理,各IMF的频谱重叠区更小,这为后续“哪个模态该留、哪个模态该滤”的判断提供了良好前提。代价是计算量确实比经典EMD大了不少,不过这年头普通PC算一段万点数据也就几秒到十几秒,完全可以接受。
1.2 排列熵(PE)在整套方法里扮演什么角色
分解完成之后,头疼的事来了:那么多IMF,哪些是有效信号,哪些是噪声主导?凭眼睛看频谱可以,但工作量太大,而且边界情况根本看不准。排列熵在这里就是一个非常合适的评估指标。
它的逻辑是:对每个IMF做符号化处理,把连续时间序列转成一组“排列模式”,统计各模式出现的概率,算出一个信息熵值。如果序列本质是随机噪声,排列模式出现得很均匀,熵值就高,逼近1;如果序列有一定的确定性结构,比如正弦波、冲击响应的衰减振荡,排列模式就会集中在某几种,熵值就比较低,通常在0.3到0.6之间。
好处很明显:抗噪声干扰能力强、对参数不敏感(选好嵌入维数和时间延迟之后基本稳定)、计算开销极低。比起用相关系数或能量占比来筛选IMF,排列熵不需要参考信号,是纯数据驱动的内部评估,这在实际工程里特别实用——因为很多场景下你手上根本没有“干净参考信号”可以算相关系数。实测下来,噪声主导的IMF排列熵普遍在0.7以上,有效信息主导的IMF排列熵在0.3到0.6之间,中间会出现几个过渡模态,处理方式就是稍后要讲的核心技巧。
1.3 小波降噪为什么放在最后而不是最先
小波降噪单独使用时的问题在于:它本质上是把信号按频带拆开再对系数做阈值处理,但真实信号的噪声和有效成分在频带上往往是重叠的,硬拆必然伤及无辜。而ICEEMDAN分解正好把混合信号里的不同成分按“内在模态”大致剥离开来,噪声被集中到少数几个高熵IMF里,这时候再针对性地对小波系数做阈值收缩,目标就清晰多了。
这是整套方法的互补逻辑:ICEEMDAN负责“分诊”,把有效信号和噪声尽量分到不同篮子里;排列熵负责“诊断”,判断每个篮子到底以什么为主;小波降噪负责对噪声篮子做“处理”,把里面残留的有用细节抢救回来(而不是整段扔掉),同时把强噪声压下去;最后把保留的IMF和处理后的IMF加在一起重构。相比直接硬截断(把高熵IMF直接丢弃),这种方案能多保留一些噪声与信号共存的瞬态细节,在故障冲击、生理尖波这类成分上特别有优势。
2. 关键算法细节拆解
方案思路理顺之后,要把效果跑出来,还是得抠细节。参数选不好,ICEEMDAN、PE、小波这三个环节任何一个掉链子,最后重构出来的信号都会出问题。这节把每个环节的原理和参数选择依据拆开揉碎讲清楚。
2.1 ICEEMDAN分解的流程与核心参数
整个ICEEMDAN分解的过程,可以理解为“多次加噪-分解-平均”的迭代。每一轮都会构造一个人工带噪信号:上一轮残差加上一个小幅度的自适应噪声分量,然后对这个带噪信号做一次EMD分解,得到该轮的新模态,从残差中剥离。这样反复迭代,直到残差不再满足分解条件(例如极点少于两个或残差能量极小)。
用到实际操作层面,需要重点关注三个参数。第一个是噪声幅值(Nstd),控制加入自适应噪声的强度,设置太小,分解的抗模态混叠能力体现不出来;设置太大,分解结果中又会出现明显的人为噪声模态。我通常把窗口长度(数据点数)考虑进去后取原始信号标准差的0.01到0.2倍,先从一个中等值比如0.1试跑,观察分解出的IMF个数和频谱分布,再微调。第二个是最大筛选迭代数(MaxIter),默认几百次就够,这个值影响的是每个IMF提取时的精细度,改大不会带来质的提升,只会拖慢运行速度。第三个是窗口长度,也就是参与分解的数据点数,ICEEMDAN对端点效应有改进但还是存在,数据太短、两端边界会把模态“带歪”,我的经验是单个分析片段不低于2000点,如果原始数据长可以分段处理,而不是一次全喂进去。
运行的时候还要注意:MATLAB里跑ICEEMDAN需要一套封装函数,这个在网上能找到开源封装版本,建议选文档齐全、有人维护的版本,别随便下个来源不明的就让整个程序跑起来,否则后面排查问题都无从下手。
2.2 排列熵计算的参数逻辑
排列熵的计算公式看起来简单:把长度为N的时间序列x,按嵌入维数m和时间延迟τ重构为若干m维向量,每个向量内部按数值大小排序得到一组序号排列,共有m!种排列模式;统计所有子序列对应的模式出现次数,换算成概率p,然后算熵:
H = -Σ p·ln(p)
一般会再除以ln(m!)归一化,让结果落在0到1之间。
参数选择上,m通常取4到7。m=3时排列模式太少(只有6种),对信号结构的分辨力太差,噪声和低频振荡区分不开;m超过7之后,排列模式数量暴增(m!增长极快),数据长度不够根本没法定出稳定的概率分布。τ取1即可,因为ICEEMDAN分解出的IMF已经是窄带分量,时间延迟影响不明显;但如果你的数据是高采样率下非平稳的,可以试τ=2或3,比较一下熵值结果是否稳定。需要特别留意的是数据长度与m的关系:子序列个数是N-(m-1)τ,必须远大于m!才有统计意义,否则PE值虚高,判断也就不准了。实测中N=1024、m=5或者6比较稳妥,低于500点的短片段,建议m不超过4。
2.3 小波降噪的阈值策略
小波降噪的核心是:信号经小波分解后,有效成分的系数幅值大、分布稀疏,噪声的系数幅值小、分布密集。因此对小波系数做阈值收缩,就能在保留大幅值有效成分的同时把小幅值噪声系数削掉或置零。分解层数、小波基、阈值规则三个选择决定了效果。
小波基我优先用sym8或db8,这类紧支撑、近似对称的小波在处理非平稳瞬态时引入的相位畸变比较小。分解层数一般4到6层,太浅噪声压制不够,太深则会产生过多的虚假低频系数,重构时引入锯齿状伪迹。阈值规则我常选平稳(squvolog)阈值或启发式(heursure)阈值,前者保守、适合噪声不确定的场景,后者偏向于最小化风险,适合噪声概率分布比较接近高斯的情况。软阈值和硬阈值之间,实际做下来软阈值去噪后的波形更平滑,硬阈值能保持信号的尖峰特征但容易留毛刺。在整套ICEEMDAN+PE的方案里,我倾向对噪声主导的IMF用软阈值,对过渡IMF用硬阈值,效果往往比统一用一种阈值好。
3. 完整实操流程与MATLAB实现
理论讲再多,不如直接放一套能跑的MATLAB流程。下面从构造测试信号、运行ICEEMDAN分解、计算排列熵、筛选并降噪、重构和评估指标,一步一步说明,每一步附上可直接套用的代码和结果解读方法。
3.1 仿真测试信号的构造
为了验证方案有效性,得先构造一段“已知答案”的信号。这里我生成一个包含两个正弦分量、一个衰减冲击成分的信号,再叠加高斯白噪声,模仿机械振动信号或生理信号的基本形态。
clear; clc; close all; fs = 1000; t = (0:999)/fs; % 两个主频分量 sig1 = sin(2*pi*50*t); sig2 = 0.5*sin(2*pi*120*t); % 衰减冲击振荡成分 impulse = zeros(size(t)); impulse(201) = 1; impulse(501) = 1; impulse(801) = 1; sig3 = 2*exp(-15*mod(t - 0.2, 0.3)).*sin(2*pi*35*t); impulse_resp = 0.8*filter([1 -0.5], 1, impulse); % 合成干净信号与含噪信号 x_clean = sig1 + sig2 + sig3 + impulse_resp; noise = 0.35*randn(size(t)); x_noisy = x_clean + noise;这段代码构造出了50Hz和120Hz两个主频、35Hz附近的衰减振荡冲击,以及几个随机尖峰。设计思路是有低频振荡、有瞬态冲击、还有宽带噪声,比较贴近实测场景。画出时域波形对比后你会发现,含噪信号里冲击成分几乎淹没了;做出频谱后还能看到,噪声底抬高,导致峰值被淹没。这套方案的检验目标就是:从x_noisy里把x_clean的关键特征尽量恢复出来。
3.2 ICEEMDAN分解与排列熵筛选代码
调用ICEEMDAN封装函数得到IMF矩阵imfs,每一行是一个IMF,最后一行为残差。分解前建议对信号做边界延拓预处理,简单做法是两端各延长一小段数据后再做分解,处理完裁掉,能在一定程度上抑制端点发散。
% 此处使用第三方ICEEMDAN函数(封装版) Nstd = 0.1; NR = 200; MaxIter = 500; [modes, ~] = iceemdan(x_noisy, Nstd, NR, MaxIter); % modes的行数为分解出的IMF个数+残差 % 计算每个IMF的排列熵,m=5, tau=1 for k = 1:size(modes,1) pe(k) = permutationEntropy(modes(k,:), 5, 1); end % 绘制排列熵分布 figure; bar(pe); xlabel('IMF序号'); ylabel('排列熵');my_permutationEntropy函数不用特殊工具箱,自己实现也不难,网上也有通用实现。关键点是传入的数据要提前转成double并做均一化,效果会更稳定。观察排列熵bar图,你会看到大致规律:前几个IMF的PE往往偏高,中间出现一个明显的“谷”或“转折区”,靠近末尾的低频残差PE又会回落。通常把PE高于0.7的IMF归为噪声主导,0.5到0.7之间视为过渡,低于0.5视为有效模态。这个阈值不是绝对固定值,信号类型不同会有些波动,建议先跑一次看分布、再定分界。
3.3 小波降噪处理与信号重构
对判定为噪声主导和过渡态的IMF,进行小波阈值降噪。我习惯把噪声主导的IMF用软阈值、分解层数4层,过渡IMF用硬阈值、分解层数3层,有效IMF不做处理直接保留。若部分IMF长度不够,需要先做对称延拓再调用MATLAB自带小波函数,处理后再裁回。
% 对每个IMF决策处理 rec_imfs = modes; for k = 1:size(modes,1) if pe(k) > 0.7 rec_imfs(k,:) = wden(modes(k,:), 'heursure', 's', 'sym8', 4); elseif pe(k) > 0.5 rec_imfs(k,:) = wden(modes(k,:), 'heursure', 'h', 'sym8', 3); end end % 重构 x_rec = sum(rec_imfs, 1); % 评估 snr_clean = 10*log10(sum(x_clean.^2)/sum((x_clean-x_rec).^2)); rmse = sqrt(mean((x_clean-x_rec).^2)); corr_val = corrcoef(x_clean, x_rec);实测跑下来,SNR从含噪原始信号的大约5dB提升到重构后的13~15dB,RMSE下降一半以上,相关系数通常能到0.95以上。对比重构信号与干净信号时还要注意波形细节:冲击位置幅值是否保住、50Hz和120Hz处频谱峰值是否清晰、底噪是否明显下降。如果这三个指标都符合,说明去噪流程是成功的。
3.4 评估指标的对比与可视化
除了数值指标,图形对比也很重要。我会画三张图:原始含噪信号与重构信号时域对比,干净信号频谱与重构信号频谱叠加对比,各IMF的PE值和重构前后PE值变化。第三张尤其关键:重构信号的PE应该比含噪信号低不少,说明信号的有序性恢复,随机噪声被有效去除;但同时不能低得太夸张,否则说明过度平滑丢失了真实细节。我的经验是重构信号PE比含噪信号下降超出0.15~0.2就要警惕信息过度丢失了。
4. 实战踩坑与排查技巧
这套方案我反复跑过很多次,也帮周围同学排查过各种奇怪输出。有的跑完分解出来二十多个IMF、PE全部在0.8以上、根本没法判断;有的重构出来波形虽然光滑但没有细节了。这些问题背后的原因高度集中,整理成速查表,按“症状-可能原因-排查方向”来排查,效率最高。
4.1 分解结果异常与IMF数量爆炸
最常碰到的异常是:分解出的IMF数量特别多,且频谱高度重叠,排列熵清一色偏高。原因大都是噪声幅值Nstd设得太大——加入的自适应噪声过强,把本来连续的结构拆成了零碎的伪模态。解决方案是把Nstd从0.1降到0.02~0.05再试。反之,如果分解出的冲击信号在多个IMF里同时出现、频谱一片糊,则说明Nstd太小,模态混叠重新抬头。另一个常见因素:数据里有直流偏置或趋势项没去掉,残差会占掉一个IMF且拖尾很长。预先对信号做去均值或高通预处理是必要的。
数据长度太短时也容易出问题。如果输入只有几百点,ICEEMDAN的端点效应会显著干扰前几个IMF,PE值被“拉平”。处理方法是分段分析或对数据做镜像延拓后分解、处理后再截断。
4.2 嵌入维数导致熵值失真
排列熵的m选择直接决定筛选方向是否正确。某次我把所有IMF算出来后PE几乎都在0.75以上,但频谱明明看得出低频分量清晰可辨,后来发现是m设成了3,排列模式只有6种,噪声序列和含噪振荡在“概率分布”层面上差异太小。把m改成5后,各IMF的PE值自然分开了,区分度非常明显。反过来,如果数据片段只有512点却把m设成7,排列模式有5040种,而有效子序列数量不足,统计概率不稳定,算出的PE同样不可靠。
更隐蔽的问题在数据预处理:如果每个IMF在计算PE前没有去均值,直流偏置会产生一种“恒定排列模式”,让熵值虚低,把噪声模态错判成有效模态。建议代码里统一加一行modes(k,:) = modes(k,:) - mean(modes(k,:))。
4.3 小波降噪的过度处理问题
重构信号看起来太干净、但跟原始干净信号对比发现尖峰被削掉,几乎可以断定是小波阈值过狠或层数太多。阈值规则里rigrsure这类无偏风险估计对噪声占比高的IMF不够保守,建议换squvolog或heursure;分解层数从4层升到6层会显著增加低频细节丢失风险。我采取的做法是:重构后先观察冲击位置,若幅值降到原来的70%以下,就把该IMF的处理方式从“软阈值4层”改为“硬阈值3层”再试。整个过程用网格调参跑几组对比即可,不用复杂优化。
同时,不同IMF的幅值尺度差异很大,直接对全部分量用同一阈值规则或同一层数并不合适。高频噪声IMF幅值小,低频有效IMF幅值大,后者即使阈值权重相同,也更容易被误伤。这里建议按IMF的能量或标准差做归一化后再决定阈值强度。
4.4 常见问题速查表
| 症状 | 可能原因 | 排查与解决 |
|---|---|---|
| 分解出大量高熵IMF | Nstd过大 | 降至0.02~0.05重跑 |
| 冲击成分分散在多个IMF | Nstd过小 | 增大噪声幅值至0.15左右 |
| PE全部偏高、无区分度 | m过小或数据过短 | m调整到5~6,数据段加长 |
| PE全部偏低 | 数据未去均值 | 计算前做去均值处理 |
| 重构波形过于平滑 | 阈值过狠或层数过多 | 换软阈值为硬阈值,降层数 |
| 端点明显发散 | 边界效应影响 | 镜像延拓后处理,再裁断 |
| 运行时间过长 | NR和MaxIter设太大 | NR取100~200,MaxIter取300~500 |
这套排查思路基本覆盖了我遇到过的大部分问题。实际项目里信号类型千差万别,参数没有“万能最优”,只能按上述逻辑一组一组试。我的习惯是先固定PE参数,调ICEEMDAN的Nstd让分解结果稳定;再固定分解参数,调PE的m让区分度最大化;最后用小波参数精调重构质量。按这个顺序走,出问题的概率低很多,排错也更快。
另外,这个方法对三种场景的收益差别很大。一种是瞬态成分突出、噪声为高斯的信号,比如轴承外圈故障信号、心电信号的突发性干扰,这套流程的改善效果非常明显;一种是多个谐波成分+低噪声的平稳信号,PE区分本来就可有可无,基本走不到小波那一步;第三种是低信噪比(SNR低于5dB)的重噪声环境,PE筛选容易把有效IMF误判成噪声,必须结合频谱和相关系数综合判断,不能只看PE一刀切。
我个人在实际操作中还会额外做一件事:把重构前后所有IMF的排列熵画在同一张图上,一旦发现某个有效IMF的熵值在处理后不降反升,就要去查是不是小波处理引入了新的伪振荡。这套方法适合快速迭代实验,如果你手头正好有脏信号要处理,从仿真信号跑通再迁移到实测数据是最高效的路径。后续如果想进一步提升,还可以尝试把PE换成多尺度熵、或者用小波包替换经典小波,思路是一致的,只是评估维度和时频分辨率发生变化。