☰
CWRU轴承数据集实战:从mat读取到故障诊断模型训练
2026/10/2 9:55:32 网站建设 项目流程

简介:凯斯西储大学(CWRU)轴承数据集是故障诊断与机器学习领域的经典公开数据,面向从事轴承故障识别、信号处理及智能算法验证的研究者与学生,可省去自行下载和整理原始数据的繁琐过程。资源共172个文件,核心为165个mat格式的振动信号数据,覆盖12kHz驱动端故障、不同负载(0~3马力对应1797~1730转/分)及滚动体、内圈、外圈多种故障类型;压缩包另含3个Python程序、2个pyc及2个txt说明文档。其中封装好的CWRU类可直接导入,通过一行代码完成训练集、测试集、标签及类别名称的自动划分,默认384点信号长度并支持自定义;配套使用说明还给出了样本数量统计与长度选取建议(300~700较合适),便于快速上手。资源包共240.31MB,已有1064人学习下载,适合作为轴承故障诊断入门与论文实验的可靠数据支撑。

1. CWRU轴承数据集:故障诊断领域绕不过去的第一课

做设备故障诊断的人,绕不过去的第一个数据集就是它。凯斯西储大学(CWRU)轴承数据集相当于故障诊断领域的MNIST:正常、内圈、外圈、滚珠四种状态齐全,故障直径有0.007、0.014、0.021三档,驱动端和风扇端各有一路加速度信号,数据是.mat格式,用Python的scipy库读出来就能开始建诊断模型。它能解决做设备健康管理时最头痛的「故障数据去哪找、标签怎么标」的问题,适合准备用Python入门故障诊断的机械或电气学生,也适合刚转行工业AI、想快速验证网络结构的算法工程师。但先记住一个反直觉的结论:在这个数据集上把准确率练到99%并不难,真正难的是搞清楚切窗、标签对齐和泛化验证这三件事,再把同一套方法搬回产线数据上。

2. 拆开CWRU数据包:文件结构、读取方式与三类信号的第一次接触

CWRU数据包拿到手后,第一件事不是跑模型,而是先把.mat文件的结构看清楚。很多人直接loadmat之后当成普通numpy数组用,结果打印出来一串奇怪的数字,这是这个数据集给新手的第一个下马威。

2.1 原厂mat文件与整理程序的常见布局

CWRU官网下载的原始数据是一批.mat文件,每个文件对应一次实验,文件里用结构体保存三路加速度信号。你拿到的这个「含数据包+整理Python程序+使用说明」的版本,最常见的做法是把这些.mat统一转成npy或者csv,同时保留一份说明文档。整理程序一般会做三件事:把采样率写进配置(12kHz和48kHz两档)、把文件名解析成故障标签、把长度不一的信号按规范重新存放。文件布局通常是下面这样:

内容常见格式用途
原始振动数据.mat官方采集的原始数据结构,保留最完整信息
整理后的一维数组.npy / .csv切窗与训练模型时的直接输入,读取快
标签表.csv / .txt记录每个样本对应哪类故障、哪种故障直径
整理脚本.py复现从.mat到训练样本的转换过程

选npy不选csv主要是速度和体积:一条12kHz采样率的信号切成几百个1024点窗口后,csv存标签还凑合,存波形会慢到让你怀疑人生。如果包里提供的是csv,读取时用pd.read_csv并指定dtype=np.float64也可以,但训练前一定要确认有没有被隐式转成float32。打开使用说明时,我建议你第一眼只看两个地方:采样率写的是多少、通道顺序是DE在前还是FE在前。

2.2 用Python读取原始mat文件的最小脚本

整理程序的核心能力,其实就是下面这段代码的封装。我用一个最小可运行脚本说明读取逻辑,你在vscode里配好Python环境后,把路径换成自己的文件就能跑。

import scipy.io as sio import numpy as np mat_path = "data/raw/12k/DE/0.007_InnerRaceway.mat" raw = sio.loadmat(mat_path) # CWRU的mat文件是嵌套结构,先打印顶层变量名再提取,别盲写索引 print([k for k in raw.keys() if not k.startswith("__")]) # 常见结构里顶层是 raw['X'],这是一个结构数组 record = raw['X'][0][0] # 结构数组里通常有 DE、FE、BA 三个字段,分别代表三路加速度计 de_signal = record['DE'][0][0].astype(np.float64) print(de_signal.shape, de_signal.min(), de_signal.max())

第一行打印raw.keys()不是多余动作:不同批次的mat文件顶层变量名不一样,有的是X,有的直接平铺了DE字段,先打印出来再写索引,能省掉后面所有报错。raw['X'][0][0]取出第一条实验记录,记录里的DE字段就是驱动端加速度计信号;FE是风扇端,BA是基座。astype(np.float64)这一步不是可选项:mat文件里读出来的原始类型往往是uint16,直接做FFT或者减均值时会出现整数溢出,波形变成一条直线,转成浮点后面才稳。如果打开包里的整理程序,你会看到它把这段逻辑封装成了load_cwru_mat(file_path, channel='DE')之类的函数,作用就是减少重复代码。

