MATLAB振动故障诊断全流程:特征提取与机器学习模型实战
发布时间:2026/10/2 3:43:45来源:尧图网络
简介针对旋转机械振动故障诊断的MATLAB源码资料包面向设备状态监测工程师、故障诊断方向研究生及自动化专业学生用于学习如何从振动信号中提取故障特征并识别不平衡、不对中、松动、裂纹等常见故障模式。包内共26个文件以25个.m脚本程序为主附带1个txt说明文档整体仅49KB便于快速下载和对比运行。源码覆盖振动信号预处理与滤波去噪、短时傅里叶变换与频谱分析、小波降噪与多分辨率分析、希尔伯特边际谱解调、模态参数估计等常用方法同时提供均值、方差、自相关方差、峭度、概率密度、时间序列重建等统计特征提取函数可串联起从原始振动序列到故障特征判别的完整流程。每个程序均以独立函数或脚本形式组织命名清晰便于按需调用和二次开发。目前已有143人学习浏览适合希望快速上手MATLAB振动信号处理与诊断建模的读者可直接修改参数迁移至滚动轴承、齿轮箱等实际设备监测场景为设备健康管理提供可靠的技术参考。1. 拿到「振动故障诊断.zip」这种 MATLAB 包先想清楚要解决什么问题拿到一个叫「振动故障诊断.zip」的 MATLAB 压缩包常见的困惑是里面脚本不少哪些是主干跑出来一张 99% 准确率的表之后还能干什么。振动故障诊断不神秘——把加速度传感器采到的波形按故障类型切片、提特征、训练分类器最后输出“哪个轴承坏了、坏到什么程度”的判据。对设备维护工程师它把靠耳朵听的经验变成可复现指标对做状态监测的研发它是信号处理到机器学习落地的完整链路。这篇笔记按我实际调这类代码的流程把数据读入、特征工程、模型训练和验证每一步的参数选择与踩坑写清楚适合手里有振动数据但不知道从哪下手的读者也适合想评估一个诊断思路值不值得投入的熟手。2. 振动信号特征提取从一维波形到故障证据所有基于机器学习的振动诊断第一步都是把一段几万点的波形压缩成几十个标量特征。别急着上深度学习先把物理特征吃透——故障在波形上留下的痕迹是确定的特征只是把这些痕迹翻译成数字。这一章按时域、频域、时频域三条路讲最后你会得到一个可以直接拼成特征矩阵的提取函数。2.1 时域特征RMS、峭度、峰值因子各自在抓什么时域特征直接对原始波形做统计计算量小、物理含义明确是最先要做的。RMS有效值反映振动能量轴承磨损、转子不平衡都会让它上升但早期故障占整体能量比例很小RMS 往往不够敏感。峭度反映分布是否“尖峰化”正常振动接近高斯分布经典定义下峭度约等于 3轴承出现点蚀后会产生周期性冲击峭度显著抬高。峰值因子是峰值除以 RMS它刻画“瞬态冲击相对整体能量有多突出”早期故障时冲击还不明显这个指标比 RMS 先变色。我一般用下面这段代码提取一组时域特征。注意 MATLAB 自带的kurtosis()返回的是超额峭度高斯分布对应 0而很多故障诊断文献里的阈值 3.5 是经典定义高斯分布对应 3换算错位是新手最常见的翻车点所以我习惯自己写公式。function feat time_domain_features(x) % x: 单通道振动信号列向量建议长度不小于 4096 点 x x(:); N length(x); feat.rms sqrt(sum(x.^2) / N); % 有效值振动能量 feat.peak max(abs(x)); % 峰值 feat.crest feat.peak / feat.rms; % 峰值因子对早期冲击敏感 mu mean(x); sigma std(x); % 峭度用经典定义高斯分布约为 3便于对照文献阈值 feat.kurt mean((x - mu).^4) / (sigma^4); % 偏度齿轮局部磨损可能破坏分布对称性 feat.skew mean((x - mu).^3) / (sigma^3); feat.pp peak2peak(x); % 峰峰值对松动、碰撞敏感 end逻辑说明先对信号去中心化再算高阶矩避免直流偏置干扰峭度用四次方除以方差平方量纲被消除所以它和传感器灵敏度无关适合跨设备比较。参数说明里最值得提的是样本长度——一个样本至少要覆盖 10 个以上故障周期。以 1500 rpm、转频 25 Hz 的轴承为例一个 1024 点、采样率 25.6 kHz 的样本只包含 10 个转频周期勉强够用时域统计用但包络谱会嫌短建议按 4096 点起取。特征物理含义对什么故障敏感RMS振动能量磨损、不平衡、不对中峭度分布尖峭程度轴承点蚀、早期冲击峰值因子峰值与 RMS 之比早期冲击相对整体能量峰峰值最大位移范围松动、碰撞2.2 频域特征FFT 频谱和包络谱怎么配合FFT 频谱看的是振动能量在频率上的分布。转子不平衡会在 1 倍转频处出现明显谱峰不对中常伴随 2 倍转频抬高齿轮故障会出现啮合频率及其边带。但轴承故障是另一套逻辑故障冲击会激起传感器或结构的高频谐振故障特征频率本身很弱直接看频谱基本发现不了必须做包络解调。包络谱的流程是先用 Hilbert 变换得到解析信号的幅值即包络再对包络做 FFT。故障冲击被解调成包络里的周期性起伏其特征频率就显现了。下面是两个函数前者是带汉宁窗的频谱后者基于前者做包络谱。function [f, amp] fft_spectrum(x, fs) N length(x); x x - mean(x); % 去直流 win hanning(N, periodic); X fft(x .* win); % 单边谱幅度校正因子 2/sum(win)汉宁窗相干增益约 0.5 amp abs(X(1:floor(N/2))) .* 2 ./ sum(win); f (0:floor(N/2)-1) * fs / N; end function [f, env_amp] envelope_spectrum(x, fs) env abs(hilbert(x)); % 包络解调 env env - mean(env); [f, env_amp] fft_spectrum(env, fs); % 对包络做频谱 end逻辑说明hilbert(x)返回解析信号取绝对值就是包络。包络里是缓慢变化的冲击幅值FFT 后对应故障特征频率位置的谱峰。参数说明汉宁窗能压频谱泄漏但会牺牲频率分辨率频率分辨率是fs/N样本越长时间窗越宽分辨率越高幅度校正因子对非整周期截断的信号仍然有残余误差所以工程上更看重谱峰位置而不是绝对幅值。轴承故障特征频率由几何参数和转频算出比如外圈故障 BPFO、内圈 BPFI包络谱的峰应该落在这些理论频率附近偏差超过 1% 就要怀疑转速读数或几何参数不对。2.3 时频域小波包和 EMD 什么时候值得上FFT 把整个样本的能量做了全局平均变转速、启停机、冲击性工况下瞬时频率信息被抹掉频谱特征不稳定。这时需要时频分析。小波包分解把信号按频带逐层细分每层节点的能量占比可以做特征适合频带能量模式稳定的故障经验模态分解EMD把信号拆成若干本征模态函数 IMF自适应性强但存在模态混叠同一个故障可能被拆进多个 IMF。MATLAB 里小波包用wpdec建树、wpcoef取节点系数EMD 在 Signal Processing Toolbox 里有现成的emd()R2018a 之后稳定可用。下面是提取小波包频带能量占比的代码。function band_energy wp_band_energy(x, level, wname) T wpdec(x, level, wname); % 建立小波包分解树 n_band 2^level; % level 层对应 2^level 个频带 band_energy zeros(1, n_band); for i 1:n_band node n_band - 1 i; % 第 level 层节点编号从 2^level-1 开始 coef wpcoef(T, node); band_energy(i) sum(coef.^2); end band_energy band_energy / sum(band_energy); % 归一化成能量占比 end逻辑说明wpdec的第三层节点编号从 7 到 14对应 8 个等宽频带wpcoef取出节点系数后按能量求和再归一化这样特征与信号幅值无关跨传感器可比。参数说明分解层数决定频带宽度25.6 kHz 采样率下 3 层分解每个频带宽 1.6 kHz层数加一特征维数翻倍样本数不足时训练会明显退化优先保证每类样本不少于 100 条再考虑加深。EMD 计算慢且有模式混叠经验是先用小波包EMD 只在小波包分不开的工况里做交叉验证。3. 用 MATLAB 跑通振动诊断最小流程从文件夹到诊断准确率特征函数写好后剩下的工作是把数据组织好、批量提特征、归一化、训一个分类器。这一章给一条能完整跑通的最小链路照着改路径和字段名就能出结果。3.1 数据组织按故障类型分文件夹、分段与多通道读取常见做法是把数据按故障类型放在不同子文件夹里每个文件夹下若干.mat或.csv文件。读入后要做分段一段连续波形通常有几秒到几十秒几万到几百万个点直接当一条样本既浪费又会让类别不均衡正确做法是滑窗切段段与段之间可以重叠以增加样本量。function [featMat, labels] build_dataset(data_root, seg_len, overlap) % data_root 下每个子文件夹是一种故障类型文件夹名即标签 sub dir(data_root); featMat []; labels []; step round(seg_len * (1 - overlap)); % 重叠率决定滑窗步长 for i 1:length(sub) if ~sub(i).isdir || strcmp(sub(i).name, .) || strcmp(sub(i).name, ..) continue; end files dir(fullfile(data_root, sub(i).name, *.mat)); for j 1:length(files) d load(fullfile(data_root, sub(i).name, files(j).name)); sig d.signal; % 字段名按你的数据改常见的是 X、DE、acc for k 1:step:length(sig) - seg_len 1 seg sig(k:kseg_len-1); featMat [featMat; extract_feature_vec(seg)]; labels [labels; i]; end end end end逻辑说明文件夹遍历用的是dir加isdir过滤标签取文件夹顺序号滑窗从 1 开始按步长切保证每个窗口不越界。参数说明seg_len就是单条样本点数和 2.1 里说的 4096 起取一致overlap取 0 到 0.75重叠越大样本越多但相邻样本相关性越强后续划分数据时更要小心泄漏。多通道数据常见做法是把每个通道的特征横向拼接MATLAB 里取多列就是sig d.data(:, 1)如果多通道相关性高先做 PCA 降维再拼接否则特征维数膨胀很快。extract_feature_vec是把 2.1 和 2.2 的时域、频谱、包络谱特征拼成一行向量的包装函数实际项目中还会把第 2.3 节的小波包频带能量拼进去。3.2 特征拼接与归一化均值方差只能在训练集上算特征量纲差异很大——RMS 是加速度值数量级可能是 0.1峭度是纯数字数量级是 3 到 10包络谱谱峰幅值又完全不同。不归一化的 SVM 和神经网络会天然偏向数值大的特征。归一化用 z-score 即可但这里有一条铁律均值和标准差只能在训练集上计算测试集必须沿用同一组参数。rng(42); idx randperm(size(featMat, 1)); n_train round(0.7 * length(idx)); train_idx idx(1:n_train); test_idx idx(n_train1:end); X_train featMat(train_idx, :); y_train labels(train_idx); X_test featMat(test_idx, :); y_test labels(test_idx); % 标准化参数只在训练集上估计 mu mean(X_train); sd std(X_train); % 常数列标准差为 0直接丢弃或置 1 防止除零 sd(sd eps) 1; X_train (X_train - mu) ./ sd; X_test (X_test - mu) ./ sd;逻辑说明randperm打乱样本索引后按比例切分rng(42)固定随机种子保证可复现。参数说明归一化参数必须从训练集算否则测试集的均值方差会“泄漏”进训练流程最终准确率虚高、现场数据一测就崩这是诊断项目里最隐蔽也最致命的坑。标准差接近 0 的特征说明该特征在训练集里几乎不变丢掉它不会损失信息反而能避免除零。3.3 分类器怎么选SVM、神经网络和随机森林的取舍故障诊断的常用分类器就三类SVM、BP 神经网络、随机森林。我的选型习惯是样本量小于几千条时优先 SVM它在小样本高维特征上很稳样本上万且特征分布复杂时再考虑神经网络要求快速上线、不想精细调参时用随机森林它对特征标准化不敏感省掉 3.2 那一步也能跑。分类器数据量需求是否需要标准化主要超参数可解释性SVMfitcecoc小样本即可需要核函数、BoxConstraint、KernelScale低BP 神经网络大样本需要隐层节点、学习率、正则化差像黑匣子随机森林中等样本不需要树数量、最小叶节点中可看特征重要性SVM 多分类在 MATLAB 里用fitcecoc底层是若干二分类器投票。下面这段是标准训练代码注意我们已经在 3.2 手动标准化过所以要把fitcecoc自带的标准化关掉避免重复计算。mdl fitcecoc(X_train, y_train, ... Learners, templateSVM(KernelFunction, rbf, ... BoxConstraint, 1, ... KernelScale, auto), ... Standardize, false); % 已手动标准化这里必须关 y_pred predict(mdl, X_test); acc mean(y_pred y_test); fprintf(测试集准确率: %.2f%%\n, acc * 100);逻辑说明templateSVM配置基分类器RBF 核把特征映射到高维空间处理非线性边界fitcecoc自动处理多类问题。参数说明KernelScale设auto时按训练集自动估计核宽度特征标定不准时容易出问题BoxConstraint越大对训练集边界越严格、越容易过拟合常见范围是 0.1 到 10先按 1 跑基线再上下扫。神经网络如果要用MATLAB 里的patternnet能快速搭一个单隐层网络但收敛依赖随机初始化和学习率复现性差建议只在样本量足够时和 SVM 对比着用。4. 振动故障诊断里最容易翻车的 5 个坑现象、原因与排查思路这一章是血泪经验汇总。每个坑我都按“现象 → 原因 → 解决”写排查时照着顺序过一遍能省下大量时间。4.1 频谱图出现镜像峰采样率和频率轴没对齐现象FFT 频谱在某个频率两侧对称出现两个峰或者谱峰频率和理论转频对不上。原因采样率fs写错比如实际采集是 25.6 kHz代码里写成了 12.8 kHz或频率轴生成公式不对把 Nyquist 频率算错了。解决固定用f (0:floor(N/2)-1) * fs / N生成频率轴并在处理真实数据前先用一个已知频率的标准正弦信号验证整条链路。我自己习惯把采样率写进数据文件名或旁边一个 txt而不是依赖代码里的默认值。4.2 峭度指标翻车高通滤波把冲击能量滤没了现象轴承已经有明显点蚀峭度却接近 3和正常状态没差别。原因预处理里加了高通滤波截止频率定太高比如 5 kHz而轴承冲击的能量主要分布在由结构谐振决定的频段被滤掉了另一种可能是样本太短冲击事件没有完整包含在窗内。解决先对原始波形算时域特征需要滤除趋势项时用低于故障特征频率的截止频率样本长度按 10 个故障周期起步拿不准就把 2.1 的代码在滤波前后各跑一遍对比。4.3 变转速工况下模型全部失效转频漂移打乱了特征分布现象训练集用 1500 rpm 的数据准确率 99%拿到现场变速工况直接掉到 60% 上下。原因FFT 和包络谱特征都依赖绝对频率转速一变故障特征频率整体平移分类器学到的其实是转速而不是故障。解决优先做阶次跟踪把横轴从频率换成转频倍数或者改用小波包频带能量这种相对特征它对转速变化的鲁棒性强一些。另一个务实方案是训练数据里显式混入多转速样本让分类器学会忽略转速差。4.4 99% 准确率是假的数据划分泄漏现象测试集准确率接近满分心里发虚果然现场新数据一测就崩。原因同一段连续波形滑窗切出的相邻样本高度相似随机打乱后训练集和测试集里各混了一部分模型相当于“背答案”。按样本划分而不是按文件划分是所有特征工程项目里最典型的隐藏泄漏。解决划分必须按原始文件分组进行保证测试集整段文件不参与训练代码用cvpartition(file_ids, KFold, 5)按文件编号分组。准确率回归到 90% 以下不要慌那才是真实水平。4.5 MATLAB 版本和工具箱差异函数调用崩溃现象老代码在 R2022b 上跑wpddec、nprtool报“未定义函数”或者信号处理工具箱的函数签名变了。原因MATLAB 版本迭代会移除或改名老函数新版本的小波工具箱和神经网络工具箱接口变化很大有些代码还依赖了第三方工具箱换个机器就没装。解决先ver(wavelet)和which wpdec确认工具箱存在及函数路径再查doc找替代函数项目启动时把它写成一个环境检查脚本跑数据前先过一遍比运行到一半报错好得多。安装一个新版本 MATLAB 后第一件事也是跑这个检查别等高成本代码跑挂了再回头查。5. 模型验证让诊断结果能扛住现场工况的三个关卡训练集上的准确率只是及格线。诊断模型要上现场至少要过三关文件级分组交叉验证、按漏报误报评估、以及处理实验室数据到现场数据的偏移。5.1 文件级分组交叉验证避免特征泄漏单次划分结果波动大样本少时尤其明显。工程惯用做法是 K 折交叉验证但必须按文件分组做。file_ids build_file_id_list(data_root); % 每个样本对应原始文件的编号 cv cvpartition(file_ids, KFold, 5); % 按文件分组做 5 折 fold_acc zeros(cv.NumTestSets, 1); for k 1:cv.NumTestSets tr cv.training(k); te cv.test(k); fold_acc(k) train_and_eval(X_train(tr,:), y_train(tr), ... X_train(te,:), y_train(te)); end fprintf(5 折平均准确率: %.2f%%±%.2f%%\n, ... mean(fold_acc)*100, std(fold_acc)*100);逻辑说明cvpartition的第一个参数是分组变量同一文件切出的所有样本会被分进同一折杜绝跨折泄漏。参数说明折数 K 取 5 是兼顾偏差和方差的常规选择类别不平衡时加Stratify, true保证每折里各类比例接近总体。标准差大于 5 个百分点说明模型对某几组数据很不稳优先检查那几折对应的文件是否有异常。5.2 混淆矩阵、漏报与误报诊断指标比准确率重要准确率把正常和故障一视同仁但在设备诊断里把坏轴承判成正常漏报的代价远大于把正常误报成故障。误报最多让人多检查一次漏报直接导致非计划停机。所以要单独看每类的召回率和精确率。cm confusionmat(y_test, y_pred); % 类别 1比如正常的召回率漏报越多这个值越低 recall_1 cm(1,1) / sum(cm(1,:)); % 类别 1 的精确率误报越多这个值越低 precision_1 cm(1,1) / sum(cm(:,1)); % F1 综合两者 f1_1 2 * precision_1 * recall_1 / (precision_1 recall_1);逻辑说明confusionmat生成混淆矩阵行是真实类别列是预测类别对角线是判对的样本。参数说明诊断类项目我会把正常类别的召回率作为核心指标它低于 95% 就说明模型会把故障放过这种情况下宁可选一个总准确率稍低但漏报更少的模型。5.3 实验室数据到现场数据特征偏移怎么处理实验室数据干净、转速稳定、传感器安装规范现场数据振动大、转速波动、安装位置不同特征分布天然偏移。这是诊断模型落地最现实的障碍调参解决不了得靠策略。常见做法是先用实验室数据训练再到现场采集少量有标签数据做阈值微调或简单迁移学习如果现场标签难获得退一步只做“正常 vs 异常”二分类用正常状态数据建立基线偏离基线即报警比强行分故障类型更可靠。这个方向不依赖大量现场标签也保留了物理可解释性是投入产出比最高的落地路径。6. 把脚本封装成现场随手能用的诊断小工具训练好的模型如果只留在脚本里换个人就不知道怎么用了。我的一般做法是把训练好的模型、归一化参数、特征提取函数封装成一个小工具现场人员只需要选文件点按钮。6.1 训练好的模型怎么带到新机器上训练完成后把分类器和归一化参数存成一个.mat文件新机器上启动工具时直接加载不需要重装训练环境。核心代码就三行% 保存模型和参数包括 mu、sd 这两个归一化参数 save(trained_model.mat, mdl, mu, sd); % 新数据预测时加载并复用 S load(trained_model.mat); feat extract_feature_vec(new_signal); feat_norm (feat - S.mu) ./ S.sd; label predict(S.mdl, feat_norm);逻辑说明特征提取必须和训练时完全一致函数、参数顺序都不能改否则特征含义错位保存时把mu和sd一并存进去避免每次预测前重新算。参数说明现场数据进来后先看一眼采样率是否和训练数据一致不一致时要么重采样要么直接拒判这是现场翻车最常见的原因。6.2 批处理与报表输出现场需求往往是批量处理几十个文件并出一张表。用writetable导出 Excel 是成本最低的方案T table(file_names, pred_labels, rms_vals, kurt_vals, ... VariableNames, {文件名, 诊断结果, RMS, 峭度}); writetable(T, diagnosis_report.xlsx);输出的表按诊断结果排序把异常项排在最前面现场人员一眼能看到该处理哪台设备。最后说一个我自己的习惯每个数据文件旁边放一个 txt记录采样率、转速、负载和传感器安装位置没有这些元数据特征算得再准也无法复现和对比。这个习惯救过我很多次也是所有诊断模型能持续迭代的根基希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网