☰
基于SVM的齿轮箱轴承故障诊断:从振动信号特征提取到MATLAB实现
2026/9/25 15:16:05 网站建设 项目流程

简介:这是一份基于支持向量机(SVM)的齿轮箱轴承故障诊断文档,面向机械设备状态监测、故障诊断方向的研究人员、工程师及相关专业学生。文档内容扎实,先概述轴承在旋转设备中的重要性,再系统分析滑动轴承的磨粒磨损、刮伤、咬合、疲劳剥蚀、腐蚀等失效形式,继而介绍轴承故障诊断的发展趋势与智能诊断思路,并重点讲解SVM的统计学习原理、结构风险最小化思想和在故障分类中的应用价值。同时,文档给出诊断流程与MATLAB程序,覆盖振动信号数据采集、预处理、特征提取、模型训练和故障识别等关键环节,便于读者理解并复现基于SVM的故障诊断方案。资源包为1个docx文件,大小仅196KB,轻量易读;截至目前已有1944人学习下载,适合课程设计、毕业设计或工程入门人员参考。

1. 基于SVM的齿轮箱轴承故障诊断:先让振动信号变成一张能训练的表格

轴承故障早期,冲击成分往往埋在噪声里,频谱上的边带肉眼很难分辨。与其靠经验盯包络谱,不如把问题交给分类器——基于SVM的齿轮箱轴承故障诊断,本质上就是把振动信号分到“正常、内圈、外圈、滚动体”这几个类别里。SVM在小样本、二维表格数据上的稳定性,恰好对得上故障诊断的真实场景:故障样本难得、标注成本高、数据量通常只有几百组。这个方向常见的交付物,就是一份包含MATLAB程序和说明的文档,核心流程是:先从振动信号里提取特征,再训练SVM分类器,最后用混淆矩阵验证效果。适合正在做设备状态监测的人、拿这类题目做毕业设计的学生,以及想从深度学习回归到经典机器学习里找可靠方案的一线工程师。

2. 从振动信号到特征矩阵:时域、频域与标签的组织方式

很多第一次接触SVM故障诊断的人会问:为什么不能把原始波形直接丢给分类器?从原理上讲,SVM输入的是一个二维矩阵,行是样本、列是特征。原始振动序列虽然也能被当成一行特征,但一段8192点的信号就意味着8192维,RBF核的核矩阵是样本数的平方量级,算不动是小事,更麻烦的是“维度灾难”——样本只有几百组,特征却有几千维,SVM几乎必然过拟合。特征提取的作用是把一段信号压缩成十几个有物理意义的指标,同时完成降维和去噪。这一章解决的就是诊断流程的第一步:怎么把原始波形整理成SVM能直接吃进去的表格。

2.1 为什么不能把原始波形直接丢给SVM

从数学上看,SVM在一个特征空间里切超平面,样本维度越高,超平面越容易“钻空子”把训练集分对,但换一组数据就翻车。轴承振动信号里还藏着相位问题:同一类故障在不同转速下,波形起始相位完全不一样,按逐点欧氏距离去度量,两个同类样本之间的距离可能比不同类的还要大。特征提取把波形压缩成均值、峭度、重心频率这类统计量之后,相位信息被丢掉,留下来的才是和故障类型真正相关的信息。

另外还有一个工程原因:原始波形的存储和读取成本高。现场采集的数据动辄几十MB,而特征矩阵只有几百KB,无论做交叉验证还是后续部署,特征表格都用起来更顺手。这个阶段做扎实了,后面SVM训练只是几分钟的事。

2.2 时域特征:峭度、峰值因子这类冲击敏感指标怎么算

轴承故障在时域上最典型的表现是周期性冲击,时域特征里最能抓住这一点的是峭度和峰值因子。峭度是四阶中心矩除以方差平方,正常振动信号近似高斯分布,峭度接近3;出现早期剥落时冲击成分让峭度明显升高。峰值因子是峰值除以均方根值,对单次大幅值冲击更敏感。下面是提取一组时域特征的MATLAB函数:

