搞故障诊断这些年,我最常听同行抱怨的一句话是:"传感器装了一堆,数据采了一大堆,可真到要判断设备哪儿坏了,还是得靠拆机。"这话听着像段子,其实是大多数团队的真实处境:原始信号拿到了,可在频域里看、在时域里看,故障特征就是不肯老老实实冒出来。后来我把 VMD、FFT、HHT 这一套组合用顺了,才意识到问题多半不在数据质量,而在分析思路——信号是混在一起的,你不分层拆解、逐级聚焦,直接拿全局频谱去下结论,当然容易翻车。
这篇文章重点记录我在信号数据分析和故障诊断项目里的完整方法链:先用 VMD 把复杂振动信号拆成干净模态,再用 FFT 快速锁定故障特征频率,最后用 HHT 处理非平稳的瞬态冲击并验证诊断结论。内容会尽量偏实操,公式只讲够用的程度,重点放在参数怎么设、代码怎么跑、结果怎么读、坑怎么躲。想抄作业做轴承故障诊断的学生,正在做设备状态监测的工程师,以及被频谱图逼疯的入门选手,都可以按这条链路直接上手。
提示:检索"VMD"时,你会看到大量跟 Intel 磁盘阵列驱动有关的内容,那属于存储领域的 Volume Management Device,和信号处理里的变分模态分解不是一回事。下文所有 VMD 均指 Variational Mode Decomposition。
1. 为什么故障诊断要把 VMD、FFT、HHT 串成一条流水线
很多初学者做故障诊断时有一个直觉:先对原始信号做一次 FFT,看到哪个频率峰值高,就认定是哪种故障。这个思路不能说错,但它默认了一个前提——信号是平稳的、故障特征是持续存在的。现实中的机械设备往往不满足这个前提:转速有波动,载荷在变化,转轴每转一圈产生的冲击能量时强时弱,再加上背景噪声,频谱会被摊得非常糊。
单独用 HHT 也不是万能。HHT 里的 EMD 确实擅长处理非平稳非线性信号,可它有一个很著名的毛病:模态混叠。直接对含强噪声的原始信号跑 EMD,同一个时间尺度可能被拆到好几个 IMF 里,特征能量被分散,后续无论做包络谱还是边际谱都会失真。单独用 VMD 呢?它能把信号分解得很干净,但分解完你拿到的是若干时域分量,没有进一步做频率定位,也不知道哪个模态对应故障,等于白拆。
1.1 三种方法的分工:拆解、聚焦、定位
用一个容易理解的类比:这三件套配合起来,就像医生诊断一套流程。
VMD 是"CT 扫描",它把混在一起的振动信号按不同频带拆开,每个模态相当于一个"组织切片"。FFT 是"化验单",对每个切片做定量分析,告诉你里面包含哪些主要频率成分、各自能量有多大。HHT 则像"动态心电图",它关注的是信号随时间的瞬时变化,专门捕捉 FFT 这种全局平均手段容易忽略的短暂冲击和频率突变。
实际项目里,我通常把诊断路径固定成三步:VMD 负责把原始信号分解成若干个窄带模态,接下来对每个模态分别做 FFT 频谱分析,找出故障特征频率集中的那个模态;最后对关键模态使用 HHT 做时频分析,观察能量随时间的变化规律,确认故障是持续存在还是间歇性冲击。三步走完,诊断报告基本就站稳了。
1.2 处理顺序为什么不能乱
这个顺序是踩坑踩出来的。最开始我偷懒,拿到信号直接先做 FFT 想要"总览全局",结果低频趋势项和高频噪声搅在一起,频谱图上全是峰值,根本分不清哪个才是故障频率。后来我改用 HHT 先行,把含噪信号直接丢给 EMD,结果分解出的 IMF 前几阶几乎全是噪声,真正的故障特征也被拆散到多个模态里。
正确的顺序逻辑在于:VMD 是一个约束优化过程,它能把具有不同中心频率的调幅-调频信号分离开,相当于在进入频率分析之前先做了一次"信号提纯"。FFT 的优势是快且直观,适合用来做频率定位,但它天然假设信号是稳态周期性的,一旦信号里有强瞬态成分,频谱就会变得很难解。HHT 恰恰擅长分析瞬态和非平稳成分,可它最怕噪声污染,所以必须让 VMD 先处理噪声问题,把相对干净的模态交给 HHT,时频图才不会糊成一片。
所以这条流程的本质,是让每种算法在它最擅长的环节工作,而不是指望某一个算法包打天下。
2. VMD 变分模态分解:把复杂信号拆成可解释的"零件"
VMD 最早由 Dragomiretskiy 和 Zosso 在 2014 年提出,核心思想是:把信号 (f(t)) 分解成若干个具有特定中心频率和有限带宽的模态 (u_k(t)),并让所有模态的带宽之和最小。每个模态被建模成一个调幅-调频信号,带宽通过解析信号梯度的 (L^2) 范数来估计,整个问题用交替方向乘子法迭代求解。
这个思路和 EMD 最大的区别,在于它把"分解"从启发式筛选变成了一种数学优化。EMD 靠包络线和均值线不断筛选,效率不算高,而且对采样率和噪声极度敏感。VMD 则是在频域里不断更新每个模态的中心频率和频谱成分,分解结果更稳定,也能指定模态数量。
2.1 VMD 核心原理与参数含义
要调好 VMD,先得理解两个关键参数:
模态数 K,决定把信号拆成几个分量。K 设小了,多个不同频率成分会被硬塞进同一个模态,欠分解;K 设大了,同一个物理成分会被拆碎,出现中心频率接近的虚假模态。惩罚因子 alpha,控制模态带宽的紧致程度。alpha 越大,模态带宽越窄,频率分辨率越高,但对分解误差也更敏感;alpha 越小,模态带宽越宽,容错强但可能把不该混的频带混进来。
此外还有 tau,它是噪声容忍参数,更新步长相关,实测中一般设 0;DC 设为 1 表示保留包含直流成分的模态,大多数振动分析场景设 0;init 表示中心频率初始化方式,通常设 1 表示初始化为均匀分布,避免过早收敛到局部解;tol 是迭代停止阈值,默认 1e-7 即可。
2.2 模态数 K 和惩罚因子 alpha 怎么选
这是 VMD 使用中问得最多的问题,也是最没有标准答案的问题。我自己摸索出的经验是先粗后细:
第一步,先固定 alpha=2000,把 K 从 2 开始逐步增加,每跑一次都看一眼分解出的中心频率。如果某两个模态的中心频率非常接近,或者出现了明显没有物理意义的纯噪声模态,说明 K 已经过头了,退回上一个值。
第二步,观察残差信号,即原始信号减去所有模态之和的剩余部分。如果残差里仍有明显周期性,说明 K 不够,信号还没拆干净;如果残差接近白噪声,那当前 K 基本合适。
第三步,结合相关性和互信息做定量验证:计算每个模态与原始信号的相关系数,以及模态之间的相关系数。模态之间相关性很小说明分解成功;某个模态相关系数接近 1 但频谱很宽,可能这个模态里塞了多个成分,需要加大 K 或调整 alpha。
alpha 的调整逻辑也类似。噪声较强时,我会把 alpha 适当调大,让每个模态更"窄"一些,把窄带里的噪声滤掉;但如果太大,可能出现模态失真,时间波形会变得过于光滑。实际项目里 alpha 在 1500 到 3000 之间最常见,特殊情况下也会用到 5000 以上。
2.3 VMD 在实际诊断中的关键使用细节
VMD 有一个容易被忽略的前提:输入信号最好是零均值的。如果原始振动信号有明显的直流偏置,分解出的低频模态可能被污染,所以在调用 VMD 之前,我通常会对信号先做去均值处理,也就是减去时间序列的算术平均。
另外,VMD 对信号长度有要求。分解效果跟频率分辨率直接挂钩,信号太短,模态中心频率的估计就不稳定。我一般建议单段分析长度不少于 2000 点,采样频率越高、需要的分析时长越长。做在线监测时,可以按固定窗口滑窗处理,但相邻窗口之间要有 50% 以上重叠,避免在窗口边界丢掉瞬态冲击信息。
还有一个细节,VMD 的初始化随机性会导致结果有细微差异。为了让结果可复现,在写代码时固定随机种子,或者在命令里指定 init 为某种确定性方式。如果同一组参数跑两次结果差别很大,大概率是信号本身信噪比太低,需要先做带通滤波。
3. FFT 频谱分析:把模态分量变成故障"指纹"
VMD 拆完模态之后,下一步就是让 FFT 上场。FFT 是离散傅里叶变换的快速算法,它把时域信号转换到频域,让我们能直观看到每个频率成分的幅值大小。理论上说,只要是周期性信号,都能通过 FFT 得到频谱,而机械故障往往会激发特定频率的周期冲击,这就是我们说的"故障指纹"。
3.1 采样率、频率分辨率与频谱泄漏
做 FFT 之前,三个概念必须算明白。
采样率 fs。它决定频谱能看到的最高频率,也就是奈奎斯特频率 fs/2。如果你的采样率是 25600 Hz,那么频谱最高只能分析到 12800 Hz,超过这个频率的成分会折叠回来,形成伪峰。
分析点数 N。它决定频率分辨率 Δf = fs/N。比如 fs=25600 Hz,N=4096,那么 Δf 约为 6.25 Hz,两个频率相差小于 6.25 Hz 时在频谱上无法分开。要提高分辨率,最直接的办法是采集更长的信号,而不是靠补零。
频谱泄漏。截取一段有限长信号本质上等于在无限长信号上乘了一个矩形窗,矩形窗的旁瓣会在频谱上"拖尾",把真实频率的能量泄漏到邻近频点。解决办法是加窗,比如 Hanning 窗、Hamming 窗或 Blackman 窗。加窗能降低旁瓣,但也会让主瓣变宽,这是分辨率与泄露出此消彼长的关系,需要根据实际需求取舍。
3.2 轴承故障特征频率的计算方法
轴承故障诊断离不开特征频率计算。滚动轴承有四个典型故障部位,分别对应四个特征频率,均与转频 fr 和轴承几何参数有关:
外圈故障特征频率 BPFO、内圈故障特征频率 BPFI、滚动体故障特征频率 BSF 和保持架故障特征频率 FTF。以常见的角接触球轴承为例,假设滚动体个数 Z=9,节圆直径 D=62mm,滚动体直径 d=13mm,轴转速 1770 r/min,即转频 fr≈29.5Hz。代入公式:
- 外圈:BPFO ≈ (Z/2)×(1-d/D)×fr ≈ 105.0 Hz
- 内圈:BPFI ≈ (Z/2)×(1+d/D)×fr ≈ 160.6 Hz
- 滚动体:BSF ≈ (D/d)×[1-(d/D)²]×fr ≈ 134.8 Hz
- 保持架:FTF ≈ (1/2)×(1-d/D)×fr ≈ 11.7 Hz
算出来之后,再去看 FFT 频谱上相应频率附近是否有明显峰值。注意,实际转速会略有波动,所以不要盯着理论值的小数点后一位,而是看附近带宽内有没有峰值群。
3.3 加窗与包络谱的实际使用技巧
在提取早期微弱故障特征时,我会优先看包络谱,而不是直接看原始频谱。原因在于,早期轴承故障的冲击会激起高频固有振动,故障特征频率本身表现为对高频载波的幅度调制。直接对原始信号做 FFT,能量会集中在高频固有频率附近,低频调制边带很难看清楚。但用 Hilbert 变换先提取包络,再对包络做 FFT,故障特征频率就会变得非常醒目。这个方法也叫包络分析或解调分析。
操作顺序是:先对模态做带通滤波,把分析频段选在固有共振峰附近,再求解析信号幅度得到包络,最后对包络做 FFT。工程上,带通滤波中心频率可以先看原始频谱里哪一段能量集中,再选取 1/3 倍频程带宽。
4. HHT 时频分析:捕捉非平稳信号的"瞬间变化"
FFT 给的是"全局平均"的视角,但它处理不了非平稳信号。在故障诊断里,非平稳意味着什么?意味着冲击是间歇出现的,例如滚动体经过外圈故障点时会产生一次冲击,转一圈打一次,但打完之后冲击迅速衰减。这种瞬态信息恰恰是判断故障严重程度最宝贵的东西。HHT 的价值就在这里。
4.1 EMD 分解与 Hilbert 谱
HHT 最早由 Huang 等人在 1998 年提出,核心分两步。
第一步是经验模态分解 EMD,它把信号按时间尺度逐级分解成若干本征模态函数 IMF。IMF 要满足两个条件:极值点数和过零点数相等或最多相差一个;上下包络的均值在局部时刻为零。EMD 不依赖预设基函数,因此具有极强的自适应性,适合处理非线性非平稳信号。
第二步是对每个 IMF 做 Hilbert 变换,构造解析信号,从而得到瞬时幅值和瞬时频率。把所有 IMF 的瞬时幅值叠加在时频平面上,就得到了 Hilbert 时频谱,也叫时频图。它展示了信号频率随时间的变化,以及各时刻的能量强弱。
4.2 HHT 和 VMD 衔接的合理姿势
我见过不少人把 VMD 和 HHT 对立起来,觉得既然 VMD 已经能分解了,为什么还要 EMD?其实它们是配合关系。EMD 的递归筛选特性决定它对噪声敏感,信号里稍微有一点强噪声,分解出来的第一个 IMF 常常全是噪声。所以在我的流程里,EMD 从不直接处理原始信号,而是交给 VMD 输出的某个关键模态。
还需要说明一点:如果你用的是 EEMD 或 CEEMDAN,那是给 EMD 增加了辅助白噪声来抑制模态混叠,效果确实更好,但计算量也明显上升。VMD 本身比较稳定,先 VMD 后 EMD 的做法在实践中计算效率更高,模态结果也更容易解释。
此外,也不一定每个模态都需要做 HHT。实际操作时,我通常是先用 FFT 对每个 VMD 模态做频谱扫描,挑出包含故障特征频率的那个或那几个模态,然后只对这些模态做 Hilbert 包络谱和时频分析。这样既节省算力,又能避免无关模态干扰诊断结论。
4.3 时频谱图怎么读
读时频谱图要养成一个习惯:不要只看某个时刻的颜色深浅,要看横轴时间上是否有周期性亮点。
以一个典型外圈故障为例,时频图上你会看到在故障频率 BPFO 附近,每隔一个转轴周期就出现一次短暂的能量增强,像一串间隔均匀的"柱子"。内圈故障则不一样,因为负载区在旋转,故障点进入和离开负载区会让冲击幅值出现周期性变化,时频图上会叠加一个转频调制的包络。滚动体故障的调制规律更复杂,通常和保持架转动有关。
分析这些特征时,把 VMD 模态时域波形、FFT 频谱、Hilbert 包络谱和时频图四张图摆在一起对比,基本就能给故障定性了。只靠一张图下结论,是诊断里最容易犯的错。
5. 实战:滚动轴承故障信号诊断完整流程
理论讲透了,我直接上一套可复现的流程。数据用公开的滚动轴承故障数据集,采样频率 fs=25600Hz,转速约 1770r/min,故障类型为外圈故障。分析环境用 Python 3.8 以上版本,需要安装 numpy、scipy、matplotlib、vmdpy 和 PyEMD(或 emd 库)。
注意:完整代码段较长,核心函数我会分块展示。实际跑通时建议用交互式环境,便于随时观察中间结果。
5.1 数据准备与预处理
import numpy as np from scipy.io import loadmat from scipy.signal import hilbert, butter, lfilter import matplotlib.pyplot as plt # 假设 mat 文件中变量名为 X,第 1 列是振动信号 data = loadmat('bearing_outer.mat')['X'].flatten() fs = 25600 # 采样率 Hz # 取一段 4096 点数据做稳态分析 sig = data[0:4096] sig = sig - np.mean(sig) # 去均值这段代码的关键是去均值。VMD 基本原理不会主动处理直流分量,信号带偏置会直接污染低频模态。还有就是分段长度,4096 点对应 0.16 秒,能看到 160 Hz 左右的频率细节,对外圈故障足够了。
5.2 VMD 分解实现
from vmdpy import VMD alpha = 2000 tau = 0 K = 6 DC = 0 init = 1 tol = 1e-7 u, u_hat, omega = VMD(sig, alpha, tau, K, DC, init, tol) # u 的维度是 (K, len(sig)),omega 的维度是 (K, 迭代次数) print("各模态中心频率(最后迭代值):", omega[:, -1])跑完之后先看 omega 最后一行,如果发现两个模态中心频率靠得很近,比如 500Hz 和 520Hz,基本可以判断 K 取大了,把 K 减 1 或者减 2 再试。我这里 K=6 是经验值,对多数轴承数据都够用,但不保证最优,需要根据实际中心频率分布微调。
5.3 FFT 频谱分析与特征频率比对
def fft_amp(sig, fs): n = len(sig) freqs = np.fft.rfftfreq(n, 1/fs) amp = np.abs(np.fft.rfft(sig)) * 2 / n return freqs, amp fr = 29.5 # 转频 Hz Z = 9 # 滚动体个数 D = 62e-3 # 节圆直径 m d = 13e-3 # 滚动体直径 m bpfo = 0.5 * Z * (1 - d/D) * fr print(f"理论外圈特征频率: {bpfo:.2f} Hz") for k in range(K): freqs, amp = fft_amp(u[k], fs) # 找出故障频率附近 ±5Hz 的最大峰值 idx = np.where((freqs > bpfo-5) & (freqs < bpfo+5))[0] if len(idx) > 0: peak = amp[idx].max() if peak > 0.1 * amp.max(): print(f"模态{k+1}在{bpfo:.1f} Hz附近有明显峰值: {peak:.3f}")我把轴承参数和特征频率计算直接码进了脚本里,这样每次新数据进来都能自动比对。实际项目里,转频一般用编码器测速或者电网频率估计,不要只看铭牌转速。
5.4 Hilbert 包络谱与时频图
def envelope_spectrum(sig, fs): analytic = hilbert(sig) env = np.abs(analytic) return fft_amp(env, fs) # 只对包含 BPFO 峰值最明显的模态做包络谱 target_k = 1 # 按上一步输出确定 freqs_env, amp_env = envelope_spectrum(u[target_k], fs) plt.figure(figsize=(10, 6)) plt.plot(freqs_env, amp_env) plt.xlim([0, 300]) plt.xlabel('Frequency / Hz') plt.ylabel('Amplitude') plt.title('Envelope Spectrum of Mode %d' % target_k) plt.grid(True) plt.show()如果包络谱里在 BPFO 附近出现明显谱峰,而且还有间隔等于转频的边频带,那外圈故障的判断就不太会错了。若想看时频图,可以用 PyEMD 对目标模态再跑一次 EMD,但注意只要你只关心包络谱,时频图不是必需环节。
5.5 结果解读的完整视角
拿到全套图之后,按这个顺序综合判断:
先看 VMD 中心频率是否稳定分布,确认没欠分解也没过分解。再看 FFT 频谱,确认特征频率峰值是否存在。接着看包络谱,确认调制关系是否成立。最后把时频图摆上来,如果看到故障频率附近有周期性能量簇,基本可以写诊断结论了。
单一证据很容易被噪声骗,多层证据互相印证才是工程上靠得住的做法。
6. 常见问题与排查技巧实录
三件套组合看上去挺顺,实际操作中遇到的问题着实不少。我把踩过的坑按频率排序整理成表,方便大家速查。
| 现象 | 可能原因 | 排查思路 |
|---|---|---|
| VMD 分解后模态中心频率重叠 | K 设置过大 | 减小 K,观察中心频率差值是否拉大 |
| 某模态全是噪声 | 原始信噪比太低,或 alpha 太小 | 增大 alpha,或先做带通滤波 |
| FFT 频谱峰值位置飘移 | 转频波动、滑差 | 用实测转频计算特征频率,而不是只看理论值 |
| 频谱多出等间隔伪峰 | 频谱泄漏或采样率引入工频干扰 | 加窗,检查地线/屏蔽,排除 50Hz 干扰 |
| EMD 分解严重模态混叠 | 输入模态仍含多频率成分 | 先用 VMD 二次分解,再用带通滤波提纯 |
| 包络谱峰值不明显 | 带宽选择错误 | 观察原始频谱共振峰位置,调整带通中心频率 |
| 代码跑出 NaN | 信号包含 NaN 或无穷值 | 检查数据清洗,插值或删除异常段 |
6.1 典型的 VMD 参数"翻车"现场
有个项目让我印象特别深,拿到的是齿轮箱数据,断齿故障。我按默认 alpha=2000、K=5 分解,结果第三和第四个模态中心频率只差 12Hz,一看就知道过分解了。我把 K 降到 4,又发现第一个模态包含一个很宽的 0-300Hz 平台,明显欠分解。最后参考中心频率逐步递增原则,把 alpha 提到 3000、K 保持 4,中心频率才拉开到 45Hz 以上,频谱也干净了。
所以别指望一组参数走天下。最好是写一个小循环,把 K 从 2 到 10、alpha 从 1000 到 5000 扫一遍,用中心频率差值和残差能量两个指标自动选参。虽然跑起来慢一点,但比肉眼反复试靠谱得多。
6.2 我特别想强调的独家心得
第一,包络谱比原始 FFT 更值得优先看。早期故障特征在原始频谱里几乎都被噪声盖住,包络谱等于先把"冲击包络"提出来,再做一次频率分析,等效信噪比高很多。
第二,HHT 的时频图不是越细越好。时频分辨率受 Heisenberg 不确定性原理约束,频率分辨率越高,时间分辨率就越差。在故障诊断里,我更在意时间维度上的冲击间隔,所以频率轴够用就行,不要为了"高清"把图搞得花花绿绿,重点是用视觉判断周期性。
第三,所有诊断结论都要回到时域波形验证。就算频域特征再亮眼,你也应该在原始时域波形上找到对应冲击。找不到对应冲击的特征频率,很可能只是某个共振峰被误判了。
7. 从代码到工程落地:还有哪些坑要踩
在实验室里跑通一套 Python 脚本,和真正在产线上落地,中间至少隔着三个现实问题。
第一个是数据导入。现场工程师常用 CSV 或 Excel 保存数据,直接用 MATLAB 或 Python 读入固然简单,但采样信息往往写在一个单独的参数文件里,如果采样率、触发方式、传感器灵敏度这些元数据对不上,后续所有频率计算全是白搭。我建议在采集端就把元数据打包成标准格式,比如 CSV 文件头中加入 fs、通道号、传感器灵敏度字段,避免分析时靠猜。
第二个是实时性问题。VMD 是迭代算法,HHT 里的 EMD 也是递归筛选,直接上在线实时诊断并不现实。工程上的做法是分段滑窗做准实时分析:数据窗口每推进 4096 点做一次完整分析,中间结果缓存,诊断结论滞后一个窗口周期输出。这样既能保留算法精度,又能满足大部分监测需求。
第三个是嵌入式部署。如果你需要在 MCU 或 FPGA 上跑 FFT,我对 Vivado FFT IP 核的使用建议是:配置时重点关注采样点数、数据位宽和 FFT 架构(流水线还是突发式)。嵌入式环境里资源有限,很少能把 VMD 和 HHT 完整放进去,通常的做法是嵌入式端只做 FFT 和简单阈值判断,边缘侧网关定期拉数据做 VMD+HHT 的深度分析。这样的两级架构既省资源,又能覆盖大多数硬件的性能边界。
从算法组合的角度,VMD-FFT-HHT 这条技术链路本身并不新,核心价值在于"递进式证据链"构建:先自适应地分离信号,再定量地定位频率,最后从时频域交叉验证动态特征。只要数据的信噪比和采集质量没有大问题,这套流程在轴承、齿轮、转子等旋转机械故障诊断上都能给出相对稳健的结论。
我自己在实际项目里最深的体会是:工具链再成熟,也替代不了对设备的理解。轴承参数、转频、负载变化、安装方式,这些看似琐碎的信息最终都会体现在信号里。分析之前多花半小时搞清楚设备物理背景,比多跑十个算法更有用。另一个小建议是,把每次成功诊断的频谱图和特征频率存档,形成你自己的故障样本库,遇到类似工况时直接对照,效率会高很多。分布式能帮你把复杂问题变简单,但真正的诊断能力,始终来自你对信号和设备的双重敏感。