☰
轴承故障诊断四种方法详解:FFT包络谱、Haar小波与CNN实战
2026/10/16 7:22:49 网站建设 项目流程

简介:这份MATLAB代码包聚焦轴承内外圈故障诊断,面向机械故障诊断初学者与研究人员,可直接用于振动信号分析实验。资源整合四种经典方法:时域无量纲参数分析、FFT频谱分析、Hilbert包络谱分析以及Haar小波分析,通过同一转动频率下不同处理方法的结果对比,以及同一方法在不同转动频率下的表现,清晰展示各方法在故障识别和故障频率提取上的适用差别。代码包共30个文件,包括5个m脚本、11个dat采样数据文件和14张结果图片,压缩包仅约1MB;其中dat文件提供不同转速下的内外圈故障数据,m脚本实现各算法流程,jpg图片直观展示频谱、包络与小波变换结果。资源已有12922人学习下载。借助完整代码与配套数据,读者可轻松复现实验,对比时域指标、FFT、包络谱与小波分析的效果,深入理解从振动信号中提取故障特征频率并判别故障类型的方法。

1. 把四种轴承故障诊断方法一次讲透:从FFT包络谱到Haar小波

做设备状态监测的工程师应该都有过这种经历:现场采集回来的振动信号一长串,打开MATLAB却不知道从哪里下手。直接看时域波形,噪声大得根本看不出冲击特征;用FFT做频谱分析,转频成分又常常把故障特征频率盖得死死的。这是我在某模拟项目X上真实踩过的坑,而这份轴承故障诊断matlab代码(四种方法)就是来填这个坑的。

项目一口气实现了四种不同思路的诊断方法:经典FFT频谱分析、包络谱解调(希尔伯特变换)、Haar小波时频分析、以及基于深度学习网络的自动分类。覆盖了从“人工看谱图找频率”到“数据驱动自动识别故障”的全流程路线,适合刚接触故障诊断的学生、做设备健康管理的工程师,以及所有想把MATLAB信号处理技能落地到实际工况的人。

这套代码的最大价值在于它不是一个黑匣子——每种方法都能独立运行、独立出图,也可以串成一个完整的诊断流程,方便你从原理上搞懂每个步骤在干什么,然后针对自己的数据去改。

2. 核心技术拆解:四种诊断方法的原理与MATLAB实现

2.1 FFT频谱分析法:先看懂转频和故障特征频率

FFT频谱分析是轴承故障诊断的入门第一课。它的核心思路很简单:把时域振动信号变换到频域,找出与轴承各部件故障特征频率对应的谱峰。轴承外圈、内圈、滚动体、保持架各自有理论计算公式,你可以把这些计算值作为“期望频率”标注在频谱图上。

% FFT频谱分析核心代码 fs = 12000; % 采样率,单位Hz N = length(data); % 信号长度 f = (0:N-1) * fs / N; % 频率轴 y = fft(data); % 快速傅里叶变换 amp = abs(y) / N * 2; % 幅值谱,单边谱修正 % 提取主要频率成分(忽略直流分量) [~, idx] = max(amp(2:N/2)); main_freq = f(idx); fprintf('主频成分: %.2f Hz\n', main_freq);

这段代码的逻辑分三步:先通过fft得到复数频谱,再取模并做单边谱的幅值修正(除以N乘以2是因为FFT结果对称,实际幅值要还原到原始信号量级),最后扫描频段找最大峰值。关键参数是采样率fs,它直接决定频率分辨率,分辨率等于fs/N,信号越长频率分辨越精细。大多数公开数据集用12kHz采样率,但工业现场要根据传感器带宽和最高分析频率来定,一般满足fs ≥ 2.56倍的最高分析频率。

FFT方法比较考验经验,因为故障特征频率往往比较微弱,尤其早期故障信号几乎被噪声和转频淹没。所以它更多用于“先粗看”——判断信号里有没有明显异常频率,再决定是否上包络谱。

2.2 包络谱解调:把高频冲击“检波”出来

包络谱是诊断滚动轴承最有用的工具,它的思想是:轴承故障引起的高频冲击会在共振频段激起大幅振动,这个高频振动的“包装”本身包含着故障频率信息。你先把信号带通滤波到共振频段,再做希尔伯特变换求包络,最后对包络信号做FFT,就能在低频段清晰看到故障特征频率。这个过程也叫解调分析。

% 包络谱分析核心代码 % 步骤1:带通滤波,突出共振频段 [b, a] = butter(2, [1500 5000]/(fs/2), 'bandpass'); filtered = filtfilt(b, a, data); % 步骤2:希尔伯特变换求包络 hilbert_env = hilbert(filtered); envelope = abs(hilbert_env); % 步骤3:对包络做FFT得到包络谱 env_fft = fft(envelope); env_amp = abs(env_fft) / N * 2; env_freq = (0:N-1) * fs / N;