function fea = extract_features(x, fs) % x: 单段振动信号,行向量 % fs: 采样率,用于频域特征计算 % fea: 1x12 的特征向量 N = length(x); M = mean(x); % 均值,反映信号直流分量 S = std(x); % 标准差,能量波动程度 RMS = sqrt(mean(x.^2)); % 均方根值,振动能量总体水平 Peak = max(abs(x)); % 峰值,冲击幅值 % 峭度:四阶中心矩 / 方差^2,早期故障冲击越强峭度越高 Kurt = mean((x - M).^4) / (S^4 + eps); % 偏度:三阶中心矩 / 方差^1.5,反映波形不对称性 Skew = mean((x - M).^3) / (S^3 + eps); AR = mean(abs(x)); % 平均绝对值,作为稳定分母 CF = Peak / (RMS + eps); % 峰值因子,冲击类故障的经典指标 SF = RMS / (AR + eps); % 波形因子 IF = Peak / (AR + eps); % 脉冲因子 CIF = Peak / (mean(sqrt(abs(x))) + eps)^2; % 裕度因子 % 频域特征,见下一小节 Xf = fft(x); A = abs(Xf(1:floor(N/2))); f = (0:floor(N/2)-1) * fs / N; FC = sum(f .* A) / (sum(A) + eps); % 重心频率 RMSF = sqrt(sum((f.^2) .* A) / (sum(A) + eps)); % 均方频率 VF = sum(((f - FC).^2) .* A) / (sum(A) + eps); % 频率方差 fea = [M, S, RMS, Peak, Kurt, Skew, CF, SF, IF, CIF, FC, RMSF, VF]; end

这段代码里有几个地方值得说明。计算波形因子和脉冲因子时,如果直接用mean(x)做分母,遇到直流分量为零的振动信号(绝大多数情况都是零)会产生无穷大或极不稳定的数值,所以这里用平均绝对值AR替代。每个除法后面都加了eps,防止除以零。峭度公式里的S^4在MATLAB里可能超出数值范围,如果遇到警告,可以先对x做归一化再用。

2.3 频域特征:重心频率与频率方差

时域特征只看幅值随时间的变化,看不出能量集中在哪个频段。轴承内圈故障的特征频率和转频、啮合频率往往不同,频域特征能把这些差异表达出来。对每段信号做FFT取单边幅值谱,然后计算三个统计量:重心频率表示频谱能量集中的位置,均方频率反映频带分布范围,频率方差衡量能量在重心附近的离散程度。这三个量在齿轮箱不同故障状态下区分度比较明显,代码已在上面函数中一并实现。

如果发现时域加频域特征仍然无法区分某些类别,比如滚动体故障和正常状态在频谱上几乎重合,常见做法是按频带拆开看能量分布。MATLAB里用小波包分解很方便:

wpt = wpdec(x, 3, 'db4'); % 3层小波包分解,db4小波 E = wenergy(wpt); % 各节点能量百分比

把小波包各频带能量百分比追加到特征向量后面,相当于把频域特征细分到子带。这个做法能有效提升滚动体故障的分类效果,代价是特征维度增加,需要相应增加样本量或做特征筛选。

2.4 批量生成特征矩阵与标签表

单个样本的特征提取写好之后,要把整个数据集批量跑一遍,组织成标准的特征矩阵。假设原始数据按故障类型分目录存放,每个目录下是若干段振动信号的mat文件:

% 数据目录结构: ./data/1_normal, ./data/2_inner, ./data/3_outer, ./data/4_ball dirs = {'1_normal', '2_inner', '3_outer', '4_ball'}; labels = [1 2 3 4]; % 标签用数字编码 fs = 12800; % 采样率,按实际数据修改 X = []; % 特征矩阵 Y = []; % 标签向量 for k = 1:length(dirs) files = dir(fullfile('data', dirs{k}, '*.mat')); for i = 1:length(files) d = load(fullfile(files(i).folder, files(i).name)); x = d.signal; % 每段信号, 注意字段名要对应 fea = extract_features(x, fs); X = [X; fea]; % 行拼接 Y = [Y; labels(k)]; end end save('feature_matrix.mat', 'X', 'Y');

注意:每类样本量最好不少于30段,总量在100组以上,SVM的交叉验证结果才有意义。故障样本少,就通过重叠滑窗把长信号切成分段样本,段长度取转频周期的整数倍左右。

标签和故障状态的对应关系建议单独存一份说明,避免后续弄混。常见编码是1正常、2内圈、3外圈、4滚动体,这个映射关系在训练和评估阶段要始终保持一致。

3. SVM核函数与关键参数在MATLAB里的设置:C、KernelScale、多分类策略

特征矩阵准备好之后,下一步是在MATLAB里训练SVM。这一章先把SVM最影响诊断结果的三个设置讲清楚:惩罚系数C、核函数及KernelScale、多分类策略。很多教程直接给一句“用fitcecoc就行”,但参数为什么这么设、改了会怎样,才是实际调试时最花时间的部分。

3.1 硬间隔、软间隔和BoxConstraint的关系

