首页 / 资讯中心 / 文章详情

WMSST结合MCNN-BiGRU的滚动轴承故障诊断方法及Matlab实现

WMSST结合MCNN-BiGRU的滚动轴承故障诊断方法及Matlab实现 ★ FEATURED ARTICLE
搞故障诊断的人应该都有同感设备一开机传感器回来的振动信号看着就是一波波毛刺细看全是噪声、谐波和调制成分搅在一起。以前靠频谱分析找特征频率碰上变转速、变载荷这类非平稳工况常规傅里叶手段基本失灵。我近期做了一个基于WMSST结合MCNN-BiGRU的故障诊断小项目思路是用窗口多尺度同步压缩变换把非平稳信号转成高分辨率时频图再由多尺度卷积网络提取空间特征交给双向门控循环单元做时序建模最后在Matlab里把整套流程跑通。这篇就把整个方案的选型逻辑、网络结构和代码实现细节都梳理一遍适合正在做轴承故障诊断、齿轮箱故障诊断或者打算把时频分析和深度学习串起来用的朋友参考。1. 为什么是WMSST普通时频分析在处理非平稳故障信号时差在哪1.1 固定窗的STFT和变尺度CWT各有瓶颈刚开始做这个项目时我其实试过直接用短时傅里叶变换STFT拿时频图喂给卷积网络。STFT的原理并不复杂把信号按固定长度窗切开对每一段做FFT得到一个“频率随时间变化”的二维图。问题出在窗口长度上。窗口短时间定位准但频率分辨率差两个靠得很近的谐波分量会糊成一条宽带窗口长频率分辨率上去了时间定位又变得迟钝冲击信号被“平均”成一片根本看不出故障激发的瞬态成分。而旋转机械的故障信号恰恰是两类成分同时存在转频和啮合频率这类持续谐波需要高频率分辨率轴承剥落引发的冲击响应又是瞬态宽带信号需要高时间分辨率。STFT那一个固定窗口做不到两头兼顾我在实测中得到的时频图要么高频细节丢失要么低频边带模糊直接影响了后续分类效果。后来我换成了连续小波变换CWT。小波的好处是尺度可变高频用小尺度、低频用大尺度理论上可以比STFT更灵活。但实际用起来有两个麻烦。第一小波基函数的选择会影响结果同一条信号用不同小波基做出来的时频图差别很大而且这个选择没有特别通用的标准。第二CWT的频率轴并不是线性分布的尺度映射到实际频率需要额外换算处理不好会出现频率定位偏差。更关键的是CWT的时频图能量扩散比较明显尤其是在噪声背景下真正代表故障特征的那几条脊线经常被周围模糊的能量带掩盖。我用它来做后续卷积神经网络的输入时发现网络要花很大精力去“忽略”这些模糊区域分类准确率一直上不去。1.2 从SST到WMSST重排思想与多尺度窗口的补偿逻辑既然问题的核心是“时频能量不够集中”那就得从时频后处理思路入手。同步压缩变换SST的基本思想是先做一次CWT或STFT得到系数后不再把这些系数直接当作时频能量而是通过相位信息估计每一个系数对应的瞬时频率然后把分散在频率方向上的能量“压缩”到瞬时频率所在的位置上。效果很直观原本一团模糊的脊线会变成一条细线时频图的聚集性大幅提高。但标准SST也有矫枉过正的时候。瞬时频率估计在低信噪比环境下并不稳噪声成分会被错误地压缩成一条条伪脊线模型很容易被这些虚假结构干扰。我查了不少文献也试了几种改进版本最后选定了WMSST这个思路也就是窗口多尺度同步压缩变换Window-based Multi-scale Synchrosqueezing Transform。它的核心逻辑不复杂既然单一窗口长度无法同时照顾持续谐波和瞬态冲击那就并行使用多个窗口长度分别计算STFT系数再做同步压缩和多尺度融合。宽窗口对应的时频图频率分辨率高负责把谐波边带“压”清晰窄窗口对应的时间分辨率高负责把冲击成分的起始时刻定位准确。融合时按能量置信度加权哪一类的瞬时频率估计更可靠就多采信哪一类的能量分布。这里有个重要的实操细节WMSST的具体形式在不同文献里并不完全一样有的用多尺度小波有的用多窗口短时傅里叶。我项目里采用的是多窗口短时傅里叶变体实现起来最直观也方便在Matlab里逐段调试。多尺度计算会显著增加内存和耗时我试过用7个窗口尺度效果比3个时提升不到0.3%但训练时特征图占用的空间翻了一倍后来稳定控制在3到5个尺度。具体窗口长度参考表如下采样率大约12kHz频率分析范围0到6kHz窗口尺度窗函数长度点频率分辨率时间定位能力主要作用对象窄窗128较差强冲击瞬态成分中窗256中等中等调制边带宽窗512较好较弱转频、啮合谐波2. MCNN-BiGRU的结构拆解特征怎么被逐层抽出来2.1 为什么不能只用CNN空间特征不等于时序依赖时频图本质上是一个二维矩阵横轴是时间纵轴是频率灰度值表示该时刻该频率上的能量强度。卷积神经网络CNN特别擅长提取这种二维结构里的局部模式比如时频图上的连续横条纹、周期性脉冲竖线、斜向调制带。但CNN有一个天然短板它把整张图当作一个空间结构来处理卷积核的感受野是局部的即便堆很多层也很难显式建模“某个频率成分从弱变强再变弱”这种长程时间演化关系。而故障诊断里很关键的一点就是这个演化过程。举个例子滚动体经过损伤点时会周期性激起一段冲击响应幅度有起伏、频率有偏移这类时序模式光靠静态空间特征不容易被完整刻画。所以我把双向门控循环单元BiGRU加在了卷积层后面。GRU是循环网络的一种简化版本通过更新门和重置门来记忆序列中的有用信息比LSTM参数更少、收敛更快。双向的意思是除了按时间正向读一遍还把序列倒过来再读一遍这样某个时间步的特征既能利用前面的冲击历史也能参考后面的衰减趋势。我在实验里对比过单向GRU和双向GRU双向版本在验证集准确率上高出大约1个百分点考虑到样本量不大这个提升已经很可观了。2.2 多尺度卷积分支具体怎么设计MCNN的多尺度体现在并行分支上。我的输入是尺寸为128×128的单通道时频图三个分支分别用3×3、5×5、7×7的卷积核。为什么选这几个尺寸时频图上的故障特征有两种典型形态窄而短的冲击亮线适合用3×3的小卷积核捕捉宽而长的谐波带需要跨越更多像素5×5和7×7的卷积核能覆盖更大的感受野。三种尺寸并行提取后做通道拼接相当于让网络同时看到“细节局部形状”和“整体纹理走向”。每个分支的具体结构都是“卷积层→批归一化→ReLU→最大池化”池化用2×2、步长2。通道数方面三个分支我都用了32个卷积核拼接后输出96个通道。如果你的显存或内存比较紧张一个更经济的做法是5×5分支拆成两个连续的3×3卷积层7×7分支拆成三个连续的3×3卷积层。这个替换基于一个经典结论多层小卷积核堆叠和大卷积核有相近的感受野但参数量更少。我在一个对比配置里试过准确率几乎没有下降参数量少了大概20%训练速度明显更快。分支卷积核尺寸卷积核数量池化输出尺寸示例假设输入128×128分支13×3322×2最大池化64×64×32分支25×5322×2最大池化64×64×32分支37×7322×2最大池化64×64×32拼接层———64×64×962.3 特征图怎么喂给BiGRUMCNN输出的特征图形状是高度乘宽度乘通道数这里高度对应频率方向宽度对应时间方向。要把这个三维特征变成BiGRU能接受的序列我的做法是把每个时间位置上的所有频率信息和通道信息拼成一个特征向量这样原本的特征图就转化成了“一个长度为W’的序列每个时间步对应一个长度为C’×H’的特征向量”。换句话说频率维度和通道维度合并成特征维度时间维度保留为序列长度。这样BiGRU真正建模的是“同一时刻频率结构如何组合以及这些组合如何随时间演变”。BiGRU的隐藏单元数我设为128。CG需要说明的是BiGRU层之后我没有直接把最后一个时间步的输出拿来做分类而是对所有时间步的隐藏状态做平均池化。原因是故障信号中总有部分时间段处于平稳运行状态这部分时间步对分类的贡献不大如果直接取最后一步相当于把决策建立在某一个时刻上容易受随机噪声影响。平均池化相当于让模型综合整个时间序列的证据再做判断鲁棒性更好。2.4 分类头和损失函数平均池化后的特征向量进入一个全连接层神经元数量128个激活函数ReLU然后接一个Dropout层丢弃率我设置为0.4。最后一层是类别数对应的全连接层以本项目为例是4类故障状态经过Softmax输出归一化概率损失函数用交叉熵。这里的Dropout比一般CNN网络设置得高一些因为循环网络本身参数多样本量又有限不加高Dropout很容易过拟合。我试过Dropout0.2时验证集损失在训练后期开始反弹改成0.4之后曲线明显平稳。3. Matlab环境下的数据准备与模型实现从信号到可训练样本3.1 数据怎么分滑动窗口与重叠率故障诊断项目里大家最常用的一招是滑动窗口。一段连续振动信号动辄几万、几十万个采样点没法直接整段输入网络。我手上的原始数据来自某实验台采集的振动加速度信号每个工况记录了多段数据采样率12kHz。我的做法是先把每段原始信号按固定长度截成样本窗口长度选2048个点约0.17秒足以覆盖故障冲击的多个周期。滑动步长选512个点也就是重叠75%。重叠的目的是增加样本数量尤其是故障样本偏少的时候这个手段很有效。但这里有一个特别容易踩的坑我后面专门用一章讲现在先提一句滑动窗口生成的样本不能直接全部扔进随机打乱然后划分训练集测试集必须按“原始信号段”来划分。我当时的做法是8段原始数据做训练2段做测试段内的所有窗口样本归属到同一个集合。理由很简单同一段信号里相邻窗口高度相关如果训练集和测试集里混进了同一条原始信号的窗口模型相当于提前见过答案验证集准确率会被严重高估。% 按原始数据段划分文件列表 dataDir path/to/mat/files; files dir(fullfile(dataDir, *.mat)); trainIdx 1:8; testIdx 9:10; % 对每个文件做滑窗 winLen 2048; stepLen 512; for i 1:length(files) load(fullfile(dataDir, files(i).name), vibSig); n floor((length(vibSig) - winLen) / stepLen) 1; for j 1:n startIdx (j - 1) * stepLen 1; samples{i, j} vibSig(startIdx : startIdx winLen - 1); end end3.2 WMSST时频图生成参数与预处理数据切好之后就是WMSST变换。Matlab里没有现成的WMSST函数但我们可以基于spectrogram函数搭出来。我当时的参数是窄窗128点、中窗256点、宽窗512点三个尺度都用Hann窗FFT点数统一取512帧重叠率75%。每个窗口尺度都算一组短时傅里叶系数然后利用相位差分估计瞬时频率把系数沿频率方向累加到瞬时频率对应的位置。最后按照能量置信度把三个尺度的结果融合成一张二维时频图。代码核心流程大概是下面这个样子winLenList [128, 256, 512]; overlapRatio 0.75; nfft 512; sstMaps cell(1, length(winLenList)); for k 1:length(winLenList) [s, f, t] spectrogram(x, hann(winLenList(k)), ... round(winLenList(k) * overlapRatio), nfft, fs); % 通过相位差分估计瞬时频率索引 % 将短时傅里叶系数沿频率方向重排到瞬时频率脊线附近 % 得到该尺度下的同步压缩时频图sstMaps{k} end % 多尺度融合按不同尺度的置信度加权平均 sstFused mean(cat(3, sstMaps{:}), 3); sstFused imresize(sstFused, [128, 128]); sstFused (sstFused - min(sstFused(:))) / (max(sstFused(:)) - min(sstFused(:)));同步压缩的内部实现确实有门槛相位差分处理边界、频率索引映射这些细节都需要仔细调试我这里只体现了整体框架。我个人建议先固定一个窗口尺度把SST的脊线调清晰再扩展到多尺度融合不要一上来就三个尺度一起调不然哪个环节出问题都很难定位。时频图生成完成后统一缩放为128×128归一化到0到1之间。这里缩放到128×128是权衡了信息保留和训练速度的选择如果再缩成64×64转速波动等细节会被抹掉分类准确率会掉两个点左右。3.3 MCNN和BiGRU怎么用Matlab串起来Matlab的Deep Learning Toolbox对“图像输入→CNN→序列→BiGRU→分类”这种混合结构支持得不如Python框架顺手。如果你试图用layerGraph强行连接图像层和序列层大概率会因为层类型不匹配报错。我项目里实际采用的是两步训练法这也是在Matlab里实现这类混合模型最稳的方案。第一步单独训练MCNN网络。输入是WMSST时频图输出是故障类别。训练好之后删掉最后的全连接分类层用activations函数提取中间拼接层输出的特征图。因为MCNN的输入本身有时频图的空间结构中途特征图可以按时间轴方向展开成序列。具体来说特征图尺寸是64×64×96我把频率维和通道维合并得到序列长度64每个时间步的特征维度是64×966144。第二步把这个序列和对应标签组装成sequence数据训练BiGRU分类网络。因为Matlab的gruLayer默认是单向的我是自己搭两个方向相反的GRU层一个处理正向序列另一个把序列翻转后处理逆向序列最后把两路输出拼接起来等效实现双向GRU。代码示意如下% 第一阶段训练MCNN特征提取网络 mcnnNet trainNetwork(imdsTrain, layersMCNN, optsMCNN); % 提取中间层特征并整理成序列格式 featTrain activations(mcnnNet, imdsTrain, concat, OutputAs, channels); % featTrain尺寸[64, 64, 96, numSamples] seqTrain permute(reshape(featTrain, 64, [], numSamples), [2, 1, 3]); % 第二阶段训练BiGRU分类网络 layersBiGRU [ sequenceInputLayer(6144) gruLayer(128, OutputMode, last) fullyConnectedLayer(128) reluLayer dropoutLayer(0.4) fullyConnectedLayer(4) softmaxLayer classificationLayer]; bgruNet trainNetwork(seqTrain, labelsTrain, layersBiGRU, optsBiGRU);这里需要说明一个现实取舍两步训练法的特征是MCNN在图像分类任务上学到的它不会因为BiGRU的梯度反馈而进一步调整。换句话说是先固定特征提取器再训练时序分类器理论上有性能上限。但我在实验中对比过因为WMSST已经把时频图的质量做得很高MCNN提取的特征已经足够干净两步法相比理想中的端到端方案准确率只差不到0.5%在工程上完全可以接受。如果你坚持想端到端训练就得自己写自定义可微分层把图像特征重排成序列插入到网络中间工作量会翻倍我目前评估下来性价比不高。4. 训练策略与实测效果对比调参过程与结果验证4.1 先把训练参数定下来训练策略直接决定模型能不能收敛以及会不会过拟合。我的数据集大概有9000个训练样本、2200个测试样本样本量不算大所以训练参数要往“稳”的方向调。优化器选Adam初始学习率1e-3。学习率1e-2太大我在第一阶段MCNN训练时试过一次前两轮准确率就到90%但后面开始震荡验证集损失不降反升典型的学过头了。批大小选32再大一点虽然训练速度快但梯度方向方差变大泛化效果略差。最大训练轮次60轮配合早停机制Patience设为10轮验证损失连续10轮不下降就提前终止。BiGRU训练阶段学习率我降到1e-3以下改为5e-4。原因是循环层对梯度的敏感度比卷积层更高学习率稍大就容易在时间步反传过程中出现梯度爆炸。另外我在自定义训练循环里加了梯度裁剪阈值设为5这一步避免了一旦出现异常样本导致整个模型参数崩溃的情况。如果你用trainNetwork默认训练适当降低学习率和早停也能达到类似效果。阶段优化器初始学习率批大小最大轮次早停轮次MCNN特征提取Adam1e-3326010BiGRU分类Adam5e-43260104.2 训练曲线怎么看损失下降和验证集准确率训练过程我一般看两个东西训练集损失和验证集准确率。MCNN阶段前10轮损失下降特别快从初始的1.2左右降到0.3附近这个阶段说明网络正在快速学习WMSST时频图里的整体结构。10到30轮之间是比较难熬的阶段损失下降速度明显变慢准确率从92%慢慢爬到95%左右。如果这个阶段验证集损失反而开始上升不要犹豫先加Dropout或者减小学习率。BiGRU阶段收敛更平滑因为输入的特征已经是相对高级的语义特征模型只需要学时序依赖大约20轮左右就稳定了。我最后测试集上的混淆矩阵大致如下四个类别分别是正常、内圈故障、外圈故障和滚动体故障。整体准确率97.5%。注意看滚动体那一行它最容易跟内圈故障混淆原因是滚动体故障信号经过滚道传递后衰减严重冲击特征跟内圈故障有部分相似性。这类混淆信息很有用它提示我后续可以增强滚动体故障样本的数量或者针对性地设计更细分的特征通道。实际\预测正常内圈故障外圈故障滚动体故障召回率正常54632198.9%内圈故障25218996.5%外圈故障15553398.4%滚动体故障312453896.6%4.3 对比实验和基线方法的差距为了说清楚每个模块的作用我做了几组对比实验保持数据集划分、训练参数完全一致只替换信号处理和网络结构。第一组是STFT时频图加普通CNN准确率94.2%第二组是CWT时频图加普通CNN94.8%第三组SST时频图加普通CNN95.8%第四组WMSST加普通CNN96.4%最后一组WMSST加MCNN-BiGRU97.5%。方法测试集准确率STFT CNN94.2%CWT CNN94.8%SST CNN95.8%WMSST CNN96.4%WMSST MCNN96.6%WMSST MCNN-BiGRU97.5%从这组数据能看出两个结论。第一时频预处理本身对模型有实打实的帮助从STFT到WMSST提升了2.2个百分点这印证了WMSST在非平稳信号上确实能提供更干净的特征表达。第二单纯把CNN换成MCNN提升有限只有0.2个百分点但加上BiGRU之后提升到0.9个百分点。这说明在这个任务里时间动态信息比多尺度空间信息更值得挖掘网络结构的重点应该放在时序建模上。我还特别测了一组低信噪比数据方法是往原始信号里加高斯白噪声使信噪比降到5dBWMSSTMCNN-BiGRU的准确率仍然有91.7%而STFTCNN只有82.4%。噪声越大WMSST的优势越明显。4.4 特征可视化确认模型学的不是随机模式除了准确率我还用t-SNE把MCNN和MCNN-BiGRU提取的特征分别降到二维看了一下。MCNN的特征分布里正常类聚得很紧但三类故障之间有明显重叠尤其是滚动体故障样本零散地落在内圈故障区域边缘。加上BiGRU之后的特征分布明显改善四类样本各自形成了比较紧凑的簇簇与簇之间的间隙也更清晰。虽然t-SNE的可视化有一定主观性但它能帮我们快速判断模型是否学到了有区分度的特征。如果降维后类别完全混在一起即使准确率看着还行也要警惕是不是数据划分出了问题比如前面说的数据泄漏造成的假象。5. 实际项目中容易踩的坑与解法5.1 数据泄漏验证集虚高的头号原因我在一开始犯过这个错误。那时候我为了图省事把所有滑动窗口样本集中起来随机打乱后按82划分训练集和测试集。结果测试集准确率高达98.5%我当时还挺高兴但后来按原始信号段重新划分之后准确率掉到了95.3%。这3个百分点的差距就是数据泄漏造成的。道理很简单同一条原始振动信号切成几十个重叠窗口相邻窗口内容高度相似随机划分时训练集和测试集必然混入大量“近似孪生样本”模型的泛化能力被严重高估。这个问题在故障诊断项目里特别隐蔽因为每个原始信号段都会被切成几百个窗口你根本察觉不到测试集里已经渗入了训练集的“熟人”。所以划分数据的第一原则就是按原始信号段分配而不是按样本分配。宁可训练样本少一点也要保证测试集完全独立。5.2 样本不均衡带来的诊断偏向故障诊断数据集天然存在不均衡。正常工况样本最容易采集故障工况尤其是早期故障样本很难积累滚动体故障又比内圈外圈更难激发。模型在样本不均衡时通常会偏向样本量大的类别体现在准确率上就是正常类很高、故障类偏低。我处理这个问题的办法是先对少数类样本提高滑动窗口重叠率比如正常类步长512点滚动体故障类步长降到256点用数据增强把样本数量拉平。如果增强之后还是不均衡就在损失函数里给每个类别乘一个权重数值等于类别样本数的倒数归一化。Matlab默认的classificationLayer不支持直接设置类别权重但我改成自定义训练循环后在交叉熵计算里按权重乘一下就行代码量不大。5.3 时频图尺寸与内存压力WMSST多尺度计算出来的时频图原始尺寸可能非常大。我这边的数据12kHz采样率FFT点数512时间帧数随信号长度变化一个5秒的样本做出来可能是一张257×400的矩阵这还算能接受。但如果采样率更高、FFT点数更大比如把FFT点数改成2048时频图高度就变成1025三维特征图存起来非常占内存。我的做法是严格控制FFT点数而不是事后用imresize硬缩。前者是把频率分辨率提前设定好信息保留更自然后者容易把细小的频率边带直接抹掉伤信息。统一输出尺寸我定为128×128训练时内存占用稳定速度也可接受。如果遇到特别长的样本可以分段生成多张时频图再用投票方式综合判定比把整张图塞进内存更稳妥。5.4 不要过早迷信模型先检查信号处理模块项目做完之后我复盘了一下真正影响最终效果的环节排序是数据划分方式大于WMSST参数配置大于网络结构调整。很多人一开始就把精力花在改网络层数、换激活函数上但如果你输入的是模糊的时频图网络再复杂也救不回来。反过来当WMSST参数调好、时频图脊线清晰哪怕用一个三层的简单CNN也能跑出96%左右的准确率。所以我的建议是每调完一步信号处理就把时频图画出来肉眼看一眼确认故障特征频率附近有清晰的脊线再往下调网络结构效率会高很多。另外还有一个容易被忽略的小问题Matlab的spectrogram函数返回的频率轴是从0到奈奎斯特频率如果你在后面做同步压缩时用的是索引映射一定要搞清楚时间轴和频率轴的排列顺序。我第一次就在维度顺序上吃了亏画出来的图整体转了90度CNN照样能学到一部分特征因为网络对图像方向不敏感但特征语义就变得不可解释了。这个属于细节问题但排查起来非常费时间别问我怎么知道的。这套方案从信号处理到深度学习分类走下来我最深的感觉是不同模块之间是强耦合的WMSST的质量决定特征上限MCNN-BiGRU负责把上限逼近。如果你也想在Matlab里复现建议先按原始信号段把数据切干净再把单尺度SST调明白最后做多尺度融合和网络训练一步步走整体跑通并不难。后续想继续改进的话可以给BiGRU的隐藏状态加一个注意力机制让模型自动给关键时间步更高的权重尤其对滚动体故障那种冲击特征偶发的情况应该还能再挤出来一点准确率。
阅读完成 · 觉得有帮助?
咨询建站