☰
CEEMD分解与信息熵特征提取:非平稳信号处理实战指南
2026/10/13 4:49:57 网站建设 项目流程

简介:这份MATLAB资源面向从事非线性、非平稳信号处理与特征提取的学习者和研究者,围绕CEEMD分解、IMF分量相关系数筛选与信息熵特征计算展开,可用于振动信号分析、故障诊断及机器学习分类前的特征工程。压缩包共4个文件,约60KB,包含3个m脚本与1个xlsx数据文件:脚本分别实现CEEMD分解、极值点计算与信息熵特征提取,xlsx则提供示例信号数据,便于直接运行验证。目前已有5245人学习下载,说明该方案在相关方向具有较高的参考价值。读者可据此掌握从信号分解、相关系数筛选有效IMF分量,到计算各分量信息熵并构建特征向量矩阵的完整流程,理解如何去除冗余分量、量化信号复杂度,并将结果用于后续分类任务,适合作为课程设计、论文实验或工程预处理的起步模板。

1. 信号拆解的三件套:CEEMD 分解、IMF 相关系数、信息熵特征到底在解决什么问题

做非平稳信号特征提取的人,大概率都经历过这样的场景:轴承振动信号、心电信号、风速序列、语音波形,直接丢进分类器或回归模型,效果时好时坏,换一段数据就翻车。问题往往不在模型,而在特征本身——原始时序把太多频段、太多尺度上的信息混在一起,模型学到的只是表面统计量。CEEMD 分解、IMF 分量相关系数、信息熵特征这三件套,就是用来把一锅粥拆成可量化的结构:先分解成若干本征模态函数(IMF),再用相关系数筛掉伪分量,最后用信息熵把每个有效分量的复杂度量化成特征向量。这套流程在故障诊断、生理信号分析、金融时序波动刻画里都很常见,适合已经会调 sklearn 或 PyTorch、但特征工程还停留在均值方差层面的从业者。下面按“先立住原理、再跑通代码、最后避坑”的顺序讲透。

2. CEEMD 分解的工程实现:从 EMD 到互补集合经验模态分解

2.1 为什么直接上 CEEMD 而不是 EMD 或 EEMD

EMD 的核心思路是把信号拆成有限个 IMF,每个 IMF 满足两个条件:极值点数和过零点数相差不超过一个,且上下包络均值为零。听起来很美,但 EMD 有个经典缺陷——模态混叠。同一个 IMF 里混进了差异很大的时间尺度,或者相近尺度被拆到不同 IMF 里。EEMD 通过加白噪声再平均来缓解,但引入的噪声残留和重构误差又成了新问题。CEEMD 的做法是加一对正负白噪声,成对做 EMD,再取平均。正负噪声在平均时相互抵消,重构误差显著降低,同时保留了 EEMD 抑制模态混叠的能力。我一般会优先用 CEEMD,除非数据量特别大、实时性要求极高,才会退回 EEMD 或直接 EMD。

2.2 用 Python 跑通 CEEMD 的最小代码

import numpy as np from PyEMD import CEEMDAN # 常见做法是用 PyEMD 库,CEEMDAN 是其改进版本 def ceemd_decompose(signal, trials=100, noise_std=0.2, max_imf=10): """ signal: 一维 numpy 数组,长度建议 >= 512 trials: 加噪次数,越大越稳定但越慢,常用 50~200 noise_std: 噪声标准差相对信号标准差的倍数,常用 0.1~0.3 max_imf: 最大 IMF 数,防止无限分解 """ ceemdan = CEEMDAN(trials=trials, epsilon=noise_std) imfs = ceemdan(signal, max_imf=max_imf) # imfs 形状为 (n_imf, len(signal)),最后一行通常是残差 return imfs # 示例:构造一个含趋势和两个振荡分量的合成信号 t = np.linspace(0, 1, 1000) sig = 0.5 * np.sin(2 * np.pi * 5 * t) + 0.3 * np.sin(2 * np.pi * 20 * t) + 0.1 * t imfs = ceemd_decompose(sig, trials=80, noise_std=0.2, max_imf=8) print("IMF 数量:", imfs.shape[0])

这段代码里,trials控制加噪次数,太小会导致分解结果不稳定,太大则计算时间线性增长。noise_std是噪声幅度系数,经验值在 0.1 到 0.3 之间,信号信噪比低时可以适当调大。max_imf是硬性截断,因为 CEEMDAN 在极端情况下会一直分解下去,产生无意义的低频分量。分解完成后,imfs的每一行是一个 IMF,最后一行往往是残余趋势项,后续做特征时通常要单独处理或丢弃。

2.3 分解结果怎么判断靠不靠谱

拿到 IMF 后,别急着往下走。先看两个东西:一是每个 IMF 的极值点数和过零点数是否接近,二是重构误差。把所有 IMF 加回去,和原信号的均方误差应该在 1e-6 量级以下,如果误差明显偏大,说明trials不够或者噪声系数设得不对。另一个实用技巧是画时频图,观察 IMF 的频率是否从高到低排列,如果出现频率交叉,说明模态混叠还没压住,需要增大trials或换用 CEEMDAN 的更多集成次数。