这段代码效果好坏的关键在步骤1的带通滤波参数。如果通带选得不准——比如共振频率是4kHz但你的带通选在2kHz以下——包络就会丢失真实冲击特征。我一般会先对原始信号做一次宽频FFT,观察哪个频段能量最高、冲击特征最明显,再根据这个观察设定带通范围。filtfilt是零相位滤波,比filter更合适,因为不会造成包络波形偏移。

步骤2的hilbert是核心,MATLAB的hilbert函数返回的是解析信号,取abs就是包络。这一步相当于做了“检波”,把高频载波去掉、保留低频调制信息。最后包络谱上,故障特征频率和它的倍频会像梳状谱一样出现,这是典型故障的指纹。

2.3 Haar小波分析:多尺度看信号的“变脸”

FFT频谱适合平稳信号,但轴承故障信号是瞬态冲击,频域上并不容易定位冲击发生的时刻。Haar小波是入门最简单的小波基,它通过高低通滤波把信号逐层分解成不同频带,并且保留时间位置信息。这样可以同时看到频率成分和对应的时间段,非常适合观察“哪个时刻发生了冲击”。

% Haar小波三层分解核心代码 [ca3, cd3, cd2, cd1] = wavedec(data, 3, 'haar'); % ca3是第三层近似系数(低频) % cd1是细节系数(高频),cd2、cd3逐层降低频带 figure; subplot(4,1,1); plot(data); title('原始信号'); subplot(4,1,2); plot(cd1); title('Haar小波第1层细节'); subplot(4,1,3); plot(cd2); title('Haar小波第2层细节'); subplot(4,1,4); plot(cd3); title('Haar小波第3层细节');

wavedec是MATLAB自带的小波分解函数,第三个参数‘haar’指定小波基类型。分解层数3是经验值——如果你只需要看高频冲击分量,1到2层就够;如果想分析低频趋势或工频调制,加深到5层也不是问题,但每多一层,时间分辨率就降一半。

Haar小波虽然简单,却特别适合冲击信号特征——因为Haar本身就是阶跃型基函数,和故障冲击波形相近,匹配度高。实际诊断场景中,我常把Haar小波细节系数的峰值位置作为故障冲击的“时间戳”,再对照转速信息来推算是哪一圈出现了异常。

2.4 1D-CNN自动分类:不靠经验,靠数据说话

前面三种方法是特征工程路线,需要人来判断特征频率。1D-CNN(一维卷积神经网络)则完全不同——你直接把原始振动信号切片喂给网络,让卷积层自动学习故障特征并完成分类。这种方法的优点是把“人工找特征”变成了“机器学特征”,而且工业界在实际应用中泛化能力更强。

% 1D-CNN简单示例:基于深度学习工具箱 layers = [ sequenceInputLayer(1) % 输入层: 单通道信号 convolution1dLayer(3, 16, 'Padding', 'same') % 一维卷积 batchNormalizationLayer % 批归一化加速收敛 reluLayer maxPooling1dLayer(2, 'Stride', 2) convolution1dLayer(3, 32, 'Padding', 'same') fullyConnectedLayer(4) % 4种故障类别 softmaxLayer classificationLayer ]; options = trainingOptions('adam', ... 'Plots', 'training-progress', ... 'Verbose', false, ... 'MaxEpochs', 20, ... 'MiniBatchSize', 64); net = trainNetwork(XTrain, YTrain, layers, options);

这个网络的输入是处理成序列格式的振动数据,sequenceInputLayer(1)表示每个时间步输入一个特征维度。网络结构上是经典的小型CNN:两轮“卷积+归一化+ReLU+池化”,卷积核大小是3,相当于每次看3个相邻时间点的局部模式;池化层步长2把序列长度减半,让网络逐层感受更大范围的时域特征。最后是全连接层输出4类——具体类别取决于你的数据标签,比如内圈故障、外圈故障、滚动体故障、正常状态。

训练参数比较关键:adam优化器适合振动信号这种非平稳输入,MaxEpochs设20是防止过拟合,MiniBatchSize 64是按经验取的值。如果你的数据量少——比如每类只有几百个样本——网络容易过拟合,可以把卷积核数量减半,或者在池化层后加一个dropout层。

3. 数据集构造与实验参数:怎么把原始信号变成能跑代码的输入

3.1 信号切片与标签制作

深度学习和大批量信号处理之前,第一步是把长信号切分成短样本。轴承诊断常用做法是每个样本取2048或4096个采样点,对应12kHz采样率下大约0.17到0.34秒。太短会丢失低速轴承的完整旋转周期,太长则样本数量不足。我一般把重叠率控制在50%,这样既扩增数据量又不至于让相邻样本相关度过高。

