☰
基于Matlab的轴承故障诊断:西储数据从读取到分类全流程
2026/10/19 2:21:39 网站建设 项目流程

干这行久了,有个非常实在的体会:机械设备百分之八十的故障,最后都能在轴承上找到线索。跑着跑着温度上来、异响明显、振动越来越大,十有八九就是轴承出了问题。而做设备状态监测的人,入门第一课基本都是轴承故障诊断,用的也基本都是同一套公开数据——西储轴承数据中心,也就是大家口里的“西储数据”。我的建议是,别一上来就研究各种深度学习算法,先用Matlab把这套经典数据彻底玩明白,把信号处理的基本功打扎实,后面再看机器学习、看深度学习,才会真的有感觉。这篇文章我会从原理开始,带着你一步步把数据读进去、画出波形、算出特征频率、提取特征、最后用分类器把几种故障状态区分开,全过程都有代码和参数说明,属于拿到手就能照着跑的那种。

西储数据之所以能在轴承故障诊断领域火这么多年,一是它的实验条件做得规范,故障类型齐全,二是数据完全公开,任何人下载下来就能在自己电脑上复现,做对比实验也都用同一套基准。我自己当年入门的时候,就是在Matlab里反复琢磨这套数据,才把包络谱、时域特征、频域分析这些概念真正对应到实际信号上,而不是停留在教科书里。这篇文章就是把那套折腾过程整理出来,适合刚接触设备故障诊断的学生、想转行做状态监测的工程师,也适合想快速验证信号处理思路、又懒得自己搭实验台的研究者。全篇文章没有任何需要专业硬件的东西,一台普通电脑加Matlab就够了。

刚开始玩这套数据的时候,我最大的感受就是“信息量太大,无从下手”。正常信号、外圈故障、内圈故障、滚动体故障,光文件名就能看出好几种组合,数据量又不小,怎么选、怎么读、怎么处理,每一步都需要理清楚。这篇博文我就按照自己一路走过来的顺序来讲:先搞清楚轴承为什么能“看出”故障,再把数据正确读进Matlab,接着做时域和频域分析,然后提取特征并分类识别,最后把实操中踩过的坑和排查思路一并列出来。

1. 轴承为什么能“看出”故障:核心原理与频率公式

1.1 滚动轴承的四种典型坏法和它们的“指纹”频率

要诊断轴承故障,首先得知道故障信号长什么样。滚动轴承的故障通常出现在四个部位:外圈、内圈、滚动体、保持架。其中外圈、内圈、滚动体三种故障最容易通过振动信号识别,也是西储数据里重点提供的类型。每种故障在运转时,接触点会周期性遇到损伤位置,产生一个周期性的冲击力,这个冲击力会激起轴承和结构的固有振动,从而在传感器信号里留下一个“指纹”——每隔一定时间出现一次脉冲。

这个“指纹”出现的频率不是随机的,而是由轴承的几何参数和转速决定的,有明确的计算公式。假设滚动体数量为 n,滚动体直径为 d,节圆直径为 D,接触角为 α,转频(轴的旋转频率)为 fr,那么:

  • 外圈故障特征频率 BPFO = n × fr / 2 × (1 - d/D × cosα),损伤点固定,保持架转动时每个滚动体滚过损伤点,这个频率就是外圈故障的基频。
  • 内圈故障特征频率 BPFI = n × fr / 2 × (1 + d/D × cosα),内圈随轴旋转,损伤点跟着转,相对滚动体的通过频率比外圈稍高。
  • 滚动体故障特征频率 BSF = D × fr / (2 × d) × (1 - (d/D × cosα)²),滚动体自转一圈撞击内外圈滚道两次,所以这个频率通常更低一些。
  • 保持架故障频率 FTF = fr / 2 × (1 - d/D × cosα),保持架转动的频率,相对最低,实际诊断中很少单独用。

这几个公式看起来多,其实理解了物理过程就好记了:哪个零件上有伤,哪个零件的运动频率就是故障的节奏。

1.2 西储数据:为什么大家都拿它当标准答案

