ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

CWRU轴承数据集深度解析:Python处理与故障诊断实战指南

CWRU轴承数据集深度解析:Python处理与故障诊断实战指南 简介凯斯西储大学(CWRU)轴承数据集是机械故障诊断领域的经典基准资源涵盖正常、内环故障、外环故障、滚珠故障等多种工况的振动信号适用于滚动轴承故障识别与诊断研究可满足故障诊断初学者、设备健康管理研究者及机器学习建模人员的不同需求。资源包共172个文件以165个.mat振动信号数据文件为主体另含3个Python整理脚本、2个pyc辅助程序和2个txt使用说明整体大小230.77MB数据格式规整、目录结构清晰。配套Python程序覆盖原始数据读取、信号预处理、特征提取到故障模式识别的完整流程能帮助用户高效完成数据整理与分析避免下载文件格式不符、路径配置错误等常见问题数据样本丰富适合开展特征工程与分类模型验证。目前已有24495人学习下载适合希望快速上手CWRU数据集、专注故障诊断算法研究与工程应用的中高阶用户。 每次带新手做故障诊断项目我第一件事就是让他们先把CWRU轴承数据集的结构吃透。原因很简单——这是目前全球学术界最常用的滚动轴承故障诊断基准数据集从朴素贝叶斯到最新的Transformer几乎所有算法论文都会用它做验证。这个由美国凯斯西储大学轴承数据中心发布的经典数据集包含正常、内圈故障、外圈故障、滚动体故障四大类状态覆盖多工况、多损伤尺寸、多采样频率拿到手就相当于拥有了一个标准化的“轴承故障实验室”。这篇文章就来聊透它mat文件里到底藏了哪些数据、文件编号怎么破译、如何用Python批量解析和构造数据集以及我在实际做研究时踩过的坑和验证过的可靠套路。不管你是刚入门想做复现的新手还是已经跑过不少实验的老手照着做都能少走弯路。1. CWRU轴承数据集全景解读1.1 实验装置与数据采集逻辑先把这个数据集的“出身”讲清楚。这个实验是在凯斯西储大学的专用试验台上完成的整个台架由电机、扭矩传感器/编码器、测功机以及控制电子设备组成。被测轴承安装在电机轴两端一个是驱动端一个是风扇端型号是6205-2RS JEM SKF深沟球轴承。驱动端和风扇端各布置了加速度计分别采集驱动端振动信号DE列和风扇端振动信号FE列部分数据还采集了基座振动信号BA列。采样频率有两个档位12kHz和48kHz。这个选择对后续处理影响很大同一个故障在不同采样率下序列长度和频率分辨率完全不同。实验还设置了4种负载工况0马力约1797转/分、1马力约1772转/分、2马力约1750转/分、3马力约1730转/分。注意CWRU数据集里还有一个“驱动端正常基线数据”文件名带后缀_0很多人第一次跑的时候会忽略导致训练集里缺少正常类别。后面解析文件时我会专门演示怎么处理。1.2 故障类型与文件命名规则这是新手最容易懵的部分。CWRU数据包里有大约270个mat文件文件名从97.mat到300.mat不等表面看毫无规律其实每个数字都对应一组实验条件。故障类型包括文件范围示例故障类型故障直径英寸负载马力采样位置备注97、98、99、100正常无0-3驱动端/风扇端97是12k驱动端98是48k驱动端105、118、130、144、158内圈故障IR0.007、0.014、0.0210-3驱动端105IR 0.007 0HP 12k169、185、197滚动体故障B0.007、0.014、0.0210-3驱动端数字分布较广234、237、240外圈故障OR中心6:000.007、0.014、0.0210-3驱动端外圈故障还分方向209、222外圈故障正交3:000.007、0.014、0.0210-3驱动端方向不同特征不同外圈故障有3个方向中心Centered负载区6:00、正交Orthogonal3:00、反向Opposite12:00。这也是CWRU数据的一个隐藏特点——同样是外圈故障方向不同振动传播路径不同特征差异很明显。文件名解析这件事千万别用“猜的”我见过太多人把105当成内圈0.007英寸结果用错标签不说跑出来的混淆矩阵还“看起来很好”实际上是标签错位了。正确做法是写一个解析函数从文件名映射出完整工况条件再结合文件内容校验这个我放在后面代码里。2. Python处理方案从原始mat到可训练数据集2.1 数据结构剖析mat文件里到底装了什么用scipy.io.loadmat读一个常规的12k驱动端文件会得到一个dict里面字段包括DE驱动端加速度、FE风扇端加速度、BA基座加速度、以及相关转速等元数据。但不同文件的字段名有差异——有些风扇端文件的字段是fan_DE有些文件名带_0后缀代表正常基线数据。48kHz文件同样有DE列但可能没有FE列。这是第一个关键坑字段名不统一。不能硬编码字段名来批量读取必须写成动态判断逻辑先打印keys()再确定通道。还有一个细节每个样本其实是在等时间间隔内采集的连续信号长度通常在10秒到60秒不等12kHz采样率下12万到几十万个点。做分类时不能直接喂几十万维序列给模型需要做滑窗分段。2.2 批量解析代码一次干净地读完全部数据下面是我常用的解析参考代码经过多次打磨可以直接用import os import numpy as np import pandas as pd from scipy.io import loadmat def parse_cwru_filename(filename): 从CWRU文件名中解析出核心信息。 返回字典数字编号、位置、故障类型、损伤直径、负载、采样率。 name filename.replace(.mat, ).replace(_0, _NORMAL_0) parts name.split(_) info {} info[orig_num] parts[0] # 数字在186-190附近的一般是滚动体在197-222附近一般外圈 num int(parts[0]) if num in [97, 98, 99, 100]: info[fault] NORMAL info[location] DE if DE in name else FE else: # 根据实验记录表映射 if num in [105, 106, 118, 119, 130, 131, 144, 145, 158, 159]: info[fault] IR elif num in [169, 170, 171, 185, 186, 187]: info[fault] B else: # 外圈 info[fault] OR # 继续补充负载、尺寸等字段 return info # 批量读取某个目录下所有12k驱动端mat文件 def load_cwru_batch(mat_dir, wanted_channelsNone): 返回一个完整的DataFrame列包含DE/FE/BA、标签、工况信息。 data_rows [] for fname in sorted(os.listdir(mat_dir)): if not fname.endswith(.mat): continue info parse_cwru_filename(fname) mat loadmat(os.path.join(mat_dir, fname)) keys [k for k in mat.keys() if not k.startswith(__)] # 字段名确定逻辑 channel_map {} for key in keys: if DE in key or FE in key or BA in key: channel_map[key] mat[key] # 将数据写入 row {filename: fname, **info} data_rows.append(row) # 这里只记录了元数据实际数据可另存 return pd.DataFrame(data_rows)这段代码的关键是parse_cwru_filename函数——它把“数字→故障类型”的映射规则集中起来避免在数据分析环节东拼西凑。实际使用时你还要把DE信号取出来进行滑窗切分生成样本和标签。我通常的做法是每段连续信号按1024或2048点为一个窗口、步长512切分这样单样本既保留了足够周期特征又不会让数据量爆炸。2.3 滑窗切分与标签生成滑窗切分不是无脑切。要知道同一段连续振动信号里前一部分和后一部分来自同一个实验如果不做随机化直接放进训练集和测试集之间会存在“相邻片段泄漏”——模型学会了背样本id而不是学特征。正确做法是按文件来分train/test而不是按窗口来分。比如把0马力所有文件放训练集3马力所有文件放测试集这样能验证泛化性。def split_windows(signal, window_size1024, step512): windows [] start 0 n len(signal) while start window_size n: windows.append(signal[start:start window_size]) start step return np.array(windows) def make_dataset_from_mat(mat_path, fault_label, channelDE, window_size1024, step512): mat loadmat(mat_path) key [k for k in mat.keys() if channel in k][0] sig mat[key].flatten().astype(np.float32) windows split_windows(sig, window_size, step) labels np.full(len(windows), fault_label, dtypenp.int64) return windows, labels这里窗口大小我推荐1024因为12kHz下对应约0.085秒刚好覆盖几十个轴承转频周期足够提取特征。如果要跑时频分析256或512也行但越小噪声越大。3. 核心细节解析与实操要点3.1 为什么要做“工况级别”的数据划分这个问题我在带学生和做论文实验时反复讲CWRU数据集如果不加处理直接随机切分模型准确率几乎都能到99%以上但这不代表模型有泛化能力。原因在于同一文件切出来的窗口高度相关随机切分会把同一个实验的相邻片段同时扔进训练和测试。测试集里的样本是训练集样本的“近亲”相当于开卷考试。所以我建议做法是按文件/实验条件划分不在文件内部分窗口做跨工况实验比如用0、1、2马力训练3马力测试检验模型的转速适应能力如果想比较不同算法的优劣固定统一划分策略保证公平。3.2 样本类别不均衡问题CWRU数据虽然各类别都有但不同故障尺寸、不同负载下的样本量并不均衡。特别是正常数据只有3个文件对应多个故障文件切窗后正常类样本远少于故障类。处理不平衡的方式包括过采样少数类、欠采样多数类、使用加权损失函数、或者做数据增强。在CWRU上我个人的经验是使用类别权重比直接重采样要稳因为重采样容易引入重复样本导致过拟合。3.3 信号预处理降噪、归一化与去趋势振动信号在采集过程中会受到传感器噪声和工频干扰影响虽然CWRU数据质量算好的但直接喂原始波形给深度学习模型时最好还是做两步预处理归一化常用的有Z-score标准化减均值除标准差或min-max归一化到[-1, 1]去趋势消除传感器零点漂移用一阶差分或减去滑动平均。对传统机器学习特征来说这步特别重要。比如峭度、均方根这些时域特征受趋势项影响很大如果不先去趋势特征值会失真。4. 实操过程与核心环节实现4.1 最小复现5分钟跑通一个分类baseline这里我用最经典的方式给大家演示手工特征随机森林作为一个可靠的baseline。虽然现在的论文都上深度学习但baseline的价值在于快速验证数据加载正确性。import numpy as np from sklearn.ensemble import RandomForestClassifier from sklearn.preprocessing import StandardScaler from sklearn.metrics import accuracy_score, classification_report def extract_features(win): 从一维窗口提取时域特征。 feats [] feats.append(np.mean(win)) feats.append(np.std(win)) feats.append(np.max(np.abs(win))) feats.append(np.sqrt(np.mean(win**2))) # RMS # 峭度 mu np.mean(win) sigma np.std(win) 1e-12 feats.append(np.mean((win - mu)**4) / (sigma**4)) # 峰峰值 feats.append(np.ptp(win)) # 波形因数 feats.append(np.sqrt(np.mean(win**2)) / (np.mean(np.abs(win)) 1e-12)) return np.array(feats) # 假设已经加载好windows和labels # X np.array([extract_features(w) for w in windows]) # y labels # 按工况划分后 # clf RandomForestClassifier(n_estimators200, random_state42) # clf.fit(X_train, y_train) # pred clf.predict(X_test) # print(accuracy_score(y_test, pred))这个流程一跑准确率通常在85%~98%之间取决于工况划分的难度如果低于这个范围大概率是数据加载或标签映射有bug。你可以把这个当作“数据是否读对”的冒烟测试。4.2 进阶用1D-CNN直接学原始信号手工特征需要人工经验深度学习则让模型自己学特征。如果你有GPU环境可以跑一个轻量级的1D-CNN这是我实测下来非常稳定的结构import torch.nn as nn class CWRU_1DCNN(nn.Module): def __init__(self, num_classes4, input_len1024): super().__init__() self.conv1 nn.Sequential( nn.Conv1d(1, 16, kernel_size64, stride8), nn.BatchNorm1d(16), nn.ReLU(), nn.MaxPool1d(2)) self.conv2 nn.Sequential( nn.Conv1d(16, 32, kernel_size3, stride1, padding1), nn.BatchNorm1d(32), nn.ReLU(), nn.MaxPool1d(2)) self.conv3 nn.Sequential( nn.Conv1d(32, 64, kernel_size3, stride1, padding1), nn.BatchNorm1d(64), nn.ReLU(), nn.MaxPool1d(2)) # 动态计算flatten维度 self._flatten_len None self.fc None self._build_fc(input_len) def _build_fc(self, input_len): dummy torch.zeros(1, 1, input_len) x self.conv1(dummy); x self.conv2(x); x self.conv3(x) self._flatten_len x.view(1, -1).size(1) self.fc nn.Linear(self._flatten_len, 4) def forward(self, x): x x.unsqueeze(1) x self.conv1(x); x self.conv2(x); x self.conv3(x) x x.view(x.size(0), -1) return self.fc(x)我在多个配置下跑过用Adam优化器、学习率1e-3、训练30个epoch分类准确率能稳定到98%以上。如果你想复现代码注意cnn第一层的kernel_size不宜太小64能抓到单个冲击的特征太大则计算量上升训练变慢。4.3 数据增强与泛化提升想让模型在实际场景里更鲁棒可以给CWRU数据加点“真实感”。我尝试过的有效增强包括加高斯噪声SNR在10~20dB之间模拟环境噪声时间偏移随机平移几个采样点模拟触发时刻不同幅值缩放随机乘一个0.9~1.1之间的系数模拟传感器安装松紧带来的增益变化。这些增强方法在跨工况实验中都稳定带来了2~5个百分点的提升但注意增强幅度别太大太大反而引入偏差。5. 常见问题与排查技巧实录5.1 踩坑记录加载、标签、采样率问题现象原因分析解决方案loadmat报错NotImplementedError: Please use HDF readermat文件是v7.3版本CWRU部分新打包版本可能使用hdf5格式用h5py读取或者检查文件版本是否v5/v7。CWRU官网下载的经典mat是v5格式直接用loadmat没问题明明跑了个模型准确率超高但换个工况就崩按窗口随机切分导致数据泄漏改为按文件/工况划分数据确保训练测试无重叠片段解析文件名时_0正常数据被当成故障数据正常数据带_0后缀而部分故障文件名没有该标记在解析函数里统一处理_0后缀显式映射为NORMAL12k和48k数据混在一起形状不同报错采样率不同序列长度差异大统一重采样到指定采样率或分开建模。不能用一份代码同时处理两种采样率的数据而不做长度对齐5.2 避坑清单那些文档里没写明的陷阱不要相信文件名排序即标签顺序。CWRU的编号不是严格递增映射中间有正常基线数据插入、有故障方向分类必须用官方实验记录表逐一确认。字段名差异。有的mat文件里是DE有的可能是fan_DE有的BA字段在部分文件里缺失。写代码时要做容错用try/except或缺失值丢弃处理。类别不平衡。如果训练脚本里没有设置class_weight或采样策略把正常类单独抽取出来测试时精准率会非常难看。训练前先检查数据形状和范围。我习惯在加载后立刻打印出一个样本的shape、dtype、min/max这一步能拦住90%的脏数据问题。窗口重叠率不要太大。虽然重叠可以增加样本但重叠率过高会让训练集和验证集之间产生相关性导致验证曲线失真。推荐重叠率在50%左右即可。5.3 几个提高效率的工程技巧CWRU数据总量不大几百MB完全可以一次性load进内存。但当你做超参搜索时频繁读取mat文件会非常慢。我的经验是第一次解析完就把所有窗口数据存成npy或h5文件后续实验直接读npy能节省80%的数据加载时间。import h5py # 保存成h5 with h5py.File(cwru_windows.h5, w) as f: f.create_dataset(X, dataX_all) f.create_dataset(y, datay_all) f.create_dataset(condition, datacondition_ids)另外我在实际项目中经常会把DE、FE通道混合使用因为某些故障在驱动端表现不明显在风扇端更清晰。如果你只做四分类基础实验用DE单通道就足够了如果做故障尺寸或位置细粒度分类建议把多通道拼成多输入模型鲁棒性会好很多。最后再分享一个小技巧CWRU数据集里外圈故障因为有3个安装方向很多论文其实只用了其中一种方向导致对比不公平。你在跟自己或他人的方法做对比实验时务必在论文里写明用了几种方向、哪些工况、窗口大小、划分方式否则结果完全不可比。这个数据集的“标准”只是采集方式标准使用方式上并没有金标准——恰恰是谁能讲清楚数据处理细节谁的结果更经得起推敲。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进