EEMD分解结合样本熵的振动信号重构方法:按复杂度分离IMF频段

发布时间:2026/9/26 20:33:46
EEMD分解结合样本熵的振动信号重构方法:按复杂度分离IMF频段 写这篇的起因是上周有人问我手里有一段振动信号噪声很大特征频率都埋在底噪里了想按频段拆开看趋势但又不愿意用带通滤波器去硬切怕边界效应把相位搞坏。我给的方案就是标题里这套组合拳EEMD 分解降低模态混叠样本熵量化每个分量的复杂程度再按熵值大小把 IMF 重组成低、中、高频三组信号。这篇文章就把这套流程的完整逻辑、实际代码思路和踩坑记录都摊开讲清楚给做故障诊断、生物电信号处理和结构监测的同行一个可以直接拿去参考的落地方案。1. 从 EMD 到 EEMD为什么要换这个分解工具1.1 经验模态分解的基本思路理解 EEMD 之前先得说清楚 EMD 到底在干什么。经验模态分解全称 Empirical Mode Decomposition做的事情很直观把一段复杂信号自适应地拆成若干个本征模态函数也就是 IMF再加一个残差。每个 IMF 需要满足两个条件极值点数量和过零点数量相等或至多相差一个上下包络的均值在任意位置都趋近于零。换句话说EMD 不是用固定基函数去拟合信号而是完全跟着信号本身的局部特征走所以它在处理非线性、非平稳信号时比傅里叶变换和小波变换更灵活。理论上原始信号可以被写成所有 IMF 加上残差的形式。这个分解过程是数据自适应的不同信号的 IMF 数量和频率成分都不一样。拿机械振动信号举例如果转频是 50 Hz啮合频率是 800 HzEMD 会依据信号自身的时间尺度把这两个成分分别分离到不同 IMF 中这对后续的包络分析或者特征提取非常友好因为它不需要预先设定滤波器的通带和阻带。但 EMD 有一个很出名的问题就是模态混叠。所谓模态混叠是指分解出的某个 IMF 中出现跨度很大的异尺度成分或者一个相似尺度成分被拆分到两个不同 IMF 中。最常见的触发因素有三个信号中存在间歇性高频成分比如瞬态冲击噪声水平过高导致包络拟合失真以及信号幅值动态范围过大端点效应和三次样条插值把包络算偏了。模态混叠直接影响后续分析因为一旦 IMF 成分不纯希尔伯特谱上就会出现虚假频率带样本熵也会被杂散成分主导。1.2 集合平均是怎么抑制模态混叠的EEMD 的全称是 Ensemble Empirical Mode Decomposition思路非常巧妙甚至可以说带着一点“暴力美学”既然 EMD 对噪声敏感那就在原始信号上人为添加白噪声用噪声的统计特性去“填充”信号中缺失的尺度让 EMD 能更充分地分离各种成分。每添加一次不同幅值的白噪声就做一次 EMD得到一组 IMF。重复多次之后对所有对应的 IMF 取平均因为白噪声在多次试验中是不相关的平均之后噪声成分趋近于零剩下就是真实的模态成分。写成数学一点的说法是第 i 次分解时构造信号xi(t) x(t) wi(t)对 xi(t) 做 EMD得到 IMFi1(t), IMFi2(t)...重复 N 次后最终第 j 个 IMF 是IMF_j(t) (1/N) * Σ IMFij(t)这个平均过程的核心意义在于每一次加入不同的白噪声相当于给原始信号提供了不同的局部扰动参考让极值点在包络拟合时不容易被间歇成分“带偏”。只要集合次数 N 足够大白噪声贡献的残余就会互相抵消。这就是为什么 EEMD 能有效缓解模态混叠的原理也是它相对 EMD 最大的工程价值。但这里要注意EEMD 不是没有代价。计算成本高是一方面另一方面如果参数选得不好比如噪声幅值太小对模态混叠没有任何改善噪声幅值太大又会对原始信号产生过多扰动导致分解出的 IMF 被噪声污染反而把信噪比拉低。后面我会专门讲参数怎么定。2. 样本熵是干什么的怎么算2.1 从近似熵到样本熵分解完之后每个 IMF 都是一段“较纯”的成分但问题来了哪些 IMF 属于低频趋势哪些属于中频主成分哪些属于高频细节如果只看频谱峰值可以做一个粗略判断但在实际信号里频谱峰值往往模糊不清特别是存在噪声底和高次谐波的时候。这时候我习惯用样本熵作为每个 IMF 复杂度度的量化指标。样本熵即 Sample Entropy是用来衡量时间序列产生新模式概率的指标。序列越规律、越周期化样本熵越小序列越随机、越无序样本熵越大。它和近似熵思路相似但克服了近似熵对短序列估计偏差较大的问题也不依赖模板自身的匹配稳定性更好。在信号重构中的应用逻辑是低频分量往往对应信号的主体趋势或慢变特征周期性强复杂度低样本熵最小高频分量对应细节、冲击、噪声等快速起伏成分随机性强复杂度高样本熵最大。通过计算每个 IMF 的样本熵我们就能得到一个“复杂度谱”按阈值把 IMF 分成低频、中频、高频三组然后重新叠加成三路信号这就是标题里“按样本熵大小进行信号重构”的技术含义。2.2 样本熵的计算步骤和参数选择样本熵的计算涉及几个关键参数模式维度 m 和容差阈值 r此外需要一个序列长度 N。计算过程我可以简化描述如下把长度 N 的时间序列按顺序构造成 N-m1 个 m 维向量每个向量包含连续的 m 个点。对每个向量和所有其他向量计算切比雪夫距离即两个向量对应位置差值的绝对值的最大值。统计距离小于 r 的向量对数量并计算其占比例。然后同样的流程换成 m1 维向量再做一次。样本熵的最终公式是负的 ln(两个比例相除的结果)。这里有一个常见误区很多初学者对公式本身很熟悉但参数乱选。实际工程中Pincus 提出的建议是 m2r 取原始序列标准差的 0.1 到 0.25 倍。我自己在振动信号上做过反复测试m2 是几乎不会出错的默认设定因为 m3 虽然对复杂度分辨更精细但对噪声更敏感而且计算量大很多。r 则需要根据信噪比调整信号比较干净时取 0.1 倍标准差较好能分辨细微复杂度差异信号噪声大时取 0.2 倍标准差更稳避免把噪声当成有效复杂度。样本熵的值本身没有绝对标尺它是一个相对比较的指标脱离信号类型谈“样本熵大于多少算高频”没有意义。这一点我特别强调因为不同信号的能量分布差异巨大相同的样本熵值在一段加速度计信号里可能代表噪声居多在一段心电信号里可能代表生理细节。所以实际做法永远是先对全部 IMF 算出各自的样本熵再排序、聚类或者按比例阈值分组而不是对着绝对数值判断。3. 第三步按熵分箱重构出低中高频信号3.1 IMF 分组策略阈值怎么定当我们拿到 N 个 IMF 以及对应的样本熵值 S1, S2, ..., SN 之后要做的事情就是把它们分成低频组、中频组和高频组。分组策略大致有四种我按实用性排序临近算法分组把样本熵值排序后设定两个阈值 T1 和 T2小于等于 T1 的归入低频大于 T1 且小于等于 T2 的归入中频大于 T2 的归入高频。T 的取值可以用等百分比法比如所有熵值的三分位点也可以用离群值法。聚类分组对样本熵值做 K-means 聚类K3自动分成三组。这个方法的好处是不需要人为定阈值坏处是聚类结果不定需要设置随机种子才能复现。结合能量和熵联合分组样本熵只反映复杂度没有反映能量大小。有些场景下一个熵值很大的 IMF 可能能量极小对重构结果影响微乎其微此时可以把能量占比低于 1% 的分量直接忽略再对剩余分量按熵分组。频率验证兜底分组完成后对每组重构信号计算主频检查是否符合预期频段。例如低频组主频应该在几十赫兹以下中频组对应转频或故障特征频率高频组对应啮合频率及边带。如果不一致大概率是分解参数有问题。如果追求可复现性和稳定性我推荐阈值法。具体做法是把样本熵从小到大排序低频阈值 T1 取第 33 百分位高频阈值 T2 取第 66 百分位。但注意这只是一个公平的起点不是每个信号都均匀落在三组里。有些信号只有中低频高频组可能一个 IMF 都分不到这很正常不必硬凑三组。3.2 重构过程和细节残差怎么处理样本熵分组完成之后重构就是把同组 IMF 直接求和。假设原信号被分解为 M 个 IMF 加一个残差 R(t)那么低频组重构信号为L(t) Σ_{j in low group} IMF_j(t)中频、高频同理。残差 R(t) 通常是信号趋势项它是单调序列或者极低频率成分样本熵必然很小一般直接归入低频组也可以单独提出来看需求而定。我的经验是如果后续要做趋势分析和基线漂移校正残差单独保留更好如果要还原完整信号残差就放到低频组里。重构时有一个很容易被忽略的点IMF 求和后的幅值和原始信号幅值不一定完全一致。原因在于 EEMD 是近似分解每个 IMF 都可能带有微小噪声残余平均化处理之后这些噪声不会完全消除。所以重构后我建议做一次幅值校准具体做法是计算原始信号 x(t) 和重构信号 x_rec(t) 之间的线性回归系数也就是让 x_rec(t) a * x(t) b用最小二乘估计 a 和 b如果 a 偏离 1 超过 5%就要重新审视 EEMD 的参数是否合理。实际上这就是一个简单的代码核对步骤能很好地暴露分解质量问题。重构的本质是“按复杂度分箱”不是“按频段硬滤波”。这是两种完全不同的思路。硬滤波假设信号频率范围已知且通带内的噪声和有效成分无法区分而 EEMD 加样本熵是数据自适应的不预设频段它更擅长对付那些频率随时间漂移的信号。但这也带来一个缺点无法精确指定输出的截止频率。如果你需要严格意义上的 0-100 Hz 低频信号那还是得用滤波器EEMD 加样本熵给的是一种“近似低频但更保真”的选项。4. 实操过程Python 实现一整套流程4.1 环境准备与关键函数库我实现这套流程用的主要工具是 Python核心库是 PyEMD 和 NumPy辅助库是 SciPy 和 Matplotlib。PyEMD 是专门做 EMD 和 EEMD 的库GitHub 上一直有人维护安装直接用 pip。SciPy 用来做信号模板匹配和滤波校验NumPy 做数组运算Matplotlib 出图对比。另外如果信号量很大我建议用 Numba 给样本熵的计算加速否则纯 Python 循环算几千个点的样本熵会有些慢。具体实现上先做两件事设置 EEMD 参数和定义样本熵函数。PyEMD 库中调用 EEMD 的核心代码如下这可以作为一个基本框架from PyEMD import EEMD, EMD eemd EEMD( n_splits100, # 集合试验次数 noise_width0.02, # 噪声幅值系数 parallelTrue, # 并行计算 emdEEMD().emd if False else None ) # 上面这行 emd 参数只是示例实际我用的是默认 EMD eemd EEMD(trials200, noise_width0.05) IMFs eemd.eemd(signal, T)PyEMD 不同版本的接口略有差异有的版本用 trials有的版本用 n_splits使用时先看版本说明。noise_width 是白噪声幅值相对信号标准差的比值取值 0.01 到 0.1 是比较常见的区间。trials 建议最低 50追求稳定跑 200 到 500。看到这里你可能觉得 trials 越高越好但实际要考虑计算时间和随机种子问题。如果 trials 太低比如 20 次白噪声残余太多了均值之后信号会被压低trials 太高比如 1000 次计算时间倍数增长而最后 200 次到 1000 次的差异很小。4.2 样本熵函数的实现与验证样本熵的计算逻辑前面已经讲了但代码实现上有一些加速手段值得分享。最原始的双重循环写法是这样的外层对每个模板向量内层对每个后续向量计算距离并统计。问题在于当序列长度达到几千点维度 m2 时复杂度是 O(N^2)跑起来会特别难受。对一段 10 秒 1000 Hz 采样的信号也就是 10000 个点双循环可能要几十秒。我的优化思路是利用 SciPy 的空间距离计算函数 cdist 一次性算出所有向量对的距离矩阵然后直接向量化比较。这个优化对长度在 10000 以内的序列特别有效。样本熵函数可以直接参考这个核心逻辑import numpy as np from scipy.spatial.distance import cdist def sample_entropy(x, m2, r_factor0.2): x np.asarray(x, dtypenp.float64) x x - np.mean(x) std np.std(x) r r_factor * std N len(x) # 构造 m 维向量 def _phi(m): n_v N - m 1 mat np.array([x[i:im] for i in range(n_v)]) dist cdist(mat, mat, metricchebyshev) count np.sum(dist r, axis1) - 1 count np.maximum(count, 0) return np.sum(count) / (n_v * (n_v - 1)) phi_m _phi(m) phi_m1 _phi(m 1) if phi_m 0 or phi_m1 0: # 出现零概率时返回极大值或 NaN实际处理中可以跳过该IMF return float(nan) return -np.log(phi_m1 / phi_m)这里要说明几点。切比雪夫距离用 cdist 的 metricchebyshev 直接算一行搞定。对角线的距离是 0 一定被计入所以需要减 1。m1 维向量个数是 N-m模板对总数是 n_v*(n_v-1)注意分母别算错。如果某组数据过于规律可能出现 phi_m1 为 0 的情况此时样本熵定义为无穷大但实际处理中我会直接返回 NaN并在分组时手动剔除。这类情况多发生在纯正弦信号或完全周期的仿真信号中实测信号很少遇到。4.3 重构校验和三维信号对比拿到 IMF 和样本熵之后重构这部分我给出一个比较完整的操作框架。首先计算所有 IMF 的样本熵得到数组 S。然后设定阈值把 IMF 分成三组最后按组求和得到 L、M、H 三个信号。对应代码如下# 计算每个IMF的样本熵 entropies [] for imf in IMFs: se sample_entropy(imf, m2, r_factor0.2) entropies.append(se) entropies np.array(entropies) # 排除NaN分量 valid_idx ~np.isnan(entropies) sorted_ent np.sort(entropies[valid_idx]) t1 np.percentile(sorted_ent, 33) t2 np.percentile(sorted_ent, 66) low_group [] mid_group [] high_group [] for idx, se in enumerate(entropies): if np.isnan(se): continue if se t1: low_group.append(idx) elif se t2: mid_group.append(idx) else: high_group.append(idx) L_sig np.sum(IMFs[low_group], axis0) M_sig np.sum(IMFs[mid_group], axis0) H_sig np.sum(IMFs[high_group], axis0)这段代码里有个隐藏前提IMFs 数组的行是不同 IMF列是时间点。如果你的分解结果是列表格式记得先堆叠成二维数组。重构完之后我强烈建议出三张图第一张是原始信号和低频组信号对比看趋势跟踪是否到位第二张是中频组信号和原始信号叠加看主特征频率保留程度第三张是高频组信号的频谱确认高频成分没有被中频组吞掉。用频谱来验证分组是否合理是我每次都必做的环节。可以分别对 L、M、H 做快速傅里叶变换查看它们的主频是否落在合理的频段内。比如振动信号转速是 30 Hz故障特征频率是 180 Hz齿轮啮合频率是 1080 Hz那预期结果是低频组主频集中在 30 Hz 附近及以下中频组主频在 180 Hz 附近高频组主频在 1080 Hz 和更高频段。如果发现高频组主频跑到中频组去了优先检查 EEMD 的噪声幅值是否过大再检查样本熵的 r 值是否选小了。4.4 参数调试实例一组仿真信号的完整结果为了演示参数对结果的影响我构造了一段仿真信号来说明fs 1000 T np.arange(0, 5, 1/fs) x_low 0.6 * np.sin(2*np.pi*2*T) x_mid 1.0 * np.sin(2*np.pi*45*T 0.5) x_high 0.4 * np.sin(2*np.pi*180*T) 0.25*np.sin(2*np.pi*420*T) noise 0.15 * np.random.randn(len(T)) signal x_low x_mid x_high noise这段信号理论上应该重构出三个清晰频段。我分别用三组参数跑了一遍结果差异非常明显参数组合集合次数噪声幅值重构结果描述第一次1000.02低频和中频分离干净高频组有底噪混入包络毛刺多第二次1000.05三频段分离都很好高频组毛刺明显减少第三次5000.05和第二次基本一致但计算时间从 12 秒增加到 50 秒这个实验说明两个结论噪声幅值比集合次数更敏感集合次数超过一定值后收益递减。所以实操中我建议先用 100 次和 0.05 噪声幅值跑一遍看结果如果 IMF 频谱混叠明显再加大 noise_width如果只想降低随机波动再提高 trials。不要一开始就上 500 次跑半天发现参数选错了白白浪费时间。另外这段仿真信号也体现了样本熵分组的一个特点三个正弦成分频率分别是 2 Hz、45 Hz、180 Hz实际上样本熵大小除了和频率有关还和波形复杂度、信噪比有关。45 Hz 附近如果叠加了高次谐波它的样本熵可能比 180 Hz 纯正弦还高。这时候按样本熵分组出来的“中频”不一定对应数学上的频段但它一定是复杂度上更接近的分组。这在某些工程场景正好是优点因为它能自动把“形态复杂”的成分归到一起。5. 实际操作中的常见问题和避坑经验5.1 高频段出现低频趋势端点效应在捣乱我在用 EEMD 处理长度较短信号时经常遇到一个奇怪现象最后一个 IMF 明明是趋势项但高频组重构信号里却叠了一个缓慢起伏的基线漂移。最初我以为是分组分错了后来看了 IMF 的单独波形才发现问题出在 EMD 的包络拟合在信号两端产生了畸变导致一个原本低频的成分泄漏到了其他 IMF 中。这种端点效应在信号首尾不连续时尤其严重。解决这一问题有两个常用手段。第一在分解前对信号做镜像延拓PyEMD 库中可以通过设置 spline_kind 和 range_threshold 等参数来控制端点效应但最稳妥的办法还是手动在信号两端各拼接一段镜像数据分解后再截断。第二在分组前把每个 IMF 的首尾 5% 数据做渐变衰减也就是加一个汉宁窗的斜坡减少边界异常对整体样本熵计算的影响。不过方法二会损失边界信息如果边界正好包含瞬态特征我宁可选择镜像延拓。我个人的经验是在分解前先对整段信号做趋势去除。拿原始信号减去它的局部均值或多项式拟合趋势这样 EEMD 就不需要把大量能量分配给残差值IMF端点效应会明显减弱。5.2 样本熵全是一样大r 值选错了另一种常见情况是所有 IMF 的样本熵都差不多分组阈值分不开。这个问题 90% 的概率出在 r 参数上。样本熵计算中 r 是基于每个 IMF 自身的标准差来归一化的这本身是合理的因为每个 IMF 的能量尺度不同绝对容差不同用标准差归一化可以统一比较。但如果 r 取得太大比如 0.4 倍标准差几乎所有向量对都能在 m 和 m1 维度都找到匹配比率接近 1样本熵趋近于 0区分度全丢了。相反如果 r 取得太小比如 0.02 倍标准差几乎找不到匹配样本熵全部趋近于无穷或 NaN同样没有区分度。我调试时有个快速自检法打印每个 IMF 的标准差和样本熵。如果所有样本熵都在一个极窄的区间比如 0.1 到 0.15说明 r 过大可以按 0.15 倍标准差重试如果样本熵出现大量 NaN 或几百上千的天文数字说明 r 过小改成 0.25 倍标准差再跑。对于振动信号0.15 到 0.25 倍是黄金区间对于心电、脑电等生理信号因为有效成分更规律可以试 0.1 到 0.15 倍。这个参数没有绝对最优它取决于你对“复杂度差异”的分辨需求。还有一个细节是不同 IMF 的幅值差异可能非常大特别是第一个 IMF 和最后一个 IMF 之间可能差一个数量级。如果 r 用全局统一的比例系数 0.2那么对小幅值的 IMF 来说容差可能过松熵值偏低对大幅值的 IMF 来说容差可能过紧熵值偏高。这时候可以选择按每个 IMF 自身的标准差做归一化这是标准公式的常见做法但在分组时要意识到这个归一化消除了绝对幅值的影响。5.3 重构信号和原始信号对不上这种情况多在 EEMD 参数不合适时出现。表现是低频组加中频组加高频组之和与原始信号相差很大相关系数很低。我先给一个排错顺序检查分解是否完整把 sum(IMFs, axis0) 近似等于原始信号减去残差先确认这一步是否成立。如果不等说明 EEMD 分解没有收敛或者 trials 太少导致噪声残余过大。检查缺失分量查看是否因为样本熵 NaN 跳过了某个 IMF如果跳过了一个能量很大的 IMF重构信号自然对不上。检查幅值系数对重构信号和原始信号做线性拟合得到系数 a。如果 a 在 0.9 到 1.1 之间说明整体幅值没有大偏差如果偏离太多检查是否在分解前做了归一化但没有在重构后恢复。如果确定是 trials 太少的问题把集合次数从 100 提升到 200 到 300 再跑一次。还有一个不太起眼但常见的坑你在分解前对信号做了去均值或标准化比如减去了均值并除以标准差分解和重构后忘了恢复。这会导致重构信号整体偏置和幅度错误不是方法的问题是预处理还原的问题。5.4 计算速度太慢的优化方案EEMD 本身计算量偏大集合次数 200 次意味着同一个信号要跑 200 遍 EMD每一遍还要处理几十个筛选迭代再加上样本熵的双循环或矩阵计算整条流程对短信号很轻松对长信号就可能要吃内存和时间了。我处理过一段 10 分钟、采样 2048 Hz 的信号总点数超过 120 万直接跑 EEMD 将近半小时样本熵如果用 cdist 构造 100 万乘 100 万的矩阵内存直接爆掉。优化手段按优先级排列的话信号分段分析把长信号切成有重叠的段比如每段 10 秒、重叠 2 秒分别做 EEMD 和样本熵最后拼接。分段还能顺便解决计算复杂度问题。切的时候注意重叠长度要大于最大 IMF 的周期否则接缝处会有跳变。对样本熵改用 KDTree 搜索替代全矩阵 cdist当向量数非常大时用 KDTree 查半径范围内的邻居可以大幅减少计算量。降低采样率如果分析的最高频率远低于采样率比如 2048 Hz 采样但只关心 500 Hz 以内可以先低通滤波再降采样到 1200 Hz 左右。这个操作要放在 EEMD 之前降采样后信号更短计算量下降很明显。并行计算PyEMD 的 parallel 参数可以开启多进程多个 trials 同时跑。我实测四核机器上能加速 2.5 到 3 倍没有线性加速是因为 GIL 和进程调度开销存在。5.5 边界问题低中高频三组在时间轴上的平滑性重构出的 L、M、H 三路信号如果直接在分组边界处切换很容易在时间轴上出现跳变。比如某个 IMF 在前一秒属于中频组后一秒因为信号特征变化样本熵瞬时升高就可能被分到高频组。但我们在分组时用的是该 IMF 在整个时间段的样本熵这是一个全局标量所以不会出现时刻间的跳变问题。真正要注意的是两个很相近的 IMF它们的样本熵差异很小分组时可能因为阈值刚好卡在中间导致一个 IMF 被分到中频组另一个被分到高频组而实际上它们的复杂度几乎一样。这种情况从时域波形上看不出啥问题但如果你把 L、M、H 三个信号按频谱图排列会发现频谱过渡不自然像是有个断层。要缓解这个问题可以在全局样本熵之外再计算每个 IMF 的滑动窗口样本熵把窗口熵的中位数作为分组依据这样能滤掉瞬间的复杂度异常。代价是计算量变大但多了一层稳健性。我通常会根据信号长度决定要不要做这一步如果信号在 30 秒以内直接做如果超过 5 分钟先分段再处理。6. 应用场景扩展和工程落地建议6.1 机械故障诊断里的典型用法振动信号放进这套流程里最典型的产出是低频趋势、中频故障成分、高频冲击成分三路信号。它们分别对应轴的转速波动、齿轮或轴承的故障特征频率、以及早期点蚀或裂纹引发的瞬态冲击。这三个成分如果用传统带通滤波器你得事先知道故障频率而故障频率本来就是你想要辨识的目标这就陷入一个先有鸡还是先有蛋的问题。用 EEMD 加样本熵就不需要先验频率信息让数据自己分组分组结果可以直接作为后续神经网络的输入特征。比如一个常见的做法是对三路重构信号分别计算 RMS、峰峰值和峭度得到一个三维特征向量。故障早期高频组的峭度会先上升因为瞬态冲击增多中频组的均方根会上升因为故障特征频率能量增强低频组的波动范围则反映出负载变化和轴弯曲趋势。这个三维特征比直接对原始信号算峭度更敏感因为高频冲击被单独分离出来了不会被主轴的强振动掩盖。6.2 生物电信号处理的特殊注意事项心电和脑电信号与机械信号差异很大。它们更平稳、更有节律性频率范围低采样率相对低。用 EEMD 时白噪声幅值要调小我用心电信号时一般取 0.01 到 0.02因为心电本身信噪比较高噪声幅值太大容易把 P 波和 T 波的细节磨平。样本熵的 r 建议取 0.1 倍标准差因为心电的复杂度差异主要体现在小尺度的细节变化上容差太大会把 P 波的变异忽略掉。此外心电分解重构时低频组通常对应呼吸基线漂移中频组对应 QRS 主波高频组对应 P 波细节和肌电干扰。这个分组结果可以直接用于去除基线漂移把低频组从原始信号里减掉就行比传统的高通滤波器保留更多非线性漂移特征。我实测过对运动状态下采集的心电数据做这种处理比零相位 Butterworth 滤波效果好很多因为呼吸引起的基线漂移频率和心率接近时普通滤波器会伤到 ST 段。6.3 结构健康监测和地震信号处理结构健康监测领域经常要处理长期采集的应变、位移和加速度数据。这些数据有一个特点有效信号极其微弱环境噪声和温度漂移占比很大。EEMD 加样本熵的分组逻辑在这里特别有用因为温度漂移导致的低频趋势有很强的周期性和随机性混合特征简单线性拟合无法消除而 EEMD 能把温度响应从结构振动响应中自然分离。低频组的趋势可以作为温变特征输入后续的温度补偿模型中频组对应风和微振动高频组对应局部冲击或交通载荷。地震信号处理中P 波和 S 波到达时刻往往被背景噪声掩盖EEMD 分解后高频组里会先出现幅值突增对应 P 波初至随后中频组出现密集振动对应 S 波。这个检测逻辑本质上就是样本熵突变检测因为 P 波到达前信号复杂度低到达后复杂度突然升高你可以只对高频组做滑动窗口样本熵设定一个自适应阈值来触发报警比直接在原始信号上做 STA/LTA 更少误报。6.4 工程落地的几个建议最后聊几个从仿真到实际部署的通用建议。第一个是随机种子问题。EEMD 每次运行随机数不同导致结果不完全可复现这在科研中可能不是大问题但在工业系统里如果每次程序启动跑出来的 IMF 不一样自动化流程维护起来会很痛苦。解决方案是在调用 EEMD 前设定全局随机种子比如 np.random.seed(42)或者在 PyEMD 中指定 noise_seed 参数不同版本可能命名不同但思路一致。第二个是阈值参数的自适应化。样本熵阈值 T1 和 T2 如果写死换一段信号就失效。工程上更稳的做法是每次跑完都根据当前 IMF 的熵分布动态计算阈值甚至可以把阈值做成滑动窗口版本让系统随着设备老化自动调整分组边界而不需要人工重新标定。第三个是保存中间结果。EEMD 计算成本高一次分解结果和样本熵值得序列化保存后续调参和复盘时直接加载不用重算。我习惯用 npz 格式保存 IMF 数组、样本熵数组和 EEMD 参数打包成一个字典每次实验对应一个文件。这样不仅能复现还能很方便地做多组参数对比。第四个要说的可能是最容易被忽略的EEMD 加样本熵的重构不是滤波器不要指望它能输出严格频段信号。它输出的低频、中频、高频是“复杂度分组产物”在绝大多数应用里够用、甚至更好但如果你的下游算法对频率边界有硬性要求比如需要严格的 0.1 Hz 到 40 Hz 频段那一定要在重构后再加一个相同频段的带通滤波。正确的使用姿势是把 EEMD 加样本熵当成一个自适应特征提取器而不是一个精密滤波工具。我自己用过这套组合处理过不少信号最深刻的体会是参数不会一次到位但分解结果能告诉你怎么调参数。第一次跑完多看看 IMF 波形和样本熵分布比盲目翻公式和调阈值有效得多。