西储轴承数据中心的实验台,本质上是一台电机带动一根轴,轴上装了测试轴承,电机负载可以通过扭矩控制器调节。测试轴承用了深沟球轴承,型号是电风扇、电机里最常见的那种。实验时用电火花在轴承上人为加工出单点故障,故障直径分成 0.007 英寸、0.014 英寸、0.021 英寸三档,相当于微小、中等、严重三档损伤。传感器分别安装在电机驱动端风扇端和底座上,采样频率有两档:12kHz 和 48kHz。正常数据、外圈故障、内圈故障、滚动体故障都有,负载从 0 到 3HP,对应电机转速从1797 到 1730 转/分左右。

这套数据之所以被广泛接受,根本原因在于它的故障状态和工况覆盖得比较全,而且数据文件按统一的规律命名,用脚本批量处理非常方便。我做对比实验时最喜欢的也是这一点:不需要自己制造故障轴承,不用搭建实验台,下载数据就能直接验证算法。读入后可以按文件名解析出故障类型、故障直径、负载、采样率这些字段,批量建训练集非常顺。

1.3 拿到数据先算一笔账:用铭牌参数估算特征频率

拿到一个轴承,第一件事不是急着读数据,而是先用轴承参数估算故障特征频率,这样后面看频谱的时候才有参照。以西储数据里常用的测试轴承来说,节圆直径约 39.04 毫米,滚动体直径约 7.94 毫米,滚动体数量 9 个,接触角近似 0 度。把这几项放进上面的公式,再取一个典型工况比如负载 2HP 转速 1750 转/分,换算成转频约 29.17Hz,就可以估算:

  • 外圈故障频率 BPFO ≈ 3.048 × 29.17 ≈ 88.9Hz
  • 内圈故障频率 BPFI ≈ 4.952 × 29.17 ≈ 144.4Hz
  • 滚动体故障频率 BSF ≈ 2.064 × 29.17 ≈ 60.2Hz

有了这几个参考值,再看频谱和包络谱的时候,心里就有底了。谱图上如果某个频率附近出现了明显的峰值,就可以初步判断对应哪个故障类型。而且西储数据文件名字里其实带转速信息,文件的描述文本里也有实际转速记录,可以交叉验证你的估算准不准。我个人习惯是每次打开一组数据,都先把特征频率按实际转速重新算一遍,而不是直接用铭牌参数的近似值。

2. 数据上手:读进Matlab,画出来,先看故障长什么样

2.1 数据目录结构与加载代码

西储数据下载下来是一堆 .mat 文件,每个文件就是一个单独工况下的振动信号。文件名的规则大概是“故障位置-故障直径-负载序号”,比如某文件代表驱动端、外圈故障、0.014 英寸故障直径、1HP 负载。还有一类是正常轴承的数据,文件名里直接带 normal 字样。

在 Matlab 里加载这类 .mat 文件非常简单,一行代码就搞定。假设文件放在当前目录的 data 文件夹下,我可以批量读取所有文件名,再把需要的某个文件加载进来,把信号对应的加速度数据取出来,同时记录采样频率。以 12kHz 驱动端数据为例,核心加载代码如下:

% 设置数据路径和文件名(示例,请替换为实际下载的文件名) fileName = 'data/OR_014_1.mat'; dataStruct = load(fileName); % 查看结构体里有哪些字段 fieldNames = fieldnames(dataStruct); disp(fieldNames); % 一般第一个字段就是振动信号,自动取出 signal = dataStruct.(fieldNames{1}); % 设置采样频率(12kHz 文件用 12000,48kHz 文件用 48000) fs = 12000; % 查看信号长度和数据基本信息 fprintf('信号长度: %d 点\n', length(signal));

有一点需要特别注意:.mat 文件里的信号默认是一维数组,但有些版本可能存成列向量,直接索引没问题。我实际批量加载时,会把文件名统一解析成表格,包括故障类型、故障尺寸、负载和对应采样率,然后集中读取到 cell 数组里,避免后续反复 load 造成变量混乱。建议你也在一开始就建立这个习惯——把数据管理和路径都整理好,后面做特征提取时效率会高很多。

2.2 时域波形对比:四种状态的第一印象