% 信号切片:按窗口长度和重叠率生成样本集 function [XTrain, YTrain] = makeSlices(data, labels, winLen, overlap) step = floor(winLen * (1 - overlap)); numSlices = floor((length(data) - winLen) / step) + 1; XTrain = zeros(winLen, 1, numSlices); YTrain = categorical(repmat(labels, numSlices, 1)); for i = 1:numSlices startIdx = (i - 1) * step + 1; XTrain(:, :, i) = data(startIdx:startIdx + winLen - 1); end end

这段代码输出的XTrain维度是winLen×1×numSlices的三维数组,正好匹配深度学习工具箱对序列输入的要求——第一维是时间步、第二维是通道数(振动信号单通道)、第三维是样本数。YTrain用categorical类型存储标签,trainNetwork要求标签必须是categorical或one-hot编码形式。overlap值设在0到0.5之间比较合理,太高会导致训练集和验证集样本高度重合,评估结果虚高——这是我吃过亏的地方。

3.2 训练集与验证集的划分

很多第一次跑深度学习诊断代码的人直接把所有样本一股脑喂给trainNetwork,最后准确率看着99%,放到真实数据上一塌糊涂。问题就出在没做验证集划分,或者划分时把同一段长信号切出的相邻样本同时分到了训练和验证里。

% 按样本ID划分,避免相邻样本泄漏 idx_perm = randperm(numSlices); val_ratio = 0.2; val_count = floor(numSlices * val_ratio); val_idx = idx_perm(1:val_count); train_idx = idx_perm(val_count+1:end); XTrain_sets = XTrain(:, :, train_idx); XVal_sets = XTrain(:, :, val_idx);

正确的做法是先打乱样本索引再划分,而且要把同一时刻附近的样本尽量分在同一侧。如果每个样本都来自同一次连续采集,单纯随机洗牌也可能造成数据泄漏,因为相邻样本的波形高度相似。我在实际项目中会先按“采集片段”分组再划分,比如前70%的时间片段做训练、后30%做验证,这样才能模拟真实工况下的泛化场景。

4. 避坑指南:轴承诊断代码运行的五个常见翻车点

4.1 包络谱看不到故障特征频率

现象:明明数据是故障轴承信号,包络谱图上却看不到理论计算的故障特征频率,或者谱线非常微弱。原因是对原始信号没有做带通滤波就求包络,或者带通范围选得不对。轴承故障的冲击能量集中在系统共振频段而不是低频段,直接包络等于把低频工频成分一并包络进去了,特征频率被淹没。解决方法是先用频谱图找共振峰,把带通范围设在共振峰附近2到3kHz的带宽内再做希尔伯特变换。

4.2 幅值谱和包络谱上的频率坐标对不上

现象:用fft后频率轴最大值是对的,但谱峰频率位置和理论值总差一点。原因很可能是频率轴没有做单边处理,FFT结果的前一半和后一半对称,你取max的时候取到了镜像分量,或者频率分辨率F太大导致谱峰落在两条谱线之间。解决方法是频率轴只用前N/2个点,并且在需要精确频率时用谱线内插法细化峰值频率,不要直接用离散谱线频率当真实频率。

4.3 Haar小波分解后信号长度变短

现象:wavedec出来的细节系数长度逐层减半,画图时和原始信号对不齐。原因是小波分解每层会做隔点采样,长度天然减半,这是正常现象。解决方法是画图时不要直接用系数序列长度对应时间轴,而是通过wmaxlev或detcoef返回的层数信息重新构造时间坐标,或者用waverec重构后再画图。

4.4 训练1D-CNN时损失不降

现象:深度学习训练好几轮后准确率还在20%到30%徘徊,损失几乎不变。原因通常是输入数据没有归一化。振动信号的幅值范围从零点几到几十都有可能,不归一化直接进卷积层会让梯度优化很不稳定。解决方法是每个样本按最大绝对值归一化,或者用zscore标准化到均值为0标准差为1。

4.5 测试准确率高但现场效果差

现象:离线验证集上准确率能到98%以上,但用到另一台设备或另一种工况的数据时准确率掉到60%以下。原因是训练数据和测试数据分布不同——转速不同、负载不同、传感器位置不同都会让信号分布发生偏移,模型学到的特征不可迁移。解决方法是训练数据里尽量包含多种转速、多种负载的组合,或者做信号归一化后按转速分组训练多个模型。这是我做模拟项目X时踩得最深的坑,折腾了大半个月才发现是数据分布问题。

5. 完整工作流设计:从原始振动数据到诊断结论

5.1 一套可复用的管线

