简介这套Matlab工具包面向工业设备故障诊断与状态识别场景解决一维传感器信号难以直接输入深度学习模型的问题。基于暂态提取变换TET将信号中的瞬态特征提取并映射为二维图像适用于非线性、非平稳信号分析尤其适合振动、电流等含有冲击成分的监测数据。压缩包共18个文件、3.15MB包含7个m函数脚本主程序、TET变换、奇异谱变换、Renyi熵计算、二维积分、小波变换等、2个mat数据文件带噪声信号及中间结果和9个png样本图便于用户直观对比转换效果。已有75人学习下载适合从事故障诊断、状态识别研究或需要将一维振动/电流信号可视化成图的工程师与科研人员。通过该工具集可快速掌握从原始信号到二维图像的完整转换流程并直接为深度学习分类模型提供训练样本降低入门门槛。1. 暂态提取变换为什么故障诊断要先把一维信号变成二维图在故障诊断这个方向上我见过太多人拿着同一份轴承振动信号在1D-CNN和LSTM之间反复试结构准确率就是卡在九成上下上不去。后来换了思路不折腾模型而是把原始的一维时间序列通过暂态提取变换转成二维时频图再喂给深度学习CNN做分类。模型结构没怎么变故障识别准确率却提了一截外圈、内圈、滚动体这些故障状态的区分尤其明显。这篇文章就围绕这个方案铺开暂态提取变换的原理是什么为什么它比直接拿波形或普通时频图更适合故障诊断怎么用Matlab把流程从原始数据跑到训练集以及中间有哪些绕不开的坑。适合正在做轴承故障诊断、设备状态识别、工业数据分析的工程师和研究生。2. 为什么必须转二维图一维CNN天生的短板与TET的互补逻辑2.1 一维CNN的局部感受野抓不住离散冲击的长程关系轴承、齿轮这类旋转机械的故障信号本质上是周期性的冲击分量叠加在连续旋转的平稳分量上再混入环境噪声。外圈剥落时滚动体每经过缺陷点就激发一次衰减振荡这个振荡的时间跨度通常是几十个毫秒而一维CNN一个卷积核的尺寸往往只有32到64个点。以12kHz采样率算64个点也就是5毫秒多一点一个完整的冲击激励、响应、衰减过程被切成好几段散落在不同的卷积窗口里。要让一维网络把这些碎片关联起来只能加深网络层数或者加大卷积核。但故障诊断场景的数据量普遍不大加深网络很容易在训练集上表现很好换一组工况就掉点。LSTM虽然能处理长程依赖但对这类“冲击出现的位置随机、幅度受转速影响”的非平稳信号序列模型需要先学会判断冲击起点这个学习过程非常依赖数据的覆盖度。这还不是最麻烦的最麻烦的是一维序列里混着大量与故障无关的噪声分量网络会把噪声的统计特征一并学进去到了安静环境或嘈杂现场模型表现完全是两副面孔。时频变换解决的就是“特征可视化”的问题。它不再让网络在原始波形里自己摸索规律而是把一段信号拆成“时间-频率-能量”三个维度的分布图。故障冲击在图中表现为一条条竖直的亮条纹这些条纹的重复间隔对应故障特征频率亮条纹所在的频带对应系统共振区。CNN要做的事情从“在噪声里找规律”退化成“看图上有几条竖线、竖线之间的间距有多大”学习难度是几何级下降的。2.2 二维时频图的密度优势一个像素点承载了一个频带在一个时刻的状态一维信号转二维图信息量本身不会增加但排列方式完全不同。原始波形一条线上几万个采样点网络读序列只能按顺序看时频图把这些点重新组织成了一个二维矩阵横轴是时间纵轴是频率颜色深浅代表该时刻该频率下有多少能量。对故障诊断来说这张图的密度远高于波形。举一个具体例子。内圈故障和外圈故障在原始波形上看上去很接近都是周期性冲击区别只在于冲击的位置相对载荷区的角度不同这个相位差在时域波形里非常隐蔽。但转入时频图后内圈故障会因为转轴旋转导致冲击幅值产生包络调制时频图上竖条纹的亮度出现周期性强弱变化外圈故障因为缺陷位置固定竖条纹亮度均匀。这两种模式差异在二维图上非常直观CNN很容易把它们区分开。我在用CWRU公开轴承数据做对比实验时相同网络结构下喂原始波形的1D-CNN准确率大约93%喂TET时频图的2D-CNN能稳定到99%以上差别就是这么大。另外有一个容易被忽略的点时频图对转速变化的适应性。变转速工况下冲击间隔在时间轴上不断变化一维序列模型会被“间隔不定”这件事干扰但在归一化的时频图里每个冲击的频率结构基本不变只是条纹密度不同。这也是状态识别场景下转二维图更稳的原因。2.3 STFT、CWT、TET怎么选最清晰的图才能配最轻的网络一维转二维的方法不止一种。短时傅里叶变换STFT最直观但受限于海森堡不确定原理窗函数一长频率分辨率高、时间分辨率就差反过来也一样出的图总是带一条条扩散的“裙边”。连续小波变换CWT对非平稳信号友好但需要人工选小波基不同基函数对同一段信号的出图风格差异非常大选基这件事本身就是调参玄学而且CWT的计算量比STFT大一两个数量级批量转图时耗时非常可观。方法能量集中度适合的信号主要问题计算代价STFT一般平稳、缓变信号能量扩散图偏糊低CWT较好非平稳信号小波基选择主观性强高TET高冲击、暂态、衰减振荡对窗长和带宽参数敏感中TET全称Transient Extraction Transform它是在同步提取变换SET基础上针对暂态信号做的改进。SET的思路是把时频系数压缩到瞬时频率脊线上得到极细的谱线但旋转机械的冲击不是稳态正弦能量会在脊线附近有一个与阻尼相关的分布带用SET会把这条带硬压成线丢失能量分布信息。TET的做法是把提取算子的宽度和信号的阻尼特性挂钩该集中的集中、该保留的保留输出图既锐利又不过分瘦削。对CNN来说TET这种干净的图可以直接用较小的网络结构达到高准确率部署起来也轻。3. TET内在机制从STFT到提取算子三步算出一张锐利时频图3.1 第一步先算一幅STFT粗图作为“未精修”的原始素材TET并不是从零设计的一套时频变换它的输入就是STFT的结果。STFT的做法是拿一个固定长度的窗函数沿着时间轴滑动每滑到一个位置就对窗口内的信号段做一次傅里叶变换把结果按时间顺序排成一列最终形成二维复数矩阵。STFT表达式X(t,f) ∫ x(τ) h(τ − t) e^(−j2πfτ) dτ其中h(τ − t)是滑动窗函数窗长决定了每个时间切片能“看到”多长的信号片段。这一步在Matlab里就是一条命令[S, F, T] spectrogram(x, win, nOverlap, nfft, fs);S是复数时频矩阵行对应频率、列对应时间。之所以说这一步是“粗图”是因为STFT的窗函数会把能量泄漏到瞬时频率两侧导致谱线变宽尤其在冲击信号这种宽频激励下整个图上会出现大量的能量拖尾。这些拖尾对故障诊断不仅没帮助反而会干扰CNN对条纹形状的识别。TET后续的所有操作目的都是把这些拖尾按规则切掉只留下信号真实的时频骨架。3.2 第二步沿频率方向找谱峰把每个时刻的瞬时频率脊线串起来对于一个具体时刻t0正常的轴承信号在频域里并不是所有频率都有能量而是集中在某几个共振频带。STFT矩阵里t0这一列幅值最大的那个频点就是该时刻主振荡分量的瞬时频率。把每个时刻的峰位置连起来就得到一条随时间的频率脊线。数学表达为f0(t) argmax_f |X(t, f)|这一步的核心假设是信号在任一时刻只有一个主导瞬态分量。对轴承故障诊断来说这个假设基本成立因为同一时刻滚动体通常只碰撞一个损伤点。需要特别注意的是如果信号里存在两个强度相近的共振频带argmax会在这两个频带之间来回跳导致脊线断裂。遇到这种情况可以先用带通滤波把分析频段限制在主要共振区再跑TET这是工程上非常实用的一招。3.3 第三步构造提取算子只保留脊线附近一个阻尼带宽内的系数脊线只是把每个时刻的主峰位置找了出来还需要把时频矩阵里“不属于这条主脊”的系数清理掉。问题是清到什么程度清得过狠图变细线丢失能量分布清得不够拖尾还在等于没处理。SET的算子是取极限窄的宽度只保留脊线上那一个频点TET显然发现了这对暂态信号不合适——冲击的衰减振荡本身就在频谱上展宽一个频带这个展宽和阻尼比直接相关把带内系数全部保留才是正确的物理表达。TET提取算子的思想是给每个频点算它与脊线的频率差然后按阻尼相关函数决定该点的保留权重。简化实现可以直接做一个硬阈值% 提取算子只保留瞬时频率附近 beta Hz 内的时频系数 for t 1:nT f0 F(idx(t)); for f 1:nF if abs(F(f) - f0) beta IW(f, t) abs(S(f, t)); end end endbeta就是提取带宽单位Hz它的物理含义是“一个冲击的时频能量在频率轴上能扩散多宽”。beta取太小图会变成几条没有厚度的细线beta取太大能量拖尾切不干净退化接近STFT。实际调试时从20Hz起步比较合理。3.4 三个关键参数对出图效果的控制力排序参数重要性从高到低排序第一个是窗长winLen第二个是提取带宽beta第三个是频率轴插值点数nfft。窗长决定STFT粗图的质量上限TET的后续处理只能在它的基础上做减法粗图糊了后面怎么修都白搭。以12kHz采样率、冲击衰减时间约20~40ms的信号为例窗长取256到512点约21到43毫秒覆盖一到两个冲击周期效果最稳。窗长低于128时间分辨率够但频率轴一团糟窗长超过1024每个时间切片里塞进多个冲击脊线提取会被相邻冲击干扰。nfft参数常被忽略它不改变图的信息量只是把频率轴做插值加密。一个常见的错误是nfft开得特别大比如65536图看起来细腻了但计算量暴涨转图奇慢。经验值是取窗长的4倍既平滑又不浪费算力。调整这三个参数的顺序建议是先固定beta20扫winLen找到能看出清晰竖条纹的窗长再固定窗长扫beta找到背景噪声最少、条纹仍有厚度的区间最后动nfft只影响图的细腻程度不参与前两步的调试。4. Matlab落地TET转图、数据集划分与CNN训练的完整代码4.1 数据准备目录结构决定标签生成方式别把类别混在一个文件夹做故障诊断深度学习项目数据组织永远是第一步这一步偷懒后面全是坑。推荐的做法是直接把训练集和验证集分开的目录结构类别名用英文或拼音用文件夹名充当标签这样用imageDatastore加载时不需要手动维护CSV标签表也不容易出现标签错位。假设用CWRU公开轴承数据集做验证文件组织为data/ train/ Normal/ OR (外圈故障)/ IR (内圈故障)/ B (滚动体故障)/ val/ Normal/ OR/ IR/ B/如果你手里的数据是一个长采样文件先用Matlab把文件按固定时长切成若干独立片段再把不同片段分别放到train和val。这里面埋着一个重要的原则同一个原始文件切出来的不同片段绝对不能同时出现在训练和验证集否则后面验证集准确率是假的这个细节在下一章展开。4.2 信号分段重叠采样让样本量翻倍但要注意独立信息占比一段10秒的12kHz信号有12万个点不能直接整段转图需要切段。每段1024点作为单个样本如果完全不重叠10秒信号只能得到117个样本这个数量喂CNN偏少。常见的做法是加重叠让相邻样本共享一部分信号样本量可以膨胀到几百甚至几千。分段公式很简单样本数 1 floor((总点数 − 段长) / 步长)。步长等于段长时不重叠步长等于段长的一半时重叠50%。对故障诊断重叠率上限建议50%再高就会出现大量内容重合90%的样本看起来数据集大实际上信息量没增加多少。业内把这种情况叫“样本增肥”是数据膨胀假象的根源。我一般会让独立样本信息占比不低于50%也就是每个样本至少要有一半内容是新的。4.3 核心函数TET转时频图的Matlab实现下面是简化版TET变换函数输入一段一维振动信号输出一个二维幅值时频矩阵。代码里有中文注释运行前确认Matlab编码设为UTF-8方法在最后一章避坑里讲。function IW tet_spect(x, fs, winLen, beta) % tet_spect 简化版暂态提取变换实现 % x : 1xN 振动信号 % fs : 采样率, Hz % winLen : 窗长(点数), 建议 256~512 % beta : 提取算子带宽阈值, 单位 Hz, 建议 10~30 % 输出: % IW : nFreq x nTime 的幅值时频图 win hann(winLen, periodic); % 汉宁窗, 减少频谱泄漏 nfft winLen * 4; % 频率轴插值, 让图更平滑 [S, F, ~] spectrogram(x, win, round(winLen*0.75), nfft, fs); % 第1步: 每个时刻的瞬时频率, 取该列幅值最大的频点 [~, idx] max(abs(S), [], 1); % 第2步: 提取算子, 只保留瞬时频率附近 beta Hz 内的系数 [nF, nT] size(S); IW zeros(nF, nT); for t 1:nT f0 F(idx(t)); for f 1:nF if abs(F(f) - f0) beta IW(f, t) abs(S(f, t)); end end end % 幅值归一化到 0~1, 便于后续转图像 IW IW / max(IW(:)); end逻辑说明函数先做STFT得到复数谱然后逐列找幅值最大点作为瞬时频率再从全谱中保留瞬时频率左右各beta赫兹的系数其余置零。这样一张谱里剩下的就是信号中真实存在的瞬态成分其余噪声和拖尾被过滤。注意这里用的硬阈值是简化方案真正的论文实现会用与阻尼相关的连续权重函数代替硬阈值但数据的整体流向完全一致先用这个版本跑通没有障碍。参数说明winLen256、nfft1024、beta20是一组稳妥的起点。转出来的图如果竖条纹边缘有毛刺把beta降到10再试如果背景还有大量噪点把beta加到30再试。nfft不用动4倍窗长足够。提示spectrogram输出的S是复数矩阵取abs之前不要做任何数值上的处理相位信息在脊线提取时虽然没用到但复数幅值已经是实数运算的基础保持原始输出最稳妥。4.4 批量转图归一化、尺寸统一、三通道转换一步到位TET输出的IW矩阵尺寸由nfft和时间切片数决定不同样本的结果尺寸不一致而CNN输入要求固定尺寸。常见做法是统一缩放同时按需转成三通道图像。outRoot images/train; files dir(fullfile(data/train, **, *.mat)); for i 1:numel(files) matPath fullfile(files(i).folder, files(i).name); % 变量名以实际文件为准, 这里假设是 x load(matPath, x); x x(:); % 强制转为行向量 IW tet_spect(x, 12000, 256, 20); % 12kHz采样率 img imresize(IW, [224, 224], bilinear); img uint8(img * 255); % 0~255灰度 img repmat(img, [1, 1, 3]); % 灰度复制成三通道 [~, cls] fileparts(files(i).folder); % 类别名取自上一级文件夹 outPath fullfile(outRoot, cls); if ~exist(outPath, dir), mkdir(outPath); end [~, name] fileparts(files(i).name); imwrite(img, fullfile(outPath, [name .jpg])); end逻辑说明循环读取每个mat文件调用tet_spect转图imresize统一尺寸再复制成三通道。类别名直接从文件的上一级文件夹读取保证标签和目录一一对应。imresize用双线性插值对时频图这类连续色块来说是足够的不必上更高阶插值。参数说明输出尺寸224×224对应ResNet系列的默认输入尺寸如果你用GoogLeNet或自定义网络改成对应该网络的输入尺寸即可。幅值归一化用线性方法不要用log压缩这是为了避免把微弱冲击的能量压到背景层里去具体原因在第5章避坑里说明。转完图后用imageDatastore加载trainImgs imageDatastore(images/train, ... IncludeSubfolders, true, LabelSource, foldernames); valImgs imageDatastore(images/val, ... IncludeSubfolders, true, LabelSource, foldernames);用文件夹名作为标签来源labels会自动变成类别数组后面trainNetwork直接接收。4.5 用trainNetwork快速验证一套2D-CNN基线不需要一上来就上ResNet先用一个浅层CNN跑通流程确认TET图有足够的区分度。下面这个四层卷积网络对几百个样本的小数据集非常友好训练速度快也不容易过拟合。layers [ imageInputLayer([224 224 3]) convolution2dLayer(3, 16, Padding, same) batchNormalizationLayer reluLayer maxPooling2dLayer(2, Stride, 2) convolution2dLayer(3, 32, Padding, same) batchNormalizationLayer reluLayer maxPooling2dLayer(2, Stride, 2) fullyConnectedLayer(4) softmaxLayer classificationLayer]; opts trainingOptions(adam, ... InitialLearnRate, 1e-3, ... MaxEpochs, 20, ... MiniBatchSize, 32, ... ValidationData, valImgs, ... Plots, training-progress); net trainNetwork(trainImgs, layers, opts);逻辑说明两个卷积层加池化每个卷积层后面接batchNormalization这是小数据集训练稳定的关键。训练使用了adam优化器和1e-3的初始学习率验证集传入valImgs用于监控是否过拟合。每个epoch的训练时间通常只有几十秒等训练结束后用classify在测试集上算准确率和混淆矩阵。参数说明全连接层的输出节点数改为你自己的类别数上面代码假设是4类正常、外圈、内圈、滚动体。如果你的样本量少于每类200张把卷积层的通道数从16/32降到8/16或者把MaxEpochs降到15防止小数据集直接在浅层网络上也过拟合。5. 避坑TETCNN做故障诊断最容易翻车的五个细节5.1 窗长没调好时频图“糊”成一团看不出类别差异现象转出来的图所有类别看起来都差不多都有一条粗亮的横带竖条纹的轮廓完全没有放进CNN训练loss下降慢准确率一直在七八成晃。原因窗长太短导致频率分辨率不够冲击衰减振荡的频率细节被抹平或窗长太长一个时间切片内塞了多个冲击脊线提取时被相邻冲击干扰时频图里竖条纹粘连在一起。这两个因素方向相反但结果都是图失去区分度。解决以冲击间隔为基准来初始窗长。先用包络谱估计冲击间隔大概是几十毫秒然后让窗长覆盖1到2个冲击间隔。12kHz采样的CWRU数据从256点开始逐档往大调每档都把正常、外圈、内圈三类样本各转一张图并排放着对比肉眼能看到竖条纹清晰、三类图有稳定差异时这个窗长就算定下来了。不要跳着调256到512之间经常就能碰到效果很好的值。5.2 彩色化处理丢掉了早期微弱故障信息现象训练收敛很快但现场识别的准确率上不去尤其是早期微弱故障模型基本认不出来。把训练集里故障样本的时频图打印出来看发现冲击条纹很淡背景噪点却很清楚。原因转图时用了彩色映射和log压缩。jet色系会把能量最低的区域映射成深色然后再叠加对数压缩微弱故障的冲击幅值本来就低连续两级压缩后直接沉到背景色里网络学到的是背景和条纹的对比关系而不是条纹本身。解决统一用线性归一化来转灰度图不做对数压缩。如果一定要三通道输入把单通道灰度复制三份不要在保存前用colormap做伪彩色。灰度图对CNN来说信息完全够用色系映射只会增加网络需要忽略的冗余维度。5.3 验证集和训练集之间存在数据泄漏准确率是假的现象训练曲线几乎无波动地上升到99%验证集准确率也在99%以上模型表现完美。把训练好的模型拿到现场数据上测试直接回到不到80%。原因做重叠采样时同一个原始采样文件被切成大量段部分段落到train目录部分落到val目录。这些相邻片段共享大量重合的信号点信息重叠度可能达到90%验证集形同虚设网络实际是“背”下了训练段的内容没有学会真正的故障模式。解决按文件维度做集合划分而不是按切段维度随机分。也就是先把每个原始文件完整分配到train、val、test三个集合再对集合内的文件各自切段。切完之后写一个小检查脚本打印每个样本对应的源文件名确认train和val里没有重名源文件。数据泄漏是故障诊断深度学习项目里发生率最高也最隐蔽的问题每次都值得花十分钟检查。5.4 重叠采样的样本“增肥”信息量撑不起大数据集现象用了75%重叠率数据总量从几百张膨胀到几万张训练速度慢了一截但准确率没有相应提升模型对新的未见样本反而更不稳定。原因相邻样本之间的差异只有25%大量样本可以理解为同一段信号的轻微平移。CNN卷积操作本身就有平移不变性这些高度重叠的样本对网络来说几乎是重复数据不会带来新的判别信息反而让网络在“记住这几种平移方式”上过拟合。解决把重叠率控制在50%以内让每个样本至少有一半内容是不与邻居共享的。评估数据量时看“独立信息秒数”而不是样本总数例如10秒数据、50%重叠、每段1024点等效独立样本只有100多个网络结构就要按这个量级压缩而不是按膨胀后的样本数设计。5.5 中文注释乱码和中文路径引发的玄学报错现象代码在同事电脑上跑得好好的拷到自己电脑上Matlab报一堆编码异常或者图片保存时imwrite报错提示路径无效。脚本里明明没有语法错误报错信息却杂乱无章。原因R2020b之前的Matlab默认编码是GBK新版本默认UTF-8脚本文件编码与当前环境不一致时中文注释变成乱码甚至被解析成非法字符中文路径和中文文件名的兼容性在Matlab里一直是老大难imageDatastore对中文目录的解析偶尔还会出幺蛾子。解决拿到任何脚本文件先用记事本或VS Code把它另存为UTF-8编码再放进Matlab工程根目录、数据目录、图片输出目录全部用英文命名类别文件夹用Normal、OR、IR、B这种ASCII名。中文注释不是不能用但一定要确认编码统一。这类问题说不清原理遇到了直接按这个流程排查就行。6. 进阶预训练模型迁移与Grad-CAM验证确认模型学的是物理特征浅层CNN跑通之后下一步值得做两件事一是把TET图喂给ImageNet预训练模型做迁移学习二是用Grad-CAM可视化验证网络关注的区域是不是时频图上真实的冲击位置。迁移学习的价值在于TET图本质上是纹理和边缘模式的组合ImageNet上预训练的模型对边缘、纹理、形状这些底层特征已经有很强的提取能力直接复用可以省下大量训练时间。以ResNet-18为例用Deep Learning Toolbox加载预训练模型替换最后的全连接层和分类层即可net resnet18; lgraph layerGraph(net); lgraph replaceLayer(lgraph, fc1000, ... fullyConnectedLayer(4, Name, fc4)); lgraph replaceLayer(lgraph, ClassificationLayer_Predictions, ... classificationLayer(Name, cls4));训练时用shuffle顺序加载预训练权重初始学习率降到1e-4冻结前几层的训练速度更快。预训练模型对TET图的收敛速度通常比浅层CNN快两到三倍对小数据集尤其友好。Grad-CAM验证是容易被跳过的步骤但它的价值极高。训练完成后任选一张测试图输入模型并指定类别用gradCAM函数生成热力图将其叠加在原始TET图上camMap gradCAM(netTransfer, testImg, LabelName, OR);观察热力区域是否落在时频图中冲击竖条纹出现的时刻和频带附近。如果落点集中且稳定说明模型学到的是真实的冲击特征换工况后仍然可信如果热力区域散落在背景区域说明模型可能学到了类别之间的亮度差异或噪声模式这时不要急着调网络回到第5章检查归一化方式和数据集划分。我在实际项目中的习惯是每做完一批TET图先抽十张肉眼扫一遍再进训练训练完再做一次Grad-CAM抽查。这两步加起来不到十分钟能省掉后面大量排错时间。留个心眼TET图的质量直接决定了这个流程的天花板图对了模型只是帮你把这个上限兑现出来。希望这次分享的思路和代码能帮你少走一些弯路祝顺利跑通自己的故障诊断项目。本文还有配套的精品资源点击获取