2.3 DE、FE、BA三路信号怎么分工

三路信号里,DE是驱动端加速度计,CWRU的故障注入都在驱动端,所以绝大多数公开论文里的模型只用到DE这一路。FE在风扇端,故障信号经过轴承座和转子传播之后幅度衰减明显、相位也模糊,适合用来做跨位置泛化验证——比如训练只用DE,测试换成FE,能看出模型到底学的是故障特征还是记住了数据噪声。BA是基座加速度计,离故障源最远,信号特性反而更接近现场实际测点位置,做迁移学习时适合当作目标域数据来用。

采样率选12k还是48k也是一个需要提前决定的参数。轴承故障特征频率大多集中在几kHz以内,12kHz采样率在大多数诊断场景下够用,计算量只有48k的四分之一;如果做的是早期微弱故障、或者打算用小波包分解,再额外留一份48k数据不迟。整理程序的使用说明里一般会写清楚默认采样率,我见过不少人在这个细节上栽跟头:拿着12k的数据跑出特征频率,却用48k的采样间隔去算频谱横轴,最后怀疑模型有问题,其实是坐标标错了。

3. 用CWRU数据洗出合格样本:切窗、特征提取与标签对齐

把.mat文件读进来之后,离训练模型还差最关键的一步:把一整条连续振动信号变成几十上百个独立样本。这一步做得对不对,直接决定后面模型的泛化能力。

3.1 先把连续信号切成样本:窗口长度、重叠率与样本量

用Python做量化交易策略代码的人对滑窗很熟,这里其实是同一类逻辑:滚动窗口生成样本,重叠率就是步长的另一种表达。CWRU数据集里每个.mat文件是一段几秒到十几秒不等的连续信号,直接拿整段信号训练只有一个样本,没有任何意义,所以要先切窗。常见参数组合有两种:窗口长度1024点、重叠率50%;或者窗口长度256点、重叠率75%。前者适合CNN等需要频率分辨率的模型,后者适合样本量不够时做数据扩充。

def sliding_windows(signal, win_len=1024, overlap=0.5): """把一维振动信号切成固定长度窗口。 参数: signal: 一维numpy数组,长度一般大于win_len win_len: 窗口长度,1024点是12kHz采样率下的常用值 overlap: 重叠率0.5表示步长为win_len的一半 返回: windows: 形状为 (n_windows, win_len) 的二维数组 """ hop = int(win_len * (1 - overlap)) n_windows = (len(signal) - win_len) // hop + 1 windows = np.stack([ signal[i * hop: i * hop + win_len] for i in range(n_windows) ]) return windows # 以驱动端信号为例,切成1024点窗口 samples = sliding_windows(de_signal, win_len=1024, overlap=0.5) print(samples.shape)

hop是步长,等于窗口长度乘上(1 - overlap),重叠率0.5时每次前进512点,相邻两个窗口有一半数据重合。n_windows的计算里用了整除//,这是为了防止信号最后不足一个窗口时越界;np.stack把循环生成的窗口列表堆叠成二维数组,方便后续直接作为数据集的输入。窗口长度的选择直接影响频率分辨率:1024点在12kHz采样率下对应约11.7Hz的频率间隔,能分辨轴承特征频率的不同倍频;如果窗口太短,频谱会变糊,如果太长,样本量会变少。另外要注意,切窗前不要对整段信号统一做标准化,正确做法是先切窗、再对每个窗口分别做减均值除标准差,否则会引入未来数据的信息。

3.2 把一维信号变成模型能吃的形式:FFT幅值谱与STFT时频谱

切出来的窗口是一维时域波形,可以直接喂给一维CNN、LSTM,也可以转成频域特征。最常用的做法是计算FFT幅值谱,把每个窗口变成一条频域曲线。

def get_fft_spectrum(signal, fs=12000): """计算振动信号的幅值谱。 参数: signal: 一个窗口的时域信号,长度一般为1024 fs: 采样频率,CWRU的12k数据传12000,48k数据传48000 返回: freq: 频率轴坐标 amp: 对应的幅值 """ n = len(signal) win = signal * np.hanning(n) # 加汉宁窗抑制频谱泄漏 fft_vals = np.fft.rfft(win) amp = np.abs(fft_vals) / n * 2 # 单边谱幅值修正 freq = np.fft.rfftfreq(n, d=1 / fs) return freq, amp # 取切窗后的第一个样本画出频谱 freq, amp = get_fft_spectrum(samples[0], fs=12000) print(freq.shape, amp.shape)

