☰
帕德博恩轴承数据集全解析:命名规则、故障类型与避坑指南
2026/10/11 19:42:12 网站建设 项目流程

简介:面向轴承故障诊断研究者的帕德博恩数据集解读文档,系统梳理健康(K0##)、外圈(KA##)、内外圈复合(KB##)、内圈(KI##)四类数据的分组与命名规则,并结合实例拆解 N09_M07_F10_K001_1 等文件名的六段含义。文档同时对比电火花、钻孔、电动雕刻等人工损伤与加速寿命实验真实损伤两类故障来源,说明各自对应组别与适用场景。针对 MATLAB 读取需求,重点介绍 Info、X、Y、Description 四部分结构,明确 Y 中电流、转速、温度、扭矩、振动等信号的存放位置,便于直接提取与建模。资源为单个 docx 文件,大小 1.59MB,内容紧凑但覆盖要点完整,已有 3961 人学习下载,适合刚接触该数据集、需要快速理清数据组织与字段语义的初学者,也可作为故障诊断实验前的数据预处理参考。

1. 帕德博恩轴承数据集:故障诊断绕不开的多模态数据源头

做轴承故障诊断的人,绕不开帕德博恩数据集。这份多模态数据集把健康、外圈故障、内圈故障和内外圈复合故障四种状态都打包好了,每个文件里能同时拿出电流、振动、转速、扭矩、温度等多路信号,在公开资源里相当难得。我最早拿它练手时,光弄懂文件名和 MATLAB 结构体就折腾了半天,后来发现不少论文里对它的使用方式其实都有隐患。这篇笔记把命名规则、故障类型、字段结构和踩过的坑一次讲清,适合准备拿它做实验、写论文或搭故障诊断 Demo 的从业者。

2. 命名规则这样读:N/M 编码不是日期,是转速与负载

2.1 文件名五段拆解

帕德博恩数据集的文件名长这样:N09_M07_F10_K001_1。第一次看到它的人,十有八九会把它当成“2009 年 7 月采集”——网上某个中文解读确实这么写,但实际对照数据列出来看,这个说法站不住脚。

整个文件名用下划线分隔,一共五段:

  • N09:转速编码。900 转/分对应 N09,1500 转/分对应 N15,规律是转速除以 100 后取两位。
  • M07:负载编码。负载 0.7 对应 M07,负载 0.1 对应 M01,基本是负载值乘以 10 后补零。
  • F10:机器类型标识,整份数据集统一用 F10。
  • K001:数据组编号,K 开头后接三位组号。
  • 末尾数字 1:该组内的文件编号,范围 1~20。

所以N09_M07_F10_K001_1的真实含义是:900 转/分、负载 0.7、径向力 1000 N 条件下,K001 健康轴承的第 1 个记录文件。N15_M01_F10_K001_1则是 1500 转/分、负载 0.1 下的同组第 1 个文件。

之所以有人说它“六部分”,是把 N09 和 M07 再拆成转速、负载两个语义字段。实际文件名就是五段,写解析脚本时按五段处理即可。

2.2 四类前缀对应四类状态

前缀决定了轴承状态,整份数据集一共四类:

前缀含义数据组数具体组号
K0健康轴承6K001~K006
KA外圈故障12KA01、KA03~KA09、KA15、KA16、KA22、KA30
KB内外圈复合故障3KB23、KB24、KB27
KI内圈故障11KI01、KI03~KI05、KI07、KI08、KI14、KI16~KI18、KI21

注意 KA 和 KI 的组号不是连续的,中间缺了很多号,比如 KA02 和 KA10~KA14 不存在。缺失原因一般是采集过程中某些样本被剔除,或者编号留给了其他实验。写论文列数据分组时,别想当然写“KA01~KA12”,直接抄上表的组号最稳。

每组数据下都有两种工况的文件。以 K001 为例,N09_M07_F10_K001_1~_20共 20 个文件,N15_M01_F10_K001_1~_20也有 20 个,加在一起 40 个 .mat 文件,其他组同理。

2.3 工况参数只有两套,别自己脑补

整份数据集在文件名里出现的负载/转速组合只有两套:

工况代号转速负载径向力
N09_M07900 转/分0.71000 N
N15_M011500 转/分0.11000 N

这意味着想研究“高转速高负载”或者“中转速中负载”这些组合时,这份数据集给不了你,只能换数据源。它的设计意图是让每个数据组都在两种工况下各采 20 段,方便做跨工况泛化实验,而不是覆盖全工况平面。

提示:个别二手资料把 N/M 解释成日期和月份,属于以讹传讹。判断依据很简单——如果 N 是年份,整个数据集只会有 2009 和 2015 两个年份,且恰好和 900/1500 两种转速一一对应,这种巧合在实际采集里几乎不可能发生。

2.4 用脚本批量解析文件名

手工看几十个文件还行,一旦要用全部 1200 多个文件,就得写脚本。最通用的做法是用正则把文件名拆成结构化字段:

import re from pathlib import Path pattern = re.compile( r'^(N\d+)_(M\d+)_(F\d+)_([A-Z]+\d+)_(\d+)$' ) def parse_filename(fname: str) -> dict: m = pattern.match(Path(fname).stem) if not m: raise ValueError(f"无法解析文件名: {fname}") n_code, m_code, machine, group, idx = m.groups() return { "speed_code": n_code, "load_code": m_code, "machine": machine, "group": group, "file_idx": int(idx), "speed_rpm": int(n_code[1:]) * 100, # N09 -> 900 "load": int(m_code[1:]) / 10, # M07 -> 0.7 "fault_type": group[:2], # K0 / KA / KB / KI }

解析逻辑说明:正则里N\d+抓住 N09、N15,M\d+抓住 M07、M01,[A-Z]+\d+负责 K001、KA01 这类混合编号。最后通过n_code[1:]取数字部分转成转速,m_code[1:]转成负载。这样后面做数据清单时,可以直接得到一个带fault_type、speed_rpm、load的表格,按字段筛选、分组都很方便。

参数说明:正则要求最后一位文件编号必须是纯数字,如果你的数据里有_1.mat和_1_re.mat这种二次采集文件,正则要放宽成(\d+[A-Za-z]*)。还有一点,Path(fname).stem会去掉.mat后缀,避免点号干扰匹配。

2.5 先列清单再动手,比什么都重要

我处理这一类公开数据集有个习惯:第一步永远是跑一遍文件名清单,把所有组号、文件数、工况分布先打印出来,确认和文档对得上再往下走。这一步能提前挡掉很多后面才爆的雷。

root = Path("data/Paderborn") # 按实际路径修改 rows = [] for f in root.rglob("*.mat"): rows.append(parse_filename(f.name)) import pandas as pd df = pd.DataFrame(rows) print(df.groupby(["fault_type", "speed_rpm", "load"]).size())

这段代码会把整份数据的分布按“故障类型 × 转速 × 负载”列出来,一眼就能看出 KA、KI 各有多少文件、N09 和 N15 是否成对。如果某组只有一种工况,说明文件拷贝不全,趁早处理,别等训练时报错才回头看。

3. 故障类型与损伤工艺:人工损伤和加速寿命实验决定了标签怎么打

3.1 Table4:人工制造损伤的三种工艺

帕德博恩数据集里的人工损伤,用的是三种明确标注的工艺:EDM(电火花损伤)、Drilling(钻孔)、Electric engraver(电动雕刻)。三种方式模拟的是轴承运行中不同形态的表面缺陷,损伤程度分成 1 级和 2 级。

数据说明文档里给的两个例子很能说明问题:

  • KA01:外圈故障(OR),损伤程度 1 级,由电火花人工模拟损伤(EDM)。
  • KI08:内圈故障(IR),损伤程度 2 级,由电动雕刻人工模拟损伤。

这两个例子透露了一个关键信息:同一类故障前缀下,不同组之间的损伤工艺可能完全不同,损伤位置和扩展形态也不一样。拿 KI08 训练出来的模型,直接拿去预测另一个工艺做的 KI03,效果很可能会掉一截。

3.2 Table5:加速寿命实验生成的真实损伤

加速寿命实验是另一条损伤来源。这部分样本不是人工在表面刻缺陷,而是让轴承在超负荷条件下连续跑,直到出现真实裂纹、剥落和磨损。和人工损伤相比,真实损伤的故障特征更接近现场采集的轴承振动:早期微弱、逐渐扩展、伴随非平稳成分。

从组号分布看:

前缀总组数人工损伤组数加速寿命组数
K06--
KA1275
KB303
KI1156

也就是说,KB 复合故障的三组(KB23、KB24、KB27)全部来自加速寿命实验,没有人工损伤版本。如果想单独研究“真实损伤下的复合故障”,KB 是唯一选择,千万别在这三个组上套用人工损伤的标签描述。

3.3 标签体系怎么设计

分清人工损伤和真实损伤,直接决定你怎么写标签文件。

最省事的做法是只按“健康 / 外圈 / 内圈 / 复合”做四分类。这种情况,K0 是健康样本,KA 是外圈,KI 是内圈,KB 是复合,标签直接用前缀映射。

稍微细一点的实验,会按“损伤工艺 + 位置”打标签。比如同样标注为 KA 外圈故障,EDM 人工损伤和加速寿命真实损伤在频谱能量分布上差很多,混在一起打同一个标签会拉低模型上限。建议至少给训练数据加一列damage_source:能确认人工的写artificial,确认加速寿命的写run_to_failure,再用fault_type + damage_source做分层抽样。

3.4 批量生成标签表

用第 2 章的解析函数,可以直接把全数据集的标签表生成出来:

fault_map = { "K0": "healthy", "KA": "outer", "KI": "inner", "KB": "combined", } df["label"] = df["fault_type"].map(fault_map) print(df.groupby(["label", "group"]).size())

这段代码只做两步:先按前缀映射出四类标签,再按组号校验数据量。映射关系放在fault_map字典里,想扩展五分类、六分类标签时只改字典即可。label列生成后建议直接to_csv("labels.csv")存一份,后面所有训练脚本统一读它,不要在每个脚本里各写一套标签逻辑。

人工/加速寿命的区分不能靠文件名猜,因为两种来源的文件命名格式完全一样。可以先建立一个确认清单:

# 已确认的人工损伤组号,来自 Table4 manual_groups = {"KA01", "KI08"} # KA01=EDM外圈,KI08=电动雕刻内圈 df["damage_source"] = np.where( df["group"].isin(manual_groups), "artificial", "unknown", ) print(df.groupby(["fault_type", "damage_source"]).size())

输出里能看到人工组和未知组各占多少,剩下unknown的部分就是对照 Table5 逐个补充的。这个过程没有捷径,必须查文档。

3.5 损伤程度是隐藏信息,别浪费

数据说明文档只明确写了损伤程度 1 级、2 级,但没有对所有组逐一标注。如果你的实验目标不是简单分类,而是“故障严重程度评估”,那这个字段就是关键特征。建议在建数据清单时把damage_level单独拉成一列,能查到就填,查不到就留空。

注意:损伤程度字段在部分资料里是缺失的,用之前一定要逐组核对说明文档,盲填会导致训练标签错误,而且这类错误很隐蔽,模型 loss 照样下降,但结果完全不可信。

4. MATLAB 文件内部结构:先从 Y 结构体里取回多模态信号与工况参数

4.1 Info、X、Y、Description 的分工

每个 .mat 文件打开后,命名空间里通常有四个变量:Info、X、Y、Description。

  • Info:记录文件级别的元信息,比如采样配置、文件版本一类。在多数分析流程里用不上。
  • X:在部分文件中是空变量,或者仅作辅助。数据说明文档强调“所有数据均存储在 Y 这个结构体下,从 Y 下取数据即可”,所以别在 X 上浪费时间。
  • Y:真正的核心,结构体,下面挂着一堆信号字段。
  • Description:文本描述,写论文时需要确认字段含义时回头看它。

一句话总结:分析前直接盯住 Y,其他变量最多用来交叉验证。

4.2 Y 字段逐项说明

Y 结构体下包含的字段,按类型和作用分成三组:

字段名含义备注
force负载和文件名里的 M 编码对应
phase_current_1电机电流数据 1第一组电流信号
phase_current_2电机电流数据 2第二组电流信号
speed转速采集时的转速
torque扭矩扭矩信号
temp温度数据大小 1×4,四个温度测点
vibration_1s振动数据1 秒长的振动段

这套字段组合就是典型的“多模态”:有振动、电流两个主要信号通道,还有转速、扭矩、温度、负载这些工况参数。做故障诊断时,最常见的组合是把vibration_1s和phase_current_1/2一起作为特征输入,转速扭矩温度当辅助变量。

4.3 用 MATLAB 读取 Y 里的信号

自己写 MATLAB 脚本加载时,重点是把 Y 解出来:

data = load('N09_M07_F10_K001_1.mat'); disp(fieldnames(data)); % 确认顶层变量名 info = data.Info; desc = data.Description; y = data.Y; % 所有信号都在 Y 下 vib = y.vibration_1s; cur1 = y.phase_current_1; cur2 = y.phase_current_2; spd = y.speed; trq = y.torque; tmp = y.temp; frc = y.force; disp(size(vib)); % 确认振动数据维度

这段代码先把Y单独拿出来,再按字段名取各个信号。data.Y是结构体,直接y.vibration_1s就能取到对应数组。size(vib)这一步必须做,因为不同条件下的振动数据,行数和列数可能不一样,先确认维度再写后续处理,能少踩好几个坑。

4.4 用 Python 读取,注意结构体解包

很多新项目直接用 Python 处理,读取工具首选scipy.io.loadmat。但 MATLAB 结构体在 Python 里不会自动变成字典,而是变成 NumPy 的 structured array,取数逻辑跟 MATLAB 里不太一样:

import scipy.io as sio import numpy as np mat = sio.loadmat("N09_M07_F10_K001_1.mat") print([k for k in mat.keys() if not k.startswith("__")]) y_raw = mat["Y"] # shape 通常是 (1, 1) vib = y_raw["vibration_1s"][0, 0] # 先解一层结构体 vib = np.squeeze(vib) # 去掉多余的 1 维 cur1 = y_raw["phase_current_1"][0, 0] cur1 = np.squeeze(cur1) print("vibration:", vib.shape, "current1:", cur1.shape)

逻辑说明:mat["Y"]返回的是 shape 为(1, 1)的结构化数组,字段访问要写y_raw["vibration_1s"],取出来还是个二维数组,所以后面要跟[0, 0]才能拿到真正的信号数组。np.squeeze只是兜底,把可能残留的 shape(1, n)拉直成一维。

参数说明:vibration_1s字段名末尾带_1s,意思是这段振动是按 1 秒时长切出来的段。做深度学习输入时,直接把这个一维数组当序列用即可;想要二维时频图,再对这段数据做短时傅里叶变换。

4.5 多模态信号先对齐再拼接

把vibration_1s和phase_current_1拼成多通道输入前,先检查长度:

print("vib len:", vib.size, "cur len:", cur1.size)

振动和电流可能采样率不同、长度不同。如果长度不一致,常见做法是截短到公共长度,或者分别做特征提取再融合,而不是硬性np.stack。这一条在帕德博恩数据集上特别容易翻车,因为文件名里没有直接给出采样率,不看数据就默认等长,十有八九要报错。

5. 加载实操与避坑:MATLAB 到 Python 迁移中的五个常见问题

5.1 把 N09_M07 当成采集日期,工况直接选错

现象:按照某摘要里的说法,把N09_M07_F10_K001_1理解成“2009 年 7 月采集”,于是写论文时把 N09 当成时间变量,工况分析全乱。

原因:这份数据集的 N/M 编码被二手资料错误转述成日期。实际上对照数据可知,N09 对应 900 转/分,N15 对应 1500 转/分;M07 对应负载 0.7,M01 对应负载 0.1。两者组合成唯一的两种工况。

解决:以原始文件列表和说明文档为准。拿任一组数据看,N09_M07和N15_M01两种前缀在所有组里成对出现,而“年份”不可能只出现两个值。解析文件名时直接映射转速和负载,不要保留“日期”这个错误字段。

5.2 scipy 读出来的 Y 不是字典,取数路径绕晕人

现象:mat["Y"]打印出来是一个ndarray,以为数据存的是字典,直接用mat["Y"]["vibration_1s"]取数,结果拿到一个 shape 为(1, 1)的嵌套对象,再取一次才见真身。

原因:MATLAB 的 struct 被 scipy 转成了 structured ndarray,字段访问和索引要交错使用,很多人第一次接触就卡在这。

解决:统一封装一个取数函数,内部把[0, 0]和squeeze处理掉,业务代码里只调函数,不裸写索引:

import numpy as np def load_paderborn_field(mat_file: str, field: str) -> np.ndarray: mat = sio.loadmat(mat_file) y_raw = mat["Y"] arr = y_raw[field][0, 0] return np.squeeze(arr)

调用时vib = load_paderborn_field("xxx.mat", "vibration_1s"),一处封装,到处复用,能少写一大段重复的[0, 0]。

5.3 振动和电流长度对不齐,拼接直接报错

现象:np.stack([vib, cur1], axis=1)报 shape 不匹配。或者不报错但特征矩阵里的行语义错位,模型结果不稳定。

原因:不同信号采样率不同,文件之间的振动段和电流段长度也不固定。文件名里没有直接给出采样率,不能默认等长。

解决:先打印 shapes,长度不一致时按短边截断:

min_len = min(vib.size, cur1.size) vib = vib[:min_len] cur1 = cur1[:min_len]

然后拼成双通道矩阵。更稳的做法是每段单独做时域/频域特征,再把特征拼成向量,绕开长度匹配问题。

5.4 训练测试集切分时把同一组文件拆到两边,准确率虚高

现象:训练集和测试集同时包含 K001 组的数据,测试准确率 99%,换到现场数据直接崩。

原因:同一个文件组(如 K001)下的 40 个文件来自同一轴承的连续采集,时间相关性极强。随机切分会把高度相似的数据分到两边,模型记住的是文件级噪声而不是故障模式。

解决:按组切分,同一组的 40 个文件必须全部落在同一边。用GroupShuffleSplit或手动按组号划分,保证训练时的组完全不出现在测试集:

from sklearn.model_selection import GroupShuffleSplit gss = GroupShuffleSplit(n_splits=1, test_size=0.25, random_state=42) train_idx, test_idx = next(iter(gss.split(df, groups=df["group"])))

这段代码的关键是把groups=df["group"]传给GroupShuffleSplit,分出来的两份数据在组号上互不重叠。test_size=0.25表示留 25% 的组做测试,也可以按实际组数改成 0.3。想同时保证四类故障都在训练集里出现,可以再结合stratify按label做分层,组与组之间仍然不混切。

5.5 不检查字段存在性,加载到一半才报错

现象:循环处理几百个文件时,中途抛 KeyError,前面跑完的都白跑。

原因:不同批次的 .mat 文件字段可能不完全一致,有的文件 Y 下没有某个字段,直接按固定字段名取数就崩。

解决:在取数函数里先判断字段是否存在:

def get_field_safe(y_raw, field): if field in y_raw.dtype.names: arr = y_raw[field][0, 0] return np.squeeze(arr) return None

y_raw.dtype.names能列出结构化数组的字段名列表,这个判断成本极低。返回None表示该字段缺失,调用方自行处理。数据工程先做防御再谈效率,这种细节能省下不少半夜调 bug 的时间。

6. 验证技巧:按工况组划分数据集,让准确率不虚高

帕德博恩数据集的验证策略,核心就一条:按“组”切,而不是按“行”切。K001 有 40 个文件,N09 和 N15 各 20 个,这 40 个文件必须整体进入训练集或测试集。前面给过GroupShuffleSplit的代码,这里补一个实际效果对比。下面数字是示例,具体取决于特征和模型。

划分方式测试准确率(示例)泛化风险
完全随机切分约 99%高,同组数据泄漏
按组切分,同工况约 90% ~ 95%中,工况内泛化
按组切分,跨工况约 80% ~ 90%低,接近现场场景

面子上随便写 99% 没有意义,跨工况验证才能说明模型真的学到了故障模式而不是记住了采集批次。

具体操作上,我一般会为这份数据做三折验证:第一折用N09_M07工况的全部文件训练,N15_M01的全部文件测试;第二折反过来;第三折把两种工况混合但按组不重叠切分。三折的准确率取平均作为最终报告值。这么做的好处是能明确看到模型在两种工况下的表现差异,如果跨工况准确率掉得厉害,说明特征里混进了工况相关信息,应该加工况自适应,或者改用受转速影响更小的频带特征。

最终训练脚本里建议把划分索引保存成文件,比如split_train.npy、split_test.npy,保证实验可复现。数据清洗和划分属于“没有后悔药”的环节——模型可以重训,划分错了整个实验结论都要推翻。

从那以后,我每次拿到一份陌生数据集,都强制先跑一遍文件名解析、字段检查和工况分布清单,确认数据本身的逻辑闭环了才写训练代码,再没在数据准备阶段翻过车。希望这份解读能帮你少走同样弯路。

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

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

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

立即咨询