简介:本资源是一套基于MATLAB实现设备故障诊断的完整算法实践方案,面向工业智能运维领域的研究人员、自动化专业学生及机器学习初学者,聚焦时间序列建模与小样本分类两大核心问题。压缩包共62个文件,含53个.mat数据文件(存储西储大学轴承故障数据集预处理后的特征与标签)、3个主程序脚本(run_1.m等实现LSTM训练与SVM分类流程)、2个说明文档(含数据集介绍与特征向量构建逻辑)、1个.xlsx特征表、1个.class增强信号处理工具及配套ASV备份与DOCX说明,整体大小为52.77MB。已有59人学习下载,资源结构清晰分层:data目录组织原始与归一化数据,tezhengxiangliang存放手工/ESMD提取的时频域特征,tu.m等脚本提供模型性能可视化(混淆矩阵、F1曲线、准确率对比图),并支持LSTM早期预警与SVM多类故障精分的协同诊断流程。 搞设备故障诊断有一段时间了,用的最多的工具组合就是MATLAB加上机器学习那套东西。今天我把用LSTM和SVM做设备故障诊断的完整思路、源码细节、踩坑记录一次性整理出来。这篇内容适合已经在读研或者刚进厂做设备健康管理的朋友,也适合那些想从传统信号处理转向数据驱动诊断的工程师,按着步骤走,不需要深厚的机器学习基础也能跑通整个流程。
先说清楚这活儿到底是干嘛的。所谓设备故障诊断,本质上是利用传感器采集到的振动、温度、电流等信号,判断设备当前处于什么状态。比如滚动轴承,常见故障就是内圈磨损、外圈点蚀、滚动体损伤这几类。传统做法是靠老师傅听声音、看频谱,有经验但不可复制。用LSTM和SVM这类模型,就是让算法从历史数据里自己学出故障特征,然后对新采集的数据自动分类,实现故障类型的智能识别。我这里把两个模型都做了,一个偏传统机器学习,一个偏深度学习,各有各的适用场景。
1. 整体设计思路:为什么同时用LSTM和SVM
1.1 两个模型的本质差异
在设备故障诊断这个场景里,LSTM和SVM是完全两种路子。SVM属于经典机器学习方法,它做的事情是在特征空间里找一个最优超平面,把不同类别的样本分开。它的核心优势在于样本量不大的时候泛化能力很强,而且对高维特征的处理非常稳定。LSTM则是循环神经网络的一个变种,专门处理时间序列数据,它通过门控机制记住长期依赖关系,所以在信号本身具有时序特征的情况下表现更好。
我之所以两个都做,而不是只选一个,是因为在实际项目里你根本提前不知道数据长什么样。有的设备信号周期性很强,故障特征主要体现在时间序列的形态变化上,那LSTM就有优势;有的设备信号噪声大,需要你人工提取统计特征后再分类,SVM配合好的特征工程照样能打。两个模型都落地,可以在面对不同数据时灵活选择基线方案。
1.2 方案选型为什么选MATLAB而不是Python
很多朋友会问,搞深度学习不是Python更主流吗?这话没错,但MATLAB在设备故障诊断这个特定领域有它不可替代的地方。第一,MATLAB的信号处理工具箱太成熟了,滤波、FFT、小波变换、经验模态分解,全是内置函数,比Python里到处找库再调参省事太多。第二,Simulink可以做硬件在环仿真,后面如果要往嵌入式平台部署,整个链路是通的。第三,MATLAB的Classification Learner和Deep Network Designer这两个App,让你可以先拖拽式地验证方案可行性,再转成脚本做批处理,这个工作流效率很高。
我自己的习惯是先用MATLAB把特征工程和算法原型验证完,如果后面需要大规模部署上线,再考虑把模型移植到其他平台。做学术研究或者打比赛,MATLAB的代码可读性也更好,审稿人看起来也直观。
1.3 诊断流程的整体架构
整个诊断系统可以拆成四个环节。第一步是数据采集,通过加速度传感器获取设备振动信号,采样率一般在12kHz到48kHz,这个要看你诊断的故障频率范围。第二步是数据预处理,包括去趋势、滤波去噪、归一化。第三步是特征提取和模型构建,这里分两条线,一条线走人工特征加SVM,另一条线走原始序列直接喂给LSTM。第四步是模型评估与对比,用混淆矩阵、准确率、召回率这些指标来判断模型的实用性。
后面我所有的代码和讨论,都是围绕这个架构展开的。下面一个个环节细讲。
2. 数据准备与预处理:故障诊断的地基
2.1 数据集来源说明
这个项目里我用的标准数据集是凯斯西储大学(CWRU)的滚动轴承数据中心数据,这是故障诊断领域用得最多的公开数据集。数据里有正常状态、内圈故障、外圈故障、滚动体故障四类,每类故障还分了不同的损伤直径,采样频率有12kHz和48kHz两种档位。
MATLAB读取CWRU数据的代码很简单,官方的mat文件直接load就能读,每个mat文件里包含了DE(驱动端加速度)、FE(风扇端加速度)、BA(基座加速度)几个通道,你根据自己需要取一个通道就行。实际操作中我一般取DE通道,因为故障特征在驱动端表现最明显。
如果你没有公开数据集,自己用实验台采集也完全可以。关键是保证每个状态类别下采集的样本数量均衡,别出现一类样本200组、另一类只有20组的情况,否则后面训练出来的模型基本就废了。
2.2 数据分帧与样本构造
拿到连续的振动信号后,不能直接把整段信号丢给模型。原因很简单,一整段信号可能长达几十秒,包含了很多个旋转周期,信息过于冗余,而且计算量太大。标准做法是把长信号切成固定长度的小片段,每个片段作为一个独立样本。
切片长度怎么选?我做过对比实验,在12kHz采样率下,切片长度选1024个采样点(约0.085秒)或者2048个采样点(约0.17秒)效果比较好。太短了单个样本包含的故障冲击信息不够,模型学不到东西;太长了样本数变少,而且一个样本里可能混入多种状态的过渡,反而干扰分类。
构造样本的时候还有个细节:相邻片段之间可以设置重叠率。比如切片长度2048,步长512,那相邻两个片段就有75%的重叠。这样做的好处是变相做了数据增强,样本量能翻好几倍,对LSTM这种数据饥饿型模型尤其重要。
% 信号分帧示例 function samples = signal2frames(signal, winLen, stepLen) n = length(signal); idx = 1:stepLen:(n - winLen + 1); numSamples = length(idx); samples = zeros(numSamples, winLen); for i = 1:numSamples samples(i, :) = signal(idx(i):idx(i) + winLen - 1); end end2.3 特征提取:SVM的输入是特征,不是原始信号
SVM没法直接吃原始振动信号。把2048个采样点直接作为2048维特征喂给SVM,理论上可以,但效果很差,因为原始信号里包含了大量与故障无关的噪声和冗余信息,而且维度太高还容易引发维度灾难。
所以SVM这条路必须做特征工程。我常用的特征分两组。时域特征包括均值、方差、峰值、均方根值、峭度、波形因子、峰值因子、脉冲因子、裕度因子、偏度、标准差,一共11个。频域特征包括频谱峰值对应的频率、频谱重心、均方频率、频率方差、频域幅值均值等。把这些特征拼在一起,每个样本变成一个15到20维的特征向量,再喂给SVM。
这里我强烈建议你画一下特征可视化图,就是PCA降维之后把不同类别的样本用不同颜色画在二维平面上。如果不同类别在特征空间里已经有明显的分簇现象,那后续SVM的分类效果大概率不会差。如果特征混在一起完全分不开,说明你提取的特征没有抓住故障的本质,换再好的分类器也没用。
function featVec = extractFeatures(x) % 时域特征 meanVal = mean(x); varVal = var(x); peakVal = max(abs(x)); rmsVal = rms(x); kurtVal = kurtosis(x); % 频域特征 L = length(x); Y = fft(x); P2 = abs(Y/L); P1 = P2(1:floor(L/2)+1); P1(2:end-1) = 2*P1(2:end-1); f = 12000 * (0:floor(L/2))/L; % 假设采样率12kHz [~, maxIdx] = max(P1); peakFreq = f(maxIdx); % 组合 featVec = [meanVal, varVal, peakVal, rmsVal, kurtVal, peakFreq]; end2.4 归一化处理
不管你用SVM还是LSTM,归一化这步都逃不掉。SVM对特征的尺度非常敏感,如果某个特征的数值范围是0到1000,另一个是0到1,那距离计算几乎完全被前者主导,后者形同虚设。LSTM内部用sigmoid和tanh激活函数,输入数值如果太大,梯度很容易饱和,训练直接卡死。
归一化最简单有效的方法就是z-score标准化,让每个特征变成均值为0、方差为1的分布。MATLAB里一行代码就能搞定:
% 训练数据标准化 [featTrainNorm, mu, sigma] = zscore(featTrain); % 测试数据必须用训练集的mu和sigma featTestNorm = (featTest - mu) ./ sigma;这里有个特别容易踩的坑:测试集的标准化必须用训练集算出来的均值和标准差,不能自己单独算。因为模型在训练时学习的特征分布是训练集定义的,你如果让测试集独立标准化,相当于改变了特征的相对尺度,测试结果就不准了。很多新手在这个地方栽跟头还找不到原因,最后模型精度上不去就怪算法不好,其实是数据预处理的问题。
3. SVM诊断模型:MATLAB源码实现
3.1 多分类SVM的核心思路
SVM原始版本是二分类器,只能回答"是"或者"不是"。设备故障诊断通常是多分类问题,比如判断轴承是正常、内圈故障、外圈故障还是滚动体故障,四选一。怎么让SVM处理多分类?业界有两种主流策略:一对一(One-vs-One,简称OvO)和一对多(One-vs-All,简称OvA)。
MATLAB的fitcecoc函数用的是纠错输出编码(ECOC)框架,它默认支持这两种策略。CWRU四分类问题下,fitcecoc内部会对K个类别两两训练一组二分类器,一共训练出K*(K-1)/2个子分类器,然后通过投票决定最终类别。这种做法的好处是每个子分类器只需要区分两个类别,决策边界简单,训练效率高。
3.2 完整的SVM训练与预测代码
下面这段代码我实测可以直接跑通,里面有完整的注释。注意其中OptimizeHyperparameters参数可以自动做超参数调优,但会显著增加训练时间,数据量小的时候可以用,数据量大了建议关掉手动调参。
% 加载特征数据(假设已经构造好) % featTrain: 训练特征矩阵,每行一个样本 % labelTrain: 训练标签,1=正常, 2=内圈, 3=外圈, 4=滚动体 % 使用fitcecoc训练多分类SVM svmModel = fitcecoc(featTrain, labelTrain, ... 'Learners', templateSVM('KernelFunction', 'rbf', ... 'BoxConstraint', 1, ... 'KernelScale', 'auto'), ... 'Coding', 'onevsone', ... 'Verbose', 1); % 测试集预测 labelPred = predict(svmModel, featTestNorm); % 计算准确率 accuracy = sum(labelPred == labelTest) / length(labelTest); fprintf('SVM Test Accuracy: %.2f%%\n', accuracy * 100);这段代码里容易被人忽略的是templateSVM这个函数。在MATLAB较新版本中,SVM的超参数要通过templateSVM来定义,BoxConstraint和KernelScale是两个决定性参数。
3.3 超参数寻优:BoxConstraint和KernelScale怎么调
BoxConstraint(记作C)是SVM的正则化参数,它控制"误分类惩罚"和"决策边界复杂度"之间的权衡。C值大,模型越倾向于把所有训练样本都分对,边界变得复杂,容易过拟合;C值小,模型允许一些样本被分错,边界更平滑,泛化能力可能更好。KernelScale(记作gamma)控制RBF核的宽度,gamma越大,每个支持向量的影响范围越小,边界越复杂;gamma越小,影响范围越大,边界越平滑。
这两个参数怎么选?最科学的做法是网格搜索配合交叉验证。我在这个项目里用5折交叉验证,把C从0.1到100按对数间隔取10个值,gamma从0.01到10按对数间隔取10个值,组合起来一共100个候选参数对,每组做一次5折交叉验证,选出平均准确率最高的那组参数。
% 超参数网格搜索示例 CList = logspace(-1, 2, 10); % 0.1 到 100 gammaList = logspace(-2, 1, 10); % 0.01 到 10 bestAcc = 0; bestParams = []; for c = CList for g = gammaList % 5折交叉验证 cvModel = fitcecoc(featTrain, labelTrain, ... 'Learners', templateSVM('KernelFunction', 'rbf', ... 'BoxConstraint', c, ... 'KernelScale', g), ... 'Coding', 'onevsone', ... 'CrossVal', 'on', 'KFold', 5); acc = 1 - kfoldLoss(cvModel); if acc > bestAcc bestAcc = acc; bestParams = [c, g]; end end end实测下来,CWRU数据集做过特征工程之后,C在1到10之间、gamma在0.1到1之间的区域效果最好,测试准确率能做到97%以上。但你要记住,这是这个特定数据集的结果,换到自己的设备数据上一定要重新寻优,不能直接套用别人的参数。
4. LSTM诊断模型:MATLAB源码实现
4.1 为什么用LSTM而不用普通BP神经网络
如果只是拿特征向量做分类,BP神经网络或者SVM就够了。但这里有个问题:我前面构造的每一个样本,本质上是2048个采样点的时序信号。这2048个点不是孤立的,而是有前后依赖关系的。内圈故障时,振动信号里会出现周期性的冲击脉冲,这个冲击的特征不仅体现在每个点的幅值上,更体现在一段时间内的变化规律上。
普通BP神经网络把输入当成一个平坦的向量,完全忽略了时间维度的信息。LSTM天生就是处理这种序列数据的,它在每个时间步上通过输入门、遗忘门、输出门来控制信息的流动,让网络自己学习哪些时间点上的信息重要,哪些应该遗忘。
4.2 序列数据构造与数据格式转换
LSTM在MATLAB里需要的输入格式是若干个序列的cell数组,每个cell里是一个numFeatures x numTimeSteps的矩阵。如果你训练数据是N个样本,每个样本是1通道、2048个时间步,那么cell数组的维度是Nx1,每个cell内部是一个1x2048的矩阵。
% 假设rawTrain是Nx2048的矩阵,每行一个样本 XTrainLSTM = cell(N, 1); for i = 1:N XTrainLSTM{i} = rawTrain(i, :); % 1x2048 end % 标签是分类变量 YTrainLSTM = categorical(labelTrain);如果你有多个传感器通道,比如同时采集了加速度和温度信号,那numFeatures就是2,每个cell内部变成2x2048的矩阵,LSTM会自动融合多通道信息,不需要额外拼接。
4.3 网络结构与训练选项设置
LSTM网络结构我推荐这样一个基线设计,在实际项目里能少走弯路:序列输入层 -> LSTM层(隐藏单元数64)-> dropout层(丢弃率0.2)-> 全连接层(输出节点等于类别数)-> softmax层 -> 分类层。
隐藏单元数怎么选?64是个不错的起点,数据量大可以加到128或256,但要注意过拟合。我把隐藏单元数和dropout放一起看,如果训练集准确率很高但测试集上不去,说明过拟合了,要么加大dropout,要么减小隐藏单元数。
numHiddenUnits = 64; numClasses = 4; layers = [ sequenceInputLayer(1, 'Normalization', 'zscore') lstmLayer(numHiddenUnits, 'OutputMode', 'last') dropoutLayer(0.2) fullyConnectedLayer(numClasses) softmaxLayer classificationLayer]; options = trainingOptions('adam', ... 'MaxEpochs', 50, ... 'MiniBatchSize', 64, ... 'InitialLearnRate', 0.01, ... 'LearnRateSchedule', 'piecewise', ... 'LearnRateDropFactor', 0.5, ... 'LearnRateDropPeriod', 10, ... 'GradientThreshold', 1, ... 'Shuffle', 'every-epoch', ... 'Verbose', 1, ... 'Plots', 'training-progress'); net = trainNetwork(XTrainLSTM, YTrainLSTM, layers, options);训练选项里的几个参数我逐个说下。GradientThreshold设为1是为了防止梯度爆炸,LSTM虽然比普通RNN稳定,但序列长的时候梯度爆炸还是可能发生的。LearnRateDropFactor和LearnRateDropPeriod配合,每10轮训练学习率减半,这样可以先用大学习率快速下降,后期用小学习率精细收敛。Shuffle设为every-epoch,让每轮的mini-batch顺序都不同,增强随机性。
4.4 训练过程监控与过拟合判断
上面代码里的'Plots', 'training-progress'会在训练时弹出实时曲线图,包括准确率和损失值。训练过程中你得眼睛盯着两张曲线:训练准确率和训练损失。如果训练损失在下降但下降得很慢,可能是学习率太小;如果损失先降后涨,很可能是学习率太大,在最优解附近震荡了。
关键判断点出现在训练集准确率接近100%之后。如果测试集准确率远远低于训练集,恭喜你,过拟合了。解决办法有三个方向:加dropout、加大数据量(用重叠采样扩充样本)、减小隐藏单元数。这三个方向优先顺序我建议先减模型复杂度,再加dropout,最后才想着找数据,因为找数据成本最高。
5. 模型对比与鲁棒性分析
5.1 量化对比指标的选取
两个模型都跑完之后,不能光看一个总准确率就说谁好谁坏。设备故障诊断场景里,我更关心的是每个类别的召回率,尤其关注"故障样本被误判成正常"这种情况。如果一个外圈故障样本被模型判成正常,现场维护人员就可能漏掉一次检修机会,这是最危险的情况。
所以我除了看总体准确率,一定会画混淆矩阵(confusion matrix)。MATLAB的confusionchart函数几行代码就能画出来,从混淆矩阵里可以直观看出模型在哪两个类别之间容易混淆。CWRU数据上,SVM和LSTM最容易混淆的往往是内圈故障和滚动体故障,因为这两种故障产生的振动信号在某些频率段上确实有重叠。
5.2 不同工况与噪声条件下的表现
实验室数据和现场数据的差距,往往比模型选型带来的差距还要大。我在做鲁棒性测试时,会人为在测试信号里叠加不同信噪比的高斯白噪声,看模型准确率随噪声水平的变化曲线。
实测数据显示,SVM在特征提取阶段做了平滑处理,对中低水平噪声有天然的抑制作用,所以噪声加到一定程度之前,SVM的准确率下降得比LSTM慢。但噪声再大一些,特征被污染,SVM的准确率会急剧下降。LSTM因为直接吃原始数据,对噪声的容忍度更高,因为它可以在训练过程中自己学会抑制噪声干扰。这个结论给我的启示是:如果现场环境很嘈杂,优先选LSTM;如果现场信号相对干净,SVM更轻量高效。
5.3 训练时间与部署成本的现实考量
还有一个不可忽视的维度是计算资源。我的实验环境是普通台式机,i7处理器,16GB内存,没有独显,纯CPU跑。训练一个SVM模型,特征提取加交叉验证总共不到2分钟;训练一个LSTM,50轮跑下来大概8到10分钟,看数据量和隐藏单元数。如果数据量再翻几倍或者隐藏单元加到256,LSTM的训练时间会飙升到半小时以上。
部署阶段差距更大。SVM模型本质上就是一组支持向量和权重系数,保存下来几个KB,预测一个样本只需要计算一次核函数,速度是毫秒级的,适合部署到PLC或嵌入式设备上。LSTM模型结构更复杂,参数数量多几个量级,虽然在CPU上也能跑,但在嵌入式环境里就比较吃力了。所以如果是做在线实时诊断,SVM往往是更务实的选择。
6. 常见问题与调试实录
6.1 读取mat文件时数据维度不符
CWRU数据集中不同mat文件里的数据结构有点差别,有些文件是结构体,有些直接就是数组。如果在load之后发现size跟你预期不一致,别慌,先用whos命令查看工作区变量,再用fieldnames查看结构体字段,确认到底哪个字段是你要的信号数据。我曾经在一个文件上栽过跟头,发现字段名不是DE而是drive_end,直接报错找不到字段,排查了好久。
建议写一个统一的数据加载函数,兼容两种格式,这样后面换数据集就不会再出问题。
6.2 LSTM训练不收敛
症状是损失函数一直在高位抖动,准确率保持在25%左右(四分类随机水平)上不去。这个问题我在第一次跑LSTM的时候遇到过,原因出在数据没有做z-score标准化,原始振动信号幅值范围很大,LSTM的输入门和遗忘门的sigmoid激活一路饱和,梯度根本传不回去。解决办法就是在sequenceInputLayer里设置'Normalization', 'zscore',或者在预处理阶段手动标准化,一轮训练就收敛了。
另一个可能的原因是学习率太大。如果损失曲线像过山车一样上下乱跳,把InitialLearnRate从0.01降到0.001,大概率能稳住。
6.3 SVM训练时间过长,卡在交叉验证
如果特征维度很高且样本量很大,fitcecoc默认会用全部训练数据做K折交叉验证,时间会很难看。这时候可以先减小K值,比如从5折改成3折,先把参数方向摸出来,再在最优参数附近用全量数据训练。还有一个技巧是使用OptimizeHyperparameters自动优化时,把MaxObjectiveEvaluations设小一点,比如10到20次,别让它跑满30次,不然等着吃晚饭吧。
6.4 模型精度总差那么一两个点
这是最让人抓狂的情况。我踩过最深的坑是特征提取和模型训练之间的数据顺序错位。比如分帧的时候用了重叠采样,你做了数据增强,但标签没跟着扩充,特征和标签一对不上,模型精度自然上不去。排查方法很简单,随机打印第100个样本的特征向量和对应标签,人工看一眼类别是否匹配得当。
另外一个很容易被忽略的问题是,测试集参与过归一化。有些人图省事,先把全量数据zscore一遍再划分训练测试集,这样测试集的信息已经泄露到训练集了,看起来测试准确率很高,但一到现场真实数据上就拉胯。正确做法必须像我前面代码里那样,先划分,再只基于训练集计算归一化参数。
最后说点实在的
从我个人实操经验来看,在MATLAB里用LSTM和SVM做设备故障诊断,最大的价值不是跑通一个demo,而是通过对比理解两类模型的本质区别。我再强调一个原则:SVM的性能上限由特征工程决定,LSTM的性能上限由数据质量和样本量决定。所以当你遇到模型效果不好的时候,先别急着换网络结构,先回头审视你的特征提取得够不够好、数据样本够不够多、标签有没有标错。
如果日后要把这套方案做成更完整的系统,可以考虑把两个模型做集成,比如对初判结果置信度低的样本再交给另一个模型复核。我试过用LSTM的概率输出作为SVM的附加特征,在小样本情况下有一定提升,感兴趣的可以自己实验一下。目前项目代码已经整理成脚本和函数,按模块拆好,喂入自己的CSV或mat数据就能跑,后续在做实时数据流的版本,有结果再跟大家分享。
本文还有配套的精品资源,点击获取