ARTICLE DETAIL

资讯详情

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

机器学习机械故障诊断:从振动信号到故障分类的完整工程实践

机器学习机械故障诊断:从振动信号到故障分类的完整工程实践 简介这份资源面向机械工程、工业自动化与人工智能方向的学习者和工程师聚焦如何用机器学习方法完成设备健康管理与故障预警帮助读者建立从信号采集到模型部署的完整认知。压缩包共38个文件以20个py源码脚本和18个pyc编译文件为主整体约75KB涵盖数据集处理、模型定义与训练流程等模块结构紧凑便于直接运行与二次修改。内容围绕振动、声音等传感器信号的清洗、归一化与特征工程展开并对比决策树、随机森林、支持向量机及CNN、RNN等模型在小样本与复杂非线性场景下的适用差异同时涉及训练集、验证集、测试集划分与交叉验证、准确率、召回率、F1分数、AUC-ROC等评估要点以及误报与漏报代价权衡和实时监控部署思路。目前已有618人学习下载适合希望把机器学习落地到故障诊断的中高级读者参考。1. 从一段轴承振动信号说起机器学习做机械故障诊断到底在解决什么一台 7.5kW 的电机轴承外圈剥落振动加速度传感器贴在轴承座上采样率 12.8kHz你手里拿到的是一段又一段看不出规律的波形。传统做法是老师傅听声音、看频谱、比阈值经验门槛高换一台设备、换一个工况阈值就得重调。机器学习做机械故障诊断本质是把「人看频谱判断故障类型」这件事换成「用特征加分类器自动判断」。它解决的不是采集问题而是从高维振动信号到故障标签的映射问题正常、内圈、外圈、滚动体甚至不同损伤直径都要能分出来。这套方案适合谁适合手里已经有振动或电流信号、想做状态监测和预测性维护的工程师也适合刚入门机器学习、想找一个信号处理加分类的完整落地场景的人。它不要求你从零造采集卡但要求你理解采样、分段、特征、模型这条链路。标题里的「.zip」通常意味着一个可复现的工程包数据、特征脚本、训练脚本、模型文件。下面我按这条链路把每一步的参数和坑讲清楚。2. 数据从哪来、怎么切机械故障诊断的数据集与样本构造2.1 常见数据集与选型理由做机械故障诊断绕不开几个公开数据集。凯斯西储大学CWRU轴承数据集是入门首选因为它标注清晰、工况明确、被引用最多方便你对比自己的模型是不是「正常水平」。它的结构是正常基线加内圈、外圈、滚动体三类故障每类又有不同损伤直径0.007、0.014、0.021 英寸和不同负载0、1、2、3 马力。Paderborn 数据集更接近真实工况包含不同转速和负载下的轴承电流与振动适合验证模型跨工况的泛化能力。如果做齿轮箱东南大学齿轮箱数据集更合适。选型理由很直接入门用 CWRU 建立 baseline进阶用 Paderborn 或自采数据验证鲁棒性。不要一上来就上自采数据标注成本高出了问题你分不清是模型不行还是标签错了。2.2 样本构造分段、重叠与标签对齐原始信号是一长条时间序列模型吃的是固定长度样本。常见做法是滑动窗口分段窗口长度和重叠率直接决定样本数量和信息量。import numpy as np def segment_signal(signal, window_size1024, overlap0.5): 滑动窗口分段 window_size: 每个样本的采样点数 overlap: 重叠率0.5 表示相邻窗口重叠一半 step int(window_size * (1 - overlap)) segments [] for start in range(0, len(signal) - window_size 1, step): seg signal[start:start window_size] segments.append(seg) return np.array(segments) # 假设 raw_signal 是 12.8kHz 采样的一段外圈故障信号 raw_signal np.random.randn(128000) # 这里用随机数占位实际替换为真实信号 samples segment_signal(raw_signal, window_size1024, overlap0.5) print(samples.shape) # (249, 1024)逻辑说明window_size1024在 12.8kHz 下对应约 80ms覆盖轴承故障特征频率的几个周期太短会丢低频信息太长会混入变速信息。overlap0.5是常用折中既增加样本量又避免相邻样本过于相似导致数据泄漏。参数怎么改如果转速低特征频率低窗口要加长到 2048 甚至 4096如果做在线诊断窗口要短到满足实时性比如 512。标签对齐要注意每个窗口继承它所在整段信号的标签。但如果一段信号里既有正常段又有故障段必须先按时间段切分再分段否则标签就是错的。这是新手最容易翻车的地方。2.3 训练集、验证集、测试集的划分陷阱很多人直接随机划分所有窗口这是错的。同一段原始信号切出来的窗口高度相似随机划分会让训练集和测试集共享同一段信号准确率虚高到 99%上线就崩。正确做法是按原始记录划分比如 CWRU 里按负载或按文件划分训练用负载 0、1、2测试用负载 3这样测出来的才是跨工况泛化能力。from sklearn.model_selection import train_test_split # 假设 X 是 (n_samples, window_size)y 是标签group 是每条原始记录的编号 # 按 group 划分保证同一记录不出现在训练和测试中 unique_groups np.unique(group) train_groups, test_groups train_test_split(unique_groups, test_size0.3, random_state42) train_mask np.isin(group, train_groups) test_mask np.isin(group, test_groups) X_train, y_train X[train_mask], y[train_mask] X_test, y_test X[test_mask], y[test_mask]参数说明test_size0.3是常见比例数据少时可以 0.2。random_state固定后结果可复现。如果要做交叉验证用GroupKFold把 group 传进去别用普通KFold。3. 特征工程还是端到端时域、频域、时频域特征怎么选怎么算3.1 时域与频域特征手工特征仍然能打在样本量不大、可解释性要求高的场景手工特征加传统分类器SVM、随机森林往往比深度学习更稳。时域特征包括均方根、峰值、峭度、偏度、裕度因子。其中峭度对冲击性故障特别敏感轴承早期剥落时峭度会明显上升。频域特征包括频谱峰值、重心频率、均方频率以及包络谱里的故障特征频率幅值。import numpy as np from scipy.stats import kurtosis, skew from scipy.fft import fft def time_domain_features(seg): rms np.sqrt(np.mean(seg ** 2)) peak np.max(np.abs(seg)) kurt kurtosis(seg) sk skew(seg) crest peak / rms if rms 0 else 0 return [rms, peak, kurt, sk, crest] def freq_domain_features(seg, fs12800): n len(seg) spec np.abs(fft(seg))[:n // 2] freqs np.fft.fftfreq(n, 1 / fs)[:n // 2] centroid np.sum(freqs * spec) / np.sum(spec) if np.sum(spec) 0 else 0 peak_freq freqs[np.argmax(spec)] return [centroid, peak_freq, np.max(spec)] seg samples[0] features time_domain_features(seg) freq_domain_features(seg) print(features)逻辑说明时域特征计算快适合在线频域特征能定位故障频率。参数上fs必须和实际采样率一致否则频率轴全错。峭度对早期故障敏感但对转速波动和噪声也敏感所以通常和均方根一起用不要单看一个指标。3.2 时频域特征小波包与短时傅里叶变转速工况下单纯频域会 smear这时用时频域。短时傅里叶变换STFT简单适合做深度学习输入小波包分解WPD能把信号拆到不同频带每个频带算能量作为特征向量。import pywt def wavelet_packet_energy(seg, waveletdb4, level3): wp pywt.WaveletPacket(dataseg, waveletwavelet, modesymmetric, maxlevellevel) energies [] for node in wp.get_level(level, ordernatural): energy np.sum(np.array(node.data) ** 2) energies.append(energy) energies np.array(energies) return energies / np.sum(energies) # 归一化能量占比 energy_feat wavelet_packet_energy(samples[0]) print(energy_feat)参数说明waveletdb4是振动信号常用小波level3把频带分成 8 段。层数越高频带越细但每段数据点越少方差越大。一般 3 到 5 层够用。归一化是为了消除量纲影响让不同负载下的样本可比。3.3 端到端深度学习什么时候值得上如果数据量足够每类几千个样本以上且工况复杂可以上 1D-CNN 或 LSTM 直接吃原始信号。优点是省去手工特征缺点是可解释性差、训练慢、小样本容易过拟合。我的经验是样本少于 5000 时手工特征加随机森林的性价比远高于深度学习样本上万且有多工况再考虑 CNN。import torch import torch.nn as nn class FaultCNN(nn.Module): def __init__(self, num_classes4): super().__init__() self.conv nn.Sequential( nn.Conv1d(1, 16, kernel_size15, stride2, padding7), nn.BatchNorm1d(16), nn.ReLU(), nn.MaxPool1d(2), nn.Conv1d(16, 32, kernel_size7, stride2, padding3), nn.BatchNorm1d(32), nn.ReLU(), nn.AdaptiveAvgPool1d(1) ) self.fc nn.Linear(32, num_classes) def forward(self, x): x self.conv(x) x x.view(x.size(0), -1) return self.fc(x) model FaultCNN(num_classes4) print(model)逻辑说明第一层卷积核大15是为了捕捉冲击成分第二层核小7提取更抽象特征。BatchNorm加速收敛AdaptiveAvgPool1d(1)把任意长度压成固定维度。输入需要 reshape 成(batch, 1, window_size)。参数怎么调核大小一般取采样率的 1/100 到 1/10 对应的时间尺度学习率从 1e-3 开始batch size 32 或 64。4. 模型训练与评估从随机森林到 CNN 的落地参数4.1 传统分类器随机森林和 SVM 的参数怎么设手工特征加随机森林是我在样本量有限时的默认选择。随机森林对特征尺度不敏感调参少还能输出特征重要性方便你回头检查特征是否合理。from sklearn.ensemble import RandomForestClassifier from sklearn.preprocessing import StandardScaler from sklearn.pipeline import Pipeline from sklearn.metrics import classification_report pipeline Pipeline([ (scaler, StandardScaler()), (clf, RandomForestClassifier( n_estimators200, max_depth15, min_samples_leaf2, class_weightbalanced, random_state42, n_jobs-1 )) ]) pipeline.fit(X_train_feat, y_train) y_pred pipeline.predict(X_test_feat) print(classification_report(y_test, y_pred))参数说明n_estimators200是精度和速度的折中再多收益递减。max_depth15防止过深过拟合min_samples_leaf2让叶子节点不过于碎片化。class_weightbalanced在类别不均衡时很重要比如正常样本远多于故障样本。SVM 的话RBF 核的C从 1 到 100 网格搜gamma用scale起步。4.2 深度学习训练学习率、早停与数据增强CNN 训练的关键是学习率调度和早停。振动信号做数据增强常用加高斯噪声、时间平移、幅值缩放不要用图像那套翻转裁剪物理意义不对。import torch.optim as optim from torch.utils.data import DataLoader, TensorDataset train_ds TensorDataset(torch.tensor(X_train_cnn, dtypetorch.float32).unsqueeze(1), torch.tensor(y_train, dtypetorch.long)) train_loader DataLoader(train_ds, batch_size64, shuffleTrue) device torch.device(cuda if torch.cuda.is_available() else cpu) model FaultCNN(num_classes4).to(device) criterion nn.CrossEntropyLoss() optimizer optim.Adam(model.parameters(), lr1e-3, weight_decay1e-4) scheduler optim.lr_scheduler.ReduceLROnPlateau(optimizer, patience5, factor0.5) for epoch in range(50): model.train() for xb, yb in train_loader: xb, yb xb.to(device), yb.to(device) optimizer.zero_grad() loss criterion(model(xb), yb) loss.backward() optimizer.step() # 验证集评估省略用 scheduler.step(val_loss) 触发降学习率参数说明lr1e-3是 Adam 常用起点weight_decay1e-4做 L2 正则。ReduceLROnPlateau在验证损失不降时把学习率减半patience5表示等 5 个 epoch。早停一般设 patience 10 到 15别等模型过拟合了才停。4.3 评估指标准确率会骗人看混淆矩阵和 F1机械故障诊断里类别往往不均衡正常样本多故障样本少。准确率 95% 可能意味着所有故障都漏报。必须看混淆矩阵、每类召回率和 F1。from sklearn.metrics import confusion_matrix, f1_score import seaborn as sns import matplotlib.pyplot as plt cm confusion_matrix(y_test, y_pred) sns.heatmap(cm, annotTrue, fmtd, cmapBlues) plt.xlabel(Predicted) plt.ylabel(True) plt.show() print(Macro F1:, f1_score(y_test, y_pred, averagemacro))逻辑说明averagemacro对每类 F1 等权平均能暴露小类被忽略的问题。如果某类召回率低于 0.8先查标签和特征再考虑加样本或调class_weight。5. 避坑与排查机械故障诊断落地时最容易翻车的五件事5.1 现象测试准确率 99%上线就废原因按窗口随机划分训练集和测试集共享同一段原始信号数据泄漏。解决按原始记录或工况划分用GroupKFold确保同一段信号只出现在一个集合里。5.2 现象模型在负载 0 上准负载 3 上崩原因训练集没有覆盖足够工况模型学到了负载相关的伪特征。解决训练时混入多负载数据或做工况归一化比如按转速归一化频率轴也可以加域适应。5.3 现象峭度特征忽高忽低模型跟着抖原因峭度对噪声和转速波动敏感单点计算方差大。解决对一段信号算峭度的均值或改用包络谱的故障特征频率幅值更稳。5.4 现象CNN 训练 loss 不降原因输入没归一化或学习率太大导致梯度爆炸。解决对原始信号做 z-score 标准化学习率从 1e-4 试起加 BatchNorm 和梯度裁剪。5.5 现象故障特征频率对不上原因采样率设错或没考虑轴承几何参数算特征频率。解决确认fs和实际一致用轴承型号算内圈、外圈、滚动体特征频率和包络谱峰值对照。6. 进阶技巧用包络谱和迁移学习把跨工况精度再提一档手工特征里包络谱是我最推荐的一个进阶点。轴承故障冲击会调制高频共振直接看频谱看不到做希尔伯特包络再 FFT故障特征频率就出来了。from scipy.signal import hilbert def envelope_spectrum(seg, fs12800): analytic hilbert(seg) envelope np.abs(analytic) spec np.abs(fft(envelope - np.mean(envelope)))[:len(seg) // 2] freqs np.fft.fftfreq(len(seg), 1 / fs)[:len(seg) // 2] return freqs, spec freqs, spec envelope_spectrum(samples[0]) # 找峰值对应的频率和轴承外圈故障特征频率 BPFO 对比 peak_idx np.argsort(spec)[-5:] print(Top peaks:, freqs[peak_idx])参数说明hilbert要求输入是实数序列包络去均值是为了去掉直流分量。算出来的峰值如果和 BPFO 吻合说明特征工程方向对了。迁移学习方面如果目标工况没标签可以用源工况预训练 CNN冻结卷积层只微调全连接层通常几十个目标样本就能到不错精度。方法适用场景所需目标样本预期效果手工特征RF小样本、可解释每类 100基线 85%~95%包络谱特征SVM轴承故障、变负载每类 200比时域特征高 3~8 个点CNN 端到端大样本、多工况每类 100095%但需调参迁移学习目标工况无标签每类 50接近源工况精度我自己的习惯是先用手工特征加随机森林跑一个 baseline确认数据和标签没问题再上 CNN。如果 baseline 都不到 80%别急着换模型先回去查分段和标签。这个顺序帮我省了很多后悔药。希望帮到你。本文还有配套的精品资源点击获取
返回列表