基于渥太华大学轴承数据集的多转速故障诊断实战指南

基于渥太华大学轴承数据集的多转速故障诊断实战指南 1. 项目概述从一份公开数据集说起最近在做一个关于旋转机械故障诊断的小项目手头正好缺一批高质量的轴承振动数据来做算法验证和模型训练。在网上翻找了一圈发现很多公开数据集要么工况单一要么标签不全用起来总感觉差点意思。直到我遇到了这份来自加拿大渥太华大学的轴承数据集它的全称是“University of Ottawa Bearing Dataset”在学术界和工业界的故障预测与健康管理PHM圈子里算是一块“老网红”了。这份数据的核心价值就在于它系统地采集了轴承在不同转速下的全寿命周期振动信号从健康状态一直运行到完全失效完整记录了这个“死亡”过程。对于做设备状态监测和智能运维的同行来说这种数据简直是“宝藏”。我们平时在工厂里想拿到一台关键设备从崭新到报废的完整数据成本高、周期长而且往往伴随着生产风险。这份公开数据集恰好弥补了这个缺口。它不仅仅是几段振动波形更提供了一个近乎理想的实验环境在可控的实验室条件下让轴承在不同负载的转速下持续运行直到出现故障并用高精度的传感器捕捉每一个细节。这让我们能够抛开现场复杂的干扰因素专注于研究故障本身的演化规律以及转速这一关键工况参数对故障特征的影响。无论是想验证一个新的特征提取算法还是训练一个更鲁棒的故障分类模型这份数据都能提供一个坚实、干净的基准。2. 数据核心价值与设计思路拆解2.1 为什么“不同转速”如此关键很多初入行的朋友可能会问轴承数据网上不少为什么这份特别强调“不同转速”这恰恰是它区别于其他数据集比如著名的美国凯斯西储大学CWRU数据的精髓所在。在真实的工业场景中设备很少永远恒定在同一个速度下运行。风机根据风速变速泵根据流量调节机床更是有不同的加工档位。转速的变化会直接、显著地改变振动信号的频率结构。根据旋转机械动力学的基本原理轴承的故障特征频率如内圈、外圈、滚动体的通过频率与轴的旋转频率即转速呈固定的倍数关系。转速一变这些特征频率的物理值就跟着变。如果你的故障诊断算法是在单一转速下训练出来的换一个转速工况性能就可能急剧下降这就是所谓的模型“工况迁移”能力差。渥太华大学数据集的实验设计正是为了攻克这一难题。它包含了从25 Hz到50 Hz即1500 RPM到3000 RPM多个转速档位的测试。这意味着你可以用这份数据研究故障特征的转速不变性寻找那些不随转速变化而剧烈波动的特征指标。开发工况自适应的诊断模型训练模型学会识别“在不同转速下同一种故障看起来是什么样子”。验证算法的泛化能力用25Hz的数据训练去测试模型在40Hz数据上的表现这比同工况下的测试残酷得多也真实得多。2.2 数据集结构与实验台解析这份数据是在一个精心设计的轴承试验台上获取的。简单来说它由一台交流电机驱动一根主轴主轴通过柔性联轴器连接支撑在两个测试轴承上。其中一个轴承是被测对象另一个是支撑轴承。径向负载通过一个弹簧和杠杆系统施加在被测轴承上以模拟实际受力情况。数据文件通常按以下结构组织这也是我们使用前必须弄清楚的数据集根目录/ ├── 转速_25Hz/ │ ├── 健康状态/ │ │ ├── time_domain_data_1.mat │ │ └── ... │ ├── 内圈故障/ │ ├── 外圈故障/ │ └── 滚动体故障/ ├── 转速_30Hz/ ├── 转速_35Hz/ ├── 转速_40Hz/ ├── 转速_45Hz/ └── 转速_50Hz/每个.mat文件是MATLAB的数据格式里面通常包含以下几个关键变量vibration_signal: 振动加速度信号单位是重力加速度g。这是我们的核心分析对象。sampling_frequency: 采样频率比如12.8 kHz或25.6 kHz。高采样率是为了捕捉轴承高频的冲击成分这对故障诊断至关重要。load_condition: 负载条件如果有的话。rpm: 转速转/分钟由Hz换算而来。注意下载数据后第一件事不是急着跑代码而是仔细阅读数据集附带的README或相关论文确认每个文件夹对应的具体故障类型、故障尺寸如直径、深度、负载大小以及确切的采样参数。不同版本的数据集在组织上可能有细微差别。3. 数据处理与特征工程实战要点拿到数据后直接扔进神经网络往往效果不佳。我们需要从原始的振动时序信号中提取出能够表征轴承健康状态的特征。这个过程就是特征工程它是决定诊断模型上限的关键。3.1 数据读取与预处理标准化流程由于数据是.mat格式在Python中我们通常使用scipy.io库来读取。import numpy as np import scipy.io as sio from pathlib import Path def load_bearing_data(file_path): 加载单个.mat数据文件 try: data sio.loadmat(file_path) # 注意变量名可能需要根据实际文件调整常见的是‘vibration’或‘bearing_signal’ signal data[vibration_signal].flatten() # 确保是一维数组 fs data[sampling_frequency].item() # 采样频率 rpm data[rpm].item() if rpm in data else None # 转速 return signal, fs, rpm except Exception as e: print(fError loading {file_path}: {e}) return None, None, None # 示例遍历某个转速下的健康数据文件夹 data_dir Path(./数据集根目录/转速_25Hz/健康状态) signals_list [] fs_list [] for mat_file in data_dir.glob(*.mat): signal, fs, rpm load_bearing_data(mat_file) if signal is not None: signals_list.append(signal) fs_list.append(fs)预处理的第一步通常是去趋势和归一化。传感器可能存在微小的直流偏移或基线漂移需要去除。归一化可以将不同样本的量纲统一加速模型收敛。def preprocess_signal(signal): 简单的预处理去直流归一化 signal_detrended signal - np.mean(signal) # 去除直流分量 signal_normalized signal_detrended / np.max(np.abs(signal_detrended)) # 最大绝对值归一化到[-1, 1] return signal_normalized3.2 时域、频域及时频域特征提取详解特征提取是核心我们需要从多个维度“刻画”信号。1. 时域统计特征这些特征计算简单对冲击类故障敏感。常用的有均方根值RMS表征信号的平均能量对磨损类故障比较有效。峰值Peak信号的最大绝对值对早期局部冲击敏感。峭度Kurtosis衡量信号分布尖锐程度的指标。健康轴承的振动信号近似高斯分布峭度接近3。当出现局部损伤如点蚀时会产生瞬态冲击峭度值会显著增大远大于3因此峭度是早期故障非常敏感的指标。峰值因子Crest Factor峰值与RMS值的比值。它能在信号整体能量RMS变化不大时放大局部冲击的影响。波形因子、脉冲因子等。def extract_time_features(signal): 计算一组时域特征 features {} features[rms] np.sqrt(np.mean(signal**2)) features[peak] np.max(np.abs(signal)) features[kurtosis] np.mean((signal - np.mean(signal))**4) / (np.std(signal)**4) features[crest_factor] features[peak] / features[rms] if features[rms]!0 else 0 # 可以继续计算偏度、方差等 return features2. 频域特征通过快速傅里叶变换FFT将信号从时域转换到频域观察其频率成分。故障特征频率计算这是轴承诊断的基石。你需要根据轴承的几何参数内径、外径、滚动体数量、接触角等和当前转速计算出理论上的内圈故障频率BPFI、外圈故障频率BPFO、滚动体故障频率BSF等。当频谱在这些频率及其谐波处出现明显峰值时就指示了对应的故障。频谱重心、均方频率描述频谱整体分布的位置。边带分析对于内圈故障由于故障点位置随轴承旋转而变化其冲击能量会受到“载荷调制”在频谱上表现为故障频率周围出现转速频率的边带。识别边带是诊断内圈故障的重要依据。def extract_freq_features(signal, fs, rpm): 计算频域特征需要转速信息以计算故障频率 n len(signal) freq np.fft.rfftfreq(n, d1/fs) # 获得频率轴 fft_vals np.abs(np.fft.rfft(signal)) # 计算FFT幅值 features {} # 1. 计算频谱重心 features[spectral_centroid] np.sum(freq * fft_vals) / np.sum(fft_vals) # 2. 假设已知轴承参数计算理论故障频率 (此处为示例参数需替换) d 7.94e-3 # 滚动体直径 (米) D 33.5e-3 # 节圆直径 (米) n_balls 8 # 滚动体数量 contact_angle 0 # 接触角 # 计算旋转频率 fr rpm / 60.0 # 计算外圈故障频率 (BPFO) BPFO n_balls * fr / 2 * (1 - (d/D) * np.cos(contact_angle)) features[BPFO_theoretical] BPFO # 可以在BPFO附近寻找频谱峰值作为特征... return features3. 时频域特征针对非平稳信号单纯的FFT假设信号是平稳的但轴承故障冲击往往是瞬态的。时频分析如短时傅里叶变换STFT、小波变换能同时看到频率成分随时间的变化对捕捉冲击瞬态非常有效。不过计算量较大常用于深度学习方法中作为输入。3.3 针对多转速数据的特征工程策略面对多个转速的数据特征工程需要有策略转速归一化特征将计算出的故障特征频率以Hz为单位除以旋转频率Hz得到阶次Order。例如BPFO的阶次 BPFO / fr。阶次是一个无量纲量理论上不随转速变化。这样不同转速下的同一故障其阶次特征应该在同一位置。我们可以提取阶次谱将频谱的横坐标从Hz转换为阶次上的峰值作为特征这能有效提升模型跨转速的泛化能力。构建混合特征集将时域特征如峭度、峰值因子、频域特征如故障频率幅值、阶次域特征组合在一起形成一个高维特征向量。这样既能捕捉故障的局部冲击特性又能利用其转速不变性。4. 基于该数据集的故障诊断模型构建实录有了高质量的特征我们就可以构建诊断模型了。这里以经典的机器学习流程为例。4.1 数据准备与标签生成首先我们需要为每个数据样本打上标签。假设我们有4种状态健康0、内圈故障1、外圈故障2、滚动体故障3。import pandas as pd from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler, LabelEncoder # 假设我们已经用一个函数 extract_all_features 从所有.mat文件中提取了特征并保存在一个列表feature_dicts中 # 同时有一个对应的标签列表 labels # feature_dicts [{rms:1.2, kurtosis:4.5, ...}, {...}, ...] # labels [0, 0, 1, 1, 2, 2, 3, 3, ...] # 将特征字典列表转换为DataFrame df_features pd.DataFrame(feature_dicts) df_features[label] labels # 分割特征和标签 X df_features.drop(label, axis1).values y df_features[label].values # 编码标签如果已经是数字可跳过 # le LabelEncoder() # y le.fit_transform(y) # 划分训练集和测试集 - **关键步骤按转速分层划分** # 简单随机划分会导致数据泄露同一种转速的数据既出现在训练集又出现在测试集 # 模型可能只是记住了某个转速下的模式而非真正的故障模式。 # 正确的做法是按“转速”进行分层划分或分组划分。 # 例如将25Hz, 30Hz, 35Hz的数据作为训练集40Hz, 45Hz, 50Hz的数据作为测试集。 # 这里我们用简单的随机划分做演示但实际项目中务必注意。 X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.3, random_state42, stratifyy) # 特征标准化非常重要尤其是对于基于距离的算法如SVM scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test) # 注意测试集用训练集的scaler转换避免数据泄露4.2 经典机器学习模型应用与对比我们可以尝试几种不同的分类器看看哪种更适合这份数据。from sklearn.svm import SVC from sklearn.ensemble import RandomForestClassifier from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import classification_report, confusion_matrix, accuracy_score # 初始化模型 models { SVM: SVC(kernelrbf, C10, gammascale, random_state42), Random Forest: RandomForestClassifier(n_estimators100, max_depth10, random_state42), KNN: KNeighborsClassifier(n_neighbors5) } results {} for name, model in models.items(): model.fit(X_train_scaled, y_train) y_pred model.predict(X_test_scaled) acc accuracy_score(y_test, y_pred) results[name] acc print(f{name} 准确率: {acc:.4f}) print(classification_report(y_test, y_pred, target_names[健康,内圈,外圈,滚动体])) print(-*50)模型选择心得支持向量机SVM在特征维度不高、样本量不是特别大时SVM特别是RBF核往往能产生清晰的分类边界效果不错。但需要对超参数C, gamma进行调优。随机森林Random Forest这是我个人比较偏爱的方法因为它能提供特征重要性排序。这对于我们理解哪些特征比如是峭度还是某个阶次频率的幅值对区分故障类型贡献最大非常有帮助具有很好的可解释性。K近邻KNN简单直观但计算量随样本数增大而增加且对特征缩放和无关特征敏感。4.3 跨转速泛化能力验证核心这才是检验我们工作成败的关键。我们之前按样本随机划分了数据集现在我们要模拟更真实的场景在一种或几种转速下训练在从未见过的转速下测试。# 假设我们的df_features DataFrame中还有一个‘rpm’列记录每个样本的转速 # 我们按转速分组 rpm_groups df_features[rpm].unique() print(所有转速组:, rpm_groups) # 方案一留一组转速作为测试集 test_rpm 50 # 假设用50Hz的数据测试 train_mask df_features[rpm] ! test_rpm test_mask df_features[rpm] test_rpm X_train df_features.loc[train_mask].drop([label, rpm], axis1).values y_train df_features.loc[train_mask, label].values X_test df_features.loc[test_mask].drop([label, rpm], axis1).values y_test df_features.loc[test_mask, label].values # 重新标准化 scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test) # 用随机森林训练和测试 clf RandomForestClassifier(n_estimators200, random_state42) clf.fit(X_train_scaled, y_train) y_pred clf.predict(X_test_scaled) acc_cross_rpm accuracy_score(y_test, y_pred) print(f跨转速测试训练集不含{test_rpm}Hz准确率: {acc_cross_rpm:.4f})如果跨转速测试的准确率远低于混合转速随机划分的准确率说明我们的特征或模型对转速变化依然敏感需要回头优化特征工程比如加强阶次分析或者考虑使用更复杂的深度学习模型如卷积神经网络CNN直接从原始信号或时频图中学习转速不变特征。5. 实操中的常见陷阱与排查技巧5.1 数据读取与格式不一致问题问题.mat文件版本差异导致变量名不一致或数据结构是嵌套的cell数组。排查使用scipy.io.whosmat(‘file.mat’)先查看文件内部变量名和结构。写一个健壮的加载函数用try-except包裹并打印出加载文件的变量名确保万无一失。对于嵌套结构可能需要多一层索引如data[‘struct_name’][0][‘vibration’]。5.2 特征提取无效模型性能低下问题提取了一大堆特征但模型准确率就是上不去或者跨转速泛化能力极差。排查与解决可视化检查这是最重要的步骤别急着跑模型。把健康状态和不同故障状态的时域波形、频谱图、包络谱画出来对比。肉眼看看故障特征频率处是否有明显的峰值。如果图上都不明显指望算法自动学出来就太难了。import matplotlib.pyplot as plt # 绘制时域信号对比 fig, axes plt.subplots(2,2, figsize(12,8)) # 分别绘制健康、内圈、外圈、滚动体故障的一段信号比如前5000点 # ... 绘图代码 plt.suptitle(不同状态时域信号对比) plt.show()检查采样频率与故障频率确保你的采样频率fs足够高满足奈奎斯特采样定理fs 2 * 最高分析频率。对于轴承故障我们通常关心几千Hz的频率所以12.8kHz或25.6kHz的采样率是合理的。计算出的故障特征频率比如BPFO可能在100Hz量级必须在频谱的可分辨范围内。聚焦有效特征使用随机森林的feature_importances_属性找出最重要的前10个特征。很可能你提取的几十个特征里只有少数几个是真正有用的。剔除不重要的特征有时反而能提升模型性能减少过拟合。尝试时频分析如果时域频域特征效果都不好可能是故障特征被强噪声或其它振动源淹没。尝试计算信号的包络谱Hilbert变换后求频谱它能突出冲击成分。或者直接使用小波变换、STFT得到的时频图作为CNN的输入。5.3 跨转速测试失败的深度分析问题同转速划分下准确率95%跨转速划分暴跌到60%。解决思路强制使用阶次特征确保你的特征向量中包含了基于阶次Order的特征而不是绝对的频率值。这是解决跨转速问题的物理基础。数据增强在训练集中对信号进行轻微的“转速抖动”增强。例如通过重采样技术模拟将原始信号稍微加快或减慢一点生成新的样本让模型学会适应转速的小范围变化。使用域自适应Domain Adaptation方法这是一个更高级的研究方向。将不同转速的数据看作来自不同的“域”domain使用如DANN域对抗神经网络等算法让模型学习域不变的特征表示。这在学术界是处理这类问题的前沿方法。5.4 模型过拟合与调参问题在训练集上准确率接近100%在测试集特别是跨转速测试集上表现很差。解决简化模型减少随机森林的树深度max_depth或树的数量n_estimators增加SVM的正则化参数C。交叉验证使用GridSearchCV或RandomizedSearchCV进行超参数调优选择在验证集上泛化性能最好的参数。早停法如果使用深度学习模型监控验证集损失当连续几个epoch不再下降时停止训练。处理渥太华大学轴承数据集的过程是一个标准的旋转机械故障诊断研究缩影。从数据理解、预处理、特征工程到模型构建与验证每一步都需要结合物理机理轴承动力学和数据分析技巧。这份数据的“多转速”特性逼着我们不能只做“调参侠”而必须深入思考故障的本质以及如何让算法适应工况的变化。我个人的体会是在特征工程上多花一小时可能比在模型调参上花一天更有效。当你看到自己提取的阶次特征成功让模型识别出它在训练中从未见过的转速下的故障时那种成就感是实实在在的。最后一个小建议可以把不同转速下的频谱图或特征分布图用不同颜色画在一张图上直观地感受一下转速带来的变化这往往能给你带来优化特征的新灵感。