ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

基于EMD的IMF分量优选与多尺度熵特征提取实践

基于EMD的IMF分量优选与多尺度熵特征提取实践 做信号处理项目这些年我越来越觉得“先分解、再提取”的思路比直接拿原始波形硬啃要靠谱得多。EMD经验模态分解作为典型的自适应时频分析方法能把一段非平稳非线性信号拆成一串不同尺度的IMF本征模态函数听起来很美好但真正落地才会发现分解只是开胃菜怎么从十几个IMF里挑出真正携带有效信息的分量再用多尺度熵这类手段把分量压缩成稳定可用的特征向量才是决定下游模型效果的关键。这篇文章来自我刚完成的一个完整实践——基于EMD分解的IMF分量优选与多尺度熵特征提取把整套流程、代码、踩坑和参数心得都整理出来给正在做故障诊断、生理信号分析或者振动特征提取的朋友做个参考。1. 先把整件事拆明白EMD、分量优选和多尺度熵各自解决什么问题1.1 EMD本质上是把事情变简单做信号分析的人都知道傅里叶变换在处理平稳信号时几乎是无敌的但一遇到非平稳、非线性的信号就露怯了——频率随时间的漂移、瞬态冲击、突变成分这些用固定基函数展开很难描述清楚。短时傅里叶变换和小波变换算是折中方案但窗口长度定了之后分辨率就锁死了怎么调都别扭。EMD的思路完全不同。它不需要预先设定基函数而是完全依据信号自身的时间尺度特征把信号自适应地分解成若干个IMF加一个残余项。每一个IMF都要求满足两个条件一是整段数据里极值点数量和过零点数量相等或最多差一个二是在任意时刻由局部极大值定义的上包络和局部极小值定义的下包络的平均值为零也就是上下包络关于时间轴局部对称。说白了EMD就是在做一件事把一团乱麻似的信号按照“振荡尺度”从快到慢逐层剥开。第一个IMF通常是最快的高频成分后面的IMF频率逐渐降低最后剩一个单调或者缓慢变化的残余项。整个过程像剥洋葱每剥一层就是一种时间尺度。这个特性让它在机械故障振动信号、心电脑电、地震波、海洋波浪等非平稳数据分析里非常受欢迎。1.2 分量优选从“拆开”到“挑有用的”分解完了之后一个很现实的问题就摆在面前你得到的十几个IMF里并不是每个都值得用。有些IMF是噪声主导的伪分量有些包含了边缘效应污染还有些跟原始信号的相关性低到可以忽略。如果全量保留不仅特征维度膨胀、计算量上去了还会把噪声信息带进后续的分类或回归模型里直接拉低准确率。分量优选就是在这个环节做减法。它要回答的核心问题是哪些IMF是“信号”哪些IMF是“垃圾”。判断依据可以从时域相关性、能量占比、统计特征峭度、峰值因子、频域重合度等维度去设计。选得好后面提取的特征干净且分化度高选得随意整个特征工程就输在了起跑线上。我见过不少论文把全部分量都塞进特征集里结果分类精度还比不上只选两三个关键分量的做法这就是典型的信息冗余干扰。1.3 多尺度熵在特征提取中的定位即便我们把有用的IMF挑出来了直接拿这些分量的波形去做分类仍然不方便——维度太高、噪声敏感、长度不一致。怎么把一个分量浓缩成一个或者一组数值特征是特征提取阶段的核心任务。熵是衡量信号复杂度和不规则性的经典指标样本熵、近似熵都常用。但单尺度熵有一个先天缺陷它只从“一个分辨率”去观察信号的规律性。很多真实信号的复杂度是随尺度变化的——粗尺度上看很规则细尺度上却很随机或者反过来。多尺度熵的核心思路就是在多个时间尺度上分别计算样本熵形成一条“尺度-熵值”曲线用这条曲线的形态和数值来刻画信号在不同观察粒度下的复杂程度。这样一来一个IMF分量就能被映射成一条多尺度熵曲线再降维成特征向量输入支持向量机、随机森林或者全连接网络做后续工作。它的优势是信息密度高、对单一噪声点不那么敏感非常适合跟EMD这种多尺度分解方法搭配使用。2. EMD分解实操原理、坑与代码2.1 筛分过程与IMF的定义EMD的分解过程就是反复执行“筛分”操作。具体来说对原始信号x(t)先找到所有局部极大值和局部极小值用三次样条插值分别拟合出上下包络线然后计算包络均值m₁再用x(t)减去m₁得到第一个候选分量h₁。这时候要检查h₁是否满足IMF的两个条件。如果满足h₁就是第一个IMF如果不满足就把h₁当作新的待处理信号重复上述步骤直到满足条件为止。这个迭代过程在文献里叫sifting process。拿到IMF₁之后用x(t)减去IMF₁得到残余项r₁再对r₁重复整套操作依次得到IMF₂、IMF₃……直到残余项变成单调函数或者幅度小于预设阈值分解结束。有几个实操细节值得提醒。第一三次样条插值在信号两端特别容易“甩尾”包络线会飞出天际这就是著名的端部效应后面单独讲。第二筛分迭代次数太多会把IMF磨成纯正弦波失去物理意义所以现代实现一般都限制最大迭代次数而不是死磕包络均值严格为零。第三分解顺序是天然的“高频优先”后续做分量优选的顺序感很重要。2.2 三大经典问题端部效应、模态混叠、停止准则端部效应是我在实际项目里遇到最多的坑。因为信号两端数据不完整样条插值在边界处的延拓没有依据容易出现大幅震荡。处理办法常见的有几种镜像延拓、极值延拓、AR模型预测延拓以及在EMD分解后直接舍弃两端各几个采样点。我的经验是如果后续要做多尺度熵建议分解后把每个IMF两端各裁掉信号长度1%到2%的点代价小、效果好。模态混叠则是另一个更隐蔽的问题。当一个IMF里混入了时间尺度差异很大的振荡成分或者同一个尺度的成分被分散到多个相邻IMF里就发生了模态混叠。常见诱因是间歇性信号或者强噪声背景。解决思路就是给信号添加白噪声再分解多次平均这就是EEMD的基本思想。停止准则指的是判断“sifting是否该停”的条件。早期Huang提出的SD准则连续两次迭代结果的标准化差小于0.2到0.3用得非常广但阈值的物理含义比较模糊。现在主流库的实现通常结合了包络均值绝对值和迭代次数双重限制确保IMF既有物理意义又不会过筛。2.3 工程上更稳的替代EEMD与CEEMDAN既然原始EMD对噪声这么敏感做工程的人自然会想能不能先加噪声再抵消噪声EEMD就是干这个的。它对原始信号添加M组不同的白噪声分别做EMD分解最后把所有结果按IMF序号取平均。因为白噪声的均值为零多次平均后噪声成分互相抵消模态混叠问题被有效抑制。EEMD有两个关键参数总体平均次数M和噪声幅值。M太小噪声抵消不干净M太大计算时间成倍增长。实践经验是M取100到500噪声幅值取原始信号标准差的0.1到0.4倍。我自己常用的是0.2倍标准差、200次平均兼顾稳定性和算力。CEEMDAN在EEMD基础上做了进一步优化——它在每一层分解之后才引入自适应白噪声避免了EEMD里不同IMF之间噪声残留的传递问题分解完备性更好残余噪声更小。如果项目对信号重构精度有要求CEEMDAN通常是比EEMD更稳的选择。下面这个表可以帮你快速决策方法抗模态混叠计算开销重构精度适用场景EMD差低高干净信号、快速探索EEMD中中中含噪信号、一般工程CEEMDAN好高高强噪声、需要保真的场景2.4 Python实测一套可复现的分解代码Python里最常用的库是PyEMD封装了EMD、EEMD、CEEMDAN完整实现。下面这段代码是我项目里的标准起手式可以直接套用import numpy as np from PyEMD import EMD, EEMD, CEEMDAN def decompose_signal(signal, methodceemdan, trials200, noise_width0.2): 统一封装EMD/EEMD/CEEMDAN分解 signal: 1D numpy array method: emd / eemd / ceemdan if method emd: emd EMD() imfs emd(signal) elif method eemd: eemd EEMD(trialstrials, noise_widthnoise_width) imfs eemd(signal) elif method ceemdan: ceemdan CEEMDAN(trialstrials) imfs ceemdan(signal) else: raise ValueError(fUnknown method: {method}) return imfs # 生成测试信号5Hz正弦 50Hz正弦 白噪声 fs 1000 t np.linspace(0, 1, fs, endpointFalse) x np.sin(2*np.pi*5*t) 0.6*np.sin(2*np.pi*50*t) 0.3*np.random.randn(len(t)) imfs decompose_signal(x, methodceemdan) print(f分解得到 {imfs.shape[0]} 个IMF, 信号长度 {imfs.shape[1]})跑完之后建议把每个IMF画出来看一眼确认高频在先、低频在后残余项单调。这个肉眼检查步骤虽然朴素但能第一时间发现分解异常别跳过。3. IMF分量优选用指标说话别拍脑袋3.1 相关系数法最直观的筛选分量优选的第一招也是最直观的一招就是计算每个IMF与原始信号之间的皮尔逊相关系数。如果某个IMF跟原始信号高度相关说明它保留了原始信号的主要能量结构如果相关性很小大概率是噪声分量或者边缘污染。实际使用中阈值怎么定很讲究。有人用固定阈值0.1或0.2但这些数值在不同信噪比下表现差异很大。更稳妥的做法是相对阈值算出所有IMF相关系数的最大值保留相关系数大于最大值的60%到70%的IMF。这样在不同数据集上尺度统一不需要每换一个数据就重新调参。def select_imf_by_corr(imfs, signal, threshold_ratio0.6): corrs np.array([np.corrcoef(imf, signal)[0, 1] for imf in imfs]) max_corr np.max(np.abs(corrs)) selected_idx np.where(np.abs(corrs) threshold_ratio * max_corr)[0] return selected_idx, corrs idx, corrs select_imf_by_corr(imfs, x) print(各IMF相关系数:, np.round(corrs, 4)) print(优选IMF索引:, idx)需要注意相关系数法对幅值特别敏感。如果某个IMF幅值远大于其他分量即便它是伪分量相关系数也可能虚高。所以我会把相关系数法和能量占比法结合着看避免被单一指标带偏。3.2 能量占比与方差贡献率能量占比反映的是每个IMF在总能量中的份额。计算方式很简单每个IMF的平方和除以所有IMF平方和的总和。能量占比高的分量是信号的主力占比极低的分量基本可以判定为次要噪声。方差贡献率是能量占比的亲戚只是分子用的是方差而不是平方和。在信号均值不为零或含有直流分量时方差贡献率更稳健因为它去掉了均值偏移的影响。实际操作时我常用的策略是按能量从大到小排序逐个累加能量占比取累计占比达到90%到95%的前K个IMF作为保留集合。这样做的好处是特征维度自动确定不会出现“保留全部分量”那种臃肿情况。def select_imf_by_energy(imfs, cum_threshold0.95): energies np.sum(imfs**2, axis1) sorted_idx np.argsort(energies)[::-1] cum_ratio np.cumsum(energies[sorted_idx] / np.sum(energies)) k np.searchsorted(cum_ratio, cum_threshold) 1 return sorted(sorted_idx[:k].tolist())不过要提醒一句能量占比法对微弱但关键的冲击成分不友好。比如轴承早期故障的冲击信号能量占比可能很低但恰恰是故障识别的关键信息。所以能量法适合做“去掉绝对噪声”不适合做“唯一筛选标准”。3.3 峭度与峰值因子冲击特征的专属指标如果你做的是机械故障诊断峭度是绕不开的指标。峭度描述信号分布的“尖峰程度”正常振动信号接近高斯分布峭度值约等于3出现冲击类故障时信号会出现明显的脉冲尖峰峭度值迅速升高。IMF分量的峭度正好用来识别哪些分量承载了冲击特征。def kurtosis(imf): u imf - np.mean(imf) std np.std(imf) if std 1e-12: return 0.0 return np.mean(u**4) / std**4峰值因子峰值除以有效值也是类似的用法。实践中我一般把峭度大于3的分量单独挑出来作为“冲击敏感分量”即使它的能量占比或相关系数都很低也会保留。这个习惯帮我抓到过好几次早期故障信号。3.4 多指标综合优选的实践方案单一指标都有盲区工程上最终还是要走综合评分路线。我的做法是构造一个加权评分把归一化后的相关系数、能量占比、峭度贡献按权重融合权重根据应用场景调整。通用模板如下指标归一化方式默认权重适用重点相关系数除以最大值0.4通用能量占比除以最大值0.3平稳信号峭度贡献除以最大值0.3冲击/故障特征最终每个IMF的得分是三个归一化指标的加权和从高到低保留累计得分达到总得分60%到70%的分量。这里的阈值和权重并不是金科玉律但综合评分比单一指标稳定得多尤其在不同数据批次切换的时候。4. 多尺度熵特征提取的完整实现4.1 从样本熵到多尺度熵在介绍多尺度熵之前得先说说样本熵。样本熵衡量的是一段时间序列中当嵌入维度为m时两个向量在容差r内匹配上的概率与嵌入维度为m1时匹配上的概率之比。直观理解就是“新增一个点之后原来还相似的序列还像不像”。越像说明信号越有规律熵值越低越不像信号越随机熵值越高。样本熵相比近似熵的优势是去掉了自匹配项偏差更小对数据长度的依赖性更低。多尺度熵就是在样本熵前面加了一步粗粒化先把原始信号按尺度因子τ分成若干个非重叠窗口每个窗口内取平均得到一条长度缩短为原来的1/τ的粗粒化序列再计算这条序列的样本熵。对τ1到τ_max依次做一遍就得到了多尺度熵曲线。4.2 粗粒化过程的细节粗粒化看起来简单实际有几个细节容易翻车。第一窗口必须无重叠重叠窗口会引入人为相关熵值失真。第二当τ无法整除信号长度时末尾多余的数据直接丢弃。第三也是最重要的一点——计算每一条粗粒化序列的样本熵时相似容差r应该使用原始信号的标准差来计算而不是每换一个尺度就重新用当前序列的标准差算一遍。否则不同尺度下的熵值就不具备可比性这条曲线也就失去了意义。def coarse_grain(u, scale): n len(u) // scale if n 0: return None u_cg u[: n*scale].reshape(n, scale) return np.mean(u_cg, axis1) def sample_entropy(u, m2, rNone): u np.asarray(u, dtypefloat) N len(u) if r is None: r 0.15 * np.std(u) if N 30: return np.nan B 0 # m维匹配对 A 0 # m1维匹配对 for i in range(N - m): xi u[i:im] for j in range(i1, N - m 1): if np.max(np.abs(xi - u[j:jm])) r: B 1 if i N - m - 1 and j N - m: if np.max(np.abs(u[i:im1] - u[j:jm1])) r: A 1 if B 0 or A 0: return np.nan return -np.log(A / B) def multiscale_entropy(u, max_scale20, m2, r_ratio0.15): r r_ratio * np.std(u) mse [] for tau in range(1, max_scale 1): cg coarse_grain(u, tau) if cg is None or len(cg) 30: break se sample_entropy(cg, m, r) if np.isnan(se): break mse.append(se) return np.array(mse)4.3 参数选择经验m、r、最大尺度参数怎么定直接决定熵值有没有辨识度。嵌入维数m一般取2少数情况下取3。m越大需要的匹配对越少计算越不稳定而且物理意义更难解释。相似容差r的经典取值是信号标准差的0.1到0.25倍0.15倍是文献中出现最多的值。r太小匹配对数骤减熵值方差变大r太大很多模式被“宽大处理”熵值区分度下降。最大尺度τ_max的选择受数据长度限制。粗略的经验公式是每个尺度的粗粒化序列长度至少要能支撑样本熵的可靠估计建议不低于10^m到30^m个点。对m2粗粒化序列至少需要100到900个点。如果原始信号有N点τ_max大致取N除以300到N除以100的范围。举个例子N2000时τ_max取10到20比较合理N500时τ_max取5到8。硬要超出这个范围后面的尺度就是纯噪声。4.4 一条完整链路EMD→优选→多尺度熵→特征向量把前面所有模块串起来就是整套流程的核心代码def emd_mse_feature_pipeline(signal, max_scale15, m2): # Step 1: 分解 imfs decompose_signal(signal, methodceemdan, trials100) # Step 2: 优选 idx_corr, _ select_imf_by_corr(imfs, signal, threshold_ratio0.6) idx_energy select_imf_by_energy(imfs, cum_threshold0.95) idx_kurt np.where([kurtosis(imf) 3.0 for imf in imfs])[0] selected sorted(set(idx_corr) | set(idx_energy) | set(idx_kurt)) # Step 3: 多尺度熵特征 features [] for i in selected: mse multiscale_entropy(imfs[i], max_scalemax_scale, mm) if len(mse) 0: features.extend(mse) return np.array(features), selected feat, sel emd_mse_feature_pipeline(x, max_scale10) print(f保留IMF: {sel}, 特征维度: {len(feat)})到这里每个样本从原始波形变成了一个固定长度的特征向量。后面不管是接支持向量机、随机森林还是轻量级神经网络输入特征就是这组向量。特征向量内部不同尺度熵值的分布规律能很好地反映信号在不同时间尺度下的复杂度差异。5. 项目实战典型场景、参数排查与稳定性5.1 故障诊断中的一个可复现流程拿滚动轴承故障诊断举例。采集到的振动信号经过CEEMDAN分解后前几个IMF通常包含高频冲击成分中段IMF包含转频及其谐波成分最后的低频IMF大多是趋势项。通过综合评分优选后冲击类故障样本会保留峭度偏高的前几个IMF正常样本则保留能量集中的中段IMF。对优选后的IMF分别提取多尺度熵曲线你会看到故障样本与正常样本在多尺度熵曲线上的差异非常明显。故障信号因为存在周期性的冲击和调制成分在较小尺度上复杂度高、熵值大但在较大尺度上又因为调制周期性而熵值回落正常信号整体平稳熵值曲线平缓。这种形态差异就是分类器真正学到的东西。5.2 生物医学信号的特征提取要点处理心电、脑电这类生理信号时有一个额外的细节信号的时变特性很强直接对整段信号做EMD分解再提熵特征会被不同时段的生理状态平均掉削弱区分度。我的做法是先用滑窗把信号切成若干段每段单独做分解和多尺度熵再对窗口间的熵值做统计汇总均值、标准差、斜率。这样既保留时变信息又能降低单窗口噪声的影响。另一个注意点是生理信号采样率通常不高数据长度有限。脑电一段几秒钟的数据也就几百到一两千个点多尺度熵的τ_max就别往20以上冲了取5到10更实际。宁可尺度数少一点也要保证每个尺度上的熵值估算可信。5.3 数据长度与尺度上限的匹配这一步是很多人栽跟头的地方。我在测试阶段做过一个对比对同一段长度为500的信号分别取τ_max5和τ_max15。前者计算出的前5个尺度熵值稳定后者从第8个尺度开始熵值剧烈抖动有的尺度直接算出无穷大。原因就是粗粒化序列过短样本熵匹配对不足。所以请记住这个原则先算数据长度再定尺度上限。N小于1000时τ_max别超过10N在1000到5000时τ_max取10到20N超过5000可以适当加到20到30。如果业务上必须用大尺度唯一出路是延长采集时间或者降采样率没有别的捷径。5.4 特征稳定性检验与参数敏感性特征提取做完以后不要急着训练模型先做一个稳定性检验。我的标准做法是对同一类别下的多个样本重复提取特征计算每个特征维度的变异系数标准差除以均值。变异系数大于30%的特征维大概率是不稳定的检查一下它是来自哪个IMF、哪个尺度再针对性调整。参数敏感性分析也值得做。把m从2改成3、r从0.15改到0.2观察特征向量变化有多大。如果分类精度对参数微调特别敏感说明这个特征集本身不够鲁棒需要回看分量优选环节是否选入了噪声分量。稳健的特征集应该是参数在一定范围内浮动时特征曲线形态基本不变只有轻微平移。6. 扩展想法这套方法还能往哪里走6.1 与深度学习的结合点这套流程跟深度学习不是二选一的关系。一个很自然的结合方式是把EMD分解和多尺度熵特征作为神经网络的输入特征跟原始波形特征做拼接让模型既看到时域原始信息又看到经过处理的熵特征。在样本量不大、标签不均衡的故障诊断场景里这种混合特征往往比纯端到端模型更抗过拟合。另一个方向是把IMF分量重组为多通道输入喂给卷积神经网络或Transformer。每个通道对应一个优选后的IMF模型自己去学分量之间的关联。这种做法的好处是不需要手工设计熵特征但前提是你有足够的数据量。6.2 方法组合的取舍心得做了这么多实验我对这套方法组合的边界有了一些个人的判断。如果信号本身比较干净、有明确的周期性成分用标准EMD加相关系数优选就够了完全没必要上CEEMDAN和综合评分省下的算力很可观。反过来如果信号是强噪声背景下的微弱冲击信号那就必须叠加多尺度熵这种统计型特征单纯靠时域指标很难捕捉到那些微弱但关键的差异。说到底方法没有高下之分只有匹配不匹配。EMD分解加上IMF优选和多尺度熵这一个组合解决的是“复杂非平稳信号如何变成有效特征”的问题。它能适配的领域比很多人想象中广——除了机械故障诊断还有结构健康监测、语音信号分析、气象时间序列预测等场景都能套用。我个人的体会是把这套流程跑通不难难的是在每个环节都知道为什么这样做以及遇到异常时知道该去哪里找原因。希望这篇文章能帮你少走我走过的弯路。
返回列表