SVM的目标是在两类样本之间找一个超平面,并且让间隔最大化。硬间隔要求所有训练样本都被正确分类且落在间隔边界之外,这在轴承振动数据上几乎做不到——信号里有噪声、冲击干扰,总有一个两个样本跑到对面阵营里。硬间隔SVM会把这种个别异常点当成支持向量,决策边界被带跑,训练集准确率看着不低,推广却很差。

软间隔SVM允许部分样本出现在间隔内部甚至被错分,用一个松弛变量度量违反程度,并用C参数控制惩罚力度。C越大,模型越不愿意放过训练集里的错误,边界越复杂;C越小,允许更多错分,边界越平滑,但可能欠拟合。MATLAB里C对应templateSVM的BoxConstraint参数,默认值是1。轴承故障诊断的经验范围通常是0.01到100,先按数量级网格搜索,再在最优值附近细化。

推导上不需要自己实现梯度下降,MATLAB底层用SMO算法求解对偶问题,KKT条件决定哪些样本成为支持向量。但C的数量级直接影响支持向量的数量:C过大时支持向量很多,边界曲折;C过小时支持向量很少,边界过于宽松。理解这个关系,比背公式更能指导调参。

3.2 核函数选型:RBF的KernelScale参数到底在调什么

线性核只能切线性边界,单一稳定工况下偶尔够用,但轴承故障数据在特征空间里往往是非线性分布的。多项式核需要调阶数,阶数高一点数值就溢出,工程上很少用它。默认且稳妥的选择是RBF高斯核,它把样本映射到无穷维特征空间,同时真正参与计算的只是样本间的距离。

RBF核的宽度参数在MATLAB里叫KernelScale,这个名字容易让人误解。它的含义是:当两个样本的距离达到KernelScale量级时,核函数值衰减到接近0。KernelScale越小,距离稍远一点的样本就被判定为“不像”,边界越曲折,容易过拟合;KernelScale越大,远近样本都能互相影响,边界越平滑,可能欠拟合。它和很多资料里的gamma参数的关系是:

gamma = 1 / (2 * KernelScale^2);

也就是说,热搜里常见的硬间隔SVM、梯度下降、KKT这些关键词,真正落实到MATLAB调参时,你只需要记住两个旋钮:BoxConstraint和KernelScale。第一版可以KernelScale取1,跑完交叉验证再看是增还是减。

3.3 多分类与fitcecoc的默认策略

fitcsvm原生只做二分类,齿轮箱轴承诊断有四种状态,需要用fitcecoc做多分类封装。它的原理是把多分类拆成多个二分类器,默认策略是one-vs-one,也就是任意两类之间训练一个SVM,四类问题一共训练六个分类器,最终通过投票决定类别。相比one-vs-all,one-vs-one在类别较为均衡时边界更精细,对故障诊断这种每类样本量差不多的场景更合适。

在用fitcecoc时,要把templateSVM作为'Learners'传进去,这样BoxConstraint和KernelScale才会生效。如果不传,默认用的是线性核,你再怎么调KernelScale都不起作用,这是常见的隐形坑。

3.4 网格搜索找最优C和KernelScale

手调参数靠感觉,网格搜索才是可复现的做法。先粗后细:第一轮给C和KernelScale各取四五个值,用5折交叉验证选出最优组合,第二轮在最优值附近细化。MATLAB代码如下:

rng(42); % 固定随机种子,保证结果可复现 C_list = [0.1 1 10 100]; KS_list = [0.5 1 2 4]; acc_best = 0; for C = C_list for ks = KS_list t = templateSVM('KernelFunction', 'rbf', ... 'BoxConstraint', C, 'KernelScale', ks); mdl = fitcecoc(Xtr, Ytr, 'Learners', t, 'KFold', 5); acc = 1 - kfoldLoss(mdl); fprintf('C=%.1f KernelScale=%.1f acc=%.4f\n', C, ks, acc); if acc > acc_best acc_best = acc; C_best = C; ks_best = ks; end end end fprintf('最优: C=%.1f KernelScale=%.1f acc=%.4f\n', ... C_best, ks_best, acc_best);

这里用的是kfoldLoss,它返回的是分类误差,所以用1减去得到准确率。注意变量命名,Xtr和Ytr是已经归一化过的训练集,不是原始特征,这个细节在下一章展开。网格搜索跑完后,最优C和KernelScale要保存下来,后面训练最终模型和部署都要用同一组参数。

4. 跑通最小诊断流程:训练、验证、混淆矩阵的MATLAB实现

工具与参数都准备好后,可以跑一个完整的诊断流程。这一章把从数据划分到模型保存的每一步都写成可执行代码,顺序就是正确顺序,尽量不要跳步。

