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

1. 项目概述:从一份公开数据集说起

最近在做一个关于旋转机械故障诊断的小项目,手头正好缺一批高质量的轴承振动数据来做算法验证和模型训练。在网上翻找了一圈,发现很多公开数据集要么工况单一,要么标签不全,用起来总感觉差点意思。直到我遇到了这份来自加拿大渥太华大学的轴承数据集,它的全称是“University of Ottawa Bearing Dataset”,在学术界和工业界的故障预测与健康管理(PHM)圈子里,算是一块“老网红”了。这份数据的核心价值,就在于它系统地采集了轴承在不同转速下的全寿命周期振动信号,从健康状态一直运行到完全失效,完整记录了这个“死亡”过程。

对于做设备状态监测和智能运维的同行来说,这种数据简直是“宝藏”。我们平时在工厂里,想拿到一台关键设备从崭新到报废的完整数据,成本高、周期长,而且往往伴随着生产风险。这份公开数据集恰好弥补了这个缺口。它不仅仅是几段振动波形,更提供了一个近乎理想的实验环境:在可控的实验室条件下,让轴承在不同负载的转速下持续运行,直到出现故障,并用高精度的传感器捕捉每一个细节。这让我们能够抛开现场复杂的干扰因素,专注于研究故障本身的演化规律,以及转速这一关键工况参数对故障特征的影响。无论是想验证一个新的特征提取算法,还是训练一个更鲁棒的故障分类模型,这份数据都能提供一个坚实、干净的基准。

2. 数据核心价值与设计思路拆解

2.1 为什么“不同转速”如此关键?

很多初入行的朋友可能会问,轴承数据网上不少,为什么这份特别强调“不同转速”?这恰恰是它区别于其他数据集(比如著名的美国凯斯西储大学CWRU数据)的精髓所在。

在真实的工业场景中,设备很少永远恒定在同一个速度下运行。风机根据风速变速,泵根据流量调节,机床更是有不同的加工档位。转速的变化,会直接、显著地改变振动信号的频率结构。根据旋转机械动力学的基本原理,轴承的故障特征频率(如内圈、外圈、滚动体的通过频率)与轴的旋转频率(即转速)呈固定的倍数关系。转速一变,这些特征频率的物理值就跟着变。如果你的故障诊断算法是在单一转速下训练出来的,换一个转速工况,性能就可能急剧下降,这就是所谓的模型“工况迁移”能力差。

渥太华大学数据集的实验设计,正是为了攻克这一难题。它包含了从25 Hz到50 Hz(即1500 RPM到3000 RPM)多个转速档位的测试。这意味着,你可以用这份数据:

  1. 研究故障特征的转速不变性:寻找那些不随转速变化而剧烈波动的特征指标。
  2. 开发工况自适应的诊断模型:训练模型学会识别“在不同转速下,同一种故障看起来是什么样子”。
  3. 验证算法的泛化能力:用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(f"Error 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_normalized

3.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 features

2. 频域特征:通过快速傅里叶变换(FFT)将信号从时域转换到频域,观察其频率成分。

  • 故障特征频率计算:这是轴承诊断的基石。你需要根据轴承的几何参数(内径、外径、滚动体数量、接触角等)和当前转速,计算出理论上的内圈故障频率(BPFI)、外圈故障频率(BPFO)、滚动体故障频率(BSF)等。当频谱在这些频率及其谐波处出现明显峰值时,就指示了对应的故障。
  • 频谱重心、均方频率:描述频谱整体分布的位置。
  • 边带分析:对于内圈故障,由于故障点位置随轴承旋转而变化,其冲击能量会受到“载荷调制”,在频谱上表现为故障频率周围出现转速频率的边带。识别边带是诊断内圈故障的重要依据。
def extract_freq_features(signal, fs, rpm): """计算频域特征,需要转速信息以计算故障频率""" n = len(signal) freq = np.fft.rfftfreq(n, d=1/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 features

3. 时频域特征(针对非平稳信号):单纯的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', axis=1).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_size=0.3, random_state=42, stratify=y) # 特征标准化:非常重要,尤其是对于基于距离的算法(如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(kernel='rbf', C=10, gamma='scale', random_state=42), 'Random Forest': RandomForestClassifier(n_estimators=100, max_depth=10, random_state=42), 'KNN': KNeighborsClassifier(n_neighbors=5) } 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'], axis=1).values y_train = df_features.loc[train_mask, 'label'].values X_test = df_features.loc[test_mask].drop(['label', 'rpm'], axis=1).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_estimators=200, random_state=42) 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数组。排查

  1. 使用scipy.io.whosmat(‘file.mat’)先查看文件内部变量名和结构。
  2. 写一个健壮的加载函数,用try-except包裹,并打印出加载文件的变量名,确保万无一失。
  3. 对于嵌套结构,可能需要多一层索引,如data[‘struct_name’][0][‘vibration’]