数据读进来了,第一件事当然是画图看看。正常轴承信号、外圈故障、内圈故障、滚动体故障,这四种信号放在一起对比,能直观地感受到故障对振动信号形态的影响。正常信号看起来就是比较平稳的随机振动,幅度很小;外圈故障信号会出现明显的周期性冲击脉冲,且脉冲与脉冲之间的间隔比较均匀;内圈故障的冲击强度会随着轴的旋转周期性变化,也就是说冲击幅度有调制现象,因为内圈损伤点转到承载区时冲击大,转到非承载区时冲击小;滚动体故障的冲击信号相对更难识别,脉冲间隔随保持架滑动会有一定波动,冲击幅度也比较均匀。

用 Matlab 画四幅子图堆叠在一起对比,是非常直观的做法。我常用的一段绘图代码如下:

t = (0:length(signal)-1) / fs; figure; plot(t, signal); xlabel('时间 (s)'); ylabel('加速度 (g)'); title('原始振动信号时域波形'); xlim([0 0.2]);

这里只画了其中一个信号,你可以把四个典型状态都画一遍,每个都截取前 0.2 秒来看。0.2 秒听起来很短,但 12kHz 采样率下已经是 2400 个点,足够看清冲击脉冲的形态了。画完图后你会有一个非常深的印象:外圈和内圈故障特征在时域里往往是“看得见”的,而滚动体故障靠肉眼就很难判断,必须往下做频谱和包络谱分析。

2.3 频率响应:FFT看频谱,转频和故障频率对齐

时域波形只是第一层信息,做完 FFT 看频谱,才能把隐藏在振动里的周期成分找出来。对西储数据做 FFT,最大的好处是信号平稳、转速基本恒定,直接算功率谱密度就能看到清晰的谐波峰。我习惯先把信号分成若干段,每段计算功率谱然后平均,这样得到的谱线更平滑,避免单次 FFT 的随机波动过大。

Matlab 里做 FFT 没有太多玄学,关键是设置好频率轴。代码如下:

N = length(signal); Y = fft(signal); f = (0:N-1) * fs / N; amp = abs(Y) * 2 / N; % 单边幅值谱 figure; plot(f(1:N/2), amp(1:N/2)); xlabel('频率 (Hz)'); ylabel('幅值'); xlim([0 1000]); title('FFT幅值谱');

把上一步估算的特征频率和谱图对照,你通常会看到外圈故障信号在 BPFO 及其倍频位置有谱峰,内圈故障除了 BPFI 本身,还会出现转频的边带,滚动体故障则相对隐蔽。实际玩的时候你会发现一个现象:纯 FFT 在很多情况下不如包络谱清晰,原因是故障冲击激起的是高频共振,而故障本身产生的调制频率落在低频段,常规频谱里这些低频成分容易被其他噪声掩盖。所以下一步很自然地就转到包络谱分析,这也是我对新手最推荐花时间仔细理解的一个点。

3. 特征提取:把波形变成能分类的数字

3.1 时域统计量:峭度、峰值因子、均方根的选择

画图看得懂,但诊断总不能每次都靠眼睛看,还是要把信号压缩成几个有物理意义的数字。时域特征是最容易计算的,也对故障比较敏感。常用的指标包括均方根值、峭度、峰值因子、脉冲因子、裕度因子等。均方根值反映振动能量,轴承磨损加剧时一般会增大;峭度对冲击类故障极其敏感,正常信号峭度接近 3,一旦出现显著的周期性冲击,峭度值会明显升高;峰值因子是峰值与均方根的比值,对早期故障也有一定响应,但它对噪声比较敏感,有时候不如峭度稳定。

我建议新手先从这四个指标开始:均方根值、峭度、峰值因子、脉冲因子。它们的计算在 Matlab 里非常直接:

rms_val = sqrt(mean(signal.^2)); peak_val = max(abs(signal)); kurtosis_val = kurtosis(signal); peak_factor = peak_val / rms_val; impulse_factor = peak_val / mean(abs(signal));

有一个细节值得注意:西储数据里的冲击脉冲往往只在很短的瞬间出现,整段信号很长,计算全局指标时这些冲击会被大量正常区段“稀释”。所以实际特征提取时,我习惯先把信号切成若干小段,比如每段 4096 点,逐段计算特征,再把所有段的特征作为样本。这样既增加了样本数量,也保住了冲击型故障的局部特征,后面做机器学习分类也更容易扩展样本。

3.2 包络谱:从冲击响应里把故障频率捞出来