4.1 数据划分:用cvpartition做分层HoldOut

训练SVM之前先划分数据集。常见比例是训练集70%、测试集30%,但直接用randperm随机切会有一个问题:某类故障样本本来就不多,随机切完测试集里可能只剩下两三个该类样本,混淆矩阵没法看。cvpartition在传入标签向量时会自动按标签比例分层,每一类在训练集和测试集中的占比大致相同。

load('feature_matrix.mat'); % 包含 X 和 Y rng(42); cv = cvpartition(Y, 'HoldOut', 0.3); Xtr = X(cv.training, :); Ytr = Y(cv.training); Xte = X(cv.test, :); Yte = Y(cv.test); fprintf('训练样本: %d, 测试样本: %d\n', ... sum(cv.training), sum(cv.test));

逻辑说明:cvpartition返回的对象用training和test两个索引向量区分训练集与测试集。HoldOut指定保留30%作为测试集,剩下的70%训练。这里固定rng(42)是为了让每次运行划分结果一致,否则每次跑出来的准确率都不一样,自己都说不清模型到底好不好。

4.2 归一化必须在划分之后做

这是整个流程里最容易出错也最影响结果的一步。很多人先对整个特征矩阵做zscore,再划分训练测试集,看起来无伤大雅,实际上已经造成测试集信息泄漏:归一化时用到了测试集的均值和标准差,相当于测试集的部分统计信息提前进了模型。正确做法是只计算训练集的统计量,然后用它变换测试集。

[Ztr, mu, sigma] = zscore(Xtr); % 防呆处理:常数值特征的标准差为0,会导致测试集出现NaN sigma(sigma == 0) = 1; Zte = (Xte - mu) ./ sigma;

参数说明:zscore的第一个输出是归一化后的训练集,第二、第三个输出分别是均值和标准差。测试集变换时不能用zscore直接做,而是手动减训练集均值、除训练集标准差。这一步做错,测试集准确率大概率虚高2%到5%,做跨工况验证时更明显。这是故障诊断里必须守住的边界。

4.3 训练、预测与混淆矩阵

用上一章网格搜索得到的最优参数训练最终模型,在测试集上预测并画混淆矩阵:

t = templateSVM('KernelFunction', 'rbf', ... 'BoxConstraint', C_best, 'KernelScale', ks_best); mdl = fitcecoc(Ztr, Ytr, 'Learners', t); Ypred = predict(mdl, Zte); acc = mean(Ypred == Yte); fprintf('SVM测试集准确率: %.2f%%\n', acc * 100); figure; confusionchart(Yte, Ypred);

代码里的C_best和ks_best就是3.4节网格搜索输出的值,这里直接复用。fitcecoc在训练阶段会自动生成六个二分类器,预测时每个样本让六个分类器投票,票数最多的类别作为输出。confusionchart直接用真实标签和预测标签绘图,矩阵对角线上是正确分类的数量,非对角线上的块越密集,说明哪两类最容易被混淆。老版本MATLAB没有这个函数,可以用confusionmat自己画热力图,效果一样。

4.4 保存模型:把训练结果沉淀成可复用文件

诊断模型不能每次重新训练,训练完成后要保存成文件,现场只需要加载模型和新数据的特征就能预测。MATLAB推荐的做法是:

saveCompactModel(mdl, 'bearing_svm_model.mat'); % 部署时加载模型,对新的特征向量预测 new_mdl = loadCompactModel('bearing_svm_model.mat'); Ynew = predict(new_mdl, Zte(1, :));

saveCompactModel会去掉训练数据,只保留模型结构和支持向量,文件体积比直接save小不少。部署时注意两件事:一是必须带上特征提取函数,新数据要先走extract_features再进模型;二是归一化的mu和sigma也要保存下来,预测前对特征做同样的变换。这些零散文件建议统一放在一个目录下,路径用相对路径,换机器也能跑。

5. 避坑与排查:SVM故障诊断中常见的5个翻车点

SVM本身是一个成熟算法,故障诊断项目翻车往往不在算法,而在数据准备和流程顺序。这里列五个我见过频率最高的坑,每条按现象、原因、解决顺序写清楚,对照检查能省下大量调试时间。

5.1 训练集95%,测试集60%:归一化顺序错了

现象:训练集交叉验证准确率很高,测试集突然掉20个百分点,而且每次重新划分结果波动很大。 原因:先对整个特征矩阵归一化,再划分训练测试集。测试集的均值和标准差被混进了训练过程,模型在测试集上“作弊”了,但泛化能力没有真实提升。 解决:把归一化移到划分之后,只用训练集的mu和sigma变换测试集。同时检查代码里的zscore是不是写在了cvpartition前面。这个坑在网上一搜一大片,中招的人几乎都是同样的顺序问题。

