资讯动态

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

发布时间:2026/10/20 9:09:03 来源:尧图企业网站定制
做旋转机械故障诊断的朋友大概都经历过这种阶段手里攒了一堆振动加速度信号要判断轴承是内圈故障、外圈故障还是滚动体故障。盯着时域波形看了半天除了知道信号很“吵”什么也看不出来。传统做法是先算峭度、均方根、包络谱之类的手工特征再喂给随机森林或者支持向量机特征选得顺不顺心直接决定准确率天花板。这几年大家一股脑涌向深度学习端到端模型确实热闹但工业现场的小样本条件下经常翻车。今天这篇博文讲讲我自己在这两者之间踩出来的一条路线用改进的时频分析做前端预处理把一段一维振动信号变成一张能量聚集的时频图再用“多尺度卷积抽取空间特征、双向门控循环单元抽取前后时序依赖”的混合网络去分类故障类型核心方法对应标题里的WMSST 结合 MCNN-BiGRU全部用 Matlab 实现从数据到训练到评估的完整管线我都跑通了。这个方案既保留了人工先验的物理可解释性又把深度模型真正塞进了工程现场同时解决了纯端到端模型在样本量不足时容易过拟合的问题。无论你是在校做故障诊断课题还是正准备把深度学习方法往工业数据上落地这篇内容应该能帮你少走不少弯路。主体内容的组织我按“为什么这么做 — 里面原理是什么 — 代码怎么写 — 坑在哪里”的顺序来展开每一部分都会把参数选择和失败尝试一并交代清楚尽量让你能照着复现。1. 整体思路拆解为什么把WMSST和MCNN-BiGRU凑在一起1.1 传统故障诊断的瓶颈特征要“有人味”才行常用的故障诊断流程本质是个“特征工程 浅层分类器”的组合。特征工程这个环节过去靠的是人对信号机理的理解轴承内圈损伤会产生周期性冲击外圈损伤的冲击调制形式不同滚动体故障还和保持架转频耦合在一起。懂机理的人能写出好的特征函数但这里面有两层尴尬。第一层尴尬是现场信号噪底高、工况波动大很多理论特征会在实测数据里严重“变形”。比如理想包络谱里那条故障特征频率线在转速波动下可能变成一片模糊的边带手工提的特征遇上这种情况就抓瞎了。第二层尴尬是特征选择本身是个经验活。同一份数据A 同学提了 30 个特征用顺序前向选择挑出 7 个准确率 91%B 同学用同样的特征池做 PCA 降维只留 5 个主成分准确率到了 94%。最后报告里每个数字都能自圆其说但换个工况这套特征很可能又失灵了。深度学习的思路是把特征工程这一步交给网络自己去学但有它的前提——海量标注样本和足够的算力。实际项目里故障样本往往只有几百段标签还得靠拆机确认根本喂不饱一个大型网络。我一开始也试过直接把原始振动信号丢给一维 CNN效果不算差但也不惊艳而且诊断结果很难向同事解释“网络到底学到了什么物理特征”。后来我意识到问题不在深度模型本身而在于我们喂给深度模型的不是“适合被深度学习理解的表示”。1.2 WMSST 的定位用改进时频分析把信号变成“看得见的图片”故障冲击信号最本质的特征体现在频率成分随时间的变化关系上。普通频谱把时间信息抹掉了包络谱又依赖人为选定解调频带只有时频分析能同时展示“什么时刻有什么频率成分”。传统的短时傅里叶变换受窗函数限制时间分辨率和频率分辨率不可兼得小波变换比它好一些但能量依然会沿尺度方向扩散时频图看起来“糊糊的”故障冲击的瞬态细节容易被模糊掉。同步压缩小波变换Synchrosqueezed Wavelet Transform简称 SST就是在小波变换基础上做一次“能量重排”先算出每个小波系数的瞬时频率再把分散在相邻尺度上的能量按瞬时频率“压缩回”真实的频率位置。效果很像把一张失焦照片重新对焦时频脊线明显锐利很多冲击特征一眼就能看见。Matlab 信号处理工具箱里自带的wsst函数就是干这个的。WMSST可以理解成在 SST 基础上继续加了“多尺度加权思考”实际振动信号里既有低频转频分量、又有高频冲击谐振分量单一尺度下做同步压缩容易顾此失彼。我的做法是对不同分析尺度分别做同步压缩再按尺度贡献度加权叠加低频段的权重压低一些、高频冲击对应的尺度权重拉高一些最后得到的时频图能量更集中、背景噪声更干净。这一步做下来原有的“信号处理先验”就被固化到了输入表示里后续网络更轻松。1.3 模型架构逻辑MCNN负责“看”BiGRU负责“读”时频图本质上是一张二维图像横轴是时间、纵轴是频率、颜色深浅代表能量大小。用卷积神经网络CNN来提取图像特征是非常自然的选择。但故障时频图有个特点不同故障类型对应的特征尺度差别很大。滚动体故障的冲击特征在图上可能是几个离散的高亮“斑点”内圈故障会呈现周期性的宽带调制纹理外圈故障的冲击特征相对稳定。单一固定感受野的卷积核很难同时兼顾“局部冲击细节”和“全局调制结构”。因此我采用了MCNN多尺度卷积网络也就是在同一个输入上并行拉出几条卷积分支每条分支用不同尺寸的卷积核看图。小卷积核盯细节大卷积核看整体最后把各分支的特征拼起来。这样网络从一开始就能在不同尺度上同时提取互补信息。CNN 把空间纹理特征抓出来之后还有一个信息没被充分利用就是时频图从左到右的时间顺序关系。故障冲击不是随机出现的它有严格的周期性冲击序列的间隔直接反映故障特征频率。普通 CNN 在一个卷积窗口内虽然能捕捉局部先后关系但跨较长时间周期的依赖就无能为力了。这里我引入了BiGRU双向门控循环单元让网络正向读一遍“频率成分随时间如何变化”再反向读一遍把两个方向的隐藏状态拼接在一起。换句话说MCNN 负责看清楚“图上有什么模式”BiGRU 负责读懂“这些模式是怎么按时间演化出来的”。两者一组合空间特征和时序特征就都吃到了。2. 把原理讲成人话WMSST 和 MCNN-BiGRU 内部到底在做什么2.1 WMSST 的能量重排过程同步压缩类方法的核心思想听起来复杂拆成三步去看就通了。第一步把原始信号做连续小波变换得到各尺度下的小波系数。这些小波系数的绝对值大小表示信号在该尺度大致对应某频带与该时刻的“匹配程度”。第二步对小波系数求相位关于时间的导数估计出每个系数对应的瞬时频率。注意同一时刻同一频率分量的能量往往被分散到相邻的多个尺度上去了这是小波变换自身的性质。第三步就厉害在“重排”把分布在相邻尺度上的系数全部按瞬时频率重新归位到频率轴上最准确的位置上叠加到一起。这个重排过程就像你把一本书里的字按拼音字母顺序重新排列原来散落在各页、各行的同一个字都回到同一个格子整本书瞬间变成一部字典查词效率高得多。对应到时频图上能量沿着频率轴更集中时频脊线更细更清晰随机噪声因为没有稳定的瞬时频率关系不容易被“压缩”进某个位置所以背景变得更干净。我在实际实现 WMSST 时用的并不是纯手写算法而是基于 Matlab 自带的wsst做扩展。wsst已经处理好了同步压缩的核心流程我在此基础上做了两个补充一是对信号先按频带分段在几个关键子带上分别做同步压缩再把子带结果按等残留噪声功率原则加权融合这就是“多尺度加权”这一步二是对输出矩阵做幅值归一化和二维插值统一缩放到128×128方便直接作为深度网络输入。低频能量占比高的样本如果不做归一化整张图几乎全是低频亮斑网络很容易忽略高频冲击细节这个坑下面会展开说。2.2 MCNN 的多尺度分支设计MCNN 的多尺度体现在同一个输入上并行使用不同大小的卷积核。我一开始设计的版本是三条分支分别用3×3、5×5和7×7的卷积核。3×3分支感受野最小适合捕捉冲击特征形成的孤立高亮点5×5分支看中等范围的纹理比如调制的边带7×7分支覆盖更大范围识别整段周期的重复模式。每条分支内部是“卷积批归一化ReLU最大池化”的标准组合池化步长取 2把特征图尺寸逐步压下来。批归一化在这里很关键。时频图的数值分布在不同样本之间差异极大有的样本能量集中在低频有的样本冲击幅值很高不做归一化直接进卷积层前几层参数会被少数极端样本主导。批归一化能在每个批次内把激活值拉回标准分布附近让训练稳定不少。分支合并的方式我也试了几种。最早把三条分支的特征图做逐元素相加后来发现3×3分支的特征尺度和其他分支不太一致直接加会互相干扰。后来改成按通道维度拼接concatenation把三个分支的输出在通道轴上堆叠起来让后续网络自己去学怎么组合效果稳定很多。这里给一个建议多尺度分支越多模型参数量越大对小样本数据集来说三条分支已经足够再往上加分支收益很小。2.3 BiGRU 双向信息捕捉GRU 是 LSTM 的轻量改良版内部有两个门更新门决定上一时刻的信息保留多少重置门决定当前时刻的候选状态参考多少历史信息。相比 LSTMGRU 少了一个门参数量更小在小数据集上更不容易过拟合训练速度也快一些效果几乎没有差别。双向的意思是序列既从左往右读一遍又从右往左读一遍。放在时频图上特别有效因为故障冲击具有周期性某个时刻的亮点往往和前后几个周期内的亮点相互呼应。单向 GRU 只能看到过去看不到未来可能漏掉“在这个冲击之后固定频率处会出现下一次冲击”的规律。双向 GRU 把正向隐藏状态和反向隐藏状态拼在一起等于同时拿到了上下文依赖。但在把 CNN 的输出接给 BiGRU 时有一个维度匹配问题要处理。CNN 输出是四维特征图批量、高、宽、通道BiGRU 期望的输入是序列数据时间步 × 特征维 × 批量。我的做法是先将多条分支拼接后的特征图做全局平均池化把高和宽两个维度压成 1得到一个长度等于通道数的特征向量再把时频图沿时间方向平均切成若干段每一段经过 CNN 后得到一个特征向量整张图就变成了一个由多个时间步组成的特征向量序列这样就能合法地喂给 BiGRU。分段数取 8 到 16 比较合适太少了序列信息不足太多了每个时间步内的空间上下文不够后面我会给出一张参数效果对照表。2.4 特征融合与分类头BiGRU 输出后接一个全局池化把双向隐藏状态压成一个定长向量然后接两个全连接层第一层 128 个神经元加 ReLU 和 Dropout第二层神经元数等于故障类别数。最后的输出接 Softmax计算交叉熵损失。这里的 Dropout 比例我建议设到 0.3 到 0.5因为故障样本数量普遍不大全连接层最容易过拟合。训练起来之后我发现整体网络里参数最多的部分并不在卷积层而在 BiGRU 单元和全连接层。卷积层因为共享权值参数量相对可控BiGRU 的每一个门都需要矩阵运算隐藏单元数一上去参数量就暴增。所以我建议 BiGRU 的隐藏单元数控制在 64 到 128 之间不要盲目加大。隐藏单元数从 128 加到 256准确率提升不到半个百分点显存占用和训练时间却接近翻倍性价比较低。3. Matlab 手把手实现从振动信号到时频图再到模型训练3.1 环境准备与数据整理整个流程在 Matlab R2023a 上完成需要 Signal Processing Toolbox、Wavelet Toolbox 和 Deep Learning Toolbox。机器是一台普通工作站没有独立显卡纯 CPU 训练所以我把训练轮数限制在 30 轮左右单轮耗时约两三分钟整体时间完全可以接受。如果你手上有 NVIDIA 显卡可以开启trainNetwork的ExecutionEnvironment,gpu选项速度能快一个量级。数据方面用的是某实验台采集的滚动轴承振动信号采样频率 12000 Hz包含正常状态和四种故障状态内圈故障、外圈故障、滚动体故障、保持架故障训练集每类 150 段样本测试集每类 50 段样本。每段样本长度取 1024 个点相当于约 85 毫秒的振动信号。这个长度下转频的低频成分能完整覆盖几个周期故障冲击的周期特征也能看到如果采样率更高比如 48 kHz 以上样本点数可能要扩到 2048 或 4096否则低频分辨率不够。数据整理的几个要点分段时要有重叠。我是按 50% 重叠滑窗切段的相当于把有限的数据量扩充了一倍对后续深度学习非常有帮助。切段前先做零均值化。原始采集信号常含直流分量不去掉的话时频图低频部分会被一条水平亮线占据影响归一化效果。按类别分别打标签用categorical类型组织Matlab 的分类层要求标签是类别变量。数据集划分要按“段”而不是按“时间窗”随机打乱同时确保训练集和测试集来自不同的时间段避免相邻样本高度相似导致数据泄漏。3.2 生成 WMSST 时频图的代码骨架以 1024 点的一段信号为例生成一张 128×128 的时频图。下面的代码是我在项目里实际使用的简化骨架去掉了与特定数据格式耦合的部分保留了完整处理思路function tfImg wmsst2img(x, fs, targetSize) % WMSST 时频图生成简化骨架 % x: 一维振动信号 % fs: 采样频率 % targetSize: 输出图像尺寸如 [128 128] % 1) 零均值化 x x - mean(x); % 2) 基于 Morlet 小波的同步压缩小波变换 [sst, f] wsst(x, fs); % 3) 取幅值矩阵转成 dB 尺度压缩动态范围 tf abs(sst); tf 20 * log10(tf eps); % 4) 对频率轴做对数加权低频权重低高频冲击权重高多尺度加权的核心 fw 1.0 ./ (1.0 exp(-(log(f 1) - 3.0) / 0.8)); % 逻辑加权曲线 fw fw(:); tf tf .* fw; % 5) 归一化到 0-1 并缩放到目标尺寸 tf mat2gray(tf); tfImg imresize(tf, targetSize); end实际运行时wsst输出的频率轴不是均匀分布的在低频段分辨率高、高频段分辨率低。直接imresize会破坏这种非均匀性所以在缩放前我会在频率方向上先把结果插值到均匀的频率网格再缩放到 128 维。这一步用interp1就能完成算是一个容易忽略但很重要的细节。生成全部样品的时频图之后把每张图堆叠为一个H×W×1×N的四维数组通道维度是 1灰度图N 是样本数。这里不要存成 JPEG 之类的有损图像格式直接用.mat文件保存为 double 类型避免图像压缩带来的高频细节损失。3.3 MCNN-BiGRU 模型搭建Matlab 里用layerGraph一点点搭网络比较繁琐但也比较可控。我给出一个可运行的骨架重点是展示多尺度分支怎么建立、序列怎么接入 BiGRU% 输入层128x128 灰度时频图 inputLayer imageInputLayer([128 128 1], Name, input); % 分支13x3 小卷积核 branch1 [ convolution2dLayer([3 3], 16, Padding, same, Name, conv1_1) batchNormalizationLayer(Name, bn1_1) reluLayer(Name, relu1_1) maxPooling2dLayer([2 2], Stride, 2, Name, pool1_1)]; % 分支25x5 中卷积核 branch2 [ convolution2dLayer([5 5], 16, Padding, same, Name, conv2_1) batchNormalizationLayer(Name, bn2_1) reluLayer(Name, relu2_1) maxPooling2dLayer([2 2], Stride, 2, Name, pool2_1)]; % 分支37x7 大卷积核 branch3 [ convolution2dLayer([7 7], 16, Padding, same, Name, conv3_1) batchNormalizationLayer(Name, bn3_1) reluLayer(Name, relu3_1) maxPooling2dLayer([2 2], Stride, 2, Name, pool3_1)];三条分支的输出特征图尺寸一样都是64×64×16通过一个depthConcatenationLayer拼成64×64×48。接着要接一个globalAveragePooling2dLayer把高和宽压缩掉得到长度为 48 的向量。如果你想用“分段序列接 BiGRU”的方式则需要在前面的卷积层里做一点改造不要整张图做全局池化而是把 128×128 的输入均分成 8 个 128×16 的条带每条带经过共享卷积后产生一个特征向量8 个向量拼成序列。这个实现要稍微复杂一些我在搭建时更推荐先跑通全局池化后的简单版本再迭代到序列版本。BiGRU 接入部分关键代码bigruLayer bilstmLayer(64, OutputMode, last, Name, bigru);OutputMode参数很关键。如果你只需要最后时刻的隐藏状态作为整个序列的特征表示就设成last如果你需要每个时间步的输出都保留下来供后续层次继续抽取则设成sequence。我在简单版本里用last在序列版本里用sequence再加一层全局平均池化。前者轻量后者表达能力更强但训练时间会增加。最后接全连接层、Softmax 层和分类层fcLayer [ fullyConnectedLayer(128, Name, fc1) reluLayer(Name, relu_fc) dropoutLayer(0.4, Name, dropout) fullyConnectedLayer(numClasses, Name, fc2) softmaxLayer(Name, softmax) classificationLayer(Name, output)];3.4 训练配置与参数调优训练选项方面我用的配置如下options trainingOptions(adam, ... InitialLearnRate, 0.001, ... MiniBatchSize, 32, ... MaxEpochs, 30, ... LearnRateSchedule, piecewise, ... LearnRateDropFactor, 0.5, ... LearnRateDropPeriod, 10, ... L2Regularization, 0.001, ... Shuffle, every-epoch, ... Verbose, true, ... Plots, training-progress);其中L2Regularization的正则系数值得细说。我在小样本上试过从 0.0001 到 0.01 的几组值发现 0.001 附近最稳。设太大模型欠拟合训练集准确率都上不去设太小测试集和训练集准确率差距会拉大明显过拟合。如果样本量更少每类只有几十段L2 系数可以加到 0.005同时 Dropout 提到 0.5。Adam 优化器的初始学习率 0.001 是个比较通用的起点但在 MCNN-BiGRU 这种混合结构里不同层的学习率需求是不一样的。卷积层因为共享权重学习率可以稍微大一点BiGRU 层因为要学时序门控参数学习率太大容易震荡。我自己没有在 Matlab 里做分层学习率trainingOptions不支持细粒度分层设置而是改用整体较小的初始学习率并配合分段下降效果同样不错。如果你实在想手动控制可以考虑训练两步先用较大学习率冻结 BiGRU 只训卷积部分再解冻 BiGRU 用小学习率微调这在 Matlab 里可以通过两次trainNetwork实现。一个小建议训练过程中时刻盯住“训练准确率”和“验证准确率”的曲线差。正常情况两者差距应该保持在 5 个百分点以内如果差距连续多轮扩大到 10 个点以上就说明网络开始在记训练样本了应该立即降低学习率或者提高 Dropout 与正则化系数。不要让训练跑满全部轮数发现过拟合征兆就提早停下来常规做法是在验证准确率不再提升时连续观察几个 epoch,如果没变好就中断保存当前最优的模型。4. 常见问题与排查技巧实录4.1 时频图尺寸和计算量的矛盾时频图的分辨率直接决定模型输入层的尺寸。我最初尝试用 256×256 的时频图作为输入局部细节确实更丰富但网络参数量增加后普通 CPU 训练时间翻了好几倍而且小样本下准确率并没有提升。原因在于128×128 的输入下最细的卷积核3×3已经能覆盖 3 个像素点对应频率分辨率约 94 Hz足以分辨轴承内圈和外圈故障的特征频率再往下增加分辨率增加的更多是噪声细节而非有效特征。如果你想在当前数据上快速确认多大尺寸合适有个简单实验把时频图缩小到 64×64 跑一个快速版本再看 128×128 的效果如果准确率提升非常明显说明信息确实不够值得试 256×256如果提升不到 1 个百分点就别折腾了小尺寸会平滑噪声、增强泛化能力效果甚至更好。4.2 小样本带来的过拟合问题在故障诊断场景里每类样本几百段已经算“数据充足”了实际项目里经常每类只有三四十段。这种情况下MCNN-BiGRU 这种结构注定会过拟合我踩过最深的坑是训练集准确率即使在训练后期依然保持 100%测试集却一直在 82% 左右徘徊提升非常缓慢。针对这种情况我建议按顺序尝试四招。第一招是数据增广在时频图上做随机平移、随机掩码、小幅旋转10 度以内和添加高斯噪声效果立竿见影第二招是加大 Dropout 和 L2 正则配合早停第三招是降低模型容量比如把卷积核数量从 16 减到 8、隐藏单元数从 128 减到 64减少网络可学习的“记忆空间”第四招是转移到迁移学习框架用在一批大型时频数据集上预训练过的特征提取网络做冻结主干只训练最后的分类头。我在真实工程数据上试过迁移学习加微调往往比从零训练小模型更稳。还有一个容易忽略的细节标签一定要足够干净。手动标注故障类型时如果相邻样本在时间上靠得很近滑窗切段后互相高度相似很容易让网络“背下”特定波形而不是学到普适特征。建议划分训练集和测试集时限时按时间先后切分训练集用前 70% 时间段测试集用后 30% 时间段不要全局随机打乱。这样测试集的准确率才接近部署现场的真实效果。4.3 训练不收敛或震荡的排查MCNN-BiGRU 结构里最常导致训练不稳定的是 BiGRU 输入特征尺度不一致。时频图经过卷积和池化后特征图的数值范围会随着不同分支的变化而变化如果某个分支的激活值比另一个分支大很多拼接后的特征向量尺度就会失衡进 BiGRU 之后矩阵乘积容易产生梯度爆炸。训练曲线出现“断崖式下跌”或 loss 突然变成 NaN多半就是这个原因。我的排查步骤是先检查训练曲线前几个 iteration 的 loss 是否跳跃过大如果是降低初始学习率到 0.0003 再试然后在每条分支最后一个池化层之后分别加一个batchNormalizationLayer确保拼接前各分支的输出尺度一致最后是确保数据清洗到位检查有没有样本时频图里全是 NaN 或 Inf 值这类样本一旦被送进网络损失函数就会计算出错。单独写一段脚本循环扫描所有样本确认一下isfinite是很有必要的习惯。还有一点容易被忽视bilstmLayer对输入序列的长度比较敏感。如果我的“分段序列”版本里每张时频图只切成 4 段序列长度太短BiGRU 的时序建模能力发挥不出来如果切成 32 段每个时间步对应的空间区域又太窄CNN 提不动特征。我自己调下来的经验是序列长度取 8 段时整体最优准确率比 4 段高出约 3 个百分点比 16 段高出约 1 个百分点。4.4 从混淆矩阵里找信号特征问题训练结束后我习惯用测试集画一次混淆矩阵这是定位故障诊断系统短板最直接的工具。如果发现内圈故障和外圈故障之间互相混淆典型原因是两者的故障特征频率虽然不同但在时频图上有相似的宽带冲击谱形态加上工况转速波动频率峰被展宽后重叠。这种情况下问题常常出在时频图的频率分辨率不够或者目标样本时长太短。对症下药的方法是增加样本点数、提高频率分辨率或者在 WMSST 的频率加权中增强故障特征频率附近的权重。如果发现滚动体故障被误分为正常状态常见原因是滚动体故障冲击受位置影响有时冲击出现在承载区之外该段样本里根本没留下明显故障特征。这类样本单纯靠模型拟合解决不了最好是在分段时对原始信号做包络分析预处理用包络信号的时频图替代原始振动信号的时频图故障特征会显著增强。我曾在一组数据上试过这个改动滚动体故障的召回率从 76% 提升到了 89%效果非常明显。如果每一类之间都有零星误分而且看起来毫无规律那大概率不是模型问题而是其中部分样本的标签标注不准。挑几段误判样本出来画时频图人工检查往往能看到某些样本故障特征不明显甚至特征完全相反。这种脏标签数据对深度模型性能的影响比想象中大很多宁可删掉可疑样本也不要硬着头皮喂进网络。我在实际调试这套 WMSST 结合 MCNN-BiGRU 方法的整个过程中最大的体会是深度学习和信号处理不是互相替代的关系而是互补的。WMSST 把物理先验变成高质量的输入表示MCNN-BiGRU 再把表示里的深层模式挖出来两者结合之后模型对训练样本量的要求大幅降低诊断结果也有更强的可解释性。最后分享一个小技巧在把新数据跑进模型之前每次都先画几张时频图肉眼看一遍确认信号特征符合故障机理的预期再谈训练参数。机器可以闷头调参但人一定要先理解数据。这一步看起来原始却总能帮我避免大量无效实验。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