包络谱是轴承故障诊断里最经典也最有效的工具之一。它的思路听起来复杂,实际流程却很清晰:先用带通滤波器把信号中由故障冲击激起的高频共振频带选出来,再对这个滤波后的信号做 Hilbert 变换,得到瞬时幅值(也就是包络),最后对包络做 FFT,得到的谱就是包络谱。在包络谱里,故障特征频率及其倍频会以明显谱峰的形式出现,比直接看原始频谱清楚得多。

Matlab 里实现包络谱,最简单的方式是用自带函数 envelope,不过为了理解原理,我更推荐自己写一遍希尔伯特变换的流程:

% 先对原始信号做带通滤波,选一个故障冲击激起的高频共振带 % 这里以 2000-4000Hz 为例,实际需要根据频谱观察调整 [b, a] = butter(4, [2000 4000] / (fs / 2), 'bandpass'); bandSignal = filtfilt(b, a, signal); % Hilbert 变换求包络 analyticSignal = hilbert(bandSignal); envSignal = abs(analyticSignal); % 对包络做 FFT 得到包络谱 N = length(envSignal); envY = fft(envSignal); envF = (0:N-1) * fs / N; envAmp = abs(envY) * 2 / N; % 只画低频段看故障特征频率 figure; plot(envF(1:N/2), envAmp(1:N/2)); xlabel('频率 (Hz)'); ylabel('包络幅值'); xlim([0 500]);

运行这段代码后,你会看到外圈故障在约 88.9Hz 及其二倍频、三倍频位置有清晰的谱峰,这和你第一步估算的特征频率能对上。带通滤波器的中心频率选择需要一点经验——最直接的办法是观察原始信号的 FFT 幅值谱,找一个能量集中的共振频带。如果选错了频带,包络谱可能会不明显,这也是新手最常碰到的困惑之一,后面我在问题排查部分会再展开说。

3.3 特征矩阵构建:一个脚本批量搞定

一个样本只有四五个特征往往不够稳,实际做分类时,我习惯把时域特征和频域特征组合起来形成一个特征向量。频域特征可以从原始信号的功率谱里提取,比如在几个特征频率附近的谱峰幅值,也可以在包络谱里提取 BPFO、BPFI、BSF、2倍频、3倍频处的峰值。这些特征值加在一起,对不同故障状态的区分度就高很多了。

构建特征矩阵时,推荐用脚本批量处理所有文件,而不是手动一组一组地算。我常用的流程是这样:先做一个小函数,输入一段信号和采样频率,输出一个包含 20 到 30 个特征的行向量,里面包括时域统计量、包络谱特征频率峰值、以及频谱特定频带能量比;然后在外层循环里读取所有文件,把每个文件切段,每段调用这个小函数,把得到的特征向量拼成一个大矩阵;每一行对应一个样本,每一列对应一个特征,同时维护一个标签向量,记录每个样本属于哪一类故障。

这样构建出来的特征矩阵有两个好处。第一,样本量大,而且各段之间有一定独立性,后续训练分类器时不容易过拟合;第二,特征含义明确,你可以随时回过头来看某一个特征在不同故障类型下的分布,方便判断这个特征选得是否合理。我建议你在第一次做的时候,把每个特征按类别画一个箱线图看一下分布情况,这一步会让你对“特征选得好不好”有非常直观的感受。

4. 故障识别:从人工看谱到机器学习分类

4.1 简单阈值判断:为什么够用但不耐用

特征提取出来之后,最简单的诊断方法就是看某个特征值的大小,设一个阈值,超过就报故障。比如正常状态的峭度接近 3,而带外圈故障的峭度明显变大,似乎设一个峭度阈值就能区分开来。但实际一试就会发现问题:特征值是连续变化的,阈值设小了容易误报,设大了会漏报,而且不同负载、不同转速、不同故障尺寸下,同一特征的变化范围可能差异很大,你要针对每个工况单独调阈值,维护成本非常高。

拿西储数据来说,0.007 英寸的早期故障特征幅度明显低于 0.021 英寸的严重故障,如果你按后者的标准设阈值,前者几乎全被漏掉。这就是阈值判断“够用但不耐用”的原因。不过我不建议跳过这一步,因为阈值判断能帮你理解特征分布,后面做更复杂的分类器时,你会知道哪些特征在什么区间内是真正有区分能力的。

