简介本资源是一套面向信号处理初学者与工程实践者的联合去噪MATLAB实现方案聚焦于非平稳、非线性信号中强噪声的有效抑制问题适用于机械故障诊断、生物医学信号分析及振动监测等实际场景。资源包含4个核心文件3个.m脚本含CEEMDAN分解、小波阈值处理及主流程调用与1个.mat测试数据总大小仅39KB轻量易部署代码结构清晰、注释完整便于理解CEEMDAN自适应分解与小波阈值协同去噪的原理与实现细节。已有7991人学习下载体现了其在教学演示与算法复现中的广泛认可度。用户可直接运行CEEMDAN_Wavelet.m主程序快速获得去噪前后对比结果配套y.mat提供真实含噪信号样本emd.m与ceemdan.m模块化封装便于二次开发整体设计兼顾理论严谨性与工程实用性是掌握混合去噪策略落地的关键参考。1. 为什么做了这个联合去噪的包CEEMDAN—小波阈值联合去噪.rar这个文件名是我前几天整理代码时随手起的。做信号处理的人应该一眼就明白这是一套把完全自适应噪声集合经验模态分解CEEMDAN和小波阈值去噪拼在一起的算法包。这几年它常出现在滚动轴承故障诊断、结构健康监测、脑电和心电信号预处理等场景里很多人都在问怎么把这两个方法有效结合而不是简单串在一起。之所以想把这个组合单独整理成一个包是因为我早期在项目里直接拿CEEMDAN去噪效果并不理想。当时处理一段振动信号先把CEEMDAN分解去掉几个高频IMF分量再做信号重构。重构完一看波形确实干净了不少但原始信号里那几个很明显的冲击毛刺也跟着变钝了。后来又试过只用小波阈值去噪结果是高频噪声压下去了但信号本身非平稳的趋势被当成噪声削掉一大截。最后被一篇论文点醒与其在两种方法之间二选一不如让CEEMDAN负责把信号按频率自适应拆开再对含噪分量用小波阈值做精细清洗各干各擅长的事。1.1 从一次失败的“CEEMDAN直接重构去噪”说起我先说那次翻车经历。某次做滚动轴承振动数据的故障特征提取信号采样率12800Hz数据长度2秒输入的信噪比大概在2dB左右。我按常规做法先做CEEMDAN分解得到12个IMF分量和一个残余项然后计算每个IMF与原始信号的相关系数把相关系数低于0.2的高频IMF直接扔掉剩下的重构。结果时域波形看着挺平滑但包络谱算出来后故障特征频率的幅值比原始信号直接包络分析还要低倒是几个无关的倍频成分显得很突出。我一开始以为是包络谱参数不对换了窗函数和谱线数还是不行。后来把去掉的几个IMF拿出来单个看发现第三个IMF里明明带着周期性的冲击衰减成分幅值不大但和轴承故障频率完全对应。也就是说用相关系数做筛选时这个IMF因为混有大量噪声相关系数只有0.17被“误杀”了。这件事让我意识到CEEMDAN虽然能把信号分解成不同尺度的分量但噪声并不是规规矩矩待在某个高频IMF里而是散落在多个IMF中。如果直接用“丢弃高频IMF”这样的粗放策略丢掉的可能是有效瞬态分量如果不丢重构信号里又会残留大量噪声。小波阈值去噪正好补上这个空档——它可以在不改变IMF主要趋势的前提下把系数的幅值向零收缩让噪声贡献变小而不是整个分量直接消失。1.2 CEEMDAN和小波阈值各自擅长什么CEEMDAN的全称是Complete Ensemble Empirical Mode Decomposition with Adaptive Noise中文一般叫完全自适应噪声集合经验模态分解。它是在EMD和EEMD基础上发展出来的。EMD能把非线性、非平稳信号分解成一系列固有模态函数但对噪声敏感容易出现模态混叠。EEMD通过多次添加白噪声再平均来缓解模态混叠但计算量大而且重构误差不好控制。CEEMDAN的做法是每一次分解时都加入自适应的高斯白噪声然后边分解边把残余信号平均掉既保留了EEMD抗混叠的优点又大幅减少了平均次数。小波阈值去噪则是另一套思路。它先把信号做多尺度小波分解得到近似系数和细节系数然后设定一个阈值把绝对值小于阈值的细节系数当作噪声置零或收缩再反变换回时域。这个过程对局部瞬态成分的保留能力很强因为冲击信号在小波域里会集中到少数几个大系数上而噪声会均匀分布在各尺度通过阈值就能把两者分开。两者结合的逻辑其实很简单CEEMDAN是“粗分离”把信号按频率从高到低自适应拆开小波阈值是“精清洗”把每个含噪IMF里剩下的局部噪声再处理一遍。单独用CEEMDAN你会面临“丢还是不丢”的两难单独用小波阈值你会面临“平滑还是保留瞬态”的两难。联合起来两个两难就变成了一个相对清晰的参数选择问题。1.3 什么信号适合联合去噪不是所有信号都适合这套组合。我个人总结下来联合去噪最适合三类场景。第一类是非平稳、非线性信号比如轴承故障振动、齿轮箱振动、往复机械的缸体振动。这类信号里有明显的冲击成分频率随时间变化传统带通滤波器很难同时保留宽频冲击和趋势。第二类是生物医学信号比如脑电、心电、肌电它们幅度低、干扰多CEEMDAN能把基线漂移和工频干扰分开小波阈值再处理残余的肌电噪声。第三类是结构健康监测中的应变、加速度信号环境激励强目标模态往往淹没在噪声里联合去噪能让模态参数识别更稳定。如果是平稳周期信号比如稳定的正弦波叠加白噪声直接用带通滤波或者小波阈值就够了没必要上CEEMDAN分解过程反而会引入边界效应。如果原始信号信噪比已经很高比如高于20dB联合去噪带来的提升也不明显还增加了计算量。我一般是先做一次快速频谱分析看到有明显宽频噪声底、同时又有局部瞬态成分才考虑用这套组合。2. 联合去噪主流程每一步的参数都不能拍脑袋整套流程可以概括成四步CEEMDAN分解、IMF分类、小波阈值去噪、信号重构。听起来简单但每一步都有不少参数参数选不对结果可能比单方法还差。下面把每一步的关键点拆开讲。2.1 第一步CEEMDAN分解参数设置CEEMDAN分解时最核心的三个参数是Nstd、NR和MaxIter。Nstd是添加白噪声的标准差与原始信号标准差的比值通常取0.1到0.3。NR是集成次数也就是重复分解的次数一般取50到200。MaxIter是每个IMF筛选迭代的最大次数MATLAB版通常是5000。Nstd可以理解成“探针”的力度。太小了白噪声不足以激发出潜在的模态模态混叠问题还是存在太大了白噪声会残留在IMF里后面小波阈值去噪要花更大代价才能清掉。我实际用下来常规振动信号从Nstd0.2开始试脑电这类比较弱的信号可以降到0.1强冲击信号甚至可以到0.25但要配合后面的阈值参数调整。NR决定了稳定性和计算时间的平衡。NR越大分解越稳定但计算时间成倍增加。一个长度2万点的信号NR从50涨到200运行时间可能从几十秒变成几分钟。我的经验是先用NR50快速跑一遍看IMF数量和形态是否合理如果明显有模态混叠再加到100或200。不要一上来就NR500那是在浪费机器。MaxIter一般不用动默认5000足够。如果分解后出现某个IMF明显被“截断”或出现不自然的平台段可以考虑调大MaxIter但更多时候是信号本身有间断造成的。2.2 第二步哪些IMF需要二次去噪分解完之后通常得到十几个IMF不能一视同仁地全部做小波阈值去噪。低频IMF往往已经很干净强行去噪会把趋势和缓变成分压平高频IMF又可能全是噪声去噪后仍然意义不大。真正需要处理的是那些“半干半湿”的IMF——含有有效成分但噪声污染明显。我常用的筛选指标有三个相关系数、能量占比和峭度。相关系数是最直观的。计算每个IMF与原始信号的Pearson相关系数正常情况下前几个高频IMF相关系数很低中间几个开始升高到最后几个低频分量相关系数很高。如果某个IMF相关系数低于0.1大概率是噪声主导可以考虑直接舍弃相关系数在0.1到0.5之间的是重点小波去噪对象高于0.5的直接保留。但相关系数有盲区。回到我前面提到的轴承故障案例冲击成分微弱且被噪声掩盖时相关系数可能只有0.17但它确实包含了关键故障信息。所以还需要看峭度。峭度是四阶中心矩除以方差的平方高斯噪声的峭度接近3冲击信号的峭度远大于3。如果某个IMF相关系数不高但峭度明显高于3比如大于5那这个IMF很可能藏着冲击特征不能丢必须做小波阈值去噪而不是直接舍弃。能量占比是第三个参考量。把每个IMF的能量除以所有IMF总能量占比很小的IMF通常是纯噪声可以丢。我自己习惯把“相关系数 峭度”两个指标结合用0.1和3.5作为初步阈值再观察频谱微调。千万别把阈值定死不同信号差异很大。2.3 第三步小波阈值去噪参数整定小波阈值去噪有四个参数要定小波基、分解层数、阈值规则、阈值函数。小波基的选择和信号形态有关。常见的db4、db8、sym8、coif4都能用区别在于对称性和消失矩。db4较短对冲击的定位能力强适合轴承故障这类瞬态信号sym8较平滑适合生物信号和缓变信号db8居中适合振动信号。我也见过有人用bior小波但实际对比下来db族和sym族的稳定性更好。分解层数一般取3到5层。层数太少噪声压不下来层数太多重构时边界失真变大。层数可以这样参考数据点个数在2000以内取3层5000到10000取4层更长取5层。不是层数越多越好我曾经在长信号上取7层结果去噪后波形出现明显的“分段感”就是因为每层系数长度不均匀阈值处理引入的边界误差被逐级放大。阈值规则有四个常用选项rigrsure、sqtwolog、heursure和minimaxi。rigrsure是无偏风险估计适合信噪比中等偏高的信号去噪后细节保留好sqtwolog是固定阈值压噪彻底但对细节损伤大heursure是前两者的混合兼顾一点minimaxi是最保守的去噪幅度最小。强噪声环境下我倾向于用heursure或sqtwolog弱噪声下用rigrsure。阈值函数通常分软阈值和硬阈值。软阈值把所有系数向零收缩连续性好去噪后波形光滑但信号幅值会被压缩硬阈值是保留大于阈值的系数小于阈值的置零冲击保留能力强但在阈值点不连续重构后可能出现局部抖动。做轴承故障诊断时我基本用硬阈值做脑电去噪时用软阈值。2.4 第四步重构策略重构不是简单把所有IMF加回去还要注意哪些分量参与重构、哪些不参与。最稳妥的策略是有效IMF中纯噪声主导的直接舍弃含噪但保留价值高的用小波阈值去噪后参与重构相关系数高且峭度正常的低频IMF原样保留参与重构残余项一般保留因为它代表信号的趋势。最后把处理后的所有分量相加得到去噪信号。有人会问能不能对每个IMF都做小波阈值去噪再全部重构我试过结果不理想。低频IMF本身信噪比很高做阈值去噪后幅值被压低重构信号整体幅度反而变小趋势被扭曲。所以千万别“一刀切”。另一种改进做法是加权重构。根据每个IMF去噪前后的相关系数变化给不同IMF分配不同权重。相关系数高的给权重1去噪后相关系数明显提升的给权重1.1或1.2噪声主导的给权重0。这样做理论上能进一步提升信噪比但权重系数需要调试容易过拟合。我自己的建议是先做不加权方案跑通后如果还不够再试加权。3. 仿真对比联合去噪到底带来了多少提升光说原理没用得用数据说话。我设计了一个相对苛刻的仿真信号分别用CEEMDAN直接重构、单独小波阈值去噪和联合去噪三种方式处理对比信噪比和均方根误差。下面是我的测试条件和结果。3.1 构造一个能说明问题的仿真信号我构造的信号由三部分组成一个50Hz正弦波一个120Hz二倍频正弦一个周期性冲击衰减序列最后叠加上高斯白噪声。冲击衰减的表达式可以写成x_imp(t) A * exp(-alpha * (t - t0)) * sin(2 * pi * f_c * (t - t0))其中A取1.2alpha取300f_c取800Hz冲击每0.1秒出现一次。采样率设为1024Hz时长1秒这样能模拟一个带高频冲击的旋转机械振动信号。最后加的高斯白噪声标准差调成输入信噪比约为5dB。这个参数组合的妙处在于50Hz和120Hz是平稳分量800Hz冲击是瞬态分量白噪声是宽频干扰。单独用小波阈值去噪容易把冲击的局部能量当噪声压掉单独用CEEMDAN重构则容易在筛选IMF时丢掉冲击分量。只有联合去噪才有可能同时稳住平稳分量和瞬态分量。3.2 三种方法的去噪结果对比处理前先给原始信号加噪声得到输入信噪比5dB。第一种方法是CEEMDAN直接重构Nstd0.2NR100相关系数阈值0.2低于阈值的IMF丢弃其余重构。第二种方法是单独小波阈值去噪小波基db4分解层数4heursure规则软阈值。第三种方法就是联合去噪CEEMDAN分解后对相关系数在0.1到0.5之间的IMF做小波阈值去噪相关系数大于0.5的IMF保留小于0.1的丢弃然后重构。结果如下在我这组测试条件下的数值方法SNR(dB)RMSE含噪信号5.00.243CEEMDAN直接重构11.80.102单独小波阈值去噪10.50.117联合去噪16.20.049可以看出联合去噪比CEEMDAN直接重构的SNR提升了4.4dBRMSE降了一半左右。单独小波阈值去噪反而比CEEMDAN直接重构差一点因为在仿真信号里冲击衰减成分被软阈值处理压得太狠了。3.3 从时域波形和频谱两个维度看效果时域上最明显的差异在冲击位置。原始无噪信号的冲击幅值大约是1.2加噪后冲击幅度被噪声淹没时域波形看起来就是一簇毛刺。CEEMDAN直接重构后冲击位置能看到但幅度只有0.8左右且冲击前沿变得不太陡。单独小波阈值去噪后的冲击幅度只有0.6明显被压缩。联合去噪后的冲击幅度恢复到1.05左右形状也更接近原始。频谱上含噪信号的噪声底几乎覆盖整个频带50Hz和120Hz的谱线勉强可见。CEEMDAN直接重构后噪声底有所下降但在800Hz附近还是有一段较高的噪声平台因为冲击分量所在的IMF没有被完全清洗。联合去噪后噪声底明显压低50Hz、120Hz和800Hz附近的谱峰都更加突出。这里要强调仿真结果是在特定参数下得到的换一组参数可能数值不同但趋势基本一致。如果你自己跑出来的提升没这么大大概率是IMF筛选阈值或小波阈值规则没调好。4. 工程实测那些不跑仿真就发现不了的坑仿真信号再怎么逼真也比不上实测数据“教育人”。下面这几个坑是我在项目里反复踩过之后总结出来的每一件都有实际案例支撑。4.1 端点效应怎么压都不干净CEEMDAN分解时每个IMF的两端都会出现较大的摆动这就是端点效应。因为EMD类方法用三次样条包络拟合信号极值点数据两端没有足够极值点包络就抖得厉害。小波阈值去噪虽然本身没有这个问题但如果你对含噪IMF做小波分解时边界处理不当会把端点效应再放大。我一开始没管端点效应直接分解、去噪、重构结果去噪信号的前后几十个点严重变形做功率谱时漏出来一大片低频假成分。后来试了几种延拓方法效果最稳定的是镜像延拓把信号在两端做镜像反射延长大约10%的长度分解完再截掉延拓段。AR模型预测延拓我也试过确实更精确但模型阶数不好定有时候延拓段和真实信号趋势相反反而更糟。如果是批量处理短片段比如每段只有2000点我建议直接把每段前后各砍掉1%到2%的点再用去噪后的中间部分做分析。虽然少了点数据但能避免端点效应污染整个分析结果。4.2 白噪声参数不是越大越好很多初学者认为Nstd越大抗模态混叠能力越强结果把Nstd设成0.5甚至更高。实际测试下来Nstd太大时分解出的IMF里会残留大量白噪声成分而且这些残留集中在前面几个高频IMF里。后续做小波阈值去噪时为了把这些残留清掉阈值会被迫抬得很高导致原本有效的瞬态成分一起被削掉。我现在的做法是先取一小段数据用Nstd0.1、0.15、0.2、0.25分别跑一次看前两个IMF的时域波形和频谱。如果第一个IMF和第二个IMF在某些频段同时出现大面积重叠的峰值说明模态混叠没有解决优先增加NR而不是增大Nstd。通常NR从100加到200比Nstd从0.2升到0.4更有效。还有一点MATLAB和Python里CEEMDAN的Nstd定义略有差异。MATLAB的Nstd通常指白噪声标准差与信号标准差之比Python的PyEMD库在CEEMDAN类中用的是epsilon参数含义类似但我实测下来默认阈值还需要再微调。代码跨平台或者跨语言迁移时不要再沿用老的参数组合一定要重新标定。4.3 阈值函数一选错冲击特征就没了对于带冲击的机械信号阈值函数的选择几乎决定成败。我在某次齿轮箱振动信号处理中先用了软阈值去噪后包络谱的啮合频率边带幅值正常但冲击事件对应的边带幅值压得很低。后来换成硬阈值边带幅值显著回升但时域信号里出现了一些轻微的高频毛刺——这是硬阈值不连续导致的振荡。如果既要保留冲击又不想看到硬阈值的毛刺可以用改进阈值函数比如在阈值边界做平滑过渡。还有一个小技巧是“周期平移”cycle spinning对信号做多次循环平移每次平移后去噪再平均回去。这样能大幅抑制硬阈值造成的局部不连续代价是计算量成倍增加。我一般只对关键IMF做这一步而不是对全部分量做。4.4 批量处理时的参数自适应最让人头疼的是批量处理几十上百个文件时噪声水平各不相同。固定一组参数可能前10个文件效果好第11个文件就崩了原因就是那个文件噪声特别大。手动逐个调参数不现实得让程序自己估计噪声水平。我的做法是对每个IMF先求小波第一层细节系数的中位数绝对偏差然后除以0.6745当作噪声标准差估计再结合IMF长度计算阈值。这个过程相当于把“小波阈值去噪”里的参数选择自动化了不需要人为指定阈值。对于CEEMDAN参数也可以设置一个简单规则先看信号的峭度峭度高就提高NR峭度低就降低NR信号长度长就降低NR短就提高NR。这套规则没法做到最优但能保证批量处理时结果不出现大的偏差。5. 代码模板与参数速查拿走就能跑最后给出可以直接套用的代码框架。我同时写了MATLAB和Python两个版本核心逻辑完全一致分解、筛选、小波去噪、重构。代码里用到的CEEMDAN函数MATLAB版可以在现有工具箱基础上改Python版用PyEMD库安装和调用都比较简单。5.1 MATLAB核心代码下面这段代码假设你有CEEMDAN函数函数签名是[imf, residual] ceemdan(x, Nstd, NR, MaxIter)。这个函数在不少学术代码库里都能找到自己整理一下就能用。function x_den ceemdan_wdenoise(x, fs) % 联合去噪主函数 % 输入: x - 原始信号, fs - 采样率 % 输出: x_den - 去噪后信号 Nstd 0.2; NR 100; MaxIter 5000; % 1. CEEMDAN分解 [imf, residual] ceemdan(x, Nstd, NR, MaxIter); % 2. 计算相关系数和峭度 n_imf size(imf, 2); corr_coef zeros(n_imf, 1); kurt_val zeros(n_imf, 1); for i 1:n_imf tmp imf(:, i); corr_coef(i) abs(corrcoef(tmp, x)); corr_coef(i) corr_coef(1, 2); kurt_val(i) kurtosis(tmp); end % 3. 筛选需要小波去噪的IMF x_den zeros(size(x)); for i 1:n_imf if corr_coef(i) 0.1 corr_coef(i) 0.5 % 含噪IMF用小波阈值去噪 x_den x_den wden(imf(:, i), heursure, s, mln, 4, db4); elseif corr_coef(i) 0.5 || kurt_val(i) 5 % 相关系数高或峭度高的IMF原样保留 x_den x_den imf(:, i); end % 相关系数小于0.1且峭度不突出直接丢弃 end x_den x_den residual; end这段代码把筛选逻辑写得很清楚相关系数0.1到0.5之间的分量做小波去噪相关系数高于0.5或者峭度大于5的分量原样保留其余丢弃。实际使用时如果你发现某些冲击分量相关系数低于0.1但峭度很高需要把kurt_val(i) 5这个判断条件提前。另外wden里的阈值规则、小波基和分解层数都应根据信号类型调整不能死搬。5.2 Python核心代码Python版本我习惯用PyEMD库做CEEMDAN用PyWavelets做小波去噪。安装命令是pip install PyEMD PyWavelets不同版本PyEMD的CEEMDAN接口略有不同我下面写的是兼容性比较好的写法。import numpy as np import pywt from PyEMD import CEEMDAN def ceemdan_wdenoise(x, fs): # 1. CEEMDAN分解 ceemdan CEEMDAN(trials100, epsilon0.2) imfs ceemdan.ceemdan(x) # 如果返回的是二维数组行是IMF列是时间 if imfs.ndim 2 and imfs.shape[0] imfs.shape[1]: imfs imfs.T n_imf imfs.shape[0] # 2. 相关系数和峭度 corr_coef np.array([ abs(np.corrcoef(imf, x)[0, 1]) for imf in imfs ]) from scipy.stats import kurtosis kurt_val np.array([kurtosis(imf) for imf in imfs]) # 3. 筛选并重构 x_den np.zeros_like(x) for i in range(n_imf): imf imfs[i] if 0.1 corr_coef[i] 0.5: # 小波阈值去噪 coeffs pywt.wavedec(imf, waveletdb4, level4) # 用第一层细节系数估计噪声标准差 sigma np.median(np.abs(coeffs[-1])) / 0.6745 thr sigma * np.sqrt(2 * np.log(len(imf))) coeffs_th [pywt.threshold(c, thr, modesoft) for c in coeffs] imf_clean pywt.waverec(coeffs_th, waveletdb4) x_den x_den imf_clean elif corr_coef[i] 0.5 or kurt_val[i] 5: x_den x_den imf return x_den这个Python版本和MATLAB版本有个区别阈值不是固定用heursure而是用sigma * sqrt(2*log(N))自动估计这样对不同噪声强度的IMF适应能力更强。PyEMD的CEEMDAN类参数里trials对应NRepsilon对应Nstd和MATLAB版略有差异务必根据你的库版本调整。如果分解后imfs第一维是时间第二维是IMF数量记得查看官方文档确认维度顺序。5.3 参数速查表下面是我在不同场景下比较常用的参数组合可以直接作为初始值。每个场景我都至少做过两组数据验证不能保证最优但能保证不跑偏。应用场景NstdNR小波基分解层数阈值函数备注滚动轴承故障冲击0.2100db44hard优先保留冲击特征阈值规则用heursure齿轮箱振动0.2150db84soft齿轮啮合频率平稳可适当平滑脑电信号去噪0.1200sym85soft基线漂移明显时保留残余项心电信号预处理0.15100db64soft注意避免压缩QRS波幅值结构应变慢变信号0.250sym43soft信号变化平缓层数不用太多强噪声背景下的振动0.25200db45hard先做一次预去噪再分解效果更稳这些参数不是死的。Nstd可以从0.1到0.3之间做一次小扫描看分解出的IMF个数和形态NR在100左右通常够用小波基如果感觉冲击保留不理想换成coif4试试分解层数则根据数据长度按之前说的规则调整。总之先按表跑一遍再根据结果微调是最快的路径。5.4 个人使用体会最后说点个人体会。做了这么多去噪工作我最大的感受是算法包里最值钱的部分不是那一两行核心函数而是你对自己信号形态的理解。CEEMDAN加小波阈值联合去噪不是把两个方法接起来就能用的“银弹”它需要你清楚知道信号里有哪些成分不能丢、哪些噪声必须压。跑通一个仿真很容易把一组固定参数用到所有数据上一定会翻车。我现在的习惯是拿到新数据后先不做去噪直接看时域波形、频谱、包络谱心里有个大概判断然后用默认参数跑一次联合去噪把每个IMF的相关系数和峭度打出来对照一下最后再根据结果决定是否调整小波基和阈值函数。整个流程走下来花费的时间比直接套用参数多不了多少但效果稳定得多。这个rar包里包含的就是这套流程的实现代码可以拿去改参数表也可以当速查手册用。希望这篇分享能让你少走一点我之前走过的弯路。本文还有配套的精品资源点击获取