
做设备状态监测的人都明白一个道理滚动轴承是旋转机械里最脆弱也最关键的一环。我接手这个课题的时候正赶上现场一台压缩机无故振动超标拆解后发现外圈已经出现严重的剥落坑。问题在于从振动信号出现异常到轴承彻底失效中间是有足够预警窗口的如果能在早期从信号里识别出故障特征完全可以把非计划停机变成计划内检修。这个想法驱动我完整走了一遍“基于MATLAB的滚动轴承故障诊断”的流程从数据采集、信号预处理、特征提取到故障识别模型每一步都踩了不少坑。这篇博客把这些经验和代码细节整理出来给准备入行设备故障诊断、或者正在用MATLAB做振动分析的朋友一个参考。1. 整体设计思路与MATLAB的选型逻辑1.1 轴承故障诊断的本质是什么滚动轴承故障诊断的核心任务是从振动信号中识别出轴承的健康状态。轴承在运转时滚动体与内外圈滚道接触任何局部损伤如点蚀、剥落、裂纹都会在接触点产生周期性冲击这种冲击会激励轴承座和传感器产生共振响应表现为振动信号中的周期性脉冲成分。诊断的本质就是从淹没在大量噪声和背景振动中的信号里找到这些周期脉冲并判断它们对应的是外圈、内圈、滚动体还是保持架的故障。这个问题的难点在于三点第一轴承故障信号通常很微弱尤其是在早期阶段特征成分的幅值可能只有正常振动水平的百分之几第二实际运行环境复杂齿轮啮合、轴系不对中、不平衡等干扰都会掩盖轴承特征第三不同工况下转速、负载变化信号特征会发生偏移模型泛化困难。理解了这些难点后面每一步做法的逻辑就清晰了——预处理是为了提高信噪比特征提取是为了量化故障特征模式识别是为了自动分类。1.2 为什么选择MATLAB而不是Python很多初学者会纠结用MATLAB还是Python。我的项目经历给出的答案是在信号处理链条上MATLAB的效率比Python高太多。这不单是个人习惯的问题而是MATLAB的信号处理工具箱和故障诊断相关函数已经非常成熟很多标准流程只需要几行代码比如带通滤波器的设计、包络谱分析、小波时频图绘制都有现成的、经过大量验证的函数可以直接调用。Python当然也能做但需要自己拼装scipy、numpy、pywt等库在项目初期调试阶段效率差距非常明显。MATLAB还有两个很实际的优势一个是App Designer和工具箱的交互式操作可以快速查看信号波形、频谱、时频图对理解数据非常有帮助另一个是代码可读性高矩阵运算语法天然贴近信号处理的数学表达对于工程技术人员来说学习和维护成本低。我项目后期需要把算法部署到测试台用MATLAB Coder生成C代码也省了不少事。如果你手头已经有MATLAB使用经验做故障诊断完全没必要换Python如果是从零开始我更推荐先用MATLAB跑通全流程后面有需要再迁移。2. 数据准备与信号预处理2.1 数据来源与采集参数设定我使用的数据来自公开的凯斯西储大学滚动轴承故障数据集这是行业内最经典、引用最多的轴承故障数据。实验台由电机、扭矩传感器、测功机和被测轴承组成通过电火花加工在轴承上设置单点故障故障直径有0.18mm、0.36mm和0.54mm三档分别对应轻微、中等和严重故障。采样频率有12kHz和48kHz两档我选择了12kHz档的驱动端加速度信号因为它的信号频带已经足够覆盖轴承故障特征数据量也更适中。采集参数设定是整个诊断流程的地基。这里有两个关键参数要特别留意采样率fs和采样时长T。采样率决定了能够分析的最高频率奈奎斯特频率为fs/2对于滚动轴承诊断一般要求采样率至少为最高关注频率的2.5倍。12kHz采样率意味着有效分析带宽到6kHz对于多数工业轴承的故障特征频率通常在几百赫兹到两三千赫兹以及轴承座共振频带一般在3-6kHz是足够的。采样时长决定了频率分辨率Δf 1/T。如果转频是30Hz故障特征频率在100-200Hz范围频率分辨率至少要做到1Hz以下才能准确分辨特征频率附近的边带。我取每段信号1秒频率分辨率1Hz够用。如果转速更低就需要延长采样时长。2.2 预处理该做什么拿到原始振动信号后不能直接提取特征必须先做预处理这一步直接决定了后面特征提取的质量。我的预处理链条分三步去均值、带通滤波、数据切分。去均值是必须的第一步。加速度传感器采集的原始信号往往存在直流偏移这个偏移来自传感器本身的偏置电压和采集电路的零漂。如果不做去均值做FFT时直流分量会泄漏到邻近频点掩盖低频段的有用信息。MATLAB里一句x x - mean(x)就解决了。带通滤波的选带逻辑值得细说。轴承故障信号的典型频域特征是低频段有转频及其谐波中频段有故障特征频率高频段有轴承座共振峰。为了突出故障冲击成分需要做带通滤波。我参考了一个工程经验法则带通范围选在轴承座共振频带通常用1kHz-5kHz或者更高。但实际操作中这个范围不能拍脑袋定要先看原始信号的功率谱密度找出共振峰的位置再确定频带。我用pwelch函数画出功率谱观察到这个数据集在3kHz-5kHz有明显的高频共振能量集中区域于是把带通滤波范围定为2kHz-5kHz。滤波器的实现用designfilt设计巴特沃斯带通滤波器阶数选4到6阶数太低过渡带太宽阶数太高容易引起相位失真。注意滤波后要用filtfilt做零相位滤波避免信号相位偏移影响后续的时域特征计算。数据切分是把长信号切成固定长度的样本段。这里有一个非常容易犯的错误切分时相邻样本之间如果重叠太多会引入数据泄漏导致训练集和测试集之间存在信息重叠模型评估结果虚高。我采用的策略是每段信号长度取2048个采样点约0.17秒确保每段至少包含若干个转频周期和故障冲击周期段与段之间不重叠。切分后的每个样本作为一个独立的样本单元用于后续特征提取和模型训练。2.3 预处理完整代码示例下面这段代码是我预处理环节的完整实现包含了从读数据到输出干净样本的全过程% 读取凯斯西储大学轴承数据 % 文件来自12kHz驱动端采集负载0马力转速约1797rpm data load(97.mat); % 正常状态数据 x_raw data.X097_DE_time; % 驱动端加速度信号 fs 12000; % 采样率 12kHz % 第一步去均值 x x_raw - mean(x_raw); % 第二步看功率谱确定共振频带 [pxx, f] pwelch(x, hann(4096), 2048, 8192, fs); plot(f, 10*log10(pxx)); xlabel(频率 (Hz)); ylabel(功率谱密度 (dB/Hz)); % 观察共振峰判断带通范围我这边看到3k-5k有能量集中 % 第三步零相位带通滤波 d designfilt(bandpassiir, ... FilterOrder, 4, ... HalfPowerFrequency1, 2000, ... HalfPowerFrequency2, 5000, ... SampleRate, fs); x_filtered filtfilt(d, x); % 第四步切分为样本段 segLen 2048; % 每段采样点数 numSeg floor(length(x_filtered) / segLen); segments zeros(segLen, numSeg); for k 1:numSeg segments(:, k) x_filtered((k-1)*segLen 1 : k*segLen); end % 每一列是一个样本段后续特征提取按列处理这段代码里我觉得最值得反复推敲的就是滤波器参数的确定。designfilt里的阶数和截止频率如果选得不合适要么滤不掉干扰要么连故障冲击的有用成分都削掉了。之前我偷懒直接用默认参数跑后面做包络谱发现特征频率处的幅值异常低反过来查才发现带通范围设错了把共振峰的主要频段挡在了外面。从那以后我固定了一个习惯先可视化功率谱再确定滤波参数绝不在参数没看清之前盲目定滤波器。3. 特征提取——从时域到时频域3.1 时域统计特征快速有效的第一道筛选时域特征是最直观、计算成本最低的故障指示器。基本的思路是轴承出现故障后振动信号的统计特性会改变比如幅值增大、脉冲成分增多、波形偏离正态分布。我提取的时域特征包括均方根值、峭度、偏度、峰值因子、波形因子、脉冲因子和裕度因子。RMS值是反映振动能量总体水平的指标轴承磨损或剥落会导致RMS上升但它对早期局部损伤不敏感因为局部冲击的持续时间短、能量占比小。峭度是四阶中心矩标准化的结果对脉冲成分极其敏感——正常轴承信号的峭度接近3正态分布而早期故障信号由于周期性冲击的存在峭度可能飙升到10以上。这也是为什么峭度被广泛用来做轴承早期故障的快速筛查指标。峰值因子峰值除以RMS和脉冲因子也有类似的敏感性但它们的缺点都是抗噪性差一个极端噪声尖峰就能把它们拉高。实际处理中我会把所有时域特征拼成一个特征向量。比如对每个样本段计算RMS、峭度、偏度、峰值因子、波形因子、脉冲因子、裕度因子这样每个样本得到一个7维特征向量。正常状态和故障状态在这个特征空间里往往已经有明显的可分性可以用scatter3先画出来看看分布。不过时域特征有个天然短板——它们丢失了频域信息无法区分外圈故障和内圈故障两者都产生周期性脉冲时域统计特性相近所以光靠时域特征只能判断“有没有故障”不能回答“故障在哪里”。要回答这个问题必须做频域分析。3.2 频域与包络谱定位故障部位的关键频域分析的核心是找到故障特征频率。不同的轴承故障部位对应不同的特征频率它们由轴承几何参数和转频决定。常用计算公式如下外圈故障特征频率 BPFO (n/2) × fr × (1 - d/D × cos α)内圈故障特征频率 BPFI (n/2) × fr × (1 d/D × cos α)滚动体故障特征频率 BSF (D/(2d)) × fr × [1 - (d/D × cos α)²]保持架故障特征频率 FTF (fr/2) × (1 - d/D × cos α)其中n是滚动体个数fr是轴转频Hzd是滚动体直径D是轴承节圆直径α是接触角。以我实验用的6205-2RS深沟球轴承为例n9d7.94mmD39.04mmα0°在转速1797rpmfr≈29.95Hz下BPFO ≈ 4.5 × 29.95 × (1 - 7.94/39.04) ≈ 107.3HzBPFI ≈ 4.5 × 29.95 × (1 7.94/39.04) ≈ 162.2HzBSF ≈ (39.04/15.88) × 29.95 × [1 - (0.2034)²] ≈ 69.5HzFTF ≈ 14.975 × (1 - 0.2034) ≈ 11.9Hz这些计算值就是后面对照频谱图判断故障类型的“标尺”。直接对原始信号做FFT的频谱往往在共振频带处有一大片能量隆起故障特征频率反而被淹没。这时候就需要用希尔伯特变换做包络解调把高频共振成分中的调制信息提取出来。包络谱分析的逻辑是故障冲击激励轴承座共振形成高频振荡而故障特征频率恰恰调制在这个高频振荡上。希尔伯特变换能求出信号的上包络解析信号的幅值对包络再取FFT就把“高频载波”换成了“低频调制频率”故障特征频率就清晰暴露出来了。MATLAB里直接用abs(hilbert(x_filtered))得到包络然后对包络做FFT。我在实际诊断中遇到过这样一个典型案例一段外圈故障信号直接看原始FFT频谱只看到4.5kHz附近有个大包完全分不清故障类型做了包络谱之后在107Hz处出现明显峰值并且还有二倍频约214Hz的谐波这个“基频谐波”的谱线组合模式非常典型基本可以确认外圈故障。内圈故障在包络谱上的特征是故障特征频率FSI处有峰值同时由于内圈随轴旋转故障点相对传感器的位置周期变化会额外产生转频fr的边带调制所以看包络谱时如果发现BPFI两侧有间隔约fr的边带更加支持内圈故障的判断。滚动体故障的情况复杂一些因为滚动体自转的同时还会在保持架内公转故障点周期性改变径向载荷方向所以包络谱中BSF处的峰值往往不如外圈故障那么突出有时还需要结合时频图综合判断。3.3 时频域方法处理变转速工况的进阶方案固定转速工况下频域分析已经足够。但实际工业设备的转速往往是波动的转频和故障特征频率随时间漂移直接用FFT频率成分被“平均”掉谱峰模糊。这种情况就需要用时频分析。我尝试了两种方法短时傅里叶变换STFT和连续小波变换CWT。STFT通过窗函数把信号切成短段每段做FFT得到频率随时间变化的二维图谱。MATLAB里的spectrogram函数可以直接画出瀑布图。它的局限在于窗长固定时间分辨率和频率分辨率不可兼得——窗越长频率分辨率越高但时间分辨率越差。对于轴承这种瞬态冲击信号STFT常常显得“糊”。CWT用可伸缩平移的小波基函数来替代固定窗在低频段频率分辨率好高频段时间分辨率好这种多分辨率特性很契合轴承冲击信号的时频特性。MATLAB里cwt(x_filtered, fs)一行命令就能得到小波时频图实时显示效果相当直观。在时频图上正常轴承信号的背景均匀出现故障后可以看到与特征频率对应的横向亮条带冲击越大条带越亮。不过小波变换也有代价计算量比STFT大得多12kHz采样率、1秒信号做CWT在普通笔记本上要几十秒。而且小波基函数和分解层数需要根据信号特性调我常用的经验是选Morlet小波MATLAB默认尺度范围设为自动实际效果已经足够。如果要用小波特征做批量样本的机器学习分类时间成本会是个问题。我在项目中做了取舍定转速数据集用FFT包络谱做特征提取变转速或者验证“技术展示效果”时才上CWT时频图。4. 故障识别模型的选择与实现4.1 传统机器学习路线SVM和KNN特征提取完成后故障识别问题就变成了一个标准的分类问题。每个样本已经用一个特征向量表示我拼接了时域特征和包络谱特征合计约30维带标签接下来要做的就是把数据集划分为训练集和测试集训练分类器评估泛化性能。我第一个用的分类器是支持向量机SVM。MATLAB里的fitcecoc函数可以直接训练多分类SVM底层自动为每个类别对构建二分类器用一对一策略完成多类判别的组合。这里有一个参数至关重要核函数的选择。我测试了线性核和高斯核RBF发现线性核在四分类任务正常、外圈故障、内圈故障、滚动体故障上准确率只有85%左右换RBF核之后可以达到96%以上。原因很直观不同故障类型的特征空间分布并不是线性可分的特别是外圈和内圈故障的特征有部分交叠RBF核通过隐式映射到高维空间把这些交叠区域分开了。用fitcecoc的时候我设置了OptimizeHyperparameters, auto让MATLAB自动做超参数调优跑一轮交叉验证大概需要几分钟省去手动调gamma和KernelScale的麻烦。K近邻KNN是另一个简单但有效的选择fitcknn跑起来极快关键参数是邻居数K和距离度量方式。我发现K5、距离度量用欧氏距离效果已经不错准确率和SVM相当但预测时间远短于SVM。这给了我很重要的启发很多场景下不需要追求“最先进”的模型简单模型如果特征提取得足够好效果不输复杂模型。我之前看过一些入门的代码上来就用深度学习其实没必要——特征质量决定上限分类器只是逼近这个上限。4.2 深度学习的尝试一维CNN和LSTM传统机器学习方法需要人工设计特征而深度学习方法可以自动从原始信号中学习特征表示。我用MATLAB深度学习工具箱搭建了一维卷积神经网络1D-CNN把原始振动信号2048点直接作为输入网络结构是卷积层16个滤波器核大小3→ ReLU → 池化层 → 卷积层32个滤波器→ ReLU → 池化层 → 全连接层 → Softmax输出层。训练用trainNetwork优化器用Adam初始学习率0.001BatchSize 64最大训练轮数30。训练过程中我遇到的最大问题是过拟合——训练集准确率很快跑到99%但验证集准确率只有88%左右。特征维度高、样本量少每个类别切分后只有几百个样本是过拟合的两个直接原因。我加了dropout层概率0.5情况有所缓解但仍不如SVM好。另一个问题是训练时间CPU训练一轮要十分钟左右如果没GPU就得很有耐心。最终我评估下来在这个数据集上1D-CNN的优势并不明显反而SVM人工特征的组合更稳定。这让我坚定了“先特征后模型”的思路深度学习不是银弹尤其在样本量不够大的工业场景里人工特征的先验知识仍然很有价值。LSTM我也试过用于建模信号中的时序依赖。理论上轴承振动信号是周期性的LSTM应该能捕捉到这种时间结构。但实践效果一般主要原因是我的样本段长度只有2048点LSTM的参数规模相对样本量来说偏大训练不稳定准确率在92%左右波动。如果需要处理连续长时信号、在线流式诊断LSTM才有更大优势短样本场景意义不大。4.3 结果评估与对比模型训练完后评估不能只看准确率。我用了混淆矩阵和逐类别的精确率、召回率、F1分数来分析每一类的错误分布。MATLAB里confusionchart直接画出混淆矩阵直观方便。我的SVM模型在正常状态和外圈故障上的识别几乎没有错误但在内圈故障和滚动体故障之间偶尔混淆。这个现象有物理背景内圈故障和滚动体故障的包络谱特征本身就比较相似都有较强的转频调制成分单纯从频域特征上区分确实困难。后来我加入了时频域特征比如CWT小波系数的能量分布作为额外维度把混淆率降下来了将近一半。评估时还有一个关键点数据集划分必须注意不能泄漏。我踩过一个坑——直接把所有样本随机打乱再划分训练测试集结果性能虚高到99.8%。原因是相邻时间段的样本来自同一段连续信号高度相关随机划分导致“训练集中出现过测试集的信息”。正确做法是按“时间片段”划分保证训练集和测试集来自不同的时间窗口我后来改成前80%时间的样本作为训练集后20%作为测试集性能立刻“正常”地下降到96%左右。这个降幅看似“变差了”但反映的是真实泛化能力。5. 常见问题与排查经验5.1 数据不均衡问题怎么处理真实工业场景中正常状态的样本远多于故障状态的样本可能出现9:1甚至更极端的比例。直接用原始数据训练分类器会“学会”把大部分样本判为正常因为这样整体准确率已经很高但故障样本识别率极低。我在模拟这种场景时试过几种方法最简单的是欠采样随机丢弃正常样本使两类数量均衡但这样浪费了大量数据更推荐的是过采样用SMOTE算法合成少数类样本MATLAB里可以用smote函数实现部分工具箱版本支持在特征空间中对少数类样本插值生成新样本。实际测试中SMOTE后故障类别的召回率提升了20多个百分点整体F1从0.82上升到0.93效果明显。如果数据倾斜极端且原始信号段充足也可以考虑先切分原始信号来扩充少数类再在特征层面做均衡。5.2 采样率不足、信号混叠和滤波器失真的排查采样率不足在早期做实验时常常被忽略。我试过用4kHz采样率去分析一个故障特征频率为160Hz的轴承信号理论上160Hz远低于奈奎斯特频率2kHz应该没问题但实际出来的包络谱乱成一片。排查后发现问题出在轴承座的共振频率可能在6-8kHz远超4kHz采样率的分析范围与低频故障特征频率之间的调制关系上。包络解调需要“高频载波”存在才能解出“低频调制”采样率不足导致高频共振成分被混叠到低频区破坏了包络谱的有效性。解决方法是要么提高采样率要么先做模拟滤波抗混叠滤波再降采样。工业测试中做预分析时我一般先用48kHz采样确认主要能量分布后再决定是否降到12kHz避免一开始就丢失高频信息。5.3 滤波器参数调试经验先画图再定参滤波器设计看似简单实际坑最多。我最初做带通滤波时直接指定2kHz-5kHz没先观察功率谱结果把一段在1.8kHz有明显共振峰的信号给滤“削”了。经验教训任何滤波参数都要基于信号的实际谱特征来决定。具体流程分三步先用pwelch看全频段功率谱标出共振峰位置再根据共振峰宽度确定滤波带宽比如共振峰中心在3.5kHz、宽度约1kHz带通就设3kHz-4kHz最后用fvtool查看滤波器幅频特性确认过渡带衰减达标。此外要检查滤波是否引入了相位失真用filtfilt做零相位滤波后幅值和相位都不会被扭曲这对后续提取冲击波形很重要。5.4 数据切分窗口长度选择的经验法则窗口长度每段信号的采样点数选择直接影响特征提取的稳定性。窗口太短段内可能不包含完整的故障冲击序列峭度等统计量波动大窗口太长段数变少训练样本不足。我的经验法则是每段至少包含10到20个故障特征周期同时确保转频周期的整数倍关系。以转频30Hz、故障频率160Hz为例10个故障周期约0.0625秒对应750个采样点实际取2048个点为好留足冗余同时是2的幂方便FFT计算。另外切分样本后建议做个快速检查随机抽几个样本画时域波形确认冲击特征还在没有在切分时被切断。5.5 MATLAB版本与工具箱兼容性有些读者可能在代码运行中遇到“函数未定义”的问题。我用的部分函数如designfilt、filtfilt、fitcecoc、cwt需要Signal Processing Toolbox、Statistics and Machine Learning Toolbox和Wavelet Toolbox。运行代码前先用ver检查工具箱是否安装完整。不同版本间cwt的调用方式有差异R2021a之前用的是cwt(x, bump, fs)这种语法R2021b之后改为cwt(x, fs)旧脚本可能直接报错。建议在使用前doc cwt查看当前版本的帮助文档。如果工具箱缺失很多信号处理函数用基础MATLAB也能自己写但工程效率会低很多还是建议装好对应工具箱。结语这个项目做完之后的体会是滚动轴承故障诊断的完整链路里真正决定成败的往往不是模型多高级而是每一步是否做扎实预处理时是否确定了正确的带通范围特征提取时是否理解了每种特征的物理含义和局限数据划分时是否避免了泄漏评价时是否看了混淆矩阵而非只看准确率。MATLAB在这条链路上确实提供了非常完整的工具支持但工具终究只是放大“对问题的理解”理解越深工具越能派上用场。如果你刚开始走这条路我建议先用公开数据集跑通全流程再尝试换转速、换故障尺寸、加噪声来测试方法的鲁棒性这个过程获得的感知比任何模型代码都更宝贵。