np.hanning(n)是加窗操作,因为直接对截断信号做FFT会在频谱里出现拖尾,加汉宁窗之后主瓣更集中,内圈故障的边频带更容易看清。np.fft.rfft返回单边频谱,对于实信号只需要一半频率点,amp / n * 2是把幅值修正回物理量纲,方便后续做特征阈值判断。如果打算用二维CNN,常见做法是再进一步做短时傅里叶变换得到时频谱图,也就是横轴时间、纵轴频率的二维图像。我一般直接用scipy.signal.stft或者librosa生成,把每个窗口的时频谱存成灰度图,再走图像分类的流程。需要提醒的是,时频谱图的像素大小、颜色映射会影响CNN收敛,建议统一用224×224的灰度图,不要用彩色映射。

3.3 标签对齐的黑匣子时刻:文件名解析与索引检查

切窗完成之后,最玄学的一步来了:每个窗口到底对应哪一类故障。CWRU数据集的原始文件名里包含了故障类型和故障直径信息,比如文件名里带InnerRace就是内圈故障,带OuterRace就是外圈故障,带Ball就是滚珠故障,什么都不带的就是正常数据。整理程序通常会把文件名解析成一列标签,但这个过程里最容易出现索引错位。

import os def make_labels_from_dir(data_dir, windows_per_file): """根据文件名生成标签表,并校验窗口数量。 参数: data_dir: 存放切好窗口npy文件的目录 windows_per_file: 每个文件切出的窗口数 返回: names: 文件名列表,和标签一一对应 labels: 标签列表,0表示正常,1/2/3对应内圈、外圈、滚珠故障 """ classes = {"Normal": 0, "InnerRace": 1, "OuterRace": 2, "Ball": 3} names, labels = [], [] for f in sorted(os.listdir(data_dir)): if not f.endswith(".npy"): continue for key, label in classes.items(): if key in f: names.append(f) labels.append(label) break else: raise ValueError(f"未识别的文件名: {f}") # 校验:文件数乘以窗口数必须等于总样本数 total = sum(windows_per_file.get(n, 0) for n in names) assert total == len(names) * windows_per_file[names[0]], "标签与样本数量不匹配" return names, labels

for key, label in classes.items()的顺序有讲究:如果把Ball放在InnerRace前面,文件名同时包含两个关键词时就会标错,所以要先匹配更具体的类别名。else: raise ValueError用来兜底,保证没有哪个文件被静默跳过。最后的断言是挡板:切窗数量和标签数量不一致时直接报错,而不是等训练到一半才发现损失函数不下降。整理程序附带的标签表建议你打开人工核对一遍,尤其是检查正常样本的标签是不是0,外圈故障的标签是不是被标成了内圈,这种错位通常只在训练结束、看混淆矩阵时才暴露出来,届时就只剩后悔药了。

4. CWRU数据集训练前的5个必踩坑:现象、原因与排查

这一章写的是我在CWRU数据上反复踩过的坑。每一条都按「现象→原因→解决」的顺序记录,如果训练过程中遇到类似问题,可以按顺序排查。虽然标题叫数据集的坑,但多数坑的根源是处理流程里的小疏忽。

4.1 loadmat读出来是嵌套结构,当成数组直接跑报错

现象:sio.loadmat之后直接print(raw.shape)报错,或者raw['DE']报KeyError,更隐蔽的情况是数据能print出来,但画波形图全是毛刺。

原因:CWRU原始mat文件是结构数组,顶层变量一般是X,DE藏在X[0][0]['DE']里,不存在顶层DE这个键。另一个隐蔽原因是.dtype不是float,读出来是uint16,画图时数值范围正常,一做减均值运算就整数溢出。

解决:先用2.2节的最小脚本打印raw.keys()确认结构,再按二层结构取值;取得信号后无条件astype(np.float64)。如果整理包已经把mat转成了npy,就直接np.load,不要自己再去猜结构。碰到mat文件报unsupported format的,通常是mat版本太新,需要用mat73库读,这是另一条次要分支。

4.2 评估集准确率99%,换一批负载就跑崩:数据泄露

现象:随机切分训练集/测试集之后准确率轻松到99%,但你换一个负载档位的文件进来测试,准确率掉到60%以下。

原因:这就是数据泄露最经典的形式。同一个.mat文件切出的几百个窗口,因为重叠率50%的关系,相邻窗口大量共享原始数据点;随机切分时,同一个文件的窗口同时出现在训练集和测试集里,模型等于见过测试数据的邻居,记住的是数据片段而不是故障特征。CWRU数据里不同负载档位(0到3马力)的信号特征差异本来就小,这种泄露会让指标看起来漂亮到失真。

