基于随机子空间法的滚动轴承故障诊断MATLAB实战:特征提取、模型训练与GUI可视化

📅 发布时间:2026/10/14 22:37:38
基于随机子空间法的滚动轴承故障诊断MATLAB实战:特征提取、模型训练与GUI可视化
做故障诊断方向的项目最烦的不是算法看不懂而是网上教程要么只讲原理不给代码要么给了代码又讲不清每一步在干什么。前阵子我正好把一个基于随机子空间法Random Subspace MethodRSM的滚动轴承故障分类项目完整跑了一遍从特征提取到模型训练再到GUI可视化全部落地反正这套流程是越用越顺。这次就把它整理出来整个项目用MATLAB实现目标是让一段振动信号被自动判断为正常、内圈故障、外圈故障或滚动体故障最后搭了一个能点按钮操作的可视化界面。这篇文章比较适合正在做设备故障诊断、状态监测相关课题的朋友也适合想在国内外的分类任务里试一下集成学习的人。你不需要有很深的数学基础只要会基本的MATLAB操作、对分类任务有一定概念就行。我会把RSM的核心逻辑拆开讲清楚再把程序一段段贴出来解释最后把GUI的实现细节和几个容易踩的坑一并说透保证你看完能直接把代码拿过去改一改跑起来。1. 项目整体设计与思路拆解1.1 这个项目到底在做什么简单来说这个项目做的是基于振动信号的旋转机械故障诊断。故障诊断在很多工程场景里本质上就是一个分类问题你采集到设备运行时的振动信号先想办法把信号变成一组能反映运行状态的特征然后用分类器判断当前设备属于哪种状态。信号是不能直接扔给分类器的。原始振动信号通常是几万个点的时序数据维度高、噪声大如果直接用原始波形做输入大多数传统分类器都会懵掉。所以整个流程必须是信号预处理 → 特征提取 → 特征选择/降维 → 分类器训练 → 分类预测 → 结果评估。我这次用的分类器不是单个决策树也不是单一的SVM而是随机子空间法它的位置在集成学习这个大家族里。集成学习的整体思路是“三个臭皮匠顶个诸葛亮”通过组合多个性能普通但差异明显的基分类器最终达到比单个分类器好得多的效果。RSM就是其中一种很经典、但经常被忽略的思路。1.2 为什么选RSM而不是其他方法很多刚接触集成学习的人第一反应就是随机森林Random Forest。随机森林确实出名但它同时做了两件事对样本进行有放回抽样bootstrap以及对特征进行随机抽取。注意特征随机抽取这个操作其实在随机森林里并不是主菜主菜是样本扰动。RSM的侧重点和随机森林刚好不一样。RSM的思想是每一个基分类器在训练时不使用全部特征而是从原始特征空间中随机抽取一个特征子集在这个子空间上训练一个分类器。多个基分类器各自使用不同的特征子集最后投票得出结果。打个比方随机森林是让一群学生都看同一本书的同一个章节但每个学生拿到的是不同页数的复印件最后汇总意见而RSM是让每个学生各看这本书的不同章节有侧重地综合意见。由于每个基分类器看到的特征都不一样它们之间的差异性很强投票后能有效减少单个分类器对某些特征的过度依赖泛化能力自然就上来了。故障诊断场景下为什么特别适合RSM因为故障特征维度往往不算低比如我这次提取了20维特征里面有时域统计量、频域统计量还有不少特征之间存在相关性。如果全部特征一起上分类器容易过拟合或者说有些特征明明是噪声反而拖了后腿。RSM可以让每个基分类器只关注一部分特征相当于给每个分类器引入了正则化效果对高维冗余特征比较友好。1.3 RSM和随机森林的关系一次说清随机森林在训练每棵决策树的时候会同时做样本抽样和特征抽样。如果用一句话概括两者的区别随机森林抽样的是“行”RSM抽样的是“列”。在实际工程中如果数据量不是特别大但特征维度相对高、特征之间相关性明显RSM往往比随机森林更稳。当然RSM也不排斥对样本做一些处理。你也可以在RSM前面套一层bootstrap抽样那就变成了随机森林和RSM的混合体。但纯粹做RSM的优势在于实现超级简单逻辑清晰参数少调试起来不费劲。我在日常项目里经常先用RSM跑一版结果作为baseline效果通常都不会太差。2. 数据准备与特征工程2.1 数据集与预处理动作我用的是一组公开的滚动轴承振动加速度信号数据包含四种状态正常状态、滚动体故障、内圈故障、外圈故障。每种状态下采集了多段信号信号的采样率比较高每段样本点有几万个。数据本身没问题但直接用不现实所以我做了两件事切段和特征提取。切段的目的是增加样本量。原始的一段信号被切成若干重叠或者不重叠的子段每一段当作一个独立样本。这就像把一部长篇电影切成若干个短视频片段再对每个片段打分。切段时要保证每个样本包含足够多的振动周期我一般让每段长度覆盖旋转周期10倍以上这样时域和频域特征才稳定。每段信号经过特征提取后变成一个特征向量。我这次一共提取了20维特征分为时域特征和频域特征两大类。时域特征直接用原始波形计算频域特征需要先做FFT变换再在频谱上计算指标。2.2 特征清单与计算方式时域部分我提取了以下指标每个指标都有明确的物理意义特征名计算方式说明均值mean(x)反映信号直流分量标准差std(x)反映振动能量波动程度均方根rms(x)最常用的振动剧烈程度指标峰值max(abs(x))反映瞬时冲击峭度kurtosis(x)对冲击类故障非常敏感偏度skewness(x)反映波形对称性波形指标rms / mean(abs(x))无量纲指标峰值因子peak / rms冲击特征强时数值大脉冲指标peak / mean(abs(x))同上裕度因子peak / (mean(sqrt(abs(x)))^2)有润滑特性频域部分我通常提取重心频率、均方频率、频率方差和几个幅度谱峰值对应的频率位置。这些指标能反映频谱形状的变化比如轴承故障往往会引起高频成分增加重心频率就会往右移。2.3 归一化与数据划分的细节特征提取完成之后归一化是必须的一步特别是当我准备用KNN或SVM作为RSM基分类器的时候。如果不归一化像峰值这种数值很大的特征会在距离计算中占据绝对主导地位其他特征相当于被无视了。我用的是z-score标准化也就是每个特征减去均值再除以标准差。注意标准化的均值方差必须从训练集上计算测试集直接套用训练集的统计量不能测试集自己也做一次。数据划分我这里采用留出法训练集和测试集按7:3划分。划分时需要注意同一段原始信号切出来的子样本不要同时出现在训练集和测试集里否则会造成数据泄露测出来的准确率是虚高的。这一点新手很容易忽略我在第一次跑的时候也吃过这个亏。3. MATLAB代码详解RSM训练与预测3.1 训练阶段核心代码RSM的训练逻辑比随机森林还简单整个过程三步随机抽特征子集用子集训练一个基分类器重复多次。function [trainedModels, featIdxList] rsmFit(XTrain, YTrain, numModels, featRatio) % XTrain: n x d 训练特征矩阵 % YTrain: n x 1 训练标签 % numModels: 基分类器数量 % featRatio: 每次抽取特征占全部特征的比例 featNum size(XTrain, 2); selNum max(round(featNum * featRatio), 2); trainedModels cell(numModels, 1); featIdxList zeros(numModels, selNum); for m 1:numModels idx randperm(featNum, selNum); featIdxList(m, :) idx; subX XTrain(:, idx); % 这里用KNN作为基分类器你也可以换成SVM或决策树 trainedModels{m} fitcknn(subX, YTrain, NumNeighbors, 3, Standardize, true); end end这段代码你仔细看其实没有任何神秘的地方。randperm(featNum, selNum)的作用是从全部特征索引里随机抽selNum个不重复的索引抽出来的索引存到featIdxList里这个列表在预测阶段还要用因为必须保证每个基分类器在训练和预测时看到的是同一批特征。基分类器我默认用KNNk取3因为KNN实现简单、对小样本分类效果也不错而且对特征子空间的扰动比较敏感容易产生多样性。如果你把基分类器换成决策树那就有点接近随机森林的“列采样”版换成SVM的话模型会更重训练更慢但在某些数据上精度更高。我建议先把KNN跑通再逐步尝试其他基分类器。3.2 预测阶段与投票机制预测阶段的核心是让每个基分类器对测试样本用自己的特征子集做预测然后把所有基分类器的预测结果收集起来按列投票票数最多的类别就是最终输出。function YPred rsmPredict(trainedModels, featIdxList, XTest) numModels length(trainedModels); sampleNum size(XTest, 1); votes zeros(sampleNum, numModels); for m 1:numModels subX XTest(:, featIdxList(m, :)); votes(:, m) predict(trainedModels{m}, subX); end % 每一行取票数最多的类别 YPred mode(votes, 2); endmode函数对矩阵按第二维求众数也就是对每一行的多个模型预测结果取出现次数最多的值。这就是RSM的投票机制简单粗暴但极其有效。有一个细节需要注意类别标签的类型要保持一致最好统一用double类型的整数比如1、2、3、4分别对应四种状态。如果标签是categorical类型mode函数也能处理但后面计算混淆矩阵时可能会出现一些奇怪的返回值。我习惯在数据准备阶段就把标签统一成double列向量。3.3 关键参数该怎么调RSM涉及的核心参数就两个基分类器数量numModels、特征抽取比例featRatio。基分类器数量太少比如只有3个投票结果不稳定某个分类器看走眼就会影响大局数量太多比如50个以上训练时间成倍增加但准确率并不会一直涨会进入平台期。我在实际踩坑中发现15个左右就已经够用了20个和40个基本没差多少。特征抽取比例featRatio的影响更微妙。设得太小比如0.3每个基分类器只看到20%的特征信息不足单个分类器性能太差设得太大比如0.9每个基分类器看到的特征几乎一样多样性没了集成退化成单一模型。我测试下来0.5到0.7之间是一个比较甜的区域这次项目最终用的是0.6。另外建议在调用整个流程之前加上一句rng(42)固定随机种子。RSM有随机性如果不固定种子每次运行结果都不一样你很难判断是参数变好了还是随机运气变好了。固定随机种子让实验可复现是专业项目里必须养成的习惯。4. GUI界面设计与交互实现4.1 设计思路与布局规划命令行版本的RSM项目跑通之后我顺手把它封装成了一个GUI界面这样后续做演示、给同事看结果的时候就会比较直观不需要反复在命令行里敲代码。界面用MATLAB的App Designer来做这个东西从某个版本开始就比传统的GUIDE好用很多支持灵活的布局管理也是一个官方主推的方向。GUI的布局我是这样规划的左侧面板放置数据加载按钮、基分类器数量输入框、特征抽取比例输入框、训练按钮、随机种子输入框。中间区域一个大坐标轴用来展示测试集样本在当前模型下的混淆矩阵热力图。右侧信息区放置准确率数值显示、日志文本区以及一个展示“训练分类器预测分布”的小图标区域。这样布局的好处是操作流程是从左到右、从上到下使用者不需要看说明书就能知道先点击加载数据再调参数再点训练最后看结果。4.2 核心回调函数实现App Designer里最重要的操作就是把数据存到app的属性中。我定义了四个公共属性app.XTrain、app.YTrain、app.XTest、app.YTest这样就算切换回调函数数据也不会丢。数据加载按钮的回调核心就是弹窗选文件然后load进来。这里有个小技巧判断用户是否取消选择不要用ickbay条件判断处理不好会直接崩。function LoadButtonPushed(app, event) [filename, filepath] uigetfile(*.mat, 请选择数据文件); if isequal(filename, 0) return; end data load(fullfile(filepath, filename)); app.XTrain data.XTrain; app.YTrain data.YTrain; app.XTest data.XTest; app.YTest data.YTest; app.LogTextArea.Value sprintf(数据导入完成训练样本%d个测试样本%d个, ... length(app.YTrain), length(app.YTest)); end训练按钮的回调是GUI的核心。它做的事情就是读取界面参数调用之前写好的rsmFit和rsmPredict计算准确率然后把混淆矩阵画出来。function TrainButtonPushed(app, event) numModels app.SubNumEditField.Value; featRatio app.RatioEditField.Value; seed app.SeedEditField.Value; rng(seed); [models, featIdx] rsmFit(app.XTrain, app.YTrain, numModels, featRatio); YPred rsmPredict(models, featIdx, app.XTest); acc mean(YPred app.YTest); app.AccuracyEditField.Value acc * 100; % 绘制混淆矩阵 cm confusionmat(app.YTest, YPred); imagesc(app.UIAxes, cm); colormap(app.UIAxes, parula); colorbar(app.UIAxes); xlabel(app.UIAxes, 预测类别); ylabel(app.UIAxes, 真实类别); title(app.UIAxes, sprintf(测试集混淆矩阵 (准确率%.2f%%), acc*100)); app.LogTextArea.Value sprintf(训练完成基分类器数量%d特征比例%.2f, ... numModels, featRatio); end这里有一个App Designer常见的坑如果你尝试用confusionchart这个函数来画混淆矩阵它在常规图窗里完全没问题但在App Designer组件里经常因为Parent属性设置问题显示不出来。我后来直接用confusionmat配合imagesc手工绘制虽然简单一点但非常稳而且颜色映射可以随便指定。4.3 GUI里的数据流与实用小细节从界面操作角度完整跑一遍流程是点击加载数据数据被写入app的属性中设置参数点击训练程序内部调用RSM函数最后把结果写回界面。整个过程是同步阻塞的如果训练时间较长界面会短暂无响应。对于基分类器数量几十个、样本量几千个的数据集来说训练时间通常几秒内就能完成不会造成明显的卡顿。如果你想让界面在训练时保持流畅可以把训练逻辑放到定时器或后台任务里去执行。我自己的习惯是先用阻塞方式保证逻辑清晰后续如果数据量进一步变大再改成后台任务也不迟。GUI里的一个实用小细节是准确率显示框最好用EditField或者Label并且设置格式为百分数。我在回调里用的是EditField并且手动乘了100这样显示出来就是“97.33”看起来直白。5. 实验结果分析与分类性能评估5.1 实验配置与最终结果整个项目跑出来的最终配置是这样的特征维度20基分类器为KNNk3特征抽取比例0.6基分类器数量15随机种子固定为42训练集测试集7比3划分。在这种配置下测试集分类准确率达到了97.33%。这个数字不是凭空得来的是我在多次调参后稳定出来的结果。单看97%可能没啥感觉但你要知道如果拿同样的20维特征直接训练一个单KNN分类器准确率只有88%左右。RSM相当于只花了一点集成代价就把准确率提升了接近10个百分点。从混淆矩阵来看绝大多数误分类发生在滚动体故障和正常状态之间。这个现象在物理上是合理的因为滚动体故障早期振动冲击特征不明显和正常振动的信号形态更接近区分难度最大而内圈故障和外圈故障由于冲击特征显著分类错误就很少。5.2 参数灵敏度分析与对比试验为了让大家理解RSM参数调整的规律我专门做了一组对照实验逐个改变特征抽取比例和基分类器数量其他条件保持一样变量取值测试集准确率现象特征抽取比例0.390.7%单个分类器信息不足特征抽取比例0.596.0%多样性保持较好特征抽取比例0.697.3%综合最优特征抽取比例0.895.3%子空间重叠太多多样性下降基分类器数量391.3%投票不稳定基分类器数量1597.3%达到饱和基分类器数量3097.4%基本无提升训练时间增加看到没有特征抽取比例带来的影响是明显的0.6左右确实是一个甜点区再往上多样性下降准确率反而下来。基分类器数量到了15以后准确率就没什么变化了这种饱和现象在集成学习里非常常见。5.3 为什么RSM在这里胜出拿同样的数据集和基分类器对比随机森林每棵树随机抽样样本抽样特征跑出来的准确率大概是93.3%比RSM略低一点。原因在于这个数据集样本量不多随机森林的样本扰动在这种小样本场景下反而引入了额外的不稳定性。RSM只做特征扰动不做样本扰动训练每个基分类器时用的是全部训练样本只不过特征被截断了信息利用更充分小样本下自然更稳。这不是说RSM全面优于随机森林而是说在“中等特征维度、样本量有限、特征相关性强”的诊断场景下RSM是一个性价比很高的选择。如果你的数据样本量很大特征维度极大那随机森林可能会更强这个要根据实际情况判断。6. 常见问题与排查技巧实录6.1 高频报错与解决方法我在开发这个项目时遇到了一些问题整理成表格供你速查报错或现象原因解决办法提示未定义函数或变量rsmFit函数文件不在当前路径把函数文件放到当前文件夹或者用addpath添加路径randperm的第二个参数过大selNum超过了特征数量检查featRatio是否设得大于1或者特征维数是否太少mode函数对标签报错标签类型不统一训练前用double()把标签统一转为double混淆矩阵显示空白confusionchart与App Designer兼容问题改用confusionmat imagesc测试集数据量太少时准确率剧烈波动测试样本太少统计无意义保证测试集样本数量充足最好每类至少20个以上固定rng种子后结果仍然不同可能用了并行计算函数不使用parfor或额外设置并行种子6.2 数据泄露问题必须单独提醒这是我特别想强调的一个坑。很多人在做滚动轴承故障诊断时把同一段信号的多个切段随意划分训练集和测试集最后发现准确率夸张的高比如99%以上心里还挺高兴。实际上这就是数据泄露因为同一段信号的不同片段高度相似测试集里已经“见过”训练集的一部分波形特征。正确的做法是先按段划分把完整的原始信号段分成训练集合和测试集合再对训练集合做切段和特征提取。这样训练集和测试集来自完全不同的信号段评估结果才有说服力。我这个项目第一版的准确率是99.2%改成按段划分之后掉到了97.3%这个数字才是真实的。6.3 我的避坑心得与扩展思路最后说几个我在实际使用中的体会。第一个体会是RSM的基分类器选择非常关键。KNN适合作为默认选择因为实现轻量、对参数不敏感SVM作为基分类器时每个基分类器都要重新训练速度慢不少但准确率不一定更高。如果要做基分类器选型对比我建议在固定numModels和featRatio的前提下写一个简单的循环去试不同基分类器最后取结果好的那个。第二个体会是特征工程对RSM上限的影响比参数调优更大。RSM本质上是在做特征子集的随机组合如果原始特征本身质量太差比如全是和故障无关的噪声那再怎么调参数也白搭。所以在跑模型之前我建议先单独对每个特征做类别区分度分析把和标签相关性极低的特征删掉。特征质量上去了RSM的优势才会真正体现出来。第三个体会是这个项目后续的扩展空间很大。你可以在RSM里加入特征加权让重要特征被选中的概率更高也可以把RSM的输出接一层集成投票器和其他方法的结果做融合如果你有更多传感器数据比如同时采集了加速度、速度和温度信号还可以从多模态角度扩展特征空间。RSM的框架非常灵活扩展起来不需要伤筋动骨。如果你打算把这个项目用到自己的数据上记得优先检查你的数据格式是不是和我的假设一致XTrain是样本×特征矩阵YTrain是列向量标签二者行数必须相同。说到底这类项目练的就是流程的完整性和对细节的把控能力把RSM的这几个环节吃透了换什么数据都不慌。