4.2 特征集设计:截断、归一化、标签

进入机器学习之前,需要把原始特征矩阵做一点预处理。首先是截断——我一般每段信号取 4096 点,如果信号长度不够就丢弃这个样本,保证所有样本长度一致;然后是归一化——不同特征的量纲差很多,比如均方根值可能是 0.1 到 1 之间的数,而峰值因子可能是 3 到 10,如果不归一化,距离类分类器会把量纲大的特征权重看得过高,反而影响效果。归一化方式我通常选 z-score,把每个特征减去均值再除以标准差,让所有特征统一到同一尺度下。这样的处理在 Matlab 里一行代码就行:

featureMatrix = zscore(featureMatrix);

标签向量的构建是另一件需要仔细确认的事。西储数据文件名里有故障位置和故障直径信息,你可以设定三分类的标签:外圈故障、内圈故障、滚动体故障和正常状态一起构成四类也行。我一般把正常状态也作为一类加入,这样分类器能识别出“无故障”,更接近实际工况。做一个包含四个类别的分类任务,比只做三种故障分类更能反映识别模型的真实水平。

4.3 用KNN/决策树做三分类:代码与评估

特征矩阵和标签准备好了,剩下的就是训练分类器。西储数据的特征在大多数情况下线性可分性已经相当好了,用简单的分类器就能拿到非常高的准确率。我常用的做法是先用决策树或 K 近邻验证效果,再去试支持向量机。这不仅是因为简单,更是因为这类模型的解释性强,能帮助我发现特征设计上可能存在的问题。

在 Matlab 里,KNN 分类器基本就是一个函数调用:

% trainLabels: N×1 分类标签(cell或字符串数组) % featureMatrix: N×M 特征矩阵 % 先划分训练集和测试集,这里用随机划分70%训练、30%测试 rng(42); cv = cvpartition(length(trainLabels), 'HoldOut', 0.3); trainIdx = cv.training; testIdx = cv.test; % 训练KNN分类器 knnModel = fitcknn(featureMatrix(trainIdx,:), trainLabels(trainIdx), 'NumNeighbors', 5); % 预测并计算准确率 predLabels = predict(knnModel, featureMatrix(testIdx,:)); accuracy = sum(predLabels == testLabels(testIdx)) / length(testLabels(testIdx)) * 100; fprintf('测试集准确率: %.2f%%\n', accuracy);

跑出来的准确率,如果是同一种负载下训练的,通常可以达到百分之九十几。但我强烈建议你做一个更有挑战性的实验:用 0HP 负载下的数据训练,用 1HP 或 2HP 负载下的数据测试。做过之后你就会发现,准确率会有明显下降,这一下就暴露了模型泛化能力的短板。这一步体验非常关键,它能帮你理解为什么实验室里 99% 的准确率到了现场却不好用的根本原因。

4.4 模型效果与常见“虚高”现象

很多入门者在西储数据上轻松拿到 99% 甚至 100% 准确率之后就高兴得有点过头了,但实际上这里面的准确率是有“水分”的。第一个水分来源于同段数据切割——如果你把同一段长信号的前半段用来训练、后半段用来测试,这两段信号高度相关,模型相当于开卷考试,准确率自然虚高。第二个水分来源于工况泄漏——如果你把某个负载下多种故障的数据全部混合进来随机划分训练集和测试集,分类器可能已经记住了负载工况的差异,而不是真正识别出故障特征。要想让结果更有说服力,就应该让训练集和测试集来自不同时间段的采集数据,或者直接按负载来划分数据,这样的测试结果更贴近实际系统的部署条件。

我自己现在做算法验证时的固定动作是:如果文章里要报准确率,一定标注清楚数据是怎样划分的,训练集包含哪些工况,测试集包含哪些工况,绝不笼统地写“准确率 99%”。这一点我希望刚入门的朋友也能尽早注意到,不然很容易被自己的结果误导。

5. 实战踩坑记录与排查思路

5.1 频率分辨率不够:信号长度决定你的“眼力”

