简介振动信号分析是机械设备健康监测的核心手段滚动轴承作为旋转机械中最易失效的部件其故障诊断依赖对加速度信号的有效处理。通过特征频率计算如BPFO、BPFI和包络谱解调可定位故障部位而峭度等时域指标能敏感捕捉早期异常。CWRU轴承数据集作为该领域最经典的公开基准提供了多位置、多尺寸、多负载的振动数据广泛应用于验证故障诊断算法的有效性。然而数据读取、样本切分、训练集划分等环节若处理不当极易导致数据泄漏使模型泛化能力虚高。本文系统梳理了CWRU数据的组织方式、Python读取方法、特征提取流程及深度学习建模要点并总结了常见工程陷阱帮助研究者构建可靠的轴承故障诊断实验。 凯斯西储大学CWRU滚动轴承数据在机械故障诊断这个方向几乎是绕不开的第一座山。从2015年前后深度学习刚开始应用到工业健康管理那阵子到眼下各种域自适应、少样本学习、大模型的新玩法几乎每篇论文的实验部分都会拿它跑一遍基线。说它是这个领域的MNIST一点不夸张。这套数据讲的是什么一句话就能说清在实验室条件下用可控的方式在滚动轴承上加工出不同位置、不同尺寸的故障然后采集不同负载下的振动信号供研究者验证各种故障诊断算法。它能解决的问题很具体——轴承故障在不在故障在内圈、外圈还是滚动体故障多严重以及工况变了以后算法还稳不稳。适合谁来读如果你刚开始做设备故障诊断或者正准备用CWRU做第一个实验这篇文章能把数据组织、读取方式、特征提取、模型搭建和常见坑一次讲清楚。有点经验的朋友可以直接跳到后面的踩坑部分那几段基本是我反复被绊倒过的位置。1. 先读懂这套数据实验台、故障类型与文件组织1.1 实验台一个高度可控的“故障制造工厂”CWRU数据来自一个很经典的轴承实验台核心是一台2马力约1.5kW的Reliance Electric电机。电机轴通过联轴器连接扭矩传感器/编码器和测功机测功机用来给电机施加可调的负载。试验台的布置逻辑我理解是这样电机转动带动轴承旋转测功机给电机加负载振动传感器贴在轴承座上采集加速度信号。传感器位置有三个——驱动端DE、风扇端FE和基座BA分别采集不同位置的振动。这里有个概念容易绕所谓“驱动端”和“风扇端”是指电机的两端驱动端是输出轴那侧风扇端是散热风扇那侧。两个位置装的是不同型号的轴承所以数据也是两套。驱动端轴承是SKF的6205-2RS JEM深沟球轴承风扇端是6203-2RS JEM。论文里最常用的是驱动端数据因为故障都加工在驱动端轴承上信号特征最清晰。1.2 故障是怎么“造”出来的这个数据集最有价值的地方在于故障的真实性。故障不是仿真出来的也不是在模型里加个冲击脉冲模拟的而是用电火花加工EDM直接在轴承上打出来的单点损伤。加工出来的故障按两个维度区分故障位置内圈Inner RaceIR、外圈Outer RaceOR、滚动体BallB加上正常轴承NormalN。故障直径0.007英寸、0.014英寸、0.021英寸后续版本还补了0.028英寸。换算成公制分别大约是0.18mm、0.36mm、0.53mm和0.71mm。此外还有外圈故障的安装角度问题这个放到后面坑位部分细说。负载则分了0、1、2、3马力四档对应的电机转速大约是1797、1772、1750、1730 rpm。为什么这组参数设计得好因为它是一个近乎正交的实验矩阵——位置、尺寸、负载三个变量分别变化你可以单独研究任何一个变量对振动信号的影响也可以控制变量构造迁移学习任务。这是它比一堆无序采集的现场数据好用得多的根本原因。1.3 数据文件是怎么组织的官网下载下来是一堆.mat文件文件名是数字编号比如97.mat、105.mat、169.mat。不同编号对应不同的故障位置、故障尺寸和负载组合。这里我要先提醒一句文件编号和工况的对应关系网上流传的版本比较多如果你要严谨地写论文请一定以官网提供的文件列表为准别直接引用二手博客的编号表。我自己用的时候习惯是先加载某个编号的文件检查里面的字段再对照官网说明确认负载和故障类型——因为同一个故障位置、同一个故障尺寸在0HP和3HP下信号差异非常大一旦对应错整个实验结论都会出问题。每个.mat文件内部的变量结构一般是这样的DE驱动端加速度计信号FE风扇端加速度计信号BA基座加速度计信号time时间序列部分版本有驱动端信号采样频率有12kHz和48kHz两套风扇端和基座一般是12kHz这个在后续处理中必须注意区分。采样时长大概是10秒左右所以12kHz的一套数据大约就是12万个点。2. 数据读取与样本构建动手前先把路铺好2.1 下载与数据确认CWRU数据在官网Case Western Reserve University Bearing Data Center可以免费下载但网站改版过几次部分页面链接时好时坏。我的习惯是先尝试官网原始链接下载.mat原版文件如果官网不稳定再去GitHub或Kaggle上找别人整理好的版本。下载后先别急着训练模型花几分钟做三件事确认文件格式可以被当前环境读取老版本.mat一般没问题见2.2。确认文件编号对应的工况截图保留一份对照表。确认采样频率——同一个数据集里混合了12kHz和48kHz的数据如果你拿48kHz的DE数据和12kHz的FE数据直接拼一起后患无穷。2.2 用Python把.mat文件读进来CWRU整套数据大多是老版本的MATLAB格式Python里直接用scipy.io.loadmat就能读。这里有个常见坑有些新版数据可能是mat v7.3格式HDF5scipy.io.loadmat直接报错需要换h5py读取。基础读取代码import scipy.io import numpy as np mat scipy.io.loadmat(105.mat) print([key for key in mat.keys() if not key.startswith(__)]) # 一般能看到 DE, FE, BA, time 之类的字段 de_signal mat[DE].flatten() fs 12000 # 根据文件确认是12000还是48000 print(de_signal.shape, de_signal.dtype)如果你下到的是.mat v7.3版本loadmat会报类似“NotImplementedError”的错误换h5py读取import h5py with h5py.File(105.mat, r) as f: de_signal f[DE][()].flatten()注意h5py读出来的数据可能是倒序的因为MATLAB写HDF5时默认列优先存储需要确认方向后再处理。2.3 样本切分窗口长度到底该选多少拿到一整段10秒的振动信号不可能直接丢给模型做分类——数据量太小而且整段信号只能得到一条样本。常规操作是把长序列切成固定长度的短样本。窗口长度怎么定我见过有人用256点也有人用4096点各有道理。核心逻辑是一个样本至少要包含几个完整的故障冲击周期。以0HP、1797rpm为例转频fr1797/60≈29.95Hz一个转轴周期约0.0334秒。如果采样率12kHz一转约400个采样点。而外圈故障特征频率BPFO大约是转频的3.58倍约107Hz特征周期约0.0093秒对应约112个采样点。综合考虑我通常选1024点或2048点理由1024点约3个外圈特征周期和2.5个转轴周期特征信息足够。2048点特征更丰富但样本数减半。太短的窗口128、256噪声占比大分类不稳定。太长的窗口8192以上虽然信息多但训练样本数量下降而且同段信号切出的样本时间相关性更强更容易造成数据泄漏。切分代码def sliding_window_slice(signal, length1024, strideNone): if stride is None: stride length # 不重叠切分 samples [] for start in range(0, len(signal) - length 1, stride): samples.append(signal[start:start length]) return np.array(samples)这里有个小建议默认用不重叠切分stridelength原因是不重叠样本之间的时间相关性低随机打散后训练验证更干净。用重叠滑窗stride256之类的可以扩充样本量但同一段信号切出的相邻样本高度相似如果分到训练集和测试集指标虚高到你不敢信。2.4 训练集和测试集要怎么划分这是CWRU实验里最影响结果、也最容易被忽视的一步。我见过很多新手代码把所有样本随机打乱按7:3分成训练集和测试集准确率跑了个99%然后很兴奋。实际上这种做法在CWRU上基本没有意义因为同一个.mat文件切出的样本之间高度相关本质上就是同一段波形换了几个窗口放进训练集又放进测试集等于开卷考试。正确的划分方式至少有两种按文件划分先把每个.mat文件切成样本然后整个文件的所有样本一起进入训练集或测试集。不同文件不要交叉。这样保证测试集里的信号和训练集不是同一段连续波形。按工况划分想验证泛化能力的直接指定某些负载做训练、某些负载做测试比如用0HP和1HP训练2HP和3HP测试。这种跨工况评估才是CWRU真正能帮你做的事情。我自己的实验习惯是先把所有文件按“工况-位置-尺寸”列一张表然后按组合划分确保无论是同工况评估还是跨工况评估都不会发生同文件样本跨集合泄漏。3. 特征频率与包络分析从波形里读出故障信息3.1 先算一遍特征频率所有信号分析的锚点拿到任何一段轴承振动信号第一件事不是无脑喂给深度学习而是先算特征频率。这就像听诊要先知道心率不然听到杂音也不知道是不是心律失常。6205-2RS深沟球轴承的关键参数节径Pitch Diameter39.04mm1.537英寸滚珠直径Ball Diameter7.94mm0.3126英寸滚珠数量9接触角约0°几个特征频率公式外圈故障特征频率BPFO内圈故障特征频率BPFI滚动体故障特征频率BSF保持架故障特征频率FTFBPFO n/2 × fr × (1 - Bd/Pd) BPFI n/2 × fr × (1 Bd/Pd) BSF Pd/(2×Bd) × fr × [1 - (Bd/Pd)^2] FTF fr/2 × (1 - Bd/Pd)其中fr是转频n是滚珠数Bd/Pd ≈ 0.2034。代入fr29.95Hz1797rpm可以得到一张速查表特征频率倍率关系1797rpm时约值FTF0.398 × fr11.9 HzBPFO3.585 × fr107.4 HzBPFI5.415 × fr162.2 HzBSF2.357 × fr70.6 Hz这张表在后续所有频谱分析时都要用到。你在频谱或包络谱上找故障峰值时要找的是这些频率的整数倍位置而不是随便一个谱峰。3.2 时域指标峭度为什么对早期故障敏感时域特征是最直观、计算成本最低的特征。工程上常用的几个均方根RMS反映振动能量整体水平故障严重时RMS通常升高但早期故障变化不明显。峰值因子Crest Factor峰值除以RMS对冲击性信号敏感。轴承出现点蚀时周期性冲击会让峰值升高RMS还没跟上峰值因子就会先跳起来。峭度Kurtosis四阶中心矩除以方差的平方数学上定义为K E[(x-μ)^4] / σ^4。正常轴承振动接近高斯分布峭度约等于3出现早期故障时信号中混入周期性冲击分布变得更加“高瘦”峭度明显上升可以到5、10甚至更高。峭度是早期故障检测里非常经典的一个指标但它有一个缺点对单个大冲击特别敏感偶尔一次磕碰也会把峭度顶得老高。所以我会同时看峭度和RMS两个一起涨才放心。时域特征提取代码def time_features(x): rms np.sqrt(np.mean(x**2)) peak np.max(np.abs(x)) kurtosis np.mean((x - np.mean(x))**4) / (np.std(x)**4) crest_factor peak / rms return { rms: rms, peak: peak, kurtosis: kurtosis, crest_factor: crest_factor, }3.3 包络谱解调出周期冲击时域特征告诉你“有没有问题”但告诉不了你“问题在哪个部位”。要定位故障位置靠的是包络谱分析。包络谱原理其实不难理解轴承故障产生的冲击会激起轴承座或传感器的结构共振相当于故障信号被调制到高频共振带上。原始频谱里你会看到高频段出现一大片能量但很难分辨冲击周期。包络分析就是先把高频共振区的信号提取出来再做Hilbert变换得到幅值包络最后对包络做FFT这样就把“藏在载波里的周期冲击”解调出来了。具体步骤带通滤波选一个包含共振峰的频带。CWRU数据在12kHz采样率下我习惯用1000-4000Hz做带通。对滤波后的信号做Hilbert变换取绝对值得到包络。对包络信号做FFT得到包络谱。在包络谱上找BPFO/BPFI/BSF及其谐波位置是否有突出峰值。Python实现from scipy import signal from scipy.signal import hilbert def envelope_spectrum(data, fs12000): # 带通滤波 b, a signal.butter(4, [1000, 4000], btypebandpass, fsfs) filtered signal.filtfilt(b, a, data) # 包络 envelope np.abs(hilbert(filtered)) # 包络谱 f, spec signal.periodogram(envelope, fsfs, nfft8192) return f, spec f, spec envelope_spectrum(de_signal, fs12000)实际操作中如果BPFI在162.2Hz处出现明显谱峰并且还有2倍频324Hz、3倍频486Hz那基本可以锁定是内圈故障。同理107Hz位置对应外圈70Hz位置对应滚动体。3.4 快速验证一个样本是否正常我每次拿到一个.mat文件会先画两个图一个原始时域波形一个包络谱。时域波形如果看到规则的大幅值冲击说明这个样本大概率有故障。包络谱上如果某个特征频率处谱峰特别干净、谐波整齐就能直接判断故障类型。这一步和后续的模型实验没有直接关系但能帮你建立对数据最直观的感觉。很多新手跳过这步直接跑深度学习结果模型训好了都不知道自己在学什么调参全靠猜这是最亏的。4. 从特征到模型复现一套完整诊断流程4.1 路线A特征加机器学习分类器如果你只是想做一套快速可解释的基准特征加传统分类器是最合适的选择。把每个样本切成1024点提取一组时域特征RMS、峰值、峭度、波形因子、峰值因子等再加频域特征频谱峰值、谱质心等堆起来组成特征向量然后用SVM或RandomForest分类。代码框架from sklearn.model_selection import train_test_split from sklearn.svm import SVC from sklearn.ensemble import RandomForestClassifier from sklearn.preprocessing import StandardScaler # features 是 [n_samples, n_features] 的特征矩阵 # labels 是 [n_samples] 的标签如 0Normal, 1IR, 2OR, 3B X_train, X_test, y_train, y_test train_test_split( features, labels, test_size0.3, stratifylabels, random_state42 ) scaler StandardScaler() X_train scaler.fit_transform(X_train) X_test scaler.transform(X_test) clf SVC(kernelrbf, C10, gammascale) # 或者 clf RandomForestClassifier(n_estimators200) clf.fit(X_train, y_train) print(clf.score(X_test, y_test))注意先切分再在训练集上fit标准化器然后在测试集上transform。如果你在全部数据上算mean和std再切分测试集信息就泄漏进了训练过程结果偏乐观。这套路线做4分类Normal/IR/OR/B通常能到95%以上做更细的10分类加上故障尺寸也能拿到不错的分数。它的好处是特征可视化容易能直接看出每类样本在特征空间里的分布适合写报告和放在论文的消融实验里做对照组。4.2 路线B一维CNN端到端深度学习路线就不需要手工特征了直接把原始振动段喂给网络让它自动学特征。在CWRU上一个非常简单的1D-CNN就能达到很高准确率这也是这个数据集被诟病“太简单”的原因之一。我常用的一个轻量网络结构from tensorflow.keras import layers, models model models.Sequential([ layers.Input(shape(1024, 1)), layers.Conv1D(16, 3, activationrelu, paddingsame), layers.MaxPooling1D(2), layers.Conv1D(32, 3, activationrelu, paddingsame), layers.MaxPooling1D(2), layers.Conv1D(64, 3, activationrelu, paddingsame), layers.GlobalAveragePooling1D(), layers.Dense(4, activationsoftmax) ]) model.compile(optimizeradam, losssparse_categorical_crossentropy, metrics[accuracy]) model.summary()训练参数我用默认比较多Adam优化器学习率1e-3batch_size 64epochs 30训练集和验证集划分比例8:2。有几个实用细节输入形状是[样本数, 1024, 1]最后一维是通道数也就是原始振动幅值。归一化不要用整套数据的均值/标准差。我推荐逐样本归一化把每个样本除以自身标准差这样不同负载下的幅值差异对模型的影响会小一些。同工况随机切分时这个网络很容易在几十轮内到99%以上。所以看准确率意义不大重点要看跨工况实验的分数。4.3 实验设计怎么报结果才有说服力如果你要写论文或做技术报告CWRU上的实验结果至少要有三种划分方式缺一种审稿人都可能挑刺随机划分按样本随机8:2划分作为“上限参考”证明网络有能力学到判别信息。按文件划分同一.mat文件的样本全部进训练集或全部进测试集反映真实部署时的表现。跨工况划分训练用0HP和1HP测试用2HP和3HP考察模型对转速/负载变化的鲁棒性。第三种最考验模型。很多模型在随机划分上96%跨工况直接掉到70%甚至更低。这不一定是模型不行而是你之前根本没让模型见过不同转速下的信号形态。我自己看论文时凡是只报了随机划分准确率的默认打五折理解。跨工况分数才是真实水平。4.4 迁移学习与跨域实验的可能性CWRU因为有多负载、多故障尺寸天然适合构造迁移学习任务。常见玩法负载迁移源域0HP有标签目标域3HP无标签测试域自适应算法TCA、DANN、MMD等能不能把准确率拉回来。故障尺寸迁移用0.007英寸和0.014英寸的故障训练0.021英寸故障做未知类识别或增量学习。位置迁移驱动端数据训练风扇端数据测试考验跨传感位置的泛化。这类实验的意义在于模拟工业场景——现场工况总是在变不可能把所有工况都采集一遍再部署模型。CWRU提供了一个干净可靠的环境来验证这些算法这也是它到今天还有引用量的原因。5. 避坑指南这些年我在CWRU上踩过的坑5.1 数据泄漏随机切分是最大的坑前面已经反复强调了这里单独再拎出来说一次。CWRU的数据长度有限很多人都用重叠采样扩充样本比如1024点窗口步长256一个.mat文件能切出几百条样本。然后直接随机划分训练测试同文件样本同时出现在两端分类器记住的是时间波形本身而不是故障模式。我见过有人随机划分拉到99.8%准确率换成按文件划分掉到82%再换成跨工况当场掉到60%多。你的模型不是在学故障特征是在背样本。避坑办法切样本的时候给每个样本记录来源文件ID划分数据时按文件ID划分。这是最低成本的防泄漏手段。5.2 单位之谜m/s²还是gCWRU官网标称加速度单位有时写m/s²但网上大量资料和论文实际按g处理量级对不上。这个问题其实没有确定答案不同版本的.mat文件导出的数值范围也不完全一致。我的处理建议是如果只做相对比较比如同一模型在CWRU和你的私有数据上对比趋势单位无所谓特征归一化后不影响结论。但如果要拿CWRU的数值对标现场振动标准ISO 10816之类必须先做单位校准否则结论不可信。5.3 12kHz和48kHz千万别混用CWRU的驱动端数据同时存在12kHz和48kHz两个采样率版本。如果你把两种数据都下下来然后不加区分地切样本、丢模型你的频谱分析会乱套——同样的100Hz特征在12kHz和48kHz数据里坐标完全不对应。一个常见做法是只使用12kHz的驱动端数据这是绝大多数论文的标准选择方便复现和横向对比。如果一定要用48kHz数据建议统一降采样到12kHz再用。5.4 外圈故障的位置效应CWRU的外圈故障数据包含了不同安装位置常见的是3点钟、6点钟、12点钟方向。6点钟方向恰好处于承载区故障冲击被载荷放大信号特征最明显3点钟和12点钟不在主承载区信号弱得多。这意味着同样是“外圈故障0.014英寸”如果一个是6点钟的数据、一个是12点钟的数据信号形态可能差很多。做分类时如果不加区分相当于同一标签类别里混入了不同强度的信号模式模型会学得很分裂。我的习惯默认只用6点钟的外圈故障数据或者在标签里明确把位置作为一个因素进行区分避免踩这个坑。5.5 CWRU不是万能的它不适合做什么最后说个经常被忽视的点。CWRU数据是稳态工况下的单点故障数据没有连续的退化过程也没有复合故障噪声环境也比较干净。所以不适合做剩余寿命预测RUL没有退化轨迹想预测“还剩多少寿命”无从下手这块得找XJTU-SY、IMS之类的退化数据集。不适合做强噪声鲁棒性测试实验室数据信噪比高不能完全代表工厂环境需要自己加噪做压力测试。不适合验证变转速诊断CWRU的转速在每档负载下基本恒定变转速场景要找专门的变速轴承数据集。CWRU的正确用法是把算法在这个干净环境里验证有效再去现场数据里检验工程表现。它是起跑线不是终点线。个人经验是每次拿到新的诊断方法我都会先在CWRU的随机划分和跨工况划分上各跑一遍如果随机划分都到不了高准确率说明方法本身有逻辑问题如果随机划分很高、跨工况掉得很惨说明模型的泛化能力不行先去解决这个短板再上现场数据。这套筛选流程帮我省下了大量在脏数据上调参的时间。本文还有配套的精品资源点击获取