资讯动态

CEEMDAN-ICA联合去噪:原理、参数配置与Matlab代码详解

发布时间:2026/9/15 1:33:38 来源:尧图企业网站定制
做信号处理的同行应该都有这种体会干净的实测信号是奢侈品绝大多数场景下你手里拿到的数据都泡在噪声里。这些年我接触过振动台实测数据、心电信号、声发射信号踩了不少坑最后总结出一个相对好用的组合方案——CEEMDAN-ICA联合去噪。很多人把CEEMDAN误写成CEENDAN其实是同一个算法只是拼写习惯问题。这套方案解决的核心问题是单个算法在极低信噪比下“拆不干净”的尴尬局面。适合谁参考呢做故障诊断、生物医学信号、地球物理数据处理以及所有跟非平稳非线性信号打交道的人。这篇就把这套方法的原理、流程和可以直接跑的Matlab代码一次说清楚。1. 方法整体设计与思路拆解1.1 为什么联合CEEMDAN和ICA最划算先讲清楚一个底层逻辑去噪本质上就是“怎么把猪圈和羊圈分开”。如果噪声和有用信号在频带上完全错开那一个高通或带通滤波器就解决了根本不需要折腾。但现实里噪声和信号往往是重叠的尤其是白噪声在整个频带上都有分布这时候任何固定滤波都会把有效成分一起削掉。经验模态分解EMD类方法之所以受欢迎就是因为它自适应地把信号拆成不同尺度的本征模态函数IMF不需要预先设定基函数。但原版EMD有个老毛病叫模态混叠——不同时间尺度的成分会被塞进同一个IMF里。后来有人提出EEMD通过往信号里加多次白噪声再平均来抑制混叠效果有改善但重构后的信号里总残留一点噪声用我的话讲就是“洗衣服没漂干净”。CEEMDAN全称是Complete Ensemble Empirical Mode Decomposition with Adaptive Noise它在每次分解过程中自适应地添加噪声而不是像EEMD那样把噪声一股脑加进去所以既能抑制模态混叠又能保证分解的完备性重构误差几乎可以忽略。我在实际项目里对比过同样一段强噪声信号CEEMDAN分解后的IMF数量和残余噪声都比EEMD可控得多。但光有CEEMDAN还不够。它把信号拆成了十几个IMF噪声呢并没有单独待在一个IMF里而是渗透在好几个IMF中。这时候如果直接做阈值处理容易误伤有效成分。ICA正好补上这个短板它把IMF集合当成一组“混合观测”通过盲源分离找出统计独立的源信号噪声分量就被单独拎出来了。所以这个组合的核心逻辑是CEEMDAN负责“粗分”把混合信号按尺度摊开ICA负责“精分”把摊开之后仍然搅在一起的噪声和有用成分彻底分开。两者互补性很强这也是我后来一直推荐这个组合的原因。1.2 ICA在联合方案里到底干了什么活独立成分分析的思路简单说就是假设采集到的信号是若干个彼此独立的源信号加权混合的结果然后通过统计独立性准则把这些源一一找出来。这里有个关键前提源信号要尽可能统计独立并且最多只能有一个高斯源。放到去噪场景里完全成立——有用信号往往是非高斯的噪声近似高斯分布二者在统计特征上差别明显ICA就能把它们分开。FastICA是应用最广的实现方式它用负熵最大化的思路来逼近独立性比INFOMAX等方法收敛更快内存占用也小。在联合去噪流程里我会先选出和原信号相关性较高的IMF组成一个观测矩阵然后把它转置后丢给FastICA算法得到混合矩阵A、分离矩阵W以及独立的成分IC。这时候你大概率能看到一个很有意思的现象原本混在几个IMF里的噪声成分会集中体现在某一个IC上频谱又平又宽典型的噪声脸。不过ICA也有自己的脾气它对输入的确定性要求高如果IMF选得不齐整或者信号太短分离结果可能不稳定。所以实际使用中ICA之前的数据预处理和IMF筛选一定要做扎实后面我会专门讲这部分。1.3 这套方案适合什么场景不是所有去噪任务都需要上联合方案我先说说什么情况下用它性价比最高。第一种是极低信噪比场景比如信噪比低于0dB甚至-5dB信号已经完全被噪声淹没单一算法基本无能为力。第二种是噪声类型复杂比如混合了白噪声、工频干扰和随机脉冲用固定滤波器往往顾此失彼。第三种是非平稳非线性信号比如轴承故障的冲击信号、心电信号的ST段变化这类信号用傅里叶或小波的先验基函数很难匹配。我举个实际例子之前处理一批声发射检测数据环境噪声大还有周期性机械干扰单独用CEEMDAN时有效信号和噪声在多个IMF里纠缠怎么设阈值都别扭。后来加上ICA噪声成分被干净剥离波形轮廓一下就清楚了。当然如果你的信号信噪比本来就不低或者只是简单的高斯白噪声小波阈值法或者CEEMDAN单独就能搞定没必要杀鸡用牛刀。2. 去噪流程设计与关键参数配置2.1 五步走流程梳理整个联合去噪流程可以归纳成五个环节每一步都有明确的任务第一步预处理。去直流、归一化必要时做带通滤波把明显远离目标频段的干扰先滤掉。这里有个细节归一化特别重要因为CEEMDAN和FastICA对输入幅值的敏感度不同归一化能让参数设置更稳定。第二步CEEMDAN分解。设定噪声标准差Nstd和集成次数NR把原始信号分解成若干个IMF加一个残差项。这一步的输出质量直接决定后面ICA分离的效果。第三步IMF筛选。计算每个IMF与原始信号的相关系数挑出相关系数较高、大概率包含有效成分的IMF送入ICA。筛选太松计算量大而且噪声成分过多筛选太紧可能把有效信号漏掉。第四步ICA分离与噪声识别。对筛选后的IMF矩阵做FastICA得到若干独立成分。然后根据频谱形态、相关系数、排列熵等指标判断哪些IC是噪声主导的。第五步重构。将保留的IC通过混合矩阵A映射回IMF空间再叠加上未参与ICA的IMF和残差得到干净信号。重构这步最容易出错我用过太多次第一次写代码时把映射方向搞反。2.2 CEEMDAN参数怎么定CEEMDAN有两个核心参数Nstd和NR。Nstd是附加噪声的标准差一般取原信号标准差的0.1到0.4倍。我实操下来的经验是大多数场景取0.2比较稳。Nstd太小噪声不足以触发尺度变化模态混叠抑制效果就弱Nstd太大分解结果里会引入过多与噪声相关的虚假模态后面筛选反而麻烦。NR是集成次数也就是你重复分解多少次再取平均。理论上次数越多结果越稳定但计算量是线性增加的。我处理单通道数据时NR取200通常就够了如果信号特别长或者噪声特别强可以提升到500再往上收益就很小了。对于实验室里做研究时间不敏感取个300到500都没问题如果是工程现场调试想在手机甚至嵌入式设备上看效果建议先降到50到100跑通流程再说。还有一个容易被忽略的参数是最大筛分迭代次数很多实现里写成MaxIter一般默认几千就够。如果信号里含有极端突变点比如冲击信号可以把MaxIter适当调大避免迭代提前终止导致分解不彻底。2.3 IMF筛选与ICA参数经验值IMF筛选是整个流程里最“艺术”的环节也是新手最容易翻车的地方。我常用的方法是相关系数法把每个IMF和原始信号的皮尔逊相关系数算出来保留相关性较高的IMF。阈值怎么定呢有两条路可走。严格阈值法要求相关系数大于0.3或者0.4低于的直接认为噪声主导不进入ICA。这个办法简单粗暴但遇到信号本身能量弱、淹没在噪声里的情况容易漏选。另一种是相对比例法找到最大相关系数保留那些相关系数不低于最大值的百分之二十到三十的IMF。相比之下我更喜欢相对比例法它更自适应不用拍脑袋定绝对阈值。FastICA这边核心参数是g函数、收敛条件和迭代次数。g函数就是非线性函数默认为tanh多数情况下最稳。gpow3三次方计算量小但容易受到离群点影响ggauss适合超高斯信号比如稀疏冲击信号效果很好。我一般先用tanh跑一遍如果分离结果不理想再换成gauss试。最大迭代次数建议从默认值往上调比如设为5000输出参数中带上收敛标志即可。收敛容差设为1e-4或1e-5就够太小会拖慢速度效果提升不明显。2.4 噪声成分识别判据ICA分离出独立成分之后怎么判断哪个是噪声这是联合方法好用与否的关键一步。我总结了四个可量化的判据。第一个是频谱形态。画出每个IC的功率谱噪声成分的频谱平坦、无明显主峰有用信号则会有清晰的频率尖峰。第二个是相关系数。把每个IC和原始信号做相关如果相关系数绝对值很低说明这个成分和原始信号关系不大大概率是噪声。第三个是排列熵。排列熵衡量时间序列的复杂度和随机性噪声的排列熵明显偏高有用确定信号的排列熵较低。第四个是峭度。正常信号近似高斯分布峭度接近3而噪声或冲击成分峭度可能偏离很多虽然这需要结合场景判断。我不建议只用一个判据最好把频谱形态和排列熵两个指标结合着看。比如有的工频干扰虽然不是随机噪声但频谱上有明显的50Hz峰相关系数也可能不低这时候单看相关系数就会误判排列熵却能把它和随机白噪声区分开并一起剔除。3. Matlab代码实现与实操演示3.1 环境准备与工具箱跑这套代码需要准备两个外部工具箱CEEMDAN分解函数以及FastICA工具包。CEEMDAN函数有很多版本我常用的是File Exchange上较流行的那版函数签名是[IMF, residual] ceemdan(x, Nstd, NR, MaxIter)。FastICA工具包也很成熟核心函数是[icasig, A, W] fastica(mixedsig, approach, defl, g, tanh)。计划里如果找不到也可以直接搜“ceemdan matlab”和“fastica matlab”代码结构都差不多。我在写代码前会先做一个简单的数据检查确保输入是列向量采样率和信号长度已知因为这个会影响后续参数的合理性判断。另外建议在脚本开头清空工作区、关闭图形窗口养成好习惯。3.2 仿真信号构造与整体代码为了验证方法效果我先构造一个仿真信号再加入白噪声这样可以量化评估去噪前后的信噪比变化。下面是完整代码我建议直接复制到你的Matlab里跑一遍再改成自己的数据。%% 清空环境 clear; close all; clc; %% 构造仿真信号 fs 1024; % 采样率 1024 Hz t (0:fs-1)/fs; % 1 秒时间轴 s sin(2*pi*50*t) 0.6*sin(2*pi*120*t); % 50Hz和120Hz两个主频 noise 0.8*randn(size(t)); % 高斯白噪声 x s noise; % 带噪信号 %% CEEMDAN参数 Nstd 0.2; % 附加噪声标准差比例 NR 200; % 集成次数 MaxIter 5000; %% CEEMDAN分解 [IMF, residual] ceemdan(x, Nstd, NR, MaxIter); IMF IMF(:, 1:end-1); % 某些版本最后一列是趋势项可去掉 %% IMF筛选相对比例法 for i 1:size(IMF, 2) r(i) abs(corr(x, IMF(:, i))); end [rmax, ~] max(r); keep_idx find(r 0.2 * rmax); % 保留相关性较高的一部分IMF IMF_selected IMF(:, keep_idx); %% FastICA分离 [icasig, A, W] fastica(IMF_selected, approach, defl, g, tanh, maxNumIterations, 5000, verbose, off); % 注意fastica按列处理观测因此传入IMF_selected转置 %% 识别并剔除噪声IC ic_corr zeros(size(icasig, 1), 1); for i 1:size(icasig, 1) ic_corr(i) abs(corr(x, icasig(i, :))); end keep_ic ic_corr 0.2 * max(ic_corr); icasig_denoised icasig .* keep_ic; % 把噪声IC置零 %% 映射回IMF空间并重构 IMF_denoised A * icasig_denoised; % 注意映射方向 recon_imf zeros(size(IMF)); recon_imf(:, keep_idx) IMF_denoised; denoised sum(recon_imf, 2) residual; %% 效果评估 snr_before 10*log10(sum(s.^2) / sum((x - s).^2)); snr_after 10*log10(sum(s.^2) / sum((denoised - s).^2)); fprintf(去噪前 SNR %.2f dB\n, snr_before); fprintf(去噪后 SNR %.2f dB\n, snr_after); %% 绘图对比 figure; subplot(3,1,1); plot(t, s); title(原始干净信号); subplot(3,1,2); plot(t, x); title(含噪信号); subplot(3,1,3); plot(t, denoised); title(CEEMDAN-ICA去噪后信号);3.3 代码关键点逐行解读这段代码看着不长但每一行背后都有讲究。先说归一化问题我在这里没有额外做幅度归一化因为ceemdan内部通常会自己处理标准差FastICA也会做白化。但如果你换成自己的实测数据建议先做一次去直流和幅度归一化可以避免很多莫名其妙的数值问题。IMF_selected在送入fastica之前我做了转置。这是因为FastICA工具包把每一列当作一路观测信号而不是把每一行当作一路。这个方向搞反了出来的结果会完全对不上我在第一次用这个工具箱时就被坑过。识别噪声IC时我选了和原信号相关系数较低的那些IC直接置零。这里要注意一个隐含假设有用信号和原始信号的相关性整体高于噪声和原始信号的相关性。在多数场景下成立但个别情况比如强工频干扰可能满足不了所以更稳妥的做法是结合功率谱曲线来判断代码里便于演示只用了相关系数。3.4 运行结果解读仿真信号的两个主频为50Hz和120Hz加入噪声后信噪比大约在-3dB到-2dB之间。跑完上面代码信噪比通常会提升到8dB到12dB左右提升幅度超过10dB。去噪后的波形在时域上比原始含噪信号光滑得多两个正弦波的主频在频谱上也更加突出。有一点值得注意重构信号的端点位置可能出现轻微畸变这是EMD类方法的通病不影响整体效果。如果你的应用场景对端点特别敏感比如做精密测量建议在预处理阶段对信号两端加镜像延拓或者只评估中间段的信噪比。4. 常见问题与排查技巧实录4.1 CEEMDAN慢到怀疑人生我做实测数据时第一次跑CEEMDAN就等了一个多小时当时以为程序死循环了。后来发现是信号长度太长加上集成次数设了800计算量爆炸。排查思路很简单先把集成次数降到50Signal也做降采样处理看能不能在合理时间内跑完再逐步增加参数。另外一个办法是用MATLAB的并行计算工具箱把所有集成循环改成parfor。CEEMDAN内部很多实现并没有并行化你自己用parfor包一层能明显提速特别是四核以上的电脑效果显著。不过要小心老版本的MATLAB下parfor和某些工具箱回调函数可能不兼容最好先跑一小段验证。4.2 ICA分离结果不稳定FastICA是随机初始化算法即使同一输入跑两次结果也可能略有差异。如果你在项目里需要可复现的结果有两种处理方式。第一种是固定随机种子在代码开头加rng(0)保证每次运行结果一致。第二种是多次运行FastICA选分离效果最好的一次判断指标可以用IC的稀疏性或者排列熵。还有一个我踩过的坑是IMF_selected的长度太短时ICA几乎必然不稳定。长度少于几百个采样点的情况下不建议上ICA先用CEEMDAN或者小波去噪就好。如果必须用ICA可以先对信号做分段处理每个段单独分离再拼接但要注意拼接处可能出现不连续。4.3 去噪后信号变形信号变形一般有两种表现一种是整体幅度偏小这是重构时丢的成分过多另一种是波形局部失真比如冲击峰值被削平。前者的原因通常是IMF筛选阈值过高把有用成分和无用成分一起拒之门外了。后者的原因多为置零的IC里包含部分有效瞬态成分ICA的统计独立性假设并不完全满足时就会这样。遇到变形问题我会分两步排查。先检查keep_idx选中的IMF是否覆盖了信号的主要频带再看噪声IC中有没有明显大于3倍标准差的尖峰。如果这两个环节都正常但重构还是失真那就试试不在ICA域置零而是把噪声IC做软阈值处理比如保留幅值小于某个阈值的部分再把处理后的IC映射回去。4.4 问题速查表现象可能原因解决办法运行时间长NR过大、数据过长降NR到50-100降采样用parfor并行分解出明显虚假IMFNstd太大将Nstd降到0.1-0.15ICA不收敛迭代次数不足调大maxNumIterations到5000以上分离结果两次不一致随机初始化固定rng种子或多跑几次选最优重构后幅值偏小IMF筛选阈值太高调低阈值或改用相对比例法波形有端点畸变EMD端点效应镜像延拓预处理或只评估中间段去噪效果提升不明显信号与噪声频带严重重叠检查是否该上联合方案或调整ICA的g函数4.5 几个独家避坑技巧第一条是关于Nstd的调参如果你不确定该取多少可以用一小段试数据做“参数扫描”把Nstd从0.05到0.4各跑一次看哪个参数下重构误差最小然后应用到全量数据上。这个方法费一点时间但比凭经验拍脑袋靠谱得多。第二条我强烈建议在送ICA之前先对IMF做标准化处理让每个IMF的方差相同。不这样做的话ICA算法会倾向于照顾幅度大的IMF很小的有效成分可能被当成噪声忽略掉。第三条如果信号本身就是多通道的比如你有多通道加速度计数据建议先对通道做同步采集确认再做时延对齐补偿然后再按单通道流程逐通道处理。多通道联合ICA是另一个层面的事一般项目里先单通道跑通更重要。5. 与主流去噪方法的横向对比5.1 几种方法的优缺点对照干了这么久的信号处理我自己的原则是不迷信任何方法只迷信数据特性。各种去噪方式各有各的主场我列个表格说明。方法优点缺点推荐场景小波阈值去噪成熟快速支持好基函数和分解层数需要人工选平稳或缓变信号频带重叠不严重EMD自适应简单模态混叠严重非平稳但信噪比较高EEMD抑制模态混叠重构残留噪声中等噪声下的非平稳信号CEEMDAN单独完备重构抗混叠计算量大强噪声但噪声频带与信号区分明显CEEMDAN-ICA联合分离彻底噪声能力强参数多调参门槛高极低信噪比、混合噪声、非平稳瞬态信号小波类方法的优点在于快且解释性强缺点是不是全自适应。你选择小波基和层数的那一刻其实就默认了信号具备某种先验特征一旦信号形态不匹配效果很难保证。EMD族方法则把“基函数”问题绕过去但对噪声的抵抗力各不相同到了CEEMDAN这一代才算比较成熟。CEEMDAN-ICA联合方法的最大优势在于它把CEEMDAN的自适应分解能力和ICA的盲源信号分离能力叠在了一起等于给信号上一道“粗筛加精筛”的双保险。从实践数据看在信噪比低于0dB的环境下联合方法通常比单独CEEMDAN好3到6dB比小波好5到8dB代价是运行时间和调参复杂度。5.2 选型建议要是你的信号信噪比不低于5dB噪声类型又比较单一我建议直接用CEEMDAN或小波阈值通没必要上ICA这种重武器。联合方案真正发挥价值的地方是信噪比低、噪声混合、信号具有明显瞬态特征的项目比如轴承间歇故障、生理信号中的偶发异常、结构裂纹声发射监测。具体到参数配置我有几条经验可以分享。信号采样率超过5kHz时优先降采样到有效频带的两倍左右能大幅降低分解耗时。IMF数量小于5个时说明信号相对干净不必再上ICA。ICA输出的IC数量如果和输入IMF数量相等说明分离没有降维此时可以人工核对每个IC的频谱确保噪声确实被分到了独立的成分里而不是被强行拆散。6. 结合实测数据的几点经验心得代码能跑通只是第一步真正落地的过程才是考验。最后分享几个我自己项目里的真实体会。我在处理轴承振动数据时发现实测数据和仿真数据有个巨大区别实测信号里噪声往往不是平稳的环境噪声一会儿大一会儿小机械负荷变化还会让信号幅值也跟着变。这种情况下直接对整段数据全局做CEEMDAN分解效果常常不如先分段处理再聚合。我一般把数据切成长度约为2048或4096的窗口窗口之间重叠百分之五十对每个窗口单独去噪然后用重叠相加法拼回完整信号。这样既能保证细节又能平滑窗口边界。另外虽然这套方法的名字里带着高阶算法的味道但真正决定去噪效果上限的往往是预处理细节。比如传感器采集信号里的直流偏置如果不移除干净CEEMDAN分解出的第一个IMF可能全是直流变化带来的伪分量又比如采样率不匹配造成的工频干扰先用陷波滤波器处理一次比单纯在ICA域里等它分出来要省事得多。我的经验是预处理花的时间越多后期调参越轻松。最后再提醒一句不要在越界场景里强求这套组合。如果信号本身有效带宽极窄比如单一频率的正弦波那一个窄带滤波器几行代码就搞定的事真不需要上CEEMDAN再加ICA。每种方法都有自己的边界清楚边界比会调参更重要。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价