资讯动态

DWVD时频图+CNN-BiGRU:旋转机械故障诊断的深度学习方案

发布时间:2026/10/20 17:49:51 来源:尧图企业网站定制
做旋转机械故障诊断大家拿到手的第一份材料基本都是加速度传感器采出来的原始振动信号。我的习惯是先问一句这里面的故障特征到底藏在哪早期轴承故障的冲击非常短促能量又分散在整段波形和频谱里直接从时域或频域下手很容易被转频、啮合频率这些强周期成分盖住。我第一次尝试用一维卷积直接吃原始波形调了两周参数测试集准确率卡在87%左右上不去后来把信号换成时频图同一套网络结构一夜之间就过了92%。这篇文章想说的就是这条链路——用离散韦格纳分布DWVD把振动信号变成高分辨率时频图再交给卷积神经网络CNN加双向门控循环单元BiGRU做故障分类最后附上Matlab代码的完整实现思路。内容适合正在做故障诊断课题、想把手头振动数据变成可复现深度学习方案的同学也适合对时频分析好奇、想搞明白WVD到底怎么落地的人。我会把原理、代码、训练细节和踩过的坑都摊开讲清楚。1. 非平稳信号到底该怎么喂给网络时频分析不是可选项1.1 傅里叶变换给了频谱却弄丢了时间维度旋转机械的振动信号绝大多数情况下都是非平稳的。轴承内圈出现点蚀时滚动体每经过一次缺陷位置就会激发一次冲击这个冲击在时域上表现为周期性的瞬态衰减振荡。频谱能告诉你哪个频带能量集中但无法告诉你这些频率成分到底是什么时候出现的。负载波动、转速变化、故障演化这些信息全藏在频率成分随时间的变化里。短时傅里叶变换STFT是最常见的补救手段把信号切成一帧一帧做FFT得到时间-频率的二维分布。可它的老毛病大家都清楚窗长一旦固定时间分辨率和频率分辨率就只能二选一。窗短了时间定位准但频率模糊窗长了频率清晰但又不知道冲击具体发生在哪一刻。我在早期版本里就是用STFT谱图喂CNN准确率一直差强人意后来才意识到问题可能不在网络而在输入。1.2 WVD为什么时频聚集性好维格纳分布Wigner-Ville DistributionWVD的思路和加窗方法完全不同。它不切窗而是把信号和自身做一种双线性变换瞬时自相关后再傅里叶变换W_x(t, f) ∫ x(t τ/2) x*(t - τ/2) e^(-j2πfτ) dτ因为没有窗函数平滑WVD对瞬时频率的定位能力非常强单分量线性调频信号在WVD时频图上会变成一条几乎无限窄的能量脊。同时它还满足边缘特性对时间积分得到功率谱对频率积分得到瞬时功率这对后续提取统计特征很有帮助。换句话说WVD是真能把“频率随时间的变化”画清楚的那一类工具。代价也很明确双线性结构会把多分量信号之间的交叉调制项带出来表现为时频平面上那些虚虚实实的伪影。轴承故障信号包含了冲击响应、转频、谐波等多分量成分交叉项如果处理不当反而会比STFT谱图更脏。1.3 离散化从连续公式到机器能算的DWVD实际工程里只能用离散形式的WVD。对采样信号x(n)离散维格纳分布定义为WD(n,k) 2 ∑_m x(nm) x*(n-m) e^(-j4πkm/N)这里x(nm)x*(n-m)本质上是沿着延迟方向构造瞬时自相关序列再做一次离散傅里叶变换。由于是二次型变换WD(n,k)理论上可能出现负值但实际使用时一般取模值或实部并做能量归一整定。离散化之后就会遇到两个工程问题。第一是频率分辨率WVD的输出尺寸近似等于信号长度信号越长时频图越大训练数据会非常庞大。第二是交叉项依旧存在。工程上常见做法是加平滑窗得到伪WVD或平滑伪WVDSPWVD用时间窗和频率窗各压制一部分交叉项。这样会损失一些时频聚集性但对深度学习分类任务来说损失一点“锐度”换来的稳定性往往更划算。我在这个项目里的取舍是核心入口用DWVD生成时频图然后对时频图做归一化和压缩尺寸。预处理阶段适当平滑交叉项依靠后续卷积网络去自动适应而不是在时频分析阶段拼命加窗。这样既保留了WVD的高时频分辨能力又不至于让伪影毁了整个训练。2. 离散韦格纳分布的Matlab实现从原理到可落地的程序2.1 信号预处理与分段策略时频分析之前必须先把振动信号处理干净。我的预处理管道只有三步去均值、带通滤波、按样本分段。去均值是必须的否则直流分量会在WVD时频图中心形成一条横向亮带占据主要动态范围。带通滤波要根据实际故障特征频带来选比如我用的某型号深沟球轴承数据集故障特征频率集中在几百赫兹到几千赫兹范围就直接用了通带200Hz到5000Hz的巴特沃斯带通滤波器。分段长度需要综合考量。样本太长DWVD输出的矩阵会非常大内存和训练时间都扛不住样本太短又可能截断冲击的完整形态。我最终用12kHz采样率下每段4096个点对应约0.34秒时长。单个轴承工频大约30Hz左右这么长的样本能包含好几个旋转周期故障冲击信息足够完整。2.2 三种DWVD实现方式对比Matlab里做WVD有现成函数也可以自己写我实际对比过三条路线。方法依赖优点注意点wvd官方函数Signal Processing Toolbox实现严谨直出时频矩阵较新版本才可用计算量和信号长度成正比tfrwv时频分析工具箱TFTB经典算法学术界常用需要单独下载工具箱自写循环无逻辑透明、方便魔改效率低需要自己处理边界和非解析信号三种我都试过官方wvd用起来最省心推荐优先使用。如果版本没有这个函数再回退到TFTB。不过纯Matlab基础工具箱用户自写一个短函数也能跑只是计算效率确实感人不建议长信号直接套用。2.3 核心代码自己实现DWVD的思路如果你也想搞清楚DWVD内部到底做了什么下面这段代码可以作为最小实现参考。它的逻辑是对每个时刻n按延迟m构造瞬时自相关序列补零后做FFT再取半谱得到该时刻的频率切片。function [wd, f] my_dwvd(x, nfft) % 离散维格纳分布的最小实现演示用 % x : 单段振动信号建议先做希尔伯特变换得到解析信号 % nfft : FFT点数需要大于信号动态延迟范围 N numel(x); x hilbert(x(:).); % 解析信号减少负频率成分干扰 wd zeros(nfft/2, N); for n 1:N tau_max min([n - 1, N - n, nfft/2 - 2]); tau -tau_max:tau_max; kernel x(n tau) .* conj(x(n - tau)); % 瞬时自相关 kernel [kernel, zeros(1, nfft - numel(kernel))]; spec fftshift(fft(kernel, nfft)); wd(:, n) abs(spec(1:nfft/2)); % 取正频域 end f (0:nfft/2 - 1) / nfft * 20000; % 采样率按实际传入换算 end这段代码的效率不高但胜在看完就能理解“对每个时刻做一次FFT”这个本质。工程上真要批量生成几千张时频图还是老老实实用官方wvd或TFTB更现实。有一点必须提醒WVD的瞬时自相关是双线性计算噪声会被放大所以信号预处理那一步一定要做扎实否则时频图上全是噪点。2.4 时频图的尺寸归一化问题DWVD输出的矩阵通常是N乘N也就是每段4096个点的信号会生成4096×4096的时频矩阵这既不算图也不算数据根本喂不进网络。我做了两步压缩先沿频率轴抽取感兴趣频带例如200Hz到5000Hz对应的行再把时间轴按固定步长抽样把整个矩阵压缩到64×64左右。压缩过程顺带做了一次线性归一化把幅度映射到0到255最后保存成灰度图。这里有个很多人踩过的坑直接对时频图做imresize缩放。双线性插值虽然能快速得到固定尺寸但会把WVD那种高分辨率能量脊磨成模糊色块严重破坏时频特征。正确做法是先做频带裁剪再做浅层池化式降采样。简单说宁可少截取一些频率范围也不要随意用图像缩放破坏原始分布结构。3. 网络结构设计CNN负责局部纹理BiGRU负责前后文依赖3.1 为什么CNN后面还要接BiGRU时频图本质上是一张二维图像X轴是时间Y轴是频率亮度代表能量。卷积神经网络天然擅长提取这种图像的局部纹理特征冲击在时频图上形成的倒V形条纹、边频带簇、能量集中区都是CNN的卷积核最喜欢捕捉的模式。但故障诊断不只是“认图”。内圈故障和外圈故障在时频图上的静态纹理可能相似真正的差异体现在故障冲击随旋转角度变化的顺序、间隔和调制方式。CNN单独使用时感受野再大也很难像序列模型那样显式建模“把一整段时频演化过程读下来”的关系。所以我选择了双向门控循环单元BiGRU。GRU比LSTM少一组门参数量更小、训练更快在故障诊断这种样本量不算富裕的场景里更稳双向结构则让每个时间步既能看见过去又能看见未来。放在时频图这个场景下就等于从左往右和从右往左各读一遍振动事件的时间线上下文信息自然比单向模型完整。3.2 分段策略把一张时频图变成一组时间序列这里要说一个关键设计CNN和BiGRU之间怎么衔接。最直觉的做法是把整张64×64时频图展开成一个4096维的向量再接BiGRU。问题在于这样BiGRU看到的“时间步”根本不是时间轴而是二维图像的像素扫描顺序语义上说不通。我的做法是把时频图沿时间轴切成若干片段每个片段单独通过CNN提取局部空间特征再把各片段特征按时间顺序拼成一个特征序列交给BiGRU。这样网络学到的东西就分了两层CNN负责“在这几毫秒里时频图上有什么纹理”BiGRU负责“这些纹理在整段样本里是怎么演化、怎么交替的”。我在实验里把64个时间点切成4段每段16个时间点效果比切8段或2段都要好。段数太少时序信息不足段数太多每段时间过短CNN能看到的局部上下文又不够。3.3 用Matlab搭建CNN-BiGRU层图Matlab从R2020a开始可以通过Deep Learning Toolbox支持图像序列输入用sequenceFoldingLayer把序列折叠成批量图像让CNN处理再通过sequenceUnfoldingLayer恢复序列交给BiGRU。这套组合虽然看起来绕但确实是官方支持的端到端方案。inputFreq 64; % 频率点数 inputTime 16; % 每段时间点数 numClasses 4; % 正常、内圈、外圈、滚动体 layers [ sequenceInputLayer([inputFreq, inputTime, 1], Name, input) sequenceFoldingLayer(Name, fold) convolution2dLayer([3 3], 16, Padding, same, Name, conv1) batchNormalizationLayer(Name, bn1) reluLayer(Name, relu1) maxPooling2dLayer([2 2], Stride, [2 2], Name, pool1) convolution2dLayer([3 3], 32, Padding, same, Name, conv2) batchNormalizationLayer(Name, bn2) reluLayer(Name, relu2) maxPooling2dLayer([2 2], Stride, [2 2], Name, pool2) sequenceUnfoldingLayer(Name, unfold) flattenLayer(Name, flatten) bilstmLayer(64, OutputMode, last, Name, bilstm) dropoutLayer(0.2, Name, dropout) fullyConnectedLayer(numClasses, Name, fc) softmaxLayer(Name, softmax) classificationLayer(Name, output) ]; lgraph layerGraph(layers); lgraph connectLayers(lgraph, fold/out, conv1); lgraph connectLayers(lgraph, pool2, unfold/in); lgraph connectLayers(lgraph, fold/miniBatchSize, unfold/miniBatchSize); lgraph connectLayers(lgraph, fold/seqLengths, unfold/seqLengths);训练数据的组织需要特别注意。每个样本不是一张图而是一个序列序列长度为分段数每个时间步是一段64×16×1的图像块。Matlab里用cell数组存储每个cell是64×16×1×seqLen的四维数组对应 batches-by-time 维度。第一次跑的时候如果报维度不匹配十有八九是这里的数据组织没对齐。3.4 训练超参数与自定义训练循环层图搭建好之后常规做法是直接trainNetwork。但如果想精细控制学习率调度推荐用dlnetwork自定义训练循环。我在实验里最终选用了Adam优化器初始学习率1e-3batch size 32最大训练轮数60验证集上连续6轮不下降就早停。这些参数看起来常规但针对时频图输入是够用的。后续如果想追求精度可以换成余弦退火或带warm-up的调度我测试下来至少能再涨零点几个百分点。4. 训练过程中的真实反馈数据切分、学习率和过拟合4.1 数据划分最大的坑按样本随机切分等于泄题刚开始我按样本整体随机划分训练集和测试集准确率冲到97%。后来仔细看实验记录发现不对劲同一个工况的连续多次采样相邻样本之间的相似度极高。如果随机划分训练集里几乎必然包含测试样本的“邻居”网络学到的是记忆而不是泛化这就是典型的数据泄漏。正确做法是按工况/故障状态划分。比如每种故障状态在同一转速负载条件下连续采集多段数据划分时把整个连续时间块归入同一集合保证同一段连续的信号不会同时出现在训练集和测试集里。这样得到的测试准确率通常比随机划分低几个百分点但那才是真实水平。4.2 学习率过大过小都有问题学习率踩过两次坑。第一次设成1e-2训练损失在前面几个epoch剧烈震荡验证准确率一直卡在70%多BiGRU输出几乎退化成随机预测。降到1e-3之后稳定很多。第二次是训练到30轮左右损失不再下降但也没到过拟合我意识到可能是学习率太小换成阶梯式下降每15轮乘以0.5最终准确率又往上提了一截。我的建议是把初始学习率控制在1e-3到3e-3之间优先让训练平稳跑完20轮再观察曲线形态。不要一上来就用0.01时频图输入的数值分布比自然图像更集中过大的更新步长很容易把batch normalization层的统计量冲乱。4.3 类别不平衡的表现和应对故障诊断数据里正常样本往往很多故障样本少。我用的数据集中正常状态有350段而滚动体故障只有250段虽然差异不算夸张但混淆矩阵里滚动体故障的召回率明显偏低。处理办法是先算每个类别的样本数在训练时给少数类更高的权重。Matlab里可以通过classWeights选项传入权重向量或者在采样时做类别均衡。实测下来类别权重设置成“总样本数/该类别样本数”的正比加权测试集F1分数能提高1个百分点左右代价是正常样本的准确率略有下降整体看非常划算。4.4 过拟合的信号训练损失下降但验证损失拐头这个模型在前30轮表现正常后30轮如果继续训练验证损失会先下降再回升训练损失却一路走低典型的过拟合信号。缓解手段我用了几层CNN部分加批量归一化BiGRU前面加Dropout层概率0.2中间层再加L2正则化。有一点要留意在时频图数据量不大的情况下数据增强能起的作用有限。我试过对时频图做小幅平移和加噪发现平移会造成故障时刻的位置偏移加噪会让WVD伪影更明显效果都不理想。最后关头反而是靠减小模型容量、把BiGRU隐含单元从128降到64保住了泛化能力。5. 实验对照DWVDCNNBiGRU到底赢在哪里5.1 实验设置为了验证每个环节的必要性我在同一份数据集上跑了五组对照实验。数据来自某型号深沟球轴承故障模拟台架包含正常、内圈故障、外圈故障、滚动体故障四种状态每种状态若干转速和负载工况每段样本4096点。训练、验证、测试按连续时间块划分的比例是6:2:2。所有深度学习模型使用同一套学习率策略和早停机制特征工程方法使用同一组时频统计特征。模型输入准确率F1分数SVM时频统计特征DWVD时频图统计量85.1%84.6%一维CNN原始波形87.6%87.1%二维CNNDWVD时频图93.4%92.9%BiGRUDWVD时频图90.2%89.7%CNN-BiGRU本文DWVD时频图96.3%96.0%5.2 结果解读每换一个组件涨点来自哪里二维CNN比一维CNN高约5.8个百分点说明时频图的表征能力确实强于原始波形。BiGRU单独用时只有90.2%和二维CNN混合后却到96.3%涨幅比单纯换输入更大。这个现象其实很好理解单一模型各有短板CNN擅长定位“故障特征长什么样”但对全局时序演化不敏感BiGRU擅长建模顺序变化却很难从原始时频矩阵里自动抓出强判别性的局部模式。两者结合互补的那部分恰好是最难分类的内圈和外圈故障。从混淆矩阵看最容易混的类别是内圈故障和外圈故障。它们的冲击特征频率不同但在WVD时频图上由于交叉项伪影和边频带泄漏某些样本的纹理非常接近。CNN-BiGRU能够把这两类准确分开主要归功于BiGRU捕捉到了冲击间隔的差异。这个结论也是我做这段实验时最有价值的发现。5.3 消融实验的顺序要讲究做消融实验时我建议不要只在最终模型上删除某个组件而是从尽量简单的基线逐步加组件。比如先跑“二维CNNDWVD”作为基线再加BiGRU再换SPWVD或原始WVD对比每一层的涨点都看得清清楚楚。如果反过来从完整模型删组件很难分清某个涨点究竟来自哪个改动。6. 附Matlab代码的目录结构和复现建议6.1 工程文件清单整个项目不是单文件脚本而是分模块组织的。我最后整理成下面这个结构文件作用main.m主流程负责读取数据、调用各模块、输出结果preprocess_signal.m去均值、带通滤波、样本分段generate_dwvd.m批量生成DWVD时频图并做归一化和压缩build_dataset.m切分训练/验证/测试集组织成序列格式create_cnn_bigru.m构建CNN-BiGRU层图train_model.m自定义训练循环包含学习率调度和早停evaluate_model.m测试集评估、混淆矩阵、分类报告6.2 运行顺序和环境要求建议按这个先后顺序跑preprocess_signal→generate_dwvd→build_dataset→create_cnn_bigru→train_model→evaluate_model。环境方面需要Matlab R2021b以上版本以及Signal Processing Toolbox、Deep Learning Toolbox和Parallel Computing Toolbox。没有GPU也能跑但训练时间会明显变长我实测CPU下60轮大约需要一晚上GPU则只要40分钟左右。6.3 复现时最容易翻车的地方第一sequenceFoldingLayer的输入要求和普通imageInputLayer完全不同数据必须是cell数组每个cell是[F, T_block, 1, L]的序列形式。第二连层图时千万别漏掉fold/miniBatchSize到unfold/miniBatchSize的连接漏掉会直接报维度不匹配。第三wvd官方函数的输出矩阵方向是频率行、时间列和图像处理的坐标习惯不同可视化时记得转置否则训练出来的模型虽然不会报错但会难调试很多。6.4 后续扩展的方向这套链路不只是轴承故障能用齿轮箱、电机、往复压缩机这些旋转机械同样适用核心在于时频图类别差异是否足够明显。想进一步迁移到变转速场景可以尝试在DWVD之前先做角域重采样或阶比跟踪把转速变化消除掉。网络端也可以把普通卷积换成深度可分离卷积来减小模型体量方便部署到边缘设备。每次改方案时先跑通小样本快速验证再扩大到全量数据能省下大量调参时间。还有个经验我想多说两句时频分析方法和深度学习模型的选择本质上要匹配。DWVD能提供高分辨率细节但对噪声敏感、有交叉项如果你的信号信噪比很差反而用SPWVD更稳。不要迷信单一工具把预处理、时频变换、网络结构当成一个整体去调才是这类故障诊断项目能出效果的关键。

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

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

免费获取报价 →
↑