ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于CWT-CNN-GRU的旋转机械故障诊断MATLAB实现

基于CWT-CNN-GRU的旋转机械故障诊断MATLAB实现 简介这份资料是一套基于连续小波变换CWT与卷积门控循环单元CNN-GRU融合的故障诊断完整工程实例面向从事工业设备状态监测、故障诊断、智能运维的科研人员、工程师和研究生。项目以MATLAB为实现环境覆盖从振动信号读取、CWT时频图生成、CNN空间特征提取、GRU时序建模到多类故障分类的端到端流程并配有GUI可视化界面便于数据加载、训练评估和单样本预测演示。压缩包内含1个docx文档大小约132KB文档以目录式结构系统阐述了项目背景、模型架构、代码示例、应用领域及部署方案适合作为项目复现和毕业设计参考。目前已有57人学习使用内容详实包含可运行的MATLAB代码片段、网络结构定义、训练参数设置及性能评估示例并探讨了多工况迁移与预测性维护扩展方向对构建智能诊断系统具有实用参考价值。1. 从CWT-CNN-GRU组合看故障诊断落地路径在旋转机械的振动数据上直接把原始一维信号喂给深度网络效果往往不如先把信号做一次连续小波变换CWT再把时频图交给CNN-GRU。原因是轴承、齿轮的故障特征通常藏在突变冲击和低频调制里时域波形看不出边界纯FFT又丢掉了时间位置。这个CWT-CNN-GRU栈把频率定位、特征重建和时序依赖三段能力拼在一起CWT把一维信号变换成二维时频图CNN从图里提取局部特征GRU在时间维度上追踪特征演化。下面用MATLAB把数据准备、模型训练到GUI部署整条路径过一遍适合正在做故障诊断项目或者想把CWT和深度学习组合迁到MATLAB上的工程师。这里所有代码都按离线采集的振动信号为前提不依赖特殊硬件实验室机器就能跑。2. 连续小波变换CWT时频图生成与数据集构造2.1 为什么这里选CWT而不是短时傅里叶变换短时傅里叶变换STFT用一个固定窗长去截信号窗一短频率分辨率就差窗一长时间分辨率就差。CWT没有固定窗长它靠母小波的伸缩来控制等效带通宽度高频段窗口窄、低频段窗口宽所以能在同一个时频面上同时保留冲击发生时刻和低频谱线位置。这对轴承外圈点蚀、齿轮断齿这类以瞬态冲击为主要标志的故障非常关键。对比项STFTCWT时间分辨率固定由窗长决定高频处自适应变高频率分辨率固定低频处自适应变高输出形式复数谱矩阵复数小波系数矩阵瞬态冲击表征容易淹没在背景频率中冲击在时间轴上更突出MATLAB调用spectrogramcwt另外要留意cwt返回的是复数系数直接当图像存会丢失尺度信息一般取模后再做归一化。同一个数据集里所有样本必须统一采样率fs否则尺度轴和频率轴的对应关系不一致后面CNN学到的纹理就失去可比性。提示如果信号里同时存在持续的周期分量和随机冲击CWT图上会看到一条水平亮纹加一条竖直亮纹。水平纹代表持续存在的频率成分竖直纹代表冲击发生时刻这两种纹理是CNN比较容易学到的局部模式。2.2 用cwt函数批量生成时频图的最小代码先看单个样本的最小命令。给定信号sig和采样率fs[wt, freqs] cwt(sig, amor, fs); % 一维信号 - 二维小波系数 figure; imagesc(t, freqs, abs(wt)); % t是时间轴向量 axis xy; xlabel(时间 (s)); ylabel(频率 (Hz));说明cwt输出矩阵wt的大小是尺度数乘信号长度取模后画图就是时频图。amor是复值Morlet母小波默认配置下对冲击类信号的分辨率已经够用。批量生成数据集时不要循环里开figure改写成写文件的方式function img cwt2img(sig, fs, targetSize) [wt, ~] cwt(sig, amor, fs); % 系数矩阵 a abs(wt); % 取模丢弃相位 a (a - min(a(:))) / (max(a(:)) - min(a(:)) eps); img imresize(im2uint8(a), targetSize); end逻辑说明min-max归一化把每个样本的相对能量压到[0,1]避免不同工况幅值差异主导分类im2uint8把系数映射成0到255灰度imresize统一尺寸。若后续要迁移预训练CNN可以在这行后面加repmat把单通道复制成三通道同时把网络输入层的通道数改成3。2.3 滑动窗口分帧与数据集划分故障数据一般是一段几十秒到数分钟的长信号样本量不足时常见做法是滑动分帧。winLen表示窗口点数stepLen表示步长两者差值就是相邻帧的重叠率。winLen 2048; % 帧长 stepLen 1024; % 步长50%重叠 outRoot ./cwt_dataset; categories {normal,inner_race,outer_race,ball}; for ci 1:numel(categories) rawDir fullfile(./raw_signals, categories{ci}); files dir(fullfile(rawDir, *.mat)); for k 1:numel(files) d load(fullfile(files(k).folder, files(k).name)); sig struct2cell(d); sig sig{1}(:); outSub fullfile(outRoot, categories{ci}, sprintf(s%02d, k)); if ~exist(outSub, dir), mkdir(outSub); end idx 1; for start 1:stepLen:length(sig)-winLen1 frame sig(start:startwinLen-1); img cwt2img(frame, fs, [64 64]); imwrite(img, fullfile(outSub, sprintf(f%03d.png, idx))); idx idx 1; end end end说明对每个原始信号文件单独建一个sXX子目录帧图像按f001、f002顺序存放这样后面组序列时不会跨文件。重叠率取50%是为了让故障冲击落在帧边界时至少能被下一帧完整覆盖。winLen如果显著小于信号的特征周期CWT的低频部分会失真。划分训练集和验证集时不能直接对所有帧shuffle同一个文件相邻帧高度相关随机混合会造成数据泄漏验证准确率虚高。按原始文件编号做划分subDirs dir(fullfile(outRoot, inner_race, s*)); numFiles numel(subDirs); cv cvpartition(numFiles, HoldOut, 0.3); isValFile test(cv); valDirs subDirs(isValFile); trainDirs subDirs(~isValFile);cvpartition按文件编号把s01、s02这类目录分成70%训练、30%验证对四个类别分别执行一次保证每类在训练和验证中都出现再合并结果。这样验证集里的帧与训练集里的帧没有任何时间上的重叠。3. MATLAB中CNN-GRU混合模型的搭建与训练3.1 为什么CNN后面接GRU而不是LSTMCNN的卷积核在图像上用局部感受野提取特征能抓住CWT图里水平方向持续频率和竖直方向冲击时刻的组合关系。但CNN不擅长表达“这一帧的卷积特征对下一帧有什么影响”因为卷积核每次只在一个局部窗口内滑动。GRU正好补这段时序关系更新门决定历史特征保留多少重置门决定当前输入与历史结合的方式。GRU比LSTM少一个门同样样本量下更不容易过拟合。对比项GRULSTM门数量更新门 重置门输入门 遗忘门 输出门参数数量更少更多训练速度更快更慢中小样本表现通常更好依赖序列长度与正则化MATLAB层函数gruLayerlstmLayer3.2 用sequenceFoldingLayer把图像序列接入CNN-GRU在MATLAB的trainNetwork流程里卷积层不接受序列输入gruLayer又不接受四维特征图。常规做法是用sequenceFoldingLayer把每个时间步的图像在batch维度上拼接CNN统一卷积再用sequenceUnfoldingLayer恢复时间维度之后接GRU。inputSize [64 64 1]; % 单帧时频图 numClasses 4; numHidden 128; layers [ sequenceInputLayer(inputSize, Name, seq_in) sequenceFoldingLayer(Name, fold) convolution2dLayer([3 3], 16, Padding, same, Name, conv1) reluLayer(Name, relu1) maxPooling2dLayer([2 2], Stride, [2 2], Name, pool1) convolution2dLayer([3 3], 32, Padding, same, Name, conv2) reluLayer(Name, relu2) maxPooling2dLayer([2 2], Stride, [2 2], Name, pool2) sequenceUnfoldingLayer(Name, unfold) flattenLayer(Name, flat) gruLayer(numHidden, Name, gru1) dropoutLayer(0.5, Name, dropout) fullyConnectedLayer(numClasses, Name, fc) softmaxLayer(Name, softmax) classificationLayer(Name, output) ]; lgraph layerGraph(layers); lgraph connectLayers(lgraph, fold/miniBatchSize, unfold/miniBatchSize);逻辑说明sequenceFoldingLayer在内部把输入序列的多张图拼成一个更大的batch交给CNN训练效率高但unfold层需要知道每个序列原来有多少时间步这个信息由fold层输出端口miniBatchSize提供那条connectLayers连接不能省。两个池化层把64×64降到16×16flatten后每帧特征长度足够GRU使用。两个3×3卷积串联感受野等价于5×5参数却少一半。训练集的每个样本是一个cell元素元素内部是H×W×C×T的矩阵。以下代码从2.3的sXX目录构建序列输入function X buildSequenceFromDirs(dirList, seqLen) X {}; for i 1:numel(dirList) f dir(fullfile(dirList(i).folder, dirList(i).name, *.png)); f sort({f.name}); for s 1:seqLen:numel(f)-seqLen1 seq zeros(64, 64, 1, seqLen, single); for t 1:seqLen img im2gray(imread(fullfile(dirList(i).folder, ... dirList(i).name, f{st-1}))); seq(:,:,1,t) img; end X{end1} seq; %#okAGROW end end end参数说明seqLen设成10表示GRU每次看10帧连续时频图对应0.17秒乘10的时间跨度每个cell元素是一个样本cell数组的长度就是样本数。跨类别合并时按类别分别调用buildSequenceFromDirs再vertcat成XTrain标签用repmat对每个类别生成相同数目的categorical值。3.3 训练配置与过拟合控制options trainingOptions(adam, ... InitialLearnRate, 1e-3, ... LearnRateSchedule, piecewise, ... LearnRateDropFactor, 0.5, ... LearnRateDropPeriod, 10, ... MaxEpochs, 40, ... MiniBatchSize, 8, ... Shuffle, every-epoch, ... ValidationData, {XVal, YVal}, ... ValidationFrequency, 10, ... Plots, training-progress, ... Verbose, true); net trainNetwork(XTrain, YTrain, lgraph, options);参数说明序列输入下MiniBatchSize的含义是每批样本数实际显存占用要乘seqLen8已经比较保守学习率每10轮衰减一半是因为振动信号特征比较平稳过早减小学习率容易停在差的局部解ValidationFrequency设10能尽早看到验证曲线拐点。训练曲线里如果训练损失持续下降而验证准确率不再升优先把dropout从0.5调到0.6或把gruLayer的numHidden降到64。注意不要用按帧划分的数据直接替换XVal否则ValidationData里混有训练样本的相邻帧曲线一开始会很高干扰对真实泛化能力的判断。4. 基于App Designer的故障诊断GUI设计与部署4.1 控件布局与信号加载App Designer是MATLAB里推荐做小工具的界面框架比老GUIDE的figure回调更直观。故障诊断界面的布局按操作顺序排成三栏左栏操作与参数、中栏原始波形、右栏时频图和诊断结果。控件类型属性用途LoadButtonButtonText加载信号读取MAT或CSVFsEditNumericEditFieldValue12000采样率需可修改RunButtonButtonText开始诊断触发CWT与模型预测ResultLabelLabelText未诊断显示预测类别RawAxesUIAxesXLabel时间(s)显示原始波形CwtAxesUIAxesTitleCWT时频图显示待诊断数据的时频图ConfAxesUIAxesXTickLabel类别显示置信度条形图采样率做成可编辑而不是写死是这类GUI的惯例现场更换采集设备或调整采样频率时不用改代码、重新编译只需要在界面里输入新值。App Designer里把FsEdit的ValueChangedFcn绑定到回调后续所有cwt调用都读这个值即可。function LoadButtonPushed(app, event) [file, path] uigetfile({*.mat;*.csv, 数据文件}, 选择信号文件); if isequal(file, 0), return; end fullPath fullfile(path, file); try if endsWith(file, .csv) app.rawSig readmatrix(fullPath); else S load(fullPath); fn fieldnames(S); app.rawSig S.(fn{1}); end app.rawSig app.rawSig(:); t (0:numel(app.rawSig)-1) / app.FsEdit.Value; plot(app.RawAxes, t, app.rawSig); grid(app.RawAxes, on); catch ME uialert(app.UIFigure, ME.message, 读取失败); end end说明uialert把异常信息弹给操作人员而不是崩溃退出load进的结构体用fieldnames取第一个字段兼容不同数据集的变量命名转列向量统一后续cwt和buffer的索引方式。4.2 诊断回调与模型调用function RunButtonPushed(app, event) if isempty(app.rawSig) uialert(app.UIFigure, 请先加载信号, 提示); return; end frames buffer(app.rawSig, app.winLen, app.stepLen, nodelay); seq zeros(64, 64, 1, size(frames, 2), single); for t 1:size(frames, 2) [wt, ~] cwt(frames(:, t), amor, app.FsEdit.Value); a abs(wt); a (a - min(a(:))) / (max(a(:)) - min(a(:)) eps); seq(:,:,1,t) imresize(im2uint8(a), [64 64]); end [pred, score] classify(app.net, {seq}); app.ResultLabel.Text char(pred); bar(app.ConfAxes, score); app.ConfAxes.XTickLabel cellstr(app.net.Layers(end).Classes); ylabel(app.ConfAxes, 置信度); end说明buffer把长信号切帧帧数就是seq的第四维长度整个cell数组作为classify的一个输入score是softmax输出的概率向量把每个类别的得分画出来能看出哪个类是次高概率比只看最终标签更有用。关键点winLen、stepLen必须和训练时完全一致否则CWT图像的分辨率结构变化后模型相当于面对分布外数据。一个常见的坑是代码里训练用2048、GUI里默认1024准确率立刻下降。我用模型mat文件携带这些参数modelPath trained_cwt_cnn_gru.mat; d load(modelPath); app.net d.net; app.winLen d.winLen; app.stepLen d.stepLen;4.3 模型保存、编译部署与路径问题训练结束后用save把网络和参数放一起打包时作为附加文件传给mccsave(trained_cwt_cnn_gru.mat, net, winLen, stepLen, fs);mcc -m DiagnosisApp.mlapp -a trained_cwt_cnn_gru.mat -o FaultDiagnosisApp.exe部署机器需要安装与编译版本匹配的MATLAB Runtime。程序运行时不要用相对路径找mat文件Runtime环境下当前工作目录经常与解包目录不一致我用ctfroot定位部署缓存目录function startupFcn(app) d load(fullfile(ctfroot, trained_cwt_cnn_gru.mat)); app.net d.net; app.winLen d.winLen; app.stepLen d.stepLen; endctfroot在开发机上会指向MATLAB安装根目录本地调试时可以直接加载模型文件打包成exe后它指向ctf归档的解压位置。写到这一步测试机、目标机和打包机三套环境差异基本都能覆盖。5. CWT-CNN-GRU模型的验证指标与调优技巧5.1 混淆矩阵定位误区来源训练结束不要只看准确率。用验证集全部预测结果画混淆矩阵几行代码就能发现模型具体错在哪两类[Ypred, ~] classify(net, XVal); figure; confusionchart(YVal, Ypred);如果inner_race和ball两个类别相互混淆明显说明它们的CWT频带能量分布过于接近。先用confusionchart把错分样本找出来看它们的原始波形特征确认是CWT尺度问题还是样本标签边界问题再决定从哪个环节改而不是盲目加深网络。5.2 频带范围与CWT尺度的配合cwt默认分析从零到奈奎斯特频率的整个频带。现场振动数据常有大量高频噪声此时用FrequencyLimits把低频优先区域保留下来[wt, ~] cwt(sig, amor, fs, FrequencyLimits, [50 2000]);设置后检查小波系数归一化后的非零比例若大部分帧几乎全黑或全白说明频带设置不合适。故障特征频率在频带边缘时前后扩大10%再试。5.3 序列长度与重叠率的上限GRU的序列长度不是越大越好。经验上seqLen在6到12帧时收益递增明显超过20帧后训练时间线性上涨准确率提升远低于预期。先做一组3、6、12帧的小实验画出验证准确率随seqLen变化的曲线找到拐点再全量训练帧间重叠从50%提高到75%是扩充样本最便宜的方式比增加卷积层数量更可控。频带、重叠率、序列长度三个参数组合优化时先固定两个逐个扫一个。本文还有配套的精品资源点击获取
返回列表