做包络谱或 FFT 时,频率分辨率等于采样频率除以信号点数。如果信号取得太短,比如只有 1024 点,12kHz 采样率下频率分辨率大约是 11.7Hz,而外圈故障特征频率和旁边某个频率的间隔可能还不到几赫兹,谱峰会被摊平,你根本分不出来。这就是典型的频率分辨率不够问题。

解决思路有两个方向:一是取更长的信号段,比如 8192 点或 16384 点,分辨率就能达到 1.5Hz 甚至 0.7Hz,特征频率足够清晰地显现;二是如果原始数据不支持更长的窗,就只能用零填充来让谱线更密,但要注意零填充并不能真正提升分辨率,只是让谱线之间更平滑,更容易观察峰值位置。实际工程中,我推荐先用 4096 点做一个快速检查,发现峰值不清晰再考虑加长窗。西储数据本身信号很长,用 16384 点完全没有压力。

5.2 训练与测试数据泄漏:同段信号切分的假高分

数据泄漏是特征分类里最隐蔽也最容易被忽视的问题。当我把一段长信号切成若干重叠的小段时,相邻段之间的相关性很高。如果把同一段信号里产生的样本同时分到训练集和测试集,分类器实际已经见过这些数据的“亲戚”,测试准确率自然偏高。这个坑我在初学时就踩过,当时测试集准确率达到 99.7%,我还以为模型做得很好,后来换了完全不重叠的数据段做测试,准确率一下子掉到 85% 左右,才意识到问题的严重性。现在我做实验,都会明确控制样本的独立性——要么按时间段划分数据,要么训练和测试用不同实验批次的信号,并且保证任何一段都不重叠。这一点对于后续发论文、做实际部署都很重要。

5.3 西储数据的“理想化”局限:真实现场怎么办

西储数据再好,也掩盖不了它的理想化特点:实验转速恒定、负载稳定、故障是人为加工出来的单点故障、信噪比很高。真实工况里,转速可能随时波动,负载剧烈变化,故障可能是早期微弱裂纹,背景噪声大得惊人,甚至还有来自齿轮、皮带等其他部件的干扰。所以你在西储数据上训练好的模型,直接拿到现场往往表现不佳。

这不代表西储数据没有价值,它的价值是用来验证算法思路是否正确、特征提取是否有效、分类流程是否跑得通。真正要落地到实际设备上,还是要采集自己设备的运行数据,或者在公开的、贴近现场工况的其他数据集上做迁移验证。我的习惯是先把西储数据作为算法开发的“练功房”,把整套流程打磨稳定后,再用现场数据来校准和调整参数。

5.4 参数速查表

为了方便实操,我把常用参数和对应建议整理成一张表,供你直接对照参考:

参数或设置项推荐值说明
采样频率12000 Hz西储数据 12kHz 文件通用,48kHz 文件用于分析更高频成分
每段信号长度4096 或 8192 点兼顾分辨率和样本数量,故障特征明显
带通滤波器2000-4000 Hz需根据信号频谱共振带调整,观察频谱峰值区域
特征向量维度20-30 维太少区分度不足,太多容易引入噪声
训练/测试比例7:3简单快速验证时常用,但要注意避免数据泄漏
分类器KNN 或决策树优先解释性强,调参少,适合验证特征有效性

这张表不是固定标准,而是我反复实验后的经验取值。你在实际跑的时候,完全可以根据自己的观察调整,比如把带通范围改到 3000-6000Hz,或者把信号段长度改成 16384 点,效果可能有差异,但整体流程是通用的。

写到这里,基本把这套“Matlab 玩转西储数据”的完整链路讲完了。我自己在实际操作中的体会是,做轴承故障诊断并不在于会用多少花哨的算法,而在于把信号处理的每个环节都吃透:从时域到频域,从谱分析到特征提取,从分类到泛化评估,每一步都有对应的物理意义和工程陷阱。如果你刚开始接触这套数据,建议别急着跑深度学习大模型,先用文中的代码把一幅幅图画出来、把一个一个特征亲手算一遍,遇到谱峰对不上的情况再回头查公式和参数,这个过程本身价值非常大。等你把这一套流程跑通了,后面再去接触更复杂的自适应滤波、深度神经网络,你会发现那些高大上的方法,本质上也是在解决我今天讲的这些问题:怎样把故障信息从振动信号里更干净地提取出来。

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

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

立即咨询