5.2 滚动体故障总被分到“正常”:样本长度不够

现象:混淆矩阵里其他三类都挺好,唯独滚动体故障大量被预测成正常。 原因:滚动体故障特征频率不是转频的整数倍,故障点接触时间短,冲击能量在时域上比较稀散。如果一段信号只覆盖一两个旋转周期,滚动体故障的冲击特征根本统计不出来。 解决:把样本长度加长到覆盖5到10个旋转周期,或者用重叠滑窗切样本。切完后检查一下每类样本的峭度均值,滚动体故障样本的峭度通常应该比正常类高出一截,如果差距不明显,再加小波包频带能量特征试试。

5.3 拿到docx里的MATLAB程序,中文注释全是乱码

现象:复制docx里的代码到MATLAB编辑器,中文注释变成乱码,直接运行报错。 原因:docx里嵌入的代码通常是GBK编码,MATLAB新版本默认UTF-8,读取时解码不一致。 解决:在MATLAB编辑器里用“另存为”把编码改成UTF-8,或者干脆把中文注释删掉只保留英文和代码。如果程序本身是用中文注释写的,先在一个文本编辑软件里转成UTF-8再复制。这个问题的触发频率很高,和MATLAB版本无关,纯编码事件。

5.4 SVM训练极慢:把原始波形当成特征了

现象:fitcecoc训练几分钟跑不完,或者直接内存溢出。 原因:输入矩阵不是特征表而是原始波形矩阵,比如X的维度是240×8192。RBF核需要计算样本间的核矩阵,复杂度接近样本数的平方再乘特征维度,特征维度上万时计算量爆炸。 解决:回到第2章,先把波形压缩成十几个特征。如果确实想保留波形部分信息,先用PCA或自编码器降维到50维以内,再进SVM。特征维度超过样本量时,优先考虑线性核,或者先做特征筛选。

5.5 换个转速就失效:工况变了

现象:训练集和测试集来自同一转速时准确率95%,换一批不同负载或转速的数据,准确率跌到70%以下。 原因:时域特征里的幅值、均方根值对转速和负载敏感,模型学到的是“这个转速下的正常状态长什么样”,而不是“轴承坏没坏”。 解决:训练时把不同转速、不同负载的数据混进训练集,让SVM见过尽量宽的工况变化。频率类特征尽量除以转频做归一化,把绝对频率变成相对阶次。这属于故障诊断里的跨工况泛化问题,SVM本身不会自动解决,要在数据组织阶段提前考虑。

6. 进阶用法:用预测分数做置信度筛选,让模型敢说“不知道”

6.1 用分数gap把不确定样本筛出来

分类准确率看着不错,并不代表模型在现场可靠。实际部署时,总有一些样本落在类别边界附近,强行给它贴一个标签,还不如直接标记为“待人工复核”。predict函数在输出标签的同时,还会返回每个样本对每个类别的分数,利用这个分数可以做置信度筛选。

[Ypred, score] = predict(mdl, Zte); % score: 样本数×类别数矩阵, 每行是该样本属于各类的得分 [score_sorted, idx_sorted] = sort(score, 2, 'descend'); gap = score_sorted(:, 1) - score_sorted(:, 2); % gap 是最高分与次高分的差距, 越大说明模型越确定 threshold = 0.1; suspicious = gap < threshold; Ypred(suspicious) = 0; % 0 表示待人工复核

这里的score是多分类器对每个类别的投票得分汇总,数值范围大致在-1到1之间。gap越大说明最高分和次高分拉开明显距离,模型对这个样本的归属比较笃定;gap很小说明两个类别得分接近,模型本质上是“掷硬币”。阈值0.1只是一个起点,我一般会先画出gap的直方图,选一个能把边界样本明显分离的拐点,再微调。

6.2 模型落地的小习惯

把训练好的模型和mu、sigma、特征提取函数打包到一起,保存成统一的版本目录。新来一段信号,先算特征,再归一化,再预测,然后看分数gap决定是否置信。我第一次上线时只盯着准确率,结果现场一条没见过的冲击干扰直接让模型把正常样本判成故障,误报了一整晚。后来我养成了一个习惯:凡是gap低于阈值的样本,不管预测成哪一类,一律标记为“待校验”,不直接进报警逻辑。这样虽然偶尔要多看几张波形图,但再也没有出现过让现场提心吊胆的误报。希望帮到你。

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

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

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

立即咨询