3. IMF 分量相关系数:筛掉伪分量与噪声主导分量

3.1 相关系数的计算逻辑与阈值选择

CEEMD 分解出来的 IMF 里,前几个往往是高频噪声主导,最后几个可能是趋势项或伪分量。直接用全部 IMF 做特征,等于把噪声也喂给模型。常见做法是计算每个 IMF 与原信号的皮尔逊相关系数,保留相关系数超过某个阈值的分量。阈值没有绝对标准,我一般会先算一遍所有 IMF 的相关系数,画个柱状图,找明显下降的拐点。如果不想画图,可以用 0.1 到 0.2 作为初始阈值,再根据下游任务微调。

from scipy.stats import pearsonr def select_imfs_by_corr(imfs, signal, threshold=0.15): """ imfs: CEEMD 分解结果,形状 (n_imf, n_samples) signal: 原始信号 threshold: 相关系数阈值,低于此值的 IMF 被丢弃 返回: 保留的 IMF 索引列表和对应的相关系数 """ corrs = [] for i in range(imfs.shape[0]): r, _ = pearsonr(imfs[i], signal) corrs.append(abs(r)) corrs = np.array(corrs) keep_idx = np.where(corrs >= threshold)[0] return keep_idx, corrs keep_idx, corrs = select_imfs_by_corr(imfs, sig, threshold=0.15) print("保留的 IMF 索引:", keep_idx) print("对应相关系数:", corrs[keep_idx])

这里用pearsonr计算线性相关性,取绝对值是因为我们关心的是相关强度而非方向。threshold设得太高会丢掉一些能量较弱但包含有用信息的低频分量,设得太低则噪声分量会被保留。一个更稳健的做法是结合 IMF 的能量占比:如果某个 IMF 能量极小且相关系数低,基本可以确定是伪分量。

3.2 相关系数筛选的边界与替代方案

相关系数筛选有个前提假设:有用分量和原信号线性相关。但有些故障特征是非线性耦合的,相关系数可能偏低,这时候单靠相关系数会误杀。替代方案是用互信息或距离相关系数,它们能捕捉非线性依赖。不过互信息计算量大,且对分箱敏感,我一般只在相关系数筛选后效果不理想时才换。另一个边界是:如果信号本身很短(比如少于 256 个点),CEEMD 分解本身就不稳定,相关系数也会波动很大,这时候建议先做数据增强或改用其他时频方法。

4. 信息熵特征提取:把 IMF 变成分类器能吃的向量

4.1 样本熵、排列熵、模糊熵怎么选

信息熵用来量化时间序列的复杂度。常见的有样本熵、排列熵、模糊熵。样本熵对数据长度要求较高,但一致性较好;排列熵计算快,对噪声鲁棒,适合实时场景;模糊熵在样本熵基础上引入模糊隶属度,对参数不那么敏感。我一般会先试排列熵,因为快且稳,如果分类效果不够再换样本熵或模糊熵。注意:熵值本身是标量,每个 IMF 算一个熵,最终特征向量长度等于保留的 IMF 数量。

import antropy as ant # 常见做法是用 antropy 库,也可自己实现 def extract_entropy_features(imfs, keep_idx, entropy_type='perm'): """ imfs: 全部 IMF keep_idx: 保留的 IMF 索引 entropy_type: 'perm' 排列熵, 'sample' 样本熵, 'fuzzy' 模糊熵 返回: 特征向量 """ features = [] for i in keep_idx: if entropy_type == 'perm': # 排列熵,order=3 是常用默认值,可调 3~7 e = ant.perm_entropy(imfs[i], order=3, normalize=True) elif entropy_type == 'sample': # 样本熵,m=2, r=0.2*std 是经典参数 e = ant.sample_entropy(imfs[i], order=2, metric='chebyshev') else: # 模糊熵需自行实现或换库,此处用近似熵替代示意 e = ant.app_entropy(imfs[i], order=2) features.append(e) return np.array(features) feat = extract_entropy_features(imfs, keep_idx, entropy_type='perm') print("信息熵特征向量:", feat)

排列熵的order参数决定嵌入维度,太小会丢失复杂度信息,太大会导致计算量上升且对短序列不友好。样本熵的m和r是经典组合,r通常取 0.1 到 0.25 倍标准差。模糊熵没有统一库,很多团队自己实现,核心是引入指数型模糊函数替代阶跃函数。

4.2 多尺度熵与特征拼接

单个尺度的熵可能不够,尤其是当信号在不同时间尺度上复杂度差异大时。多尺度熵的做法是对每个 IMF 再做粗粒化,在不同尺度上算熵,然后拼接。这样特征维度会成倍增加,但分类器往往能从中受益。我一般会在 IMF 数量较少(比如 3 到 5 个)时用多尺度,IMF 多的时候直接用单尺度,避免维度爆炸。拼接时注意归一化,熵值范围通常在 0 到 1 或 0 到 log(order) 之间,不同熵类型量纲不同,最好做 z-score 标准化。

