小样本轴承故障诊断:STFT-SVM与MATLAB GUI实现 📅 发布时间:2026/9/18 3:01:38 👁 浏览次数: 简介面向具备一定MATLAB基础、从事信号处理、故障诊断或智能运维的工程师与科研人员这份文档围绕短时傅里叶变换与支持向量机结合的故障诊断分类项目展开解决非平稳振动信号下的特征提取与多类别故障识别问题。压缩包内仅含1个docx文档约120KB集中呈现完整MATLAB程序、GUI设计、参数配置说明与代码详解便于运行和修改。目前已有132人学习下载适合工作1—3年、希望打通时频分析与机器学习落地流程的技术人员。内容按项目背景、模型架构、代码示例与工程部署组织涵盖数据准备、STFT时频分析与能量特征构造、样本标签制作、训练测试集划分、SVM训练与交叉验证、类别预测及混淆矩阵展示并展示单样本时频图与分类结果联动界面。读者可据此复现可扩展的故障诊断原型理解STFT参数、SVM调参策略及GUI回调逻辑并为旋转机械、电力系统、轨道交通等场景的预测性维护提供验证平台。1. STFT-SVM 故障诊断小样本轴承数据为什么比端到端深度学习更稳一台 15 kW 电机试验台加速度传感器贴着驱动端轴承采样率 12 kHz正常、内圈、外圈、滚动体四种状态各采 30 段一共 120 条样本——这是很多人做轴承故障诊断时真正能拿到的数据量。拿这点数据去训一阶 CNN训练集准确率能冲到 99%换个转速就掉到 60% 出头。STFT-SVM 这条路子反着来先用短时傅里叶变换把一维振动信号摊成时频图把冲击、调制、共振带这些物理上说得清的东西显式提出来再用支持向量机在小样本上找最大间隔超平面。它不需要几万条样本超参只有核宽和惩罚系数两个旋钮交叉验证几分钟出结果模型权重还能落到工程报告里。后面四章按信号处理、分类器、GUI、排错四段推进代码可以直接抄进 MATLAB 跑。2. STFT 特征提取把振动信号变成 SVM 能吃的向量STFT 的核心假设是「信号在短窗内近似平稳」。轴承故障的冲击重复频率通常在几十到几百赫兹而共振频率在几千赫兹两者差了两个数量级一个 256 点的窗在 12 kHz 采样率下是 21.3 ms窗内既能包含足够多个冲击周期又不会把转速变化平滑掉。这个尺度选对了时频图上的故障特征才立得住。2.1 用 spectrogram 得到时频矩阵的最小命令MATLAB 里两个函数都能做 STFTstft和spectrogram。前者接口更现代后者在 R2006 就有了老版本和嵌入式代码生成里更常见。下面这段是不依赖新接口的写法fs 12000; % 采样率与台架一致 winLen 256; % 窗长21.3 ms nOverlap 192; % 75% 重叠帧间更平滑 nFFT 512; % FFT 点数频率分辨率 fs/nFFT 23.4 Hz x x - mean(x); % 去直流避免 0 Hz 处一条亮线干扰 [S, F, T] spectrogram(x, hann(winLen), nOverlap, nFFT, fs, onesided); P abs(S); % 幅度谱后续做分块统计逻辑说明spectrogram先对信号分帧加窗再逐帧做 FFT返回的S是(nFFT/21) × 帧数的复数矩阵F是频率轴T是时间轴P取模后就得到一张二维时频图。参数方面winLen决定时间分辨率越小越能抓瞬态冲击但频率分辨率越差nOverlap取窗长的 50%75%重叠越大帧数越多、特征越平滑代价是计算量线性上升nFFT只影响频率轴的插值密度不改变真实分辨率习惯取窗长的 2 倍。提示hann(winLen)是周期汉宁窗做谱分析时比对称窗更合适。如果信号里直流分量大先做detrend或减去均值否则后面对数压缩时低频块会一直占主导。2.2 从时频矩阵到固定维特征向量的分块压缩时频矩阵维度随信号长度变化不能直接喂给 SVM。常见做法是把频率轴切成nBand段、时间轴切成nSeg段每块取均值得到固定维向量。我一般取 16×8特征维数 128这个量级在几百个样本上既不过拟合也不至于太稀疏。function feat stftFeat(x, fs, cfg) % 输入 x 为列向量cfg 含 winLen/nOverlap/nFFT/nBand/nSeg x x(:) - mean(x(:)); [S, ~, ~] spectrogram(x, hann(cfg.winLen), cfg.nOverlap, cfg.nFFT, fs, onesided); P abs(S); [nF, nT] size(P); fb round(linspace(1, nF1, cfg.nBand1)); % 频率分块边界 tb round(linspace(1, nT1, cfg.nSeg1)); % 时间分块边界 feat zeros(cfg.nBand * cfg.nSeg, 1); k 0; for i 1:cfg.nBand for j 1:cfg.nSeg blk P(fb(i):fb(i1)-1, tb(j):tb(j1)-1); k k 1; feat(k) mean(blk(:)); % 块内平均幅度 end end feat log10(feat 1e-6); % 对数压缩拉平动态范围 end逻辑说明双重循环把时频面划分成互不重叠的矩形块块内取均值相当于一个矩形带通加低通的能量统计保留了「哪个频段在哪个时间段活跃」的联合信息。对数压缩这一步很关键轴承早期故障的冲击能量比正常状态高两三个数量级不做对数压缩的话 SVM 的 RBF 核宽完全被高能块支配。这里没有做整体归一化因为归一化要用训练集统计量必须放到划分数据集之后做否则测试集信息会提前泄漏。2.3 三组 STFT 参数对分类结果的影响参数不是拍脑袋定的可以用一组对比实验说明下表是在 12 kHz 轴承数据上的典型结果供选参时参照窗长重叠率FFT 点数频带×时段特征维数五折交叉验证准确率12850%25616×812891.2%25675%51216×812896.7%51275%102416×812894.1%102450%204816×812890.5%窗长 256 表现最好原因是它把 21.3 ms 的时间窗和 46.9 Hz 的频率分辨率折中到了一个合理位置够短能跟上转速波动够长能把 4 kHz 附近的共振带分开。窗长继续增大频率分辨率提升但时间定位变糊冲击的周期性被平均掉准确率反而下降。频带数也不是越多越好nBand从 16 加到 64 时特征维数变成 512在 120 条样本上 SVM 开始明显过拟合验证准确率会掉 35 个百分点。注意如果数据来自变转速工况固定窗长会在低速段产生严重的频率混叠。这种情况先做阶次跟踪或转速归一化再进 STFT会比换窗长有效得多。3. SVM 分类器训练fitcecoc 多分类与超参搜索支持向量机本身是二分类器四种轴承状态要拆成多个二分类问题。MATLAB 里fitcecoc用纠错输出码把多个二分类器组合起来fitcsvm只处理二分类多类场景下前者更省事。3.1 ERF 核与一对多编码的选择核函数决定决策边界形状线性核适合类间线性可分的高维特征RBF 核适合边界弯曲的场景。时频特征经过对数压缩后不同故障类型在 128 维空间里呈现簇状分布RBF 是默认选择。t templateSVM(KernelFunction, rbf, ... KernelScale, auto, ... % 启发式核宽后面对它做搜索 BoxConstraint, 1, ... % 惩罚系数初值 Standardize, false); % 已手动归一化避免重复 mdl fitcecoc(Xtr, Ytr, ... Learners, t, ... Coding, onevsone, ... % 一对一类数少时更稳 ClassNames, {Normal,Inner,Outer,Ball});逻辑说明templateSVM只声明配置不训练交给fitcecoc复制若干份。Coding选onevsone会训练k(k-1)/2 6个二分类器每个只用到两类样本训练快且对类别不平衡不敏感onevsall只有 4 个分类器但每个都要面对正负样本 1:3 的不平衡容易偏向多数类。ClassNames显式指定顺序保证混淆矩阵的行列标签和业务含义对齐不依赖字母序。3.2 贝叶斯超参搜索在 MATLAB 里的落地写法BoxConstraint控制间隔宽度与误分类的取舍KernelScale控制 RBF 核的影响半径这两个参数互相耦合手调效率很低。fitcecoc自带OptimizeHyperparameters底层用贝叶斯优化直接接上去rng(42); % 固定随机种子结果可复现 opt struct( ... KFold, 5, ... % 分层五折 MaxObjectiveEvaluations, 30, ... % 30 次目标函数评估 AcquisitionFunctionName, expected-improvement-plus, ... ShowPlots, false, Verbose, 1); mdl fitcecoc(Xtr, Ytr, Learners, t, ... OptimizeHyperparameters, {BoxConstraint,KernelScale}, ... HyperparameterOptimizationOptions, opt);逻辑说明KFold必须设成 5 或 10让每次评估都在留出折上算避免用训练误差挑超参。MaxObjectiveEvaluations在样本量几百、参数只有两个的情况下30 次基本能收敛再往上收益递减。搜索范围由 MATLAB 自动给出BoxConstraint默认在对数尺度上取[1e-3, 1e3]KernelScale在[1e-3, 1e3]上取如果知道特征尺度在 1 附近可以手动把范围收窄到[0.1, 100]收敛更快。提示rng(42)放在搜索前保证每次跑出来的最优参数一致。工程交付时把搜到的mdl保存成.mat现场只做predict不再重训。3.3 混淆矩阵与每类召回率判断模型是真会还是靠多数类总准确率是最容易骗人的指标。四类样本如果有一类特别多模型全猜那一类也能有 70% 以上的准确率。真正要看的是confusionmat和每类召回率[ypred, score] predict(mdl, Xte); acc mean(ypred Yte); C confusionmat(Yte, ypred, Order, mdl.ClassNames); recall diag(C) ./ sum(C, 2); % 每类召回率 figure; confusionchart(C, mdl.ClassNames, ... RowSummary,row-normalized, ColumnSummary,column-normalized);逻辑说明predict第二个输出score是各类的后验得分score(:,i)越大越倾向第 i 类。recall逐类计算内圈和外圈故障往往容易混如果这两类召回率低于 85%说明时频特征里区分二者的频带被平均掉了回去把nBand调大或缩短窗长重试。confusionchart的行归一化显示每类的误分去向比裸矩阵直观。评估指标计算方式判断标准总体准确率mean(ypredYte)低于 90% 需检查特征每类召回率diag(C)./sum(C,2)最低类低于 85% 要调参类别间混淆confusionchart行归一化相邻类互混说明频带分辨率不足后验得分均值mean(max(score,[],2))低于 0.7 说明决策边界模糊4. MATLAB GUI 设计把 STFT-SVM 做成可交付工具模型训完只是半成品现场调试的同事不会用命令行。用 App Designer 搭一个界面把信号加载、特征提取、训练、预测、可视化串成一条链路交付时只给一个.mlapp文件加一份训练好的模型。4.1 界面布局与控件规划主界面分三块左侧是参数区放窗长、重叠率、FFT 点数、频带数、时段数五个编辑框加一个「提取特征」按钮中间是绘图区一个 UIAxes 显示时频图一个显示混淆矩阵右侧是结果区用 Label 或 TextArea 显示分类结果和各类后验得分。这种布局和热词里常见的 matlab gui 教程一致控件命名保持可读方便后续维护。% App Designer 属性区声明 properties (Access private) cfg % STFT 参数字典 mdl % 训练好的 SVM 模型 mu, sg % 归一化统计量 x, fs % 当前信号 endcfg用结构体存五个参数避免回调函数之间传一堆散变量mu和sg必须跟着模型一起保存否则单样本预测时归一化基准不对结果会完全偏掉。4.2 加载、提取、训练、预测的回调链路四个核心回调的骨架如下重点是数据在各回调之间的流向要和界面状态保持一致% 回调 1加载信号文件 function LoadButtonPushed(app, ~) [f, p] uigetfile({*.mat;*.csv;*.txt, 信号文件}); if isequal(f, 0), return; end raw readmatrix(fullfile(p, f)); app.x raw(:, end); % 末列视为幅值 app.fs str2double(app.FsEditField.Value); app.StatusLabel.Text sprintf(已加载 %d 点, numel(app.x)); end % 回调 2提取特征并绘制时频图 function ExtractButtonPushed(app, ~) app.cfg struct(winLen, str2double(app.WinEditField.Value), ... nOverlap, str2double(app.OverlapEditField.Value), ... nFFT, str2double(app.NfftEditField.Value), ... nBand, str2double(app.BandEditField.Value), ... nSeg, str2double(app.SegEditField.Value)); [S, F, T] spectrogram(app.x(:)-mean(app.x), hann(app.cfg.winLen), ... app.cfg.nOverlap, app.cfg.nFFT, app.fs, onesided); imagesc(app.UIAxes, T, F, 20*log10(abs(S)eps)); axis(app.UIAxes, xy); xlabel(app.UIAxes, 时间/s); ylabel(app.UIAxes, 频率/Hz); app.feat stftFeat(app.x, app.fs, app.cfg); % 复用 2.2 节函数 end % 回调 3批量训练 function TrainButtonPushed(app, ~) X cell2mat(arrayfun((i) stftFeat(data{i}, app.fs, app.cfg), ... 1:numel(data), UniformOutput, false)); % 逐样本提特征 app.mu mean(X, 1); app.sg std(X, 0, 1); app.sg(app.sg1e-12) 1; Xn (X - app.mu) ./ app.sg; app.mdl fitcecoc(Xn, labels, Learners, ... templateSVM(KernelFunction,rbf,KernelScale,auto)); app.StatusLabel.Text 模型训练完成; end % 回调 4单样本预测 function PredictButtonPushed(app, ~) f (stftFeat(app.x, app.fs, app.cfg) - app.mu) ./ app.sg; [lb, sc] predict(app.mdl, f); app.ResultLabel.Text [诊断结果 char(lb)]; app.ScoreTextArea.Value arrayfun((i) sprintf(%s: %.3f, ... app.mdl.ClassNames{i}, sc(i)), 1:numel(sc), UniformOutput, false); end逻辑说明加载回调只负责读数和存状态提取回调用spectrogram画图用imagesc配合axis xy让低频在下、时间在右转成 20log10 后动态范围更符合人眼训练回调对每个样本调同一个stftFeat保证 GUI 和脚本走的特征完全一致这是最容易出岔子的地方——脚本和 GUI 如果用了两套分块逻辑指标会对不上预测回调先把单样本特征按训练集统计量归一化再进predict。注意arrayfun拼特征矩阵时注意转置。stftFeat返回列向量arrayfun默认把结果拼成行不加转置会让X变成「样本数 × 特征维」的转置fitcecoc会报维度不匹配。4.3 在 GUI 里显示时频图与混淆矩阵时频图用imagesc或pcolor都行前者快后者对网格线控制更细。混淆矩阵直接在回调里调confusionchart会新开 Figure要显示在 App 里得用ConfusionMatrixChart对象或者先把矩阵画成热力图。简单稳妥的办法是imagesc加text标注数值C confusionmat(Yte, ypred, Order, app.mdl.ClassNames); Cnorm C ./ sum(C, 2); imagesc(app.ConfAxes, Cnorm); colormap(app.ConfAxes, parula); colorbar(app.ConfAxes); set(app.ConfAxes, XTick, 1:numel(app.mdl.ClassNames), ... XTickLabel, app.mdl.ClassNames, YTick, 1:numel(app.mdl.ClassNames), ... YTickLabel, app.mdl.ClassNames); for i 1:size(C,1) for j 1:size(C,2) text(app.ConfAxes, j, i, sprintf(%.2f, Cnorm(i,j)), ... HorizontalAlignment,center); end end逻辑说明行归一化后每行和为 1对角线上是各类召回率非对角线是误分概率看数字比看颜色准。colormap用parula在灰度打印机上也能分辨text循环把数值标在格子里工程评审时截图就能用。5. 进阶排错数据泄漏、参数耦合与现场常见报错5.1 样本切分要按「段」而不是按「点」从同一段 10 s 信号里滑窗切样本相邻窗高度重叠随机划分训练测试集时几乎必然泄漏。正确做法是先在原始记录层面划分同一段记录要么进训练集要么进测试集rng(1); idx randperm(numel(recList)); % recList 是记录级索引 nTr round(0.7 * numel(idx)); trRec recList(idx(1:nTr)); % 训练记录 teRec recList(idx(nTr1:end)); % 测试记录 Xtr buildFeat(trRec, cfg); Xte buildFeat(teRec, cfg);归一化统计量mu、sg只在Xtr上算Xte用同一组参数变换。这两条做对指标才有参考价值。5.2 时频参数与分类器参数的耦合nBand变大特征维数上升SVM 的最优KernelScale会跟着变大winLen改变特征的能量分布整体平移BoxConstraint的最优值也会漂。稳妥的顺序是先固定 STFT 参数做一轮粗扫选交叉验证最优的窗长和分块数再在此基础上调 SVM 超参。两轮都调的话组合爆炸且容易过拟合验证集。5.3 现场常见报错与排查报错或现象可能原因处理方式spectrogram报窗长大于信号长度截取的信号段太短保证段长至少 4 倍窗长或降低winLenfitcecoc报标签类型不一致标签混用字符串和 categorical统一categorical(labels)预测结果永远同一类归一化统计量丢失或基准错检查mu、sg是否与模型一起保存GUI 里指标远低于脚本分块逻辑或转置不一致抽一条样本对比两边特征向量的差值新转速数据准确率骤降训练集覆盖转速范围太窄补采数据或用阶次跟踪归一化训练很慢贝叶斯搜索评估次数过多降MaxObjectiveEvaluations或收窄搜索范围最后补一个实用技巧把mu、sg、cfg、mdl打包成一个结构体S存成model.matGUI 启动时load一次现场换台机器只要 MATLAB 版本一致就能直接跑。判断模型是否退化不用重新标注数据现场采几段已知状态的信号跑一遍看后验得分均值有没有从 0.9 掉到 0.6 以下就行。本文还有配套的精品资源点击获取