2026/10/16 15:38:32

基于MATLAB的轴承故障诊断:包络谱分析与SVM建模实战

基于MATLAB的轴承故障诊断:包络谱分析与SVM建模实战 简介面向机械工程领域的研究人员和技术人员这份资料以Matlab/Simulink为工具围绕西储数据轴承的动力学建模与仿真展开可应用在轴承性能评估、故障诊断和优化设计等研究项目中帮助将实测数据转化为可仿真的动力学模型。资源共4个文件压缩包约287KB涵盖PDF、Markdown、HTML和Word四种格式PDF适合完整研读理论Markdown与HTML便于快速查阅和在线浏览Word版则可按需编辑批注。目前已有610人学习下载。内容从轴承动力学基础理论写起覆盖力学特性与运动规律并完整演示了从读取西储数据、定义模型参数、构建动力学方程到使用Simulink完成仿真并输出图表的全流程附带一段简化Matlab代码示例可让读者快速跑通建模过程同时理解不同参数配置对仿真结果的影响。掌握基本Matlab编程后可在此基础上扩展模型提前发现潜在故障降低实验成本并提升设计质量与效率。1. 轴承数据驱动建模的完整链路从振动信号到可运行脚本做轴承故障诊断时数据驱动建模眼下是绕不开的技术路子——设备缺少精确物理参数但振动信号一抓一大把。这套基于 MATLAB 的轴承动力学建模与仿真代码正好把“数据读取→包络谱分析→特征工程→分类器训练→仿真验证”整条链路补齐了。它默认针对一组公开的滚动轴承实验台振动数据常见于机械工程与故障诊断方向的课程设计和毕业课题。适合谁用一是做设备健康管理项目的在校学生二是想快速验证特征频率理论的工艺工程师三是想拿现成脚本复现完整流程的仿真从业者。下面先把建模思路讲透再落到每段代码和参数上最后几节专门讲排查技巧保证你拿到资源后能直接跑通。2. 数据驱动模型为什么可行包络解调与特征工程选型2.1 物理模型与数据驱动模型的边界真正的轴承动力学模型会从赫兹接触、油膜刚度、保持架碰撞这些机理出发建立一组微分方程。这套做法在学术上很完整可生产现场往往凑不齐参数润滑脂牌号影响刚度游隙和预紧力随着温度漂移轴承座结构还会带来复杂谐振。真按物理模型去抄参数仿真结果经常和实测振动对不上。数据驱动建模的思路是绕开“硬参数”直接让统计特征和故障模式建立映射。最典型的一组公开实验台数据是电机驱动端和风扇端在四种工况下的振动文件。这类数据的优势有两个一是转频、采样率、负载扭矩都是文档化了的二是同一故障类型包含多组样本足够喂给分类器。我的选型建议是不要一上来就套深度学习。轴承数据一条样本动辄上万点深度学习模型需要大量样本而公开数据集的故障类别单类样本往往只有几十组。SVM 这类经典模型在小样本、多类别、特征维度几十到几百的情形下更稳训练快出错了也好查。代码包里默认的也是 SVM适合作为基准方案先跑通后面想换随机森林或者神经网络时再扩展。2.2 包络解调与故障特征频率BPFO、BPFI 怎么算真实轴承的振动信号不是直接藏在波形里。滚动体路过外圈、内圈故障点时会产生周期性冲击这个冲击会调制在轴承系统的固有频率上固有频率通常在几千赫兹而故障冲击频率只有几百赫兹。在这类信号里直接做频谱分析看到的只会是共振峰附近的一大片模糊故障频率根本看不清。所以包络解调是必须做的前置步骤。常用的做法是希尔伯特变换求出原始信号的解析信号再取模得到包络包络里保留的就是每个冲击周期的强度起伏这时候再做 FFT故障特征频率就清晰了。计算四个特征频率要记住四组公式外圈故障频率(BPFO)f_BPFO N/2 × f_r × (1 − (d/D)·cosα)内圈故障频率(BPFI)f_BPFI N/2 × f_r × (1 (d/D)·cosα)滚动体故障频率(BSF)f_BSF (D/d) × f_r × (1 − ((d/D)·cosα)²保持架故障频率(FTF)f_FTF f_r/2 × (1 − (d/D)·cosα)其中 N 是滚动体个数f_r 是转频由转速算出注意减去电机滑差d 是滚动体直径D 是轴承节径α 是接触角。很多人在这一步翻车因为只按铭牌同步转速算 f_r忽略了负载下的滑差。公开数据集中每个工况的负载功率如 0 HP 到 3 HP都需要换算考虑。提示接触角的数值不要照抄出厂值要按公开数据的实验条件核对。大多数深沟球轴承在轻载下接触角接近 0°但载荷增大后 α 会变大BPFO 计算值差出几个赫兹很常见。2.3 特征工程时域统计与频带能量的取舍包络谱只给出了一个观察角度分类器还需要一组量化的特征向量。代码包里提取三类特征时域统计特征。常用的是均方根值 RMS、峰度、峰值因数和整流平均值。峰度特别适合早期故障预警因为正常振动接近高斯分布峰度在 3 左右一旦出现周期性冲击信号尾部变厚峰度能飙到 5 甚至 10 以上。频带能量特征。把包络谱划分成几个频带统计每个频带的能量占比。滚动体故障会导致特定区间带能量集中这些特征带来的区分度远高于只看 RMS。包络谱峰值频率。直接从包络谱中提取前三个最强的峰值频率及其幅值这个特征可以认为是故障的直接证据。这里想提醒一下特征不是越多越好。数据驱动建模最怕的就是特征维度高、样本量少SVM 在无关特征干扰下会变得不稳定。建议特征数量控制在 10 到 20 个之间先跑一轮再用逐步回归或互信息法筛选一遍。代码包里已经排好了一个固定的特征向量顺序后面可以自己加列但一定记得同步改维度。3. 完整 MATLAB 实现数据划分、包络谱计算与 SVM 训练3.1 数据加载与数据集划分拿到公开数据集后先不要着急读数据。第一步是搞清楚每个 .mat 文件里的变量名。实际数据文件里变量可能叫 DE、FE、BA 之类的缩写也可能混着时间序列和采样率信息直接按固定变量名加载没两次就踩坑。dataRoot /path/to/dataset; fileList dir(fullfile(dataRoot, *.mat)); % 先看第一个文件的变量结构 vars whos(-file, fullfile(dataRoot, fileList(1).name)); disp({vars.name});逻辑说明dir列出目录下所有 .mat 文件whos(-file, ...)不加载而直接读取文件内的变量名。这一步花十秒钟能省掉后面大量的变量名冲突问题。输出结果里会显示变量名和维度接下来再写加载逻辑就清晰了。参数说明dataRoot建议先用绝对路径。MATLAB 的相对路径解析与脚本所在目录、当前工作目录都有关换机器以后相对路径经常莫名失效。数据集划分是整个流程中最容易出错的地方。惯用做法是按“实验记录”切分而不是按“样本行”切分。如果某个文件是一段连续的时域信号你把这段信号的前 80% 当作训练、后 20% 当作测试相邻数据点在时间上强相关训练集与测试集信息重叠测试准确率虚高会误导后期部署判断。% 按文件名称分组同一文件的样本只在训练集或只在测试集 fileIDs extractBefore({fileList.name}, _); [groups, fileIDVec] ismember(fileIDs, unique(fileIDs)); % 用 cvpartition 划分文件组 cv cvpartition(unique(fileIDs), Holdout, 0.2); testFiles fileList(cv.test, :); trainFiles fileList(training(cv), :);逻辑说明先用文件名前缀区分不同实验记录再对实验记录做划分避免同一记录的样本同时出现在训练集和测试集。参数说明Holdout取 0.2 表示留出 20% 的记录做测试如果总文件数很少可以调小这个比例。总记录数小于 10 时建议用留一法做交叉验证Holdout 切出来的测试集太小误差方差会很大。3.2 包络谱计算与特征提取拿到数据后第一个处理块就是包络解调。注意希尔伯特变换要求输入为实数信号采样率必须和数据集文档严格一致否则频率轴全错。fs 12000; % 采样率按数据集文档确认 vib loadData; % 从文件提取振动信号列向量 N length(vib); t (0:N-1)/fs; % 时间轴 % 希尔伯特变换提取包络 env abs(hilbert(vib)); env env - mean(env); % 去直流避免零频峰 NFFT 2^nextpow2(N); % 补零到 2 的幂便于 FFT f fs * (0:NFFT/2-1) / NFFT; envSpec abs(fft(env, NFFT)); envSpec envSpec(1:NFFT/2); % 找前三个峰值 [pks, locs] findpeaks(envSpec, f, NPeaks, 3, SortStr, descend);逻辑说明hilbert返回解析信号abs取模后得到包络fft计算包络谱。findpeaks直接输出峰值幅值和对应频率这里的频率就是后续特征向量里最关键的列。参数说明NFFT用2^nextpow2(N)会让频谱点数略大于原始信号长度提高频率分辨率的是原始采样时长而不是补零长度补零只让谱线变密不会增加真实分辨率。如果你的样本长度是 12000 点直接用原始长度做 FFT 更诚实NFFT补到 16384 不影响结果但会拉长数组后续循环处理多段数据时要注意内存。特征提取要把多个文件循环处理整理成一个二维特征矩阵。单个仿真里常见做法是这样nFiles length(trainFiles); features zeros(nFiles, 11); labels strings(nFiles, 1); for k 1:nFiles d load(fullfile(dataRoot, trainFiles(k).name)); fld fieldnames(d); vib d.(fld{1}); % 按变量名字段动态取用 env abs(hilbert(vib)); env env - mean(env); L length(env); NFFT 2^nextpow2(L); envSpec abs(fft(env, NFFT)); fvec (0:NFFT/2-1) * fs / NFFT; envSpec envSpec(1:NFFT/2); [pks, locs] findpeaks(envSpec, fvec, NPeaks, 3, SortStr, descend); features(k, 1) rms(vib); features(k, 2) kurtosis(vib); features(k, 3) max(abs(vib)) / rms(vib); features(k, 4) mean(abs(vib)); features(k, 5) sum(envSpec(1: round(NFFT/4))); features(k, 6) sum(envSpec(round(NFFT/4)1: round(NFFT/2))); features(k, 7) pks(1); features(k, 8) locs(1); features(k, 9) pks(2); features(k, 10) locs(2); features(k, 11) locs(3); labels(k) extractBefore(trainFiles(k).name, _); end逻辑说明循环内部复用前一步的包络谱特征 1 到 4 是时域统计特征 5 和 6 是低频与高频频带能量特征 7 到 11 是包络谱前三个峰值的幅值和频率。特征列对应的含义要记清楚模型调好的后面看混淆矩阵时这个映射能帮你判断哪个特征最有区分能力。3.3 标准化与 SVM 训练特征矩阵各列的量纲完全不同RMS 是振动加速度单位峰度是无量纲数包络峰值幅值可能相差几十倍。直接把原始特征丢给 SVM核函数距离会被大数量级的列主导小波动特征的贡献被淹没。标准化放在划分之后用训练集的均值和标准差去处理测试集这在数据处理顺序上是强制要求。rng(2024); cvp cvpartition(findTrainIdx, KFold, 5); % 用训练集计算均值方差 mu mean(features(trainIdx,:), 1); sigma std(features(trainIdx,:), 0, 1); ftrTrain (features(trainIdx,:) - mu) ./ sigma; ftrTest (features(testIdx,:) - mu) ./ sigma; % 多分类 SVM用错误纠错码模型包装 mdl fitcecoc(ftrTrain, labels(trainIdx), ... Learners, templateSVM(KernelFunction, rbf, ... BoxConstraint, 1, KernelScale, auto)); % 预测并评估 pred predict(mdl, ftrTest); acc sum(pred labels(testIdx)) / numel(labels(testIdx));逻辑说明std(X,0,1)求每列标准差第一个参数 0 表示减去均值按列计算。fitcecoc把二分类 SVM 扩成多分类模型内部自动对每个类别对训练独立的二分类器templateSVM的定义决定了每个子分类器都是 RBF 核支持向量机。注意learners参数如果用svm字符串就是默认线性核换 RBF 核必须用templateSVM指定。线性核在高维特征空间通常够用但遇到故障特征混叠严重要用 RBF 调。BoxConstraint越大对训练误差惩罚越重例如 100 时训练准确率会明显提升但测试效果未必变好。4. 排查模型训练中五个典型问题与对策4.1 特征频率算错包络谱峰值和理论值对不上现象内圈故障数据做包络谱后最强峰出现在 1.2 倍 BPFI 附近和计算值差了几百赫兹。原因多半是转频取错了。公开数据集提供的电机转速是同步转速例如 1797 RPM而实际负载下转差率会让转子转速低于同步转速另一个原因是接触角用了默认值 0°但大负载工况下接触角变化会让计算出的 BPFI 有几赫兹误差。解决用测得的实际转速换算 f_r不建议用铭牌值把接触角敏感度写进一个参数先跑一遍小范围扫描观察频率峰值是否随预计方向移动。常见做法是 0°、5°、10°、15°各算一次看哪个值能让包络谱峰频率落在 BPFI 理论值正负 0.5% 内。4.2 数据集划分不当测试准确率高得不真实现象5 折交叉验证准确率 99%拿到新采集数据后跌到 70% 上下。原因故障信号是周期性强、相邻段高度相关的时间序列你用随机抽样把同一段振动文件的头尾切到了训练集和测试集两者的统计特性几乎一样模型相当于“开卷考试”。解决强制按文件名前缀划分文件组同一实验记录的数据不允许跨集合切分之后检查训练集和测试集的标签分布比例如果某一类故障完全没进训练集先补样本再训练。4.3 特征归一化放错位置训练时一切正常、部署时全乱现象训练脚本准确率高换到在线采集场景分类结果明显偏斜。原因先对所有特征矩阵做全局标准化再进行训练测试划分这会让测试集样本的均值方差混进训练时的归一化参数。实际部署时只有单个样本没有这批全局统计量兜底特征分布就变了。解决严格划分完再看归一化mu和sigma只由训练集计算测试集做同样的平移缩放后送入模型把mu、sigma、模型对象一起存成 .mat 文件部署时一并加载。4.4 低通滤波参数过狠滚动体故障特征消失了现象滤波之后包络谱里 BSF 频段干净得没有峰反而出现了很多莫名峰。原因用了普通 IIR 滤波器滤波器相位在截止频率附近有非线性失真冲击信号的包络被拉宽甚至变形。滚动体故障本来就是能量微弱、频率很高的冲击滤波畸变会把故障特征直接抹掉。解决尽量用filtfilt做零相位双向滤波这样相位失真是零。这里我一般会先保留原始信号包络谱提取在原始数据上做滤波只用于辅助观察时域波形。4.5 SVM 报错提示标签必须为二元分类现象调用fitcsvm时直接报错提示响应变量必须有且仅有两个类别。原因fitcsvm只支持二分类内圈、外圈、滚动体、正常四类数据无法直接塞进去。很多人在这里以为是数据有问题实际是选错了函数。解决换成fitcecoc它是多分类封装内部自动生成多个二分类器再做投票。如果某次只想做“正常 vs 异常”二分类那用fitcsvm没有任何问题可以自由选择。5. 进阶操作用贝叶斯优化调超参数再把它固化成 Simulink 模块上一章里的BoxConstraint和KernelScale是我随手拍的值。真正要把模型推向实用这两个参数不能靠玄学定交给贝叶斯优化是更高性价比的选择。贝叶斯优化比网格搜索更适合 SVM因为每次评估都要训练一次模型网格搜索动辄几十上百组优化算法一般十几轮就能收敛到不错的区域。box optimizableVariable(BoxConstraint, [1e-2, 1e2], Transform, log); scale optimizableVariable(KernelScale, [1e-2, 1e2], Transform, log); objfun (params) kfoldLoss(fitcecoc(ftrTrain, labels(trainIdx), ... Learners, templateSVM(KernelFunction, rbf, ... BoxConstraint, params.BoxConstraint, ... KernelScale, params.KernelScale), KFold, 5)); results bayesopt(objfun, [box, scale], ... MaxObjectiveEvaluations, 25, UseParallel, false);逻辑说明kfoldLoss返回 5 折交叉验证的平均损失作为目标函数bayesopt在指定范围内搜索、评估、更新概率代理模型在较少评估次数内逼近最优解。参数说明Transform设为log表示在对数尺度上均匀采样。这两个参数跨了几个量级直接线性采样会大量浪费在无效区间。UseParallel设false是因为每个目标函数计算量不算大并行通信开销反而更高。优化完成后用最优参数重新训练最终模型然后导出供 Simulink 调用bestMdl fitcecoc(ftrTrain, labels(trainIdx), ... Learners, templateSVM(KernelFunction, rbf, ... BoxConstraint, results.XAtMinObjective.BoxConstraint, ... KernelScale, results.XAtMinObjective.KernelScale)); saveLearnerForCoder(bestMdl, bearingModel);saveLearnerForCoder会把模型序列化成适用于代码生成的格式之后在 Simulink 的 MATLAB Function 块中调用mdl loadLearnerForCoder(bearingModel); predLabel predict(mdl, double(featureRow));这里要注意三点一是 Simulink 模块里的featureRow必须和训练时的特征顺序完全一致少一列或多一列都会报错二是输入特征向量需要提前做和训练时一致的标准化mu和sigma也要加载到模块里三是模型文件路径要写绝对路径或放到 MATLAB 路径下否则代码生成阶段找不到文件。把训练好的模型嵌进 Simulink 后可以接上信号源和 Scope做“数据输入→特征提取→预测”的连续仿真。这样轴承故障诊断就从一段脚本变成了可演示、可部署的仿真系统。从那以后我每次跑新数据源都会强制走一遍这个顺序先确认采样率和转频再核算故障频率最后做数据集划分和归一化。这套流程先运行一遍再调参数能省掉大量返工时间。希望帮到你。本文还有配套的精品资源点击获取