5. 避坑与排查:CEEMD-相关系数-信息熵流程里的五个血泪坑

5.1 现象:分解结果每次跑都不一样,特征无法复现

原因:CEEMD 加噪是随机的,没有固定随机种子。解决:在调用 CEEMDAN 前设置np.random.seed(42),并且把trials固定。如果库内部有自己的随机源,查文档看是否支持random_state参数。复现性在工程落地里是硬要求,别等到模型上线才发现特征对不上。

5.2 现象:相关系数筛选后 IMF 数量为 0 或只剩残差

原因:阈值设得太高,或者信号本身信噪比极低,所有 IMF 和原信号的相关性都不强。解决:先把阈值降到 0.05 试一次,如果还是不行,检查信号是否被错误归一化或存在直流偏置。另一个可能是 CEEMD 的max_imf设得太小,分解不充分,有用分量还没被拆出来。

5.3 现象:信息熵特征在训练集上表现很好,测试集一塌糊涂

原因:熵特征对数据长度和噪声敏感,训练集和测试集的采样率、长度不一致会导致熵值分布偏移。解决:统一重采样到相同长度,并在提取熵之前做去趋势和带通滤波。如果测试集噪声水平不同,考虑用模糊熵替代样本熵,前者对噪声更鲁棒。

5.4 现象:CEEMD 分解耗时太长,无法满足实时性

原因:trials设得太大,或者信号太长。解决:把trials降到 30 到 50,同时用滑动窗口分段处理,每段长度控制在 512 到 1024 点。如果还是慢,换用 EEMD 或固定参数的 FIR 滤波器组做近似分解。实时场景下,特征提取的延迟往往比模型推理更致命。

5.5 现象:IMF 分量顺序混乱,高频低频对不上

原因:不同库对 IMF 的排序约定不同,有的从高频到低频,有的反过来。解决:分解后先算每个 IMF 的主频或过零点率,按频率从高到低重新排序。别假设库的输出顺序,自己排一遍最稳妥。

6. 进阶技巧:用重构信号做二次特征与在线更新策略

6.1 用保留的 IMF 重构信号再提特征

筛选完 IMF 后,除了直接对每个 IMF 算熵,还可以把保留的 IMF 相加得到重构信号,再对重构信号算时域统计量或频域特征。重构信号去掉了噪声主导分量,信噪比更高,有时候比单 IMF 熵特征更有效。我一般会把重构信号的均方根、峭度、峰值因子和 IMF 熵特征拼在一起,形成一个混合特征向量。注意重构时不要把残差项加进去,残差是趋势,不是振荡。

def reconstruct_signal(imfs, keep_idx): """用保留的 IMF 重构信号""" return np.sum(imfs[keep_idx], axis=0) recon = reconstruct_signal(imfs, keep_idx) # 对重构信号算峭度和均方根 kurt = np.mean((recon - np.mean(recon))**4) / (np.std(recon)**4) rms = np.sqrt(np.mean(recon**2)) print("重构信号峭度:", kurt, "均方根:", rms)

6.2 在线场景下的滑动窗口与特征缓存

如果要做在线监测,不能每次来一个新点就重新做 CEEMD。常见做法是维护一个滑动窗口,窗口长度固定,每隔一定步长做一次分解和特征提取,然后把特征送入模型。窗口重叠率一般设 50% 到 75%,保证特征平滑。另一个技巧是缓存历史 IMF,新数据只更新最后一个窗口,减少重复计算。但要注意,CEEMD 不是增量算法,窗口一变,所有 IMF 都会变,所以缓存只能用于特征平滑,不能替代重新分解。

6.3 参数搜索的实用策略

trials、noise_std、相关系数阈值、熵的order和m,这些参数组合起来空间很大。我一般不会上网格搜索,而是按优先级分步调:先固定trials=50、noise_std=0.2,调相关系数阈值看保留 IMF 数量是否合理;再调熵参数,用交叉验证看分类准确率;最后如果效果不够,再增大trials到 100 或 200。这样每一步都有明确的观察指标,不会陷入参数玄学。

6.4 一个容易忽略的验证方法

特征提取完,别只看模型准确率。用 t-SNE 或 PCA 把特征降到二维画出来,看不同类别的样本是否自然分开。如果混在一起,说明特征区分度不够,回去检查 IMF 筛选和熵参数。另一个验证是加高斯白噪声做鲁棒性测试,看特征向量在噪声下的波动范围。波动太大的特征,上线后必然不稳定。

我自己的习惯是:任何一次 CEEMD 分解后,先存一份 IMF 和相关系数日志,方便后面回溯。特征工程最怕的就是“当时跑通了,后来复现不出来”。把随机种子、参数、中间结果都记下来,比事后拍脑袋强。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询