
基于FFT频谱与时频图的双通道CNN融合的轴承故障诊断模型 数据处理获取 FFT频谱和时频图用的Matlab 双通道CNN融合实现诊断用的Pytorch轴承故障诊断这活儿现在听着可能挺玄乎但其实就是通过振动信号“看”出机器是不是有毛病。之前试过直接用时域信号训练模型效果嘛不算惊艳——毕竟时域信号的信息太散了频率和时间的分布特征都揉在一起模型得自己去“猜”效率不高。后来想了个招把信号转换成两种不同的“特征图”一个看频谱哪里频率高一个看时频哪里时间频率有异常然后让CNN“看”这两张图搞个双通道融合效果好像提升不少。第一步把时域信号“翻译”成特征图Matlab搞的数据是振动传感器采的时域信号得先转成频谱图和时频图。Matlab在信号处理这块儿确实方便几行代码就能搞定。1. FFT频谱图生成频谱图能直接告诉我们信号里哪个频率的振动最厉害。比如轴承故障通常在某个特定频率比如故障频率会有峰值。处理步骤大概是读取信号→FFT变换→取模→归一化→画出来。举个Matlab小例子假设信号叫signal.mat里面存着时域振动数据x采样频率Fs20480Hz% 读取数据 load(signal.mat); % 假设signal.mat里有x和Fs x signal; % 时域信号 N length(x); % 信号点数 Fs 20480; % 采样频率 % FFT变换 X fft(x); % FFT结果 X_mag abs(X(1:N/21)); % 取单边频谱0~Fs/2 f (0:N/2)/N*Fs; % 频率轴 % 归一化画图 X_mag_norm X_mag / max(X_mag); % 归一化到0~1 figure; pcolor(f, 1:N/21, X_mag_norm); % 这里用pcolor画频谱图频率轴幅值 shading interp; colormap jet; colorbar; xlabel(Frequency (Hz)); ylabel(Bin); title(FFT Spectrum); saveas(gcf, spectrum.png); % 保存成图片跑这段代码就能得到一张频谱图横轴是频率纵轴是傅里叶系数的序号其实对应频率颜色深浅代表幅值大小。这样机器就能直接“看”到信号里的频率成分了。2. 时频图STFT生成光看频谱还不够比如轴承故障可能不是持续在某个频率而是在特定时间段突然出现比如转了几圈后故障冲击。这时候时频图就能显示“哪个时间窗口哪个频率”有异常相当于给频谱图加了个时间维度。基于FFT频谱与时频图的双通道CNN融合的轴承故障诊断模型 数据处理获取 FFT频谱和时频图用的Matlab 双通道CNN融合实现诊断用的PytorchMatlab里用短时傅里叶变换STFT最方便代码大概这样% 时频图用短时傅里叶变换 window hamming(128); % 汉宁窗常用的窗函数减少频谱泄漏 overlap 64; % 窗重叠点数步长窗长-重叠64 nfft 256; % FFT点数和窗长对齐 % STFT结果[频率, 时间, 幅值] [F, T, Sxx] spectrogram(x, window, overlap, nfft, Fs); % 归一化dB尺度-30dB~0dB Sxx_db 10*log10(Sxx 1e-10); % 加个小值防0取log Sxx_db_norm (Sxx_db - min(Sxx_db(:))) / (max(Sxx_db(:)) - min(Sxx_db(:))); % 归一化到0~1 % 画图 figure; pcolor(T, F, Sxx_db_norm); shading interp; colormap jet; colorbar; xlabel(Time (s)); ylabel(Frequency (Hz)); title(STFT Time-Frequency Plot); saveas(gcf, stft_tf.png); % 保存时频图这里得到的时频图是个二维矩阵横轴是时间纵轴是频率颜色越亮代表该时间点的该频率幅值越大。这样就把“时间频率”的动态信息都可视化了。第二步用Pytorch搭个双通道CNN模型现在有了两张特征图频谱图和时频图怎么让模型同时“看”两张图最简单的思路是搞个双通道网络两个分支分别处理频谱图和时频图最后把两个分支的特征拼起来做分类。1. 网络结构设计分支1频谱图分支输入是频谱图假设是64×64的灰度图单通道。卷积层提取频谱特征比如低通滤波捕捉低频高通捕捉高频故障。分支2时频图分支输入是时频图同样64×64灰度图。卷积层捕捉时频的局部异常比如某段时间窗口的高频成分。融合层两个分支的输出展平后拼接最后接全连接层输出故障类别比如0:正常1:内圈故障2:外圈故障等。2. Pytorch代码实现import torch import torch.nn as nn import torchvision.transforms as transforms class SpectrogramBranch(nn.Module): def __init__(self): super(SpectrogramBranch, self).__init__() self.conv nn.Sequential( nn.Conv2d(1, 16, kernel_size3, padding1), # 输入单通道输出16通道 nn.ReLU(), nn.MaxPool2d(2, 2), # 下采样到32×32 nn.Conv2d(16, 32, kernel_size3, padding1), nn.ReLU(), nn.MaxPool2d(2, 2), # 下采样到16×16 ) def forward(self, x): return self.conv(x) class TFMapBranch(nn.Module): def __init__(self): super(TFMapBranch, self).__init__() self.conv nn.Sequential( nn.Conv2d(1, 16, kernel_size3, padding1), # 时频图同样单通道 nn.ReLU(), nn.MaxPool2d(2, 2), # 32×32 nn.Conv2d(16, 32, kernel_size3, padding1), nn.ReLU(), nn.MaxPool2d(2, 2), # 16×16 ) def forward(self, x): return self.conv(x) class DoubleChannelCNN(nn.Module): def __init__(self, num_classes3): super(DoubleChannelCNN, self).__init__() self.spectro_branch SpectrogramBranch() self.tf_branch TFMapBranch() self.fc nn.Linear(32*16*16*2, num_classes) # 两个分支各输出32×16×16拼接后全连接 self.dropout nn.Dropout(0.5) # 防过拟合 def forward(self, spec, tf): spec_feat self.spectro_branch(spec) # 频谱分支输出(B, 32, 16, 16) tf_feat self.tf_branch(tf) # 时频分支输出(B, 32, 16, 16) combined torch.cat([spec_feat, tf_feat], dim1) # 通道拼接(B, 64, 16, 16) combined combined.view(combined.size(0), -1) # 展平(B, 64*16*16) combined self.dropout(combined) out self.fc(combined) return out3. 为什么用双通道单通道模型只输入频谱图或时频图可能只学到其中一种特征比如频谱图能捕捉故障频率但不知道故障在哪个时间窗口出现时频图能看到故障的时间位置但可能忽略某些频率成分。双通道融合相当于“既看哪里频率高又看什么时候频率高”信息更全面模型更容易区分故障类型。实验效果小感悟用CWRU轴承数据集跑了下双通道模型比单通道频谱或时频准确率高了约5%~8%。比如正常/内圈故障/外圈故障单通道模型容易把“正常”和“内圈故障”搞混频率特征有重叠但双通道模型能通过时频图的时间位置差异比如内圈故障在特定转速下的冲击时间窗口辅助判断减少混淆。踩过的坑Matlab画图时频谱图的频率轴要和时频图的时间轴对应好不然模型输入的尺寸不一致比如频谱图是64×64时频图也是64×64统一尺寸才能拼接。Pytorch模型训练时两个分支的特征图要做归一化和Matlab里的归一化一致比如0~1不然通道间数值差异大模型学不进去。卷积核大小和层数别贪多参数太多容易过拟合小数据集比如几百个样本用dropout和数据增强比如频谱图左右翻转、时频图加噪声效果更好。总结把时域信号拆成“频谱时频”两张图用双通道CNN分别提取特征再融合确实是轴承故障诊断的有效方法。Matlab处理特征图简单直观Pytorch搭模型灵活易调两者结合起来效率很高下次试试小波变换的时频图看看能不能进一步提升效果