把四种方法串起来,可以形成一条完整的故障诊断流水线。第一步拿到原始信号先做预处理——去均值、去趋势项、剔除明显野值;第二步并行做FFT快速浏览频谱和Haar小波看时频冲击位置;第三步如果频谱上有可疑频带,做带通滤波加包络谱精确识别特征频率;第四步同时把所有切片样本丢给1D-CNN做自动分类,两者交叉验证。

% 完整诊断管线伪代码 raw = load('bearing_data.mat'); data = detrend(raw.vibration); % 去趋势项 data = data - mean(data); % 去直流 % 路线1:频谱+包络谱人工判读 [amp, freq] = fftSpectrum(data, fs); % 自定义函数 envelopeSpectrum(data, fs, 'bandpass', [1500 5000]); % 自定义函数 % 路线2:数据驱动自动分类 slices = makeSlices(data, 4096, 0.5); % 切样本 pred = classify(net, slices); % 用训练好的网络分类

这个流程非常适合在项目初期做算法验证——传统谱分析可以让你“看得懂”为什么模型给出这样的结论,深度学习给的是量化置信度,两者互相印证。生产环境部署时,通常会把谱分析和深度模型同时跑在边缘计算盒子上,一旦模型判断和谱图判读矛盾,就触发人工复核,避免误判。

5.2 参数调整的优先级顺序

做故障诊断调参的时候,我建议按下面的顺序来。先调数据层面的参数——窗长、重叠率、滤波范围,这些影响的是后续所有分析的输入质量;再调特征提取参数——小波层数、频带选择;最后才去调模型超参数——学习率、卷积核大小、层数。数据层面的问题不解决,后面调参都是白费功夫。

信号本身的健康状况也可以先用简单指标做快速筛查——峰值因子、峭度指标如果明显高于正常水平,说明信号里有冲击成分,值得用包络谱精确定位;如果峭度接近3(高斯分布水平),说明信号基本平稳,故障概率低,到这里就可以收工了,不需要浪费算力跑深度学习。

6. 二次开发指南:把这份代码改造成你自己的诊断工具

6.1 封装成函数库

原始代码如果是脚本式的一次性运行,二次开发的第一步就是把它改造成可复用的函数。比如fftSpectrum(data, fs, freqRange)返回频谱和幅值,envelopeSpectrum(data, fs, method, params)返回包络谱图,trainBearingCNN(dataPath, labels, options)自动完成切片、训练和模型保存。函数化之后的好处是:换一批数据时,你只需要改数据加载部分的代码,诊断算法本身完全不动。

% 二次开发建议的函数接口设计 function [result] = bearingDiag(data, fs, method) switch method case 'fft' result = fftSpectrum(data, fs); case 'envelope' result = envelopeSpectrum(data, fs, 'auto'); case 'haar' result = haarAnalysis(data, 3); case 'cnn' result = cnnClassify(data, net); end end

这样一个统一入口的好处是,业务层不用关心底层是哪种算法。你还可以做成批量处理模式,把一整批传感器通道数据循环送入bearingDiag,自动输出每个通道的诊断结果表。

6.2 做多尺度特征融合

单一方法的稳定性始终有限,比如FFT在变转速工况下基本失效,因为转速变化会让特征频率“打滑”。常见做法是提取Haar小波各层系数的统计量(峭度、均值、峰值)加上包络谱的谱峭度特征,拼成一个多维特征向量,再训练一个简单的随机森林分类器。这样既保留了传统特征工程的可解释性,又让分类器综合各域信息,比单独用谱分析更好用。

我用这个思路改造过一套代码,把FFT幅值谱的前20个主要频率分量的幅值、Haar小波三层的能量比、包络谱的峰值频率和峰值幅值共二十几个特征拼接起来,喂给一个带特征选择的SVM分类器。在模拟项目X的验证数据上,单独用包络谱的准确率在88%左右,融合后到96%以上,而且对变转速工况的鲁棒性提升明显。

6.3 实时滚动窗口诊断

离线分析是一段一段地处理,工业监测需要的是滑动窗口实时判读。做法是把makeSlices函数改成队列模式,每采集到固定长度的新数据就滑动窗口覆盖掉最旧的数据,然后丢给CNN模型做一次预测,输出当前窗口的健康状态。这套逻辑在MATLAB里可以借助dsp系统工具箱或者简单用while循环+tic/toc控制节奏来实现。实际部署时要注意单次预测的耗时必须小于窗口时间步长,否则数据会积压,实时性就变成空话了。

现在回头看这四套代码,最让我觉得方便的是它同时覆盖了经典信号处理和神经网络两种路线,做对比实验的时候不需要在多个工具箱之间来回切换,一套代码通吃。从那以后我做任何诊断类项目,都会按这个套路先跑一遍谱分析摸清数据底细,再决定要不要上深度学习,而不是一上来就无脑trainNetwork。希望这些拆解和踩坑记录能帮你在自己的数据上少走几步弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询