解决:切窗之前先按文件分组,把同一个.mat文件切出的所有窗口放进同一个集合,然后按文件级别划分训练/测试,而不是按窗口级别划分。代码上可以用GroupShuffleSplit,分组键就是文件名。如果要做严格的负载泛化验证,直接按负载档位分组:用0和1马力的数据训练,单独留2马力的数据测试,这样得到的准确率才有说服力。

4.3 每个mat文件长度不一样:类不平衡问题

现象:训练出来之后,正常样本的召回率很高,滚珠故障的召回率只有70%,混淆矩阵里滚珠故障大量被误判成内圈故障。

原因:CWRU数据集里每个.mat文件对应的实验时长不同,正常数据文件普遍偏长,故障数据文件短一些;而且滚珠故障本身的信号能量弱于内圈和外圈,特征容易被淹没。两个因素叠加,滚珠类别的有效样本数可能是正常类别的三分之一,模型天然偏向高频类别。

解决:第一道闸是统计每个类别的窗口数,确认不平衡程度。解决手段优先级从高到低:给损失函数加类别权重、对少数类做重叠率更高的切窗(比如从50%提到75%)、再用合成少数类过采样。不要一上来就用SMOTE对原始振动信号做插值,轴承故障信号是窄带冲击,插值会改变冲击间隔,等于篡改故障特征频率,这一点和表格数据完全不同。

4.4 外圈故障内部还有三种安装位置

现象:外圈故障的分类准确率总是比其他两类低,而且误判样本集中在某一个特定文件夹里。

原因:CWRU的外圈故障实验里,故障位置相对负载区分为3点钟、6点钟、12点钟三个方向,分别存在不同的.mat文件中。官方标签只告诉你这是外圈故障,没告诉你位置。外圈故障信号对负载区位置极其敏感,3点钟位置离载荷区近、冲击明显,6点钟位置冲击被负载调制得很弱。如果直接把三种位置混成一个「外圈故障」类别,类别内部的信号差异甚至大于类别间差异。

解决:两种处理方式。第一种,如果分类任务只要四种状态,那就手工限制只取同一个位置的数据,比如只用3点钟位置的三个直径档位;第二种,把标签细化成「外圈3点钟」「外圈6点钟」「外圈12点钟」,相当于把类别数从4扩到6,模型准确率会显著提升。做对比实验时务必在论文或文档里写清楚用的是哪个位置,否则别人复现你的结果会发现准确率差一大截。

4.5 整理程序生成的标签和你的切窗顺序没对齐

现象:训练Loss正常下降,但accuracy在0.25左右波动(四分类随机水平),打印几个样本的标签发现全是乱的。

原因:切窗脚本遍历文件的顺序和标签表生成的顺序不一致。比如切窗脚本用os.listdir直接扫目录,文件顺序不固定;标签表却是按文件名做sort()得到的。两边的顺序差了一个位置,从第二个文件开始标签就开始错位,越往后错得越离谱。

解决:统一用「文件名作为唯一键」来关联,不要依赖遍历顺序。把切窗结果按文件名分别存成单独文件,同时维护一张(文件名, 标签)的映射表;训练时读取样本也按文件名来读。更省事的做法是:切窗后把标签直接拼进样本文件名里,例如inner_0.007_0001.npy,彻底放弃单独维护标签表的方案。所有整理程序的使用说明里,这部分通常写得简单,我建议你拿到包之后先跑一个10行的小脚本,打印前20个样本的标签分布,确认不是齐刷刷全是0再做下一步。

5. 从CWRU到自己的产线数据:验证方法论与一个进阶技巧

CWRU数据集的价值不在让你刷高准确率,而在于给你一个标准参照物去校准整套方法是有效的。一个非常实用的验证方法是按负载档位做留一验证:训练集用0、1、2马力,验证集单独用3马力,这样能模拟「换了设备工况之后模型还认不认故障」。如果留一验证的准确率下降了20个百分点以上,问题通常出在特征里混入了转速相关的频率成分,而不是模型结构不对。检查方式是把每个窗口的主频和转速倍频画在一张图里看分布,转速影响比故障特征还大时,先做阶比跟踪再进模型,别急着换网络。

进阶技巧是双通道输入。把DE和FE两路信号分别切窗、分别做FFT,然后在通道维度上拼接成(2, 1024)的输入,喂给一维双通道CNN。FE的信号虽然微弱,但它的相位延迟和DE不同,两个通道一起输入等于给模型提供了空间位置信息,在跨负载验证时往往比单通道稳定得多。拼之前一定要确认DE和FE等长、窗口对齐,如果原始mat里两路长度差几个点,先截成相同长度再切窗。

我自己的一个教训是:第一次用CWRU数据时只做了随机切分,准确率刷到99.5%,以为万事大吉,后来拿到实验台实测数据直接掉了20个点。从那以后我只信任按文件、按负载、按测点三层分组验证出来的指标,超参数调得再玄学,也要先过这一关。把CWRU当成一面镜子而不是终点,希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询