5.2 特征提取无效,模型性能低下

问题:提取了一大堆特征,但模型准确率就是上不去,或者跨转速泛化能力极差。排查与解决

  1. 可视化检查:这是最重要的步骤!别急着跑模型。把健康状态和不同故障状态的时域波形、频谱图、包络谱画出来对比。肉眼看看故障特征频率处是否有明显的峰值。如果图上都不明显,指望算法自动学出来就太难了。
    import matplotlib.pyplot as plt # 绘制时域信号对比 fig, axes = plt.subplots(2,2, figsize=(12,8)) # 分别绘制健康、内圈、外圈、滚动体故障的一段信号(比如前5000点) # ... 绘图代码 plt.suptitle('不同状态时域信号对比') plt.show()
  2. 检查采样频率与故障频率:确保你的采样频率(fs)足够高,满足奈奎斯特采样定理(fs > 2 * 最高分析频率)。对于轴承故障,我们通常关心几千Hz的频率,所以12.8kHz或25.6kHz的采样率是合理的。计算出的故障特征频率(比如BPFO可能在100Hz量级)必须在频谱的可分辨范围内。
  3. 聚焦有效特征:使用随机森林的feature_importances_属性,找出最重要的前10个特征。很可能你提取的几十个特征里,只有少数几个是真正有用的。剔除不重要的特征,有时反而能提升模型性能(减少过拟合)。
  4. 尝试时频分析:如果时域频域特征效果都不好,可能是故障特征被强噪声或其它振动源淹没。尝试计算信号的包络谱(Hilbert变换后求频谱),它能突出冲击成分。或者直接使用小波变换、STFT得到的时频图作为CNN的输入。

5.3 跨转速测试失败的深度分析

问题:同转速划分下准确率95%,跨转速划分暴跌到60%。解决思路

  1. 强制使用阶次特征:确保你的特征向量中包含了基于阶次(Order)的特征,而不是绝对的频率值。这是解决跨转速问题的物理基础。
  2. 数据增强:在训练集中,对信号进行轻微的“转速抖动”增强。例如,通过重采样技术,模拟将原始信号稍微加快或减慢一点,生成新的样本,让模型学会适应转速的小范围变化。
  3. 使用域自适应(Domain Adaptation)方法:这是一个更高级的研究方向。将不同转速的数据看作来自不同的“域”(domain),使用如DANN(域对抗神经网络)等算法,让模型学习域不变的特征表示。这在学术界是处理这类问题的前沿方法。

5.4 模型过拟合与调参

问题:在训练集上准确率接近100%,在测试集(特别是跨转速测试集)上表现很差。解决

  1. 简化模型:减少随机森林的树深度(max_depth)或树的数量(n_estimators),增加SVM的正则化参数C。
  2. 交叉验证:使用GridSearchCVRandomizedSearchCV进行超参数调优,选择在验证集上泛化性能最好的参数。
  3. 早停法:如果使用深度学习模型,监控验证集损失,当连续几个epoch不再下降时停止训练。

处理渥太华大学轴承数据集的过程,是一个标准的旋转机械故障诊断研究缩影。从数据理解、预处理、特征工程到模型构建与验证,每一步都需要结合物理机理(轴承动力学)和数据分析技巧。这份数据的“多转速”特性,逼着我们不能只做“调参侠”,而必须深入思考故障的本质以及如何让算法适应工况的变化。我个人的体会是,在特征工程上多花一小时,可能比在模型调参上花一天更有效。当你看到自己提取的阶次特征,成功让模型识别出它在训练中从未见过的转速下的故障时,那种成就感是实实在在的。最后一个小建议,可以把不同转速下的频谱图或特征分布图用不同颜色画在一张图上,直观地感受一下转速带来的变化,这往往能给你带来优化特征的新灵感。