从EMD到CEEMDAN:噪声辅助分解的模态混叠、完备性与残余噪声 简介CEEMDAN算法配套实现包面向从事非线性、非平稳信号分析的研究者与工程技术人员聚焦EMD、EEMD在模态混叠与稳定性上的不足提供可对照学习的自适应噪声完全集成经验模态分解实现。压缩包共5个文件包含4个.m源码脚本和1个.mat信号数据整体约32KB源码覆盖分解主流程与示例调用数据可用于复现实验并观察IMF分量。已有5935人学习下载说明其在算法入门与实验复现中具有一定参考价值。读者可据此梳理添加自适应噪声、迭代执行EMD、集成平均及IMF提取的关键环节理解收敛速度与分解精度的改进逻辑并可将思路迁移至地震波解析、心电脑电处理、金融序列分析和机械故障诊断等场景适合作为算法对比实验与课程实践的轻量素材。1. 加噪声反而更干净CEEMDAN 到底在修 EMD 的哪个洞把一段含冲击的振动信号丢进 EMD经验模态分解跑出来的 IMF 常常让人皱眉同一阶分量里既有几十赫兹的工频干扰又有几百赫兹的瞬态冲击两种尺度黏在一起谁也没法单独拿去做包络谱。于是有人反其道而行往信号里塞白噪声——按直觉这应该更脏结果模态混叠反而散了。这就是 EEMD 的立论起点噪声不是干扰是脚手架。而 CEEMDAN 在 EEMD 之上又补了一刀把「集合平均留下的残余噪声」和「重构对不上原信号」这两笔欠账一起还了。搞懂这条演进线等于搞懂自适应分解里最核心的一组设计取舍确定性、完备性、计算量三者不可兼得。2. EMD 的筛分机制模态混叠为什么会自己长出来2.1 筛分与 IMF 的两个硬条件窄带假设从哪来EMD 的全部野心可以压成一句话把信号拆成若干个能算瞬时频率的分量。而「能算瞬时频率」这件事有前提——信号必须是窄带的。Huang 给的判定不玩虚的直接落成两个可编程检查的条件一是极值点个数与过零点个数之差不超过 1二是上下包络线的局部均值为零。前者拦住了「骑在另一个分量上」的情况后者拦住了「带着局部直流偏置」的情况。两条合起来就是在没有傅里叶变换的前提下硬造出一个窄带的定义。筛分sifting就是反复把这两个条件逼出来的过程。取当前信号的局部极大值做上包络、局部极小值做下包络两条包络取平均得到均值曲线 m(t)令 h(t) x(t) − m(t)再对 h 重复同样的操作。每减一次均值相当于做一次「数据自适应的去趋势」。它不依赖任何基函数也没有固定截止频率——这正是 EMD 对非平稳信号有效的原因也是它没有解析解、只能靠迭代逼近的原因。用代码把这一步摊开核心只有几十行难的是边界和停止条件import numpy as np from scipy.interpolate import CubicSpline def find_extrema(x): 差分符号变化定位局部极大/极小返回索引 d np.diff(x) max_idx np.where((d[:-1] 0) (d[1:] 0))[0] 1 min_idx np.where((d[:-1] 0) (d[1:] 0))[0] 1 return max_idx, min_idx def envelope(idx, val, n, modemirror): 三次样条构造包络端点先镜像延拓一个极值周期抑制外推发散 if mode mirror: t np.concatenate(([-idx[0]], idx, [2 * (n - 1) - idx[-1]])) v np.concatenate(([val[0]], val, [val[-1]])) else: t, v idx, val cs CubicSpline(t, v, bc_typenatural) # 自然边界二阶导端点为零 return cs(np.arange(n)) def sift(x, sd_th0.2, max_iter10): 单次筛分反复减均值直到 SD 准则或迭代上限 h x.copy() for _ in range(max_iter): max_idx, min_idx find_extrema(h) if len(max_idx) 2 or len(min_idx) 2: break # 极值点太少无法构造包络 upper envelope(max_idx, h[max_idx], len(h)) lower envelope(min_idx, h[min_idx], len(h)) m 0.5 * (upper lower) h_new h - m # SD 停止准则两次筛分结果的归一化能量差 sd np.sum((h - h_new) ** 2) / (np.sum(h ** 2) 1e-12) h h_new if sd sd_th: break return hsd_th取 0.2~0.3 是行业默认max_iter必须设上限是因为过度筛分会把 IMF 磨成纯粹的调幅调频信号物理意义反而丢失——冲击成分的瞬态特征会被「筛」平。这一点很容易踩坑把 SD 阈值调到 0.05 以下看着 IMF 更「干净」了实际上故障特征已经被磨没了。bc_typenatural只是保底真正决定端点行为的是延拓方式下一节展开。2.2 三次样条与端点效应误差怎么沿着迭代往中间爬包络拟合用三次样条几乎是默认选择理由是它二阶连续、能跟上极值点的曲率变化。代价是样条在数据区间之外是发散的——信号两端如果没有极值点样条只能靠外推而外推的曲线会剧烈上翘或下坠。这就是端点效应的源头。误差的传播有两条路径很多人只注意到第一条。第一条是向内每次筛分减均值时端点附近的错误包络值被减进 h(t)下一轮极值点定位就可能偏移误差一轮一轮往里带。第二条是向外每提取出一阶 IMF残差 r(t) x(t) − c(t) 的两端就累积一次误差等到分解低频分量时两端已经偏得离谱表现为低频 IMF 头尾翘起数值甚至超出原信号范围。常见的对策是延拓思路都是「让样条在端点附近有据可依」镜像延拓把端点附近的极值对称翻到外侧极值点延拓直接在端点补一个估计极值自回归延拓用信号自身的相关性外推一段。还有一种工程做法是加窗——对信号两端乘一个缓升缓降的窗人为把端点压到零代价是丢掉一小段数据。我一般会这么理解这三类方案延拓是「补数据」加窗是「弃数据」前者保长度但引入假设后者保真实但损失样本选哪个取决于你后面要做什么分析。2.3 模态混叠极值点分布不均才是病根模态混叠的典型表现有两种一个 IMF 里同时含尺度差异很大的成分或者同一尺度成分散落在多个相邻 IMF 里。它在时域上看着像「一阶分量忽然抖了一下」在 Hilbert 谱上看着像同一条频率脊线断成几截、跳到别的阶上去。病根不在筛分算法在极值点的分布。包络只在有极值的地方被定义如果信号前半段只有低频、后半段只有高频那么插值出来的均值曲线会把后半段的高频振荡「抄」进低频分量里——因为在那个时间段极值点全由高频提供包络自然跟着高频走。间歇性成分比如周期性出现的冲击是最容易触发这个问题的它在时间轴上是稀疏的极值点在时间轴上分布极不均匀。这里有个容易被忽略的性质EMD 是确定性算法给定信号输出唯一。所以模态混叠不是随机误差是系统性的结构缺陷重跑一百次结果一模一样。这解释了后面所有改进为什么都走「随机化 集合平均」这条路——只有引入随机性才能用统计手段去修一个确定性的结构缺陷。判断是否混叠实用做法是看每个 IMF 的瞬时频率方差或者直接把各阶 IMF 画在同一张时频图上找脊线断裂。3. EEMD 的统计化改造白噪声凭什么能抹平间歇性3.1 白噪声的二进滤波器组加噪等于给极值点重新铺格子EEMD 的做法看着粗暴往原信号里加一组高斯白噪声做一次 EMD重复 N 次把每次得到的第 k 阶 IMF 取平均作为最终的第 k 阶。噪声在平均里被压掉信号被保留。它成立的技术支点有两个缺一不可。第一个是白噪声在频域上是平的任何频段都有能量所以它能在时间轴上把所有位置的极值点密度「填匀」——原本某段只有高频极值、某段只有低频极值的信号加噪之后每一段的极值点都变得稠密且尺度混合包络均值不再被单一尺度绑架。噪声在这里扮演的是「均匀参考系」的角色让不同尺度的成分在同一套极值网格上被公平对待。第二个支点更隐蔽白噪声经 EMD 分解后各阶 IMF 的能量近似按二倍频程分布等价于一组二进滤波器组。这个性质意味着一次 EMD 分解实际上是把信号投影到一组中心频率近似倍频的频带上而这些频带的边界由数据自身决定。加噪之后再分解相当于用一个尺度均匀的「探测器阵列」去扫信号间歇成分被分散投影到多个尺度上集合平均时各自归位。注意二进滤波器组是对白噪声统计意义上的近似结论对确定性信号不严格成立。用它来指导参数选择可以用它来推导误差上界会翻车。3.2 两个旋钮噪声幅值与集合数怎么定EEMD 只有两个关键参数但它们的耦合关系经常被忽视。噪声幅值比 a 定义为加入噪声的标准差与信号标准差之比常用 0.2~0.5集合数 NE 是一次分解重复的次数常用 100~200。经验公式给了一个量化的取舍e a / √NE其中 e 是集合平均后的相对误差。代入 a 0.2、NE 100得 e 0.02想要 1% 的误差NE 得提到 400。这个公式的真正含义不是「照着填」而是告诉你两件事噪声加得越猛需要的集合数越多平方关系成本涨得很快集合数增加带来的误差下降是 1/√NE 的属于典型的边际递减——NE 从 100 加到 400 只换来误差减半计算时间却翻了四倍。选 a 的经验是看信号的频谱重心高频成分主导时 a 取小0.1~0.2否则噪声会把高频细节糊掉低频缓变信号 a 可以取大0.3~0.5因为噪声主要影响高频段对低频分量的干扰小。另一个判据是看信号是否含强冲击冲击是宽带瞬态加噪后容易和冲击的高频成分混在一起这类信号 a 要压到 0.1 以下靠加大 NE 补精度。def eemd(x, NE100, ratio0.2, max_imf8, seed0): EEMD整体加噪 - 完整 EMD - 逐阶集合平均 rng np.random.default_rng(seed) # 固定种子保证可复现 sigma np.std(x) acc [] # 按阶累积 IMF for _ in range(NE): w rng.standard_normal(len(x)) * sigma * ratio imfs emd_decompose(x w, max_imf) # 对加噪信号做完整分解 for k, c in enumerate(imfs): if k len(acc): acc.append(np.zeros_like(x)) acc[k] c imfs_avg [c / NE for c in acc] # 集合平均噪声方差降到 1/NE resid x - np.sum(imfs_avg, axis0) # 用减法制残差保证可重构 return imfs_avg, residratio是相对sigma的这一点很关键——如果实现里把它当绝对值用遇到幅度量级 1e-3 的传感器信号加进去的噪声直接等于把信号淹了。seed必须固定否则同一份数据跑两次IMF 阶数都可能不一样论文复现和工程验收都会翻车。最后用减法反算残差而不是直接用分解出的残差是为了让 ΣIMF resid 精确等于原信号。3.3 集合平均之后的那笔账残余噪声为什么还不掉EEMD 常被说成「解决了模态混叠」但它没说的是代价。加进去的噪声不会因为有 NE 次平均就消失它只是从标准差 a 降到了 a/√NE。这意味着一阶 IMF高频、能量小里始终叠着一层宽带底噪在包络谱上表现为一片抬起来的背景弱故障特征很容易被这层底噪盖住。更麻烦的是完备性。严格来说加了噪声之后分解再平均结果不等于原信号的分解——重构误差不为零且这个误差随 a 增大而增大。有些实现干脆用「原信号减去所有 IMF」来凑残差把误差全塞进残差项里看起来重构完美了实际上残差里混进了本该属于 IMF 的噪声成分趋势项被污染。还有一个理论层面的隐患EMD 是非线性变换对 N 个加噪信号分别分解得到 N 组 IMF再逐点平均平均后的分量不保证仍然满足 IMF 的两个条件。实践中大多数情况下它够用但在严格的分析场景比如要拿 IMF 去做瞬时频率的物理解释里这个「近似合法」是需要说清楚的。CEEMDAN 的改动本质上就是冲着这两笔账去的。4. CEEMDAN 的逐阶残差噪声为什么必须先过一次 EMD4.1 把 EMD 算子化E_k(·) 这个记号带来什么CEEMDAN 的第一个贡献是把 EMD 从「一次性动作」变成「可调用的算子」。记 E_k(x) 为对信号 x 做 EMD 后取第 k 阶 IMF。这个记号看着只是写法变化实际改变了算法结构既然可以单独取某一阶就不必每次都对整段信号做完整分解。有了这个算子EEMD 的结构问题就暴露得很清楚。EEMD 是对原信号加一次噪声、做完整分解、最后逐阶平均这意味着第 k 阶 IMF 的噪声污染来自「同一个白噪声经 EMD 后剩下的第 k 阶分量」。白噪声的能量按二进分布集中在高频越往高阶噪声的残余能量越小但依然存在而且它是通过一次完整的分解「顺带」留下来的无法针对性清除。CEEMDAN 把顺序倒过来不是先分解再平均而是逐阶「加噪 → 只取第一阶 → 平均 → 减残差」。每一阶只关心当前这一阶的噪声上一阶处理完立刻从残差里剥掉噪声没有机会往后面的阶累积。4.2 逐级残差加噪为什么噪声要先过一遍 EMD第一阶的处理和 EEMD 一致IMF₁ (1/N) Σ E₁(x ε₀·wᵢ)然后 r₁ x − IMF₁。真正的改动从第二阶开始IMF_k (1/N) Σ E₁( r_{k−1} ε_{k−1} · E_{k−1}(wᵢ) )注意括号里那一项加进去的不是白噪声 wᵢ而是白噪声经过 EMD 之后取的第 k−1 阶分量。这是整个算法最容易被略过、也最值得琢磨的一处设计。理由在于尺度匹配。第 k 阶残差 r_{k−1} 里剩下的主要是较低频的成分而白噪声的能量集中在高频。如果直接把白噪声加到 r_{k−1} 上噪声的大部分能量落在残差里已经不存在的频段对当前阶的极值点分布几乎没有贡献——白加了更糟的是这些高频噪声会在后续筛分中被当作独立分量提出来变成新的残余噪声留在低阶 IMF 里。先用 E_{k−1}(w) 把噪声「搬」到与残差相近的尺度上加进去才真正改变了当前阶的极值点分布加噪效率才高。另一个工程上的好处是计算量可控每次内部只取 E₁第一阶 IMF意味着内部 EMD 做几轮筛分就可以停不必分解到底。这一点在集合数 N 取几百时非常实在。def ceemdan(x, NE100, eps00.2, max_imf10, seed0): CEEMDAN逐阶加噪、只取第一阶 IMF、立刻更新残差 rng np.random.default_rng(seed) sigma_x np.std(x) imfs, r [], x.copy() for k in range(1, max_imf 1): max_idx, min_idx find_extrema(r) if len(max_idx) len(min_idx) 3: break # 残差已无足够极值退化为趋势项 # 幅值系数随残差尺度自适应残差越小噪声绝对幅度越小 eps eps0 * np.std(r) / (sigma_x 1e-12) acc np.zeros_like(x) for _ in range(NE): w rng.standard_normal(len(x)) # 关键k1 用白噪声本身k2 用白噪声的第 k-1 阶 IMF n_k w if k 1 else emd_imf(w, k - 1) acc emd_imf(r eps * n_k * sigma_x, 1) imf_k acc / NE imfs.append(imf_k) r r - imf_k # 精确减法保证完备性 return imfs, r # r 是趋势项必须一起返回eps0是基准幅值比eps eps0 · σ(r)/σ(x)是自适应缩放随着阶数上升残差幅度递减如果 ε 固定不变噪声的相对强度会越来越大最后把残差淹没分解出一堆由噪声驱动的虚假 IMF。emd_imf(w, k-1)这一行是算法灵魂注释里写清楚它的作用——尺度对齐。循环退出条件用极值点数量而不是固定阶数是因为不同信号的天然阶数不同硬编max_imf会在某些信号上切掉有效分量。4.3 ε_k 与停止条件什么时候该收手噪声幅值系数的取法在文献里有几套实用的有两套。一套是固定 ε简单但前面说的缺陷明显另一套是按残差标准差自适应即 ε_k ε₀ · σ(r_k)/σ(x)这也是多数开源实现的默认。后者的物理含义是始终保持噪声与当前残差有一个固定的信噪比不让噪声在低阶分量里相对变强。停止条件比幅值系数更容易被忽视。三条常用判据残差的极值点少于 3 个无法构造上下包络再分解没有意义残差已经单调或近似单调达到预设的最大阶数。第一条最本质它对应的是「残差已经退化成趋势项」这个物理事实。工程上还会加一条能量判据当某一阶 IMF 的能量占比低于阈值比如 0.1%时停止避免继续分解纯噪声。需要提醒的是CEEMDAN 的阶数通常比 EEMD 少。因为每阶都做了尺度对齐噪声不会在低阶累积出虚假分量分解自然更早收敛。如果发现自己的 CEEMDAN 跑出十几阶先别怀疑算法去看eps0是不是设太大了。4.4 完备性与残余噪声两笔账分开算CEEMDAN 最实在的优势是完备性。因为残差是精确减出来的r_k r_{k−1} − IMF_k 是恒等式所以 x Σ IMF_k r_K 严格成立重构误差只受浮点精度影响。这跟 EEMD 里「加噪导致重构对不上」是本质区别——EEMD 的重构误差是算法性的CEEMDAN 的不是。但完备性不等于干净。IMF 里仍然残留着噪声量级还是 O(ε/√NE)只是它不再体现为重构误差而是体现为每个 IMF 上的宽带底噪。这两笔账必须分开算重构误差看 ΣIMF r 与原信号的差值残余噪声看 IMF 在无信号频段的能量。只看前者会得出「完美」的错误结论。后续还有改进版本比如在噪声加权方式上再做调整的变体思路是把「加噪—取第一阶—平均」这套流程里的平均次数分配得更聪明让低阶 IMF 拿到更多平均次数。这类改进的收益在弱特征提取场景下明显代价是实现复杂度上升选型时要看你的信噪比是否真的到了那一步。5. 落地排查CEEMDAN 从跑通到可信之间的五道坎5.1 重构对不上末阶残差被当成噪声扔了现象很典型把imfs列表加起来和原信号差一条缓慢的曲线差值方差不为零低频段尤其明显。原因几乎都是同一个——CEEMDAN 的循环是因为极值点不够而提前退出的剩下的r是趋势项不是噪声。它包含了信号里所有的直流和缓变成分能量往往比前几阶 IMF 还大。很多人只保存imfs把r丢了。解决办法是让函数显式返回残差并在重构校验时强制加上x_rec np.sum(imfs, axis0) r。更稳妥的做法是在函数内部就断言np.allclose(x_rec, x)把这个约束焊死在代码里而不是靠使用者记得。5.2 同一份数据跑两次结果不一样现象是 IMF 的阶数、波形、能量分布全都变了看着像算法不稳定。原因是每次都重新初始化了随机数生成器或者干脆没设种子。CEEMDAN 的随机性来自加噪这是设计特性不是缺陷但可复现性是工程底线。解决方式有两层代码层固定seed并在日志里打印出来流程层把NE、eps0、seed、信号长度一起写进结果元数据。做对比实验时不同算法之间要用同一组噪声样本否则你比的是噪声差异不是算法差异。5.3 集合数不够IMF 里全是毛刺现象是第一阶 IMF 的能量异常高包络谱上出现一片抬起来的宽带底噪弱特征被盖住。原因是残余噪声按 ε/√NE 衰减NE 50 时残余噪声是 NE 200 时的两倍。默认值往往按「能跑就行」设不按「能信」设。解决思路是按目标精度反推 NE先估一个可接受的残余噪声水平再解 √NE ε/e。另一个低成本技巧是给第一阶 IMF 单独加倍集合数——高频阶的噪声最难压而它恰好是多数故障诊断最关心的那阶。5.4 小幅值信号加噪后分量被淹没现象是信号幅度在 1e-3 量级用默认参数跑完IMF 波形明显畸变甚至分解出纯噪声阶。根因是幅值系数被当成了绝对值。有些实现里ratio直接乘一个常数而不是乘std(x)信号量级一小噪声的信噪比就崩了。解决方式是所有幅值系数一律相对std(x)归一化并在分解前打印一次实际信噪比20·log10(σ(x)/(ε·σ(x)))做自检。如果信号本身含强冲击还要把eps0压到 0.1 以下靠 NE 补精度。5.5 端点翘飞低频 IMF 超出信号范围现象是最后几阶 IMF 的两端数值剧烈偏离画出来像两只翘起的角做趋势分析时误差很大。这是三次样条外推的老问题CEEMDAN 每阶都要重新构造包络端点误差会被反复引入比 EMD 更敏感。解决办法是延拓镜像或极值点延拓都行关键是延拓长度要覆盖至少一个极值周期。如果信号本身很短不足 100 点延拓反而是负担这时更实际的做法是两端各裁掉 5%~10% 再分析——牺牲样本换稳定在短数据分析里通常是划算的。6. 噪声辅助法的设计取舍什么时候该停手把三代算法放在一张表里取舍关系就一目了然了维度EMDEEMDCEEMDAN确定性完全确定随机依赖种子随机依赖种子模态混叠严重明显改善明显改善完备性严格完备不完备加噪导致严格完备残余噪声无O(a/√NE)各阶均匀O(ε/√NE)低阶更小关键参数停止准则a、NEε₀、NE、停止条件计算量1 次分解NE 次完整分解每阶 NE 次浅分解表格里最值得盯的是最后一行。EEMD 的 NE 次是「完整分解」CEEMDAN 的是「每阶 NE 次只取第一阶的浅分解」——单次便宜但阶数一多总次数是 NE × K。这意味着 CEEMDAN 的计算量并不天然优于 EEMD在阶数多的信号上甚至更慢。选型时如果只看到「CEEMDAN 更先进」就换很容易在实时场景里翻车。判断分解是否可信我会看三个指标重构误差‖x − ΣIMF − r‖/‖x‖应当在 1e-12 量级正交性指标IO Σ_{i≠j} Σ_t cᵢ(t)cⱼ(t) / Σ_t x²(t)理想值接近 0实际常在 0.01~0.05超过 0.1 说明分量之间有严重泄漏以及各阶 IMF 的瞬时频率方差方差大意味着模态混叠没压住。三个指标一起看比单看波形靠谱得多。还有一类场景根本不该用噪声辅助数据极短极值点不足十几个、信号本身是强冲击序列加噪会污染冲击的宽带特征、以及需要严格可复现的在线处理。这些情况下 EMD 加良好的端点处理和停止准则反而更合适——不是所有问题都值得引入随机性。血泪经验是从一次「看起来完美」的重构开始的。当时 CEEMDAN 的重构误差在 1e-15我直接拿 IMF 去做包络谱结果弱特征完全找不到回头把 IMF 的功率谱画出来才发现第一阶上盖着一层比信号还高的宽带底噪NE 只设了 30。从那以后我每次跑完噪声辅助分解都强制走一遍「重构校验 正交性 无信号频段底噪」三件套参数和种子一起落盘再谈结果。希望帮到你。本文还有配套的精品资源点击获取