
刚入行预测性维护那会儿我师傅跟我说包络分析这套玩不转别谈轴承诊断。当时我还不以为然觉得FFT能搞定一切。直到有一次在山东一家炼化企业的循环氢压缩机组的电机端我们怀疑是轴承内圈有早期点蚀。我做了完整的时域分析、FFT、功率谱、阶次跟踪愣是没看出来问题。但现场老师傅把耳朵贴到轴承座上听了5秒钟说有点问题拆开一看果然是内圈早期剥落。那一刻我才明白轴承故障的病灶在调制信号里不在载波信号里。FFT看到的载波共振频率根本看不到调制在上面的故障通过频率。必须做包络分析envelope analysis。今天我就用一个真实案例把包络分析的整个流程走一遍。代码全部基于真实项目脱敏Python 3.10numpy 1.24scipy 1.11。案例背景设备某化工厂循环氢压缩机电机型号YK2000-2额定转速2980rpm。 轴承NU322圆柱滚子轴承节圆直径约190mm滚动体直径28mm个数14球径接触角0。 工况实测转速2985rpm电控柜实测运行工况稳定。通过公式推算不是本文重点感兴趣可以查ISO 15243BPFI ≈ 235HzBSF ≈ 138HzBPFO ≈ 165Hz。传感PCB 352C33 IEPE加速度传感器灵敏度100mV/g采样率25600Hz。第一步时域分析看不出才正常先把原始信号做基础分析import numpy as np from scipy.io import loadmat from scipy.signal import welch # 加载原始振动信号mat文件来自客户采集系统 data loadmat(motor_vibration_20240910.mat) signal data[vib].flatten() fs 25600 # 采样率 duration len(signal) / fs print(f采样时长{duration:.2f}秒采样点数{len(signal)}) # 时域统计量 rms np.sqrt(np.mean(signal**2)) peak np.max(np.abs(signal)) kurtosis np.mean((signal - np.mean(signal))**4) / (np.std(signal)**4) print(fRMS: {rms:.2f} g, Peak: {peak:.2f} g, 峭度: {kurtosis:.2f})这台电机实测出来RMS ≈ 0.8g峭度 ≈ 3.2。看上去正常因为电机振动标准 ISO 10816 里这个转速下 ≤ 2.8g 算良好。但如果对比一周前的数据峭度从2.5升到3.2——这其实是个早期警告信号只是时域看不出来。第二步FFT看到的只是载波直接做FFTfrom scipy.fft import rfft, rfftfreq, fftshift freqs rfftfreq(len(signal), d1/fs) amp np.abs(rfft(signal)) # 找出主要频率成分 top_idx np.argsort(amp)[-10:][::-1] for i in top_idx: print(f{freqs[i]:.1f} Hz: {amp[i]:.3f})你会看到一堆频率点50Hz供电、100Hz供电谐波、2985Hz附近基频、5970Hz2x、8955Hz3x以及更高频的一些共振峰。但这里没有235HzBPFI没有138HzBSF。因为故障信号被高频载波和噪声掩盖了。这就是为什么FFT看不出轴承故障。第三步共振频率滤波——提取故障载波轴承故障信号本质上是一个低频BPFI235Hz信号调制在高频共振载波上。思路是先用带通滤波器把高频载波区域切出来然后再解调出低频调制信号。共振频率怎么选一般有两种方法小锤敲击法用冲击力锤敲击轴承座FFT看冲击响应的峰值。经验估计电机轴承常见共振频率在1-5kHz之间看实际FFT里这个区间有没有明显的峰。我们这个案例FFT在2.1kHz和3.8kHz各有一个明显的共振峰。选2.1kHz作为载波中心频率。from scipy.signal import butter, filtfilt def bandpass(sig, fs, fc, bw, order4): 带通滤波中心频率 fc带宽 bw low max(0.001, (fc - bw/2) / (fs/2)) high min(0.999, (fc bw/2) / (fs/2)) b, a butter(order, [low, high], btypeband) return filtfilt(b, a, sig) # 中心频率 2100Hz带宽 ±800Hz filtered bandpass(signal, fs, fc2100, bw800)第四步Hilbert变换提取包络带通滤波后剩下的是调制信号。用Hilbert变换解析信号取幅值的绝对值就是包络from scipy.signal import hilbert analytic hilbert(filtered) envelope np.abs(analytic) # 去直流包络均值 envelope envelope - np.mean(envelope)这一步是关键。包络信号现在应该是一个低频信号理论上它的FFT应该能看到BPFI235Hz和它的谐波。第五步包络谱——找到故障特征频率对包络信号做FFT就是包络谱freqs_env rfftfreq(len(envelope), d1/fs) amp_env np.abs(rfft(envelope)) # 在 BPFI 附近找峰值理论 235Hz bpfí_region (freqs_env 200) (freqs_env 280) peak_idx np.argmax(amp_env[bpfí_region]) peak_freq freqs_env[bpfí_region][peak_idx] peak_amp amp_env[bpfí_region][peak_idx] print(fBPFI 附近峰值{peak_freq:.1f} Hz幅值{peak_amp:.3f})实测结果在 232Hz 处有一个明显峰值和理论 235Hz 偏差是因为转速有小波动并且能看到 232Hz 的 2x、3x 谐波。这强烈指向内圈故障。一个反对意见包络谱也看不出怎么办不是说做了包络就一定能看出来。包络分析的成败取决于两个关键共振频率选得对不对。如果你选了一个没能量集中的死频率包络出来全是噪声。故障严重程度够不够。早期点蚀、剥落极轻微时调制深度太浅包络谱里看不到。这是最坑的——你会以为没事其实已经开始损坏了。解法是定期跑包络分析对比历史趋势。单次包络谱意义不大看趋势变化才有意义。我们现在的做法是每台关键设备每天跑一次自动包络分析把BPFI/BSF/BPFO三个频点的幅值存进InfluxDB 2.7画成Grafana 10.x趋势图。一旦某个频点的幅值连续3天环比上升20%自动报警。一个更狠的细节转速波动怎么办上面案例是稳态工况恒转速2985rpm。但风机、压缩机经常变速。这种情况下BPFI会跟着转速漂移固定频点的包络谱看不准。解法是阶次分析order analysis把频率域映射到阶次域阶次 频率 / 转速。BPFI/BSF/BPFO都是阶次值跟转速无关。def order_spectrum(signal, fs, rpm, bpfi_order4.95): 阶次谱把信号重采样到角度域 # 阶次采样率每转的采样点数 samples_per_rev fs / (rpm / 60) # 重采样到固定阶次分辨率比如 0.01阶 from scipy.signal import resample target_samples int(len(signal) / samples_per_rev * 100) # 100点/转 resampled resample(signal, target_samples) # FFT看阶次 from scipy.fft import rfft, rfftfreq orders rfftfreq(len(resampled), d1/100) # 0~50阶 amp np.abs(rfft(resampled)) # BPFI阶次应该是 4.95 idx np.argmin(np.abs(orders - bpfi_order)) print(fBPFI阶次 {bpfi_order} 处幅值{amp[idx]:.3f})阶次分析比FFT包络组合贵一些但对变速设备是刚需。写在最后包络分析这套东西看起来很古老1970年代就在用了但直到今天它依然是轴承故障诊断最有效的手段之一。我的观点可能有点激进真正把包络分析玩透的工程师比会调深度学习模型的工程师更稀缺、更值钱。因为前者需要对信号、对机理有深度理解后者很多时候是调参。如果你刚开始学预测性维护建议把这篇文章里的代码自己跑一遍——找一段你手头的振动数据按这个流程走一遍。遇到问题别急往下看共振频率选不对就换个频段包络谱没峰值就调滤波带宽。整个流程走通之后你会对信号诊断这件事有全新的理解。一点碎碎念包络分析最大的陷阱是把它当成万能解法。它对轴承故障非常有效对齿轮啮合故障、电机电气故障就力不从心了。下一篇我打算写写齿轮故障的边频带分析那又是一个完全不同的故事。踩过这个坑的人都懂——信号处理这块机理理解不到位代码写得再花哨也是空中楼阁。