信息速览
心电图问世一百多年,一直是心脏病学最常用的工具。它的磁学孪生兄弟心磁图却始终停在小众:测的同样是心脏电活动,只是把体表电位换成体表磁场,量级落在皮特斯拉这一档,比地磁场弱好几个数量级。测它需要超导器件加液氦,或者光泵磁力仪加磁屏蔽室,设备贵、场地贵,能稳定产出数据的实验室一直不多。Kiel Cardio Database 就是在这一背景下公开的:基尔大学把自家屏蔽室里测到的第一批心磁数据放上 PhysioNet,让没有设备的课题组也能摸到这种信号。
它规模很小——七名健康男性,每人 25 次一分钟测量,胸前共 200 个测点。结构却相当特殊:四只光泵磁力仪组成小阵列,靠人工移动夹具逐格覆盖胸前,每一格都留下坐标。拿到数据的人不只是得到一段波形,还得到一张可以重建的空间网格。心磁研究里最难复制的往往不是信号本身,而是"在哪个位置测的",这个库把它写进了头文件。
需要说清的边界:没有心电图同步,没有磁共振,没有任何注释,受试者全部健康且为男性,第一版也只有心磁一个模态。它适合练手、验证算法、评估传感器,不适合直接训练诊断模型。换个说法,它提供的是"看得到心磁"这件事本身,而不是关于心脏的任何结论。一屏速览见下表。
| 维度 | 内容 |
|---|---|
| 全名 | Kiel Cardio Database |
| 发布方 | PhysioNet(托管);数据由基尔大学采集 |
| 作者 | Erik Engelhardt、Norbert Frey、Gerhard Schmidt |
| 首次上线 | 2023 年 12 月 15 日,版本 1.0.0 |
| 规模 | 7 名受试者 × 25 次测量 = 350 条清单记录 |
| 每人测点数 | 200 个胸前位置 |
| 单次时长 | 一分钟 |
| 通道数 | 8 路(四只探头,各一至两个方向) |
| 采样率 | 200 Hz |
| 物理量 | 磁场,单位为皮特斯拉 |
| 传感器 | QuSpin QZFM Gen 1 光泵磁力仪,四只 |
| 采集场景 | 磁屏蔽室,受试者仰卧,静息 |
| 受试者 | 7 名健康男性,22–50 岁,2022 年采集 |
| 注释 | 无(官方明确本版不提供) |
| 文件格式 | WFDB:.hea / .dat,raw 与 preprocessed 两套 |
| 体积 | 未压缩 6.8 GB,ZIP 压缩包 6.5 GB |
| 许可 | CC BY-SA 4.0,免注册 |
§1 它要解决的具体麻烦
1.1 心磁的瓶颈不在算法,在能不能测到
心电图的采集门槛极低:一副电极、一片前端、一台电脑就能录。心磁图不行。心脏电活动在体表产生的磁场是皮特斯拉量级,大约只有地磁场的百万分之一,没有屏蔽的环境里会被环境磁噪声整个淹没。要测到它,要么用必须泡在液氦里的超导量子干涉器件,要么用同样离不开屏蔽室的光泵磁力仪。两条路都指向同一件事:你得先有一间磁屏蔽室。
这解释了一个长期失衡:心电的公开数据数以百万计,心磁的公开数据用"个"来数。官方在背景一节直接点名 PhysioNet 上此前没有任何其它心磁数据库;文献综述里也只数出一份公开可得的心磁参考数据,含五名 25 至 35 岁男性,用 304 通道超导系统采集,其余提到建库的文章多数没有给出可下载的入口。
所以这个库要解决的麻烦与其说在算法层,不如说在准入层:让没有屏蔽室的人也能拿到真实心磁波形,先把方法做起来。官方摘要说得很直白,目的是让这种昂贵的方法对没有相应设备的研究者也可用。
1.2 三条常见的错误期待
第一条,期待它是一份心电数据。 这是名字造成的误读。Kiel Cardio Database 里的 cardio 指心血管,不指心电图;第一版里的全部内容都是磁场,单位皮特斯拉,没有一路是毫伏级的体表电位。心电的常见处理链路——基线校正、QRS 检测、心率变异性——很多能借,但没有一条可以直接照搬而不重新标定。
第二条,期待它有病理标签。 七名受试者都是健康男性。本版没有心搏标注、没有节律标注、没有诊断结论,也没有任何解读意见。官方在用法说明里点明,拿它做分割或检测类评测之前,必须先完成人工标注。
第三条,期待它是多模态的。 官方确实说了未来版本会补入心电、磁共振与注释,但那是计划,不是现状。当前版本只有心磁,也没有与任何其它模态配对的同步记录。想做心磁与心电的联合分析,得自己另找来源或另采。
1.3 它能给到的与给不到的
| 你的需求 | 它给的 | 够不够 |
|---|---|---|
| 真实心磁波形作方法预研 | 7 人各 25 次、每次 8 路的真实信号 | 够,这是主业 |
| 胸前网格上的磁场分布 | 200 个测点,每点带三维坐标 | 够,坐标写在头文件 |
| 传感器或阵列的性能评估 | 四只光泵磁力仪的双轴原始输出 | 够,原始与滤波都在 |
| 原始与预处理链路的对照 | raw 与 preprocessed 两套并行 | 够,可直接比滤波代价 |
| 心搏或节律标注 | 无 | 不够,需自行标注 |
| 心磁与心电的同步分析 | 本版无心电 | 不够,等后续或另采 |
| 患者与健康人的判别 | 全部健康男性 | 不够,没有对照组 |
| 人群层面的统计推断 | 7 人 | 不够,样本量不允许 |
1.4 你的处境与它能帮到的事
| 你的处境 | 它能帮你什么 | 下一步该做什么 |
|---|---|---|
| 你的组刚拿到一只光泵磁力仪,还没有屏蔽室,想先看看真实信号长什么样 | 提供同型号探头(QuSpin QZFM Gen 1)在屏蔽室内的真实输出,可直接当作基线形态参考 | 先跑 §5.3 的读取,把 raw 与 preprocessed 各画一遍,再决定预处理链 |
| 你在做心磁去噪,缺带真值的干净段作参考 | 提供未经滤波的原始电压,与官方滤波版成对,可当作"输入—目标"的近似配对 | 注意官方滤波版不等于真值,见 §7.2 |
| 你想验证一个心磁源定位或等值线重建算法 | 200 个带坐标的测点构成不规则网格,正好做插值与重建 | 用 §2.3 的坐标解析把网格画出来,先确认覆盖形状 |
| 你在做心电算法向心磁迁移的可行性判断 | 同一套分割思路能否用在磁信号上,可以用它做小样本试跑 | 先自己做少数几个心搏的标注,再算迁移后的错检率 |
| 你在评估不同心磁设备的差异 | 提供光泵磁力仪这一条技术路线下的公开参照 | 与超导系统的公开数据对比,注意量级与噪声底不同 |
| 你在写综述,需要说清公开心磁数据有多稀缺 | PhysioNet 上唯一的同类数据,可作为稀缺性的直接证据 | 引用时同时给出 DOI 与官方页面的背景一节 |
1.5 一句话判断
它是一份"让你在没有屏蔽室的情况下也能摸到心磁"的样本:七个人、两百个点、一分钟一段,足以看清心磁长什么样、够不够干净,却不足以支撑任何关于人的结论。
1.6 不适合谁:四条边界
不适合做人群层面的研究。 七个人、全是健康男性、都在同一间屏蔽室、用同一套设备、在同一年完成。任何一个维度都不具备外推的条件。想用它讨论年龄、性别、体型与心磁形态的关系,样本量在第一步就会把结论压成轶事。
不适合做监督学习。 没有标签,没有对照,没有健康与患病的切分。它连一个可以当作二分类目标的字段都不具备。想用它做监督任务,得先自己标注,而标注完的类别也仍然只有"健康"一类。
不适合做多模态融合。 本版只有心磁。官方确实规划了心电与磁共振,但在它们落地之前,任何"心磁+心电"的联合研究都必须另外解决配对问题,而这个库帮不上。
不适合当作跨机构泛化基准。 只有一家机构、一间屏蔽室、一套探头。它可以告诉你某种方法在这个条件下有效,不能告诉你它在另一间屏蔽室里还灵不灵。
§2 数据构成与规格
2.1 一套文件,两个版本,七乘二十五
目录结构极其扁平。所有记录都放在 data 目录下,文件名由三段拼成:受试者编号、版本名、测次编号。受试者从 1 数到 7,测次从 01 数到 25,版本有两个取值:raw 表示原始,preprocessed 表示经过官方预处理的版本。于是每个受试者对应 50 个记录,全库共 350 条,记录清单 RECORDS 逐行列出这 350 条,一行一条,不带扩展名。
值得注意的是 RECORDS 只列了 preprocessed 一套。原记录名同样存在,文件也在同一目录,只是没有进清单。所以按清单下载只能拿到一半数据,要做 raw 与 preprocessed 的对照,得自己把文件名里的版本段替换掉。这一点在写批量脚本时必须提前处理,否则会以为"下载完了",实际上原始数据一份没拿到。
| 层级 | 命名 | 取值 | 含义 |
|---|---|---|---|
| 目录 | data/ |
单一目录 | 全部记录平铺,无二级子目录 |
| 受试者段 | subject<N>_ |
1 至 7 | 受试者编号 |
| 版本段 | _raw_ 或 _preprocessed_ |
两个取值 | 原始电压或预处理后的磁场 |
| 测次段 | trial<NN> |
01 至 25 | 第几次移动夹具 |
| 头文件 | .hea |
与记录同名 | 文本,声明通道与注释 |
| 信号文件 | .dat |
与记录同名 | 二进制,8 路交错 |
| 辅助目录 | images/ |
七张图 | 示意图与四条示例波形 |
images 目录里是文档配图,不参与分析:夹具照片、屏蔽室总览、坐标示意图、标记位置图,另有四张示例波形。这四张图命名用 patient_N,数据文件用 subjectN,两套叫法并存,检索时容易搜错。
2.2 字段与记录的完整字典
这个库的"字段"分三处:文件名、头文件正文、头文件末尾的注释行。没有独立的元数据表,唯一的结构化表格是根目录下的 subject-info.csv,只有三列。
| 信息项 | 所在位置 | 取值形态 | 含义 | 使用注意 |
|---|---|---|---|---|
| 受试者编号 | 文件名首段 | subject1–subject7 |
受试者标识 | 只有 7 个取值 |
| 版本标识 | 文件名中段 | raw / preprocessed |
是否经官方滤波 | 两者不可混入同一训练集 |
| 测次编号 | 文件名末段 | trial01–trial25 |
第几次移动夹具 | 序号越大位置越靠网格另一端 |
| 信号条数 | .hea 首行第 2 字段 |
8 |
八路通道 | 不是八个测点,见 §2.3 |
| 采样率 | .hea 首行第 3 字段 |
200 |
每秒采样点 | 与心电常见的 500 不同 |
| 采样点数 | .hea 首行第 4 字段 |
约一万三千至一万七千 | 单次总长 | 约合 65 至 87 秒 |
| 存储格式 | 信号行第 2 字段 | 212 |
WFDB 的 12 位打包格式 | 需用 wfdb 读取,不要按 int16 直读 |
| 增益 | 信号行第 3 字段 | 每通道不同 | 换算到物理单位 | raw 为伏,preprocessed 为皮特斯拉 |
| 位分辨率 | 信号行第 4 字段 | 12 |
有效位数 | 落在 16 位容器低 12 位 |
| ADC 零值 | 信号行第 5 字段 | 0 |
零电平对应整数 | 换算时无需额外偏移 |
| 初始值 | 信号行第 6 字段 | 逐通道不同 | 首采样点整数 | 可用于核验读取 |
| 校验和 | 信号行第 7 字段 | 逐通道不同 | 采样点累加和 | 与 SHA256SUMS.txt 互补 |
| 信号名 | 信号行第 9 与 10 字段 | Sensor 0 至 Sensor 3 加方向 |
哪只探头、哪个方向 | 同一探头可能出现两次 |
| 年龄 | .hea 注释行 |
整数 | 采集时年龄 | 本版只出现 26 至 35 岁 |
| 性别 | .hea 注释行 |
m |
采集时性别 | 本版全为 m |
| 采集年份 | .hea 注释行 |
2022 |
年份 | 全部一致 |
| 传感器坐标 | .hea 注释行 |
三个整数,单位厘米 | 四只探头各自位置 | 受试者坐标系 |
| 出生年份 | subject-info.csv |
整数 | 用于推年龄 | 与头文件年龄互相校验 |
| 诊断 | 全库 | 无 | — | 任何位置都没有 |
| 注释 | 全库 | 无 | — | 没有 .atr 或同等文件 |
subject-info.csv 三列:编号、性别、出生年。七行性别全为 m,出生年从 1971 到 2000 不等。头文件年龄是 2022 年采集时的年龄,与出生年推得的一致。七人实际跨度为二十六到三十五岁,是官方"22 到 50 岁"招募条件落在实际入组里的更窄区间。
"信号条数等于 8"这一行最容易被误读。做过十二导联心电的人看到 8,会条件反射地当成八导联。这里不是:八路来自四只探头,其中两只各记录一个方向,两只各记录两个方向,而且同一只探头在不同测次里记录的方向还可能不同。换句话说,通道编号固定,通道对应的方向不固定。任何想把第 k 路当作固定解剖位置的写法,都会在跨测次时出错。
2.3 一条记录的完整解剖
以 subject1_preprocessed_trial01 为例。头文件由 1 行摘要、8 行信号声明、10 行注释组成:
subject1_preprocessed_trial01 8 200 13964
subject1_preprocessed_trial01.dat 212 54.355288498234756(24)/pT 12 0 -2047 23303 0 Sensor 0 -Y
subject1_preprocessed_trial01.dat 212 57.28832847443557(937)/pT 12 0 -2047 62697 0 Sensor 0 Z
subject1_preprocessed_trial01.dat 212 48.27115581743158(87)/pT 12 0 -2047 46325 0 Sensor 1 -Y
subject1_preprocessed_trial01.dat 212 42.96730083937927(895)/pT 12 0 -2047 10916 0 Sensor 1 Z
subject1_preprocessed_trial01.dat 212 44.01762233691774(-73)/pT 12 0 -2047 52496 0 Sensor 2 -Y
subject1_preprocessed_trial01.dat 212 44.55874730282193(353)/pT 12 0 -2047 14965 0 Sensor 2 X
subject1_preprocessed_trial01.dat 212 48.32806856627415(49)/pT 12 0 -2047 42822 0 Sensor 3 -Y
subject1_preprocessed_trial01.dat 212 43.26390256684903(571)/pT 12 0 -2036 25093 0 Sensor 3 X
#-- <age>: 26
#-- <sex>: m
#-- <year of recording>: 2022
#-- <position sensor 0 [cm]>: [-11 17 -14]
#-- <position sensor 1 [cm]>: [-14 17 -11]
#-- <position sensor 2 [cm]>: [-14 17 -14]
#-- <position sensor 3 [cm]>: [-11 17 -11]
首行四个字段:记录名、八路信号、200 Hz、13964 个采样点。13964 除以 200 是 69.82 秒,比官方的"一分钟"多出近十秒;同一受试者第二次测量是 13856 点,约 69.3 秒。可见每次实际长度都略长于六十秒,一分钟是约数,固定按 12000 点切会丢掉末尾近十秒。
信号行的增益逐通道不同,54.355288498234756(24)/pT 表示浮点增益后跟括号内基线值,单位皮特斯拉。八路增益无一相同,因为对应的是不同物理通道,灵敏度各异。raw 版单位是 V,增益为几千到近万的分数量级。
注释行里的四个坐标值得单独看。sensor 0 的 [-11 17 -14] 表示 x 为 −11、y 为 17、z 为 −14,单位厘米。y 恒为 17,因为 y 轴从后背指向前胸,体位固定时夹具进深不变;变的是 x 与 z,构成胸前平面上的移动。
坐标的来源官方写得很清楚:夹具内四只探头相对位置固定,初始位置由第一次测量给出,此后 24 次各有一个偏移量,x 与 z 各取 0、3、6、9、12 五档,五乘五共 25 种组合,对应 25 次测量。夹具内相对位置是 sensor 0 在原点、sensor 1 在左后上、sensor 2 在左后、sensor 3 在正后下方。
| 夹具内探头 | X(厘米) | Y(厘米) | Z(厘米) | 相对位置描述 |
|---|---|---|---|---|
| Sensor 0 | 0 | 0 | 0 | 原点,夹具尖端中心 |
| Sensor 1 | −3 | 0 | 3 | 左侧偏上 |
| Sensor 2 | −3 | 0 | 0 | 左侧同高 |
| Sensor 3 | 0 | 0 | −3 | 同列偏下 |
把两张表叠起来就能得到每次测量的四组绝对坐标:初始位置加上夹具内相对位置,再加上该次的偏移量。这也解释了为什么 25 次乘以 4 只探头等于 100 个探头位置,而官方说 200 个——因为其中两只探头各记录两个方向,每个探头位置贡献两个测点,于是 100 个探头位置展开成 200 个测点。这个换算关系官方没有逐句推导,但两张表把它固定住了。
读取这条记录的标准写法:
import wfdb
import numpy as np
base = "https://physionet.org/files/kiel-cardio/1.0.0"
rec = wfdb.rdrecord(f"{base}/data/subject1_preprocessed_trial01", physical=True)
print(rec.fs, rec.sig_len, len(rec.sig_name))
#-- 200 13964 8
print([n.strip() for n in rec.sig_name])
#-- ['Sensor 0 -Y', 'Sensor 0 Z', 'Sensor 1 -Y', 'Sensor 1 Z',
#-- 'Sensor 2 -Y', 'Sensor 2 X', 'Sensor 3 -Y', 'Sensor 3 X']
print(rec.units)
#-- 全部为 'pT'
print(rec.p_signal.shape, round(rec.p_signal[:, 0].std(), 3))
#-- (13964, 8) 以及第一路的皮特斯拉标准差
print(rec.comments[:2])
#-- ['<age>: 26', '<sex>: m']
用 physical=True 读出的 p_signal 已经是皮特斯拉,增益与基线已经在读取时算进去了。如果读 raw 版,同一段代码给出的单位是伏,数值量级会差出好几个数量级,画图时如果不看 units 就会以为是信号坏了。
2.4 三本账:人数、记录数与体积
规模有三个口径,官方页面、记录清单与文件系统各说一部分,合起来才完整,并不矛盾。
| 口径 | 数值 | 出处 | 回答的问题 |
|---|---|---|---|
| 受试者 | 7 | 官方摘要与 subject-info.csv |
有多少人 |
| 每人测次 | 25 | 官方方法节与文件名 | 每人被移动了几次夹具 |
| 每人测点 | 200 | 官方摘要 | 胸前被覆盖了多少格 |
| 清单记录数 | 350 | RECORDS 行数 |
有多少条可下载记录 |
| 实际记录组数 | 700 | 目录内 .hea 计数 |
加上 raw 之后的总量 |
| 单次通道数 | 8 | 头文件首行 | 一条记录里几路信号 |
| 单次采样点 | 约一万四千 | 头文件首行 | 一条记录有多长 |
| 单次时长 | 略多于一分钟 | 采样点除以 200 | 实际时长 |
| 每人累计时长 | 约 29 分钟 | 25 次之和 | 每人被记录的总时长 |
| 全库累计时长 | 约 3.4 小时 | 7 人之和 | 总量级 |
| 未压缩体积 | 6.8 GB | 官方文件区 | 需要多少磁盘 |
| 压缩包体积 | 6.5 GB | 官方下载按钮 | 需要多少带宽 |
最容易出偏差的是清单记录数与实际组数两行。RECORDS 只列预处理版,不是笔误,原始版确实在目录里。只数清单会得出"齐了"的结论,而磁盘上应有七百组、一千四百个文件。体积上,6.8 GB 摊到七百组每组约 9.7 MB,原始版占大头;对心电来说这个量级很大,对心磁却合理,因为每个测点都要在胸前挪一次。
2.5 与同类资源的字段差异
| 对比项 | Kiel Cardio | Koch 参考集 | 通用心电库 | 心磁无屏蔽研究 |
|---|---|---|---|---|
| 物理量 | 磁场 | 磁场 | 体表电位 | 磁场 |
| 传感器 | 光泵磁力仪 | 超导量子干涉器件 | 电极 | 因研究而异 |
| 通道数 | 8 | 304 | 1 至 12 | 数十 |
| 受试者 | 7 | 5 | 数百至数万 | 数十至数百 |
| 是否公开下载 | 是 | 是 | 是 | 多数否 |
| 空间网格 | 200 个测点 | 固定阵列一次覆盖 | 不适用 | 取决于阵列 |
| 是否需屏蔽 | 是 | 是 | 否 | 部分否 |
| 附带心电 | 否(计划中) | 是 | 是 | 部分有 |
| 注释 | 无 | 因库而异 | 多有 | 少见 |
关键是两列形状的差异:Koch 的参考集用 304 通道一次覆盖胸前,采一次得一张完整场图;本库用 8 通道分 25 次拼图。前者空间分辨率高但时间上只有一瞬间,后者每一格都有一分钟时程。两种设计回答的问题不同,不存在谁更先进。
官方背景一节还列了几项建了库但未公开的工作:36 个位置测 125 人做缺血性心脏病预测、64 通道测数百人做心磁统计、无屏蔽心磁识别缺血性心脏病、以及一项胎儿心磁库的链接已于 2023 年 10 月不可达。这说明心磁数据总量不小,缺的是可下载的入口。真正要在选型时区分的是空间与时间这两条轴:如果你的问题需要一张覆盖完整胸前的场图,就该去找阵列式数据;如果需要看某一点在几十秒里的连续形态,本库的逐格记录才合适。两者叠加使用时要注意,本库的 8 通道不能假装成阵列式的 304 通道,通道路数与空间覆盖不是一回事。
§3 这台设备是怎么搭起来的
3.1 四只光泵磁力仪与一间屏蔽室
核心硬件是四只 QuSpin QZFM Gen 1 光泵磁力仪,原理是让激光穿过碱金属蒸气,外部极微弱磁场会改变原子自旋与光的耦合状态,测透射光即可反推磁场。相比超导器件,它室温工作、不需液氦,但同样对磁噪声敏感,仍然离不开屏蔽。
四只传感器装在一个夹具里,固定在检查床上方。受试者仰卧不动,操作员在两次测量之间手动移动夹具——官方原文说得很朴素:受试者始终躺在床上,操作员在测量之间移动传感器阵列。整个 200 点网格由此是 25 次人工挪动拼出来的,空间精度取决于操作员每次都把夹具放到标记位置的手艺。
采集在基尔大学工程学院的磁屏蔽室内完成。屏蔽室是这类测量的前提:没有它,地磁场与工频干扰会把这些皮特斯拉级信号整个盖住。这也直接抬高了复现门槛——没有同等级屏蔽环境的课题组,很难判断自己采到的信号与这里是不是同一回事。
3.2 采集软件与坐标系统
传感器由课题组自研的实时软件 KiRAT 控制和回读,这个软件出自同一院系的数字信号处理与系统理论组,名字是 “Kiel Real-time Application Toolkit” 的缩写。它在官方引用列表里作为一套软件被单独列出,说明数据的采集过程与这套软件是绑定的,复现采集链路时需要一并考虑。
坐标系统有两套。第一套是受试者坐标系,原点在检查床上脊柱与肩线水平线的交点,x 轴从左到右略高于肩,y 轴从背到前,z 轴沿脊柱从脚到头。第二套是传感器阵列坐标系,轴方向相同,原点在 sensor 0 尖端中心。头文件里的四组坐标用的是第一套。
| 坐标轴 | 方向 | 说明 |
|---|---|---|
| x | 左到右,略高于肩 | 胸前横向 |
| y | 后背到前胸 | 进深,本库所有测量恒为 17 厘米 |
| z | 脚到头,沿脊柱 | 纵向,覆盖胸骨上下 |
| 原点 | 脊柱与肩线的交点 | 位于床面 |
y 轴恒为 17 这一点很重要。它说明夹具与受试者后背的距离是固定的,测量平面与胸廓保持恒定间距。如果这个值在不同测次间变化,那么相邻格点之间的差异里会混入距离效应,做等值线重建时就得先校正。官方把距离固定住了,等于替使用者消掉了这一项混杂。
3.3 五乘五的位移表
25 次测量的位置不是随机的,而是一张五乘五的表。x 方向取 0、3、6、9、12 厘米五档,z 方向同样取五档,组合出 25 个偏移。表里编号从 1 编到 25,编号的排法是以左下角为起点先沿 x 走、再换 z 行。
| z 偏移 \ x 偏移 | 0 厘米 | 3 厘米 | 6 厘米 | 9 厘米 | 12 厘米 |
|---|---|---|---|---|---|
| 0 厘米 | 1 | 2 | 3 | 4 | 5 |
| 3 厘米 | 6 | 7 | 8 | 9 | 10 |
| 6 厘米 | 11 | 12 | 13 | 14 | 15 |
| 9 厘米 | 16 | 17 | 18 | 19 | 20 |
| 12 厘米 | 21 | 22 | 23 | 24 | 25 |
这张表把"第 25 次测量在大网格的哪个位置"这件事完全确定下来:编号除以 5 得行、取余得列,没有随机成分。也正因如此,任何以"测次编号"为特征输入的模型都会间接学到空间位置,而不是学到生理信息。这一点在 §7.3 还会再提。
网格的步长是 3 厘米,覆盖范围是 12 厘米见方。四只探头的固定间距也是 3 厘米,与网格步长一致。这个设计不是巧合:步长与探头间距对齐,意味着相邻两次测量之间,探头恰好移到上一只探头的位置,整个网格的采样密度因此是均匀的,不会出现某些区域密、某些区域疏的情况。
把夹具内偏移与位移表叠加,subject1_preprocessed_trial02 的坐标就是 [-8 17 -14]、[-11 17 -11]、[-11 17 -14]、[-8 17 -11],与第一次的 [-11 17 -14] 那一组相比,x 整体加了 3 厘米,正是表里从 1 号挪到 2 号的结果。这两个头文件可以用来交叉验证坐标推导,§4.2 的案例就是从这里起的。
3.4 信号的两条路径
每条记录都提供两个版本,文件名里以 raw 与 preprocessed 区分。两者是同一次采集的两种保存形态,不是两次采集。
| 特征 | raw 版 | preprocessed 版 |
|---|---|---|
| 物理单位 | 伏 | 皮特斯拉 |
| 是否滤波 | 否 | 是,三段滤波加缩放 |
| 单次采样点 | 约三百三十万 | 约一万四千 |
| 单次体积 | 约 6.5 MB | 约 28 KB |
| 用途 | 自建预处理、研究噪声 | 直接看形态、快速起跑 |
| 是否在清单内 | 否 | 是 |
采样点差了两个数量级,这是有原因的:raw 的采样率实际高于 200 Hz,而预处理时做了抽取,连同滤波一起降到 200 Hz。官方把预处理描述为四步——按光泵磁力仪的灵敏度缩放、100 Hz 低通、1 Hz 高通、50 Hz 带阻——但没写抽取这一步,而两条记录的首行采样点数摆在那里,说明确实发生了重采样。
这个细节对使用者的实际影响很直接:raw 的时间轴与 preprocessed 的时间轴不是同一个刻度,做两者逐点对比时必须先重采样,不能直接相减。§4.2 的案例会用这两个文件做演示。
§4 它最独特的东西:每格一分钟、每格一个坐标
4.1 为什么"逐格测量"比"一次成像"更少见
心磁的商用系统多数是阵列式的:几十上百个通道排成一个面,一次覆盖整个胸前,采一次就得到一张完整的场图。这种做法空间分辨率高、采集快,但代价是通道数多、设备贵。Kiel 走的是另一条路:只用四只探头,靠移动夹具来扩大覆盖范围,每次仍然只测一小块区域,但每一块都能连续记录一分钟。
这个选择的后果是双向的。好处是硬件便宜得多,四只光泵磁力仪加一套移动机构,成本远低于上百通道的阵列;且每次记录一分钟,任何一个测点都能看到完整的心动周期序列,而不是阵列系统那种"一次只抓一个瞬间"的快照。坏处是相邻测点时间不同步——第 1 格与第 2 格之间隔着操作员挪动夹具的几十秒,心脏已跳了几十次。想要一张真正同步的场图,只能假设各格形态在时间上可对齐,而这个假设本身要检验。
公开心磁数据里,逐格测量的比阵列成像的少:阵列式看起来更像一张图,容易套图像处理方法;逐格数据更像一堆时间序列,要先插值对齐才能成图。这份数据的设计者显然更关心后者,否则不会把 25 次测量的坐标写得这么完整。
4.2 案例:subject1 的 trial01 与 trial02
选 subject1 的前两次测量作贯穿案例,是因为这两个文件可以同时说明三件事:坐标偏移怎么叠、raw 与 preprocessed 怎么对应、通道方向为什么不能当固定导联。两次测量在头文件里都能完整读到,不需要下载信号文件。
import re
import wfdb
import numpy as np
base = "https://physionet.org/files/kiel-cardio/1.0.0/data"
def head(name):
r = wfdb.rdheader(f"{base}/{name}")
meta = dict(re.findall(r"<(age|sex|year of recording)>: (.+)", "\n".join(r.comments)))
pos = {int(k): v for k, v in re.findall(
r"<position sensor (\d) \[cm\]>: \[([^\]]+)\]", "\n".join(r.comments))}
return r.fs, r.sig_len, r.sig_name, meta, pos
for tag in ("trial01", "trial02"):
fs, n, names, meta, pos = head(f"subject1_preprocessed_{tag}")
print(tag, fs, n, round(n / fs, 2), "秒")
print(" 年龄", meta["age"], "位置", pos)
print(" 通道", [s.strip() for s in names])
跑出来的结果就是 §2.3 给出的那两行:trial01 的 sensor 0 在 x 为 −11,trial02 的 sensor 0 在 x 为 −8,差正好是 3 厘米,与 §3.3 的位移表对上。两位小数之后的时长都在 69 秒上下,比一分钟长约十秒。
再看 raw 与 preprocessed 的对应:
import wfdb
base = "https://physionet.org/files/kiel-cardio/1.0.0/data"
raw = wfdb.rdheader(f"{base}/subject1_raw_trial01")
pre = wfdb.rdheader(f"{base}/subject1_preprocessed_trial01")
print("raw 采样率与点数", raw.fs, raw.sig_len)
print("pre 采样率与点数", pre.fs, pre.sig_len)
print("raw 单位", set(raw.units))
print("pre 单位", set(pre.units))
print("两条记录时长比", round(raw.sig_len / raw.fs, 3),
round(pre.sig_len / pre.fs, 3))
两个头点数相差两个数量级,单位一为伏一为皮特斯拉,但换算出的总时长一致,说明预处理是在时间轴不动的前提下做的抽取。§1.4 表里"原始与预处理链路对照"这一行,能做的就只有这类时长与频谱对照,逐点相减需先重采样。
通道方向这一层,两次测量并排看最清楚:trial01 的八路依次是 sensor 0 的 −Y 与 Z、sensor 1 的 −Y 与 Z、sensor 2 的 −Y 与 X、sensor 3 的 −Y 与 X,trial02 顺序与方向组合都相同。这两次之间映射稳定,但官方没承诺它在全部 25 次里不变——方向按夹具配置定,不按通道号定。要确认某一测次的方向,只能读头文件。
4.3 时间对齐的三种做法
同一个测点上的信号是连续的,跨测点之间却是分离的,要把它们拼成一张场图,得先解决"不同格的哪一时刻算同一时刻"。公开文献里的做法大致有三种:以每次记录内自行检测到的心搏为锚点做叠加平均,这是最严谨也最费力的一种,前提是先有可靠的心搏检测;直接取每次记录的第 n 个采样点对齐,最省事,但把每次采集起跳时的相位差全忽略了,拼出来的图会有明显接缝;把 200 个测点当散点做空间插值,这是空间层面的处理,与时间对齐正交,可以与前两种叠加使用。§4.2 的案例给出的是每一格的原始波形,正好可以作为三种做法的共同输入。
4.4 它支撑的四类实验
| 实验 | 设计 | 它能给的 | 结论强度 |
|---|---|---|---|
| 波形形态学 | 单测点一分钟内的形态统计 | 8 通道连续记录 | 中,7 人不足以推广 |
| 传感器评估 | 比较四只探头的一致性 | 同一次记录内的四路并行 | 中,同一夹具、同一环境 |
| 噪声与滤波研究 | raw 与 preprocessed 对照 | 同一采集的两个版本 | 较高,可控条件最全 |
| 空间场重建 | 200 个带坐标的测点做插值 | 完整网格 | 中,需自行对齐时间 |
第三类结论强度最高,因为这一项完全在数据内部完成,不涉及人,也不涉及跨测点的时间假设:一份 raw 加一份 preprocessed,就能回答官方那条滤波链做了什么、丢掉了什么。其余三类都要跨出数据本身。
§5 怎么拿到:从清单到一张胸前场图
5.1 目录与体积
全库解压 6.8 GB,压缩包 6.5 GB。根目录下 RECORDS 约 10 KB、README.md 约 11 KB、LICENSE.txt 约 16 KB、SHA256SUMS.txt 约 69 KB,subject-info.csv 只有 98 字节;data 目录里预处理版的头文件约 1 KB、信号约 28 KB,原始版的头文件同样约 1 KB、信号约 6.5 MB;images 目录七张文档配图合计约 10 MB。页面上给了三种取法:网页下载 ZIP、用 wget 递归、用 AWS 命令行同步公开桶。考虑到原始版单条就有 6.5 MB,全量下载对磁盘与带宽都有要求,先只取预处理版是更常见的做法。
5.2 批量获取
#-- 只拉清单与受试者表,先看清结构
base=https://physionet.org/files/kiel-cardio/1.0.0
curl -sL "$base/RECORDS" -o RECORDS
curl -sL "$base/subject-info.csv" -o subject-info.csv
wc -l RECORDS
#-- 按清单下载预处理版(清单里就是这一套)
mkdir -p data
while IFS= read -r rel; do
for ext in hea dat; do
curl -sL --max-time 60 "$base/${rel}.${ext}" -o "data/$(basename "$rel").${ext}"
done
done < RECORDS
#-- 只取一条 raw 试通链路:把版本段换掉即可
one=subject1_preprocessed_trial01
curl -sL --max-time 180 "$base/${one/_preprocessed_/_raw_}.hea" -o data/subject1_raw_trial01.hea
#-- 核对:预处理版应有 350 个 hea
ls data/*preprocessed*.hea | wc -l
第二段用 ${one/_preprocessed_/_raw_} 做字符串替换,把版本段换掉即可拼出原始版的路径——清单里没有 raw,但文件名规则是稳定的。先按这个方法取一条 raw 查时间,再决定要不要全量。全量下载需要考虑时间:七百组文件里,三百五十个原始信号合计约 6.5 GB,按普通网络速度要跑一段时间,§2.4 的三本账就是为这个决定准备的。
5.3 建立测点索引
绝大多数实验的第一步是把坐标整理成一张表。头文件里的坐标藏在一行注释里,用正则抽出来即可:
import os
import re
import pandas as pd
ROOT = "data"
pat_pos = re.compile(r"<position sensor (\d) \[cm\]>: \[([^\]]+)\]")
pat_meta = re.compile(r"<(age|sex|year of recording)>: (.+)")
rows = []
for fn in sorted(os.listdir(ROOT)):
if not fn.endswith(".hea"):
continue
stem = fn[:-4]
m = re.match(r"subject(\d)_(raw|preprocessed)_trial(\d+)", stem)
if not m:
continue
text = open(os.path.join(ROOT, fn), encoding="utf-8").read()
meta = dict(pat_meta.findall(text))
for sid, xyz in pat_pos.findall(text):
x, y, z = [int(v) for v in xyz.split()]
rows.append({
"subject": int(m.group(1)),
"stage": m.group(2),
"trial": int(m.group(3)),
"sensor": int(sid),
"x": x, "y": y, "z": z,
"age": int(meta["age"]),
})
grid = pd.DataFrame(rows)
print(grid.shape)
print(grid.groupby("stage")["trial"].nunique())
print(grid[grid["stage"] == "preprocessed"]["sensor"].value_counts())
这段代码只读头文件,不碰信号,跑一遍只要几十秒。输出的 grid 每行是"某个受试者的某次测量里的某只探头",预处理版应有 350 乘 4 共 1400 行,raw 版同样一千四百行。sensor 的计数应当四只各占四分之一,如果某一只有缺,说明该测次记录不全。
坐标抽取时有一个坑:头文件里坐标写作 [-11 17 -14],负数前有空格,三位数字之间是双空格。用 split() 而不是按单空格切分就不会出错;若按 str.split(" ") 写,会出现空串再转整数时报错。
5.4 从测点到场图
坐标有了,剩下的工作是把 200 个测点的某一段信号投影到胸前平面上。最简单的一种做法是取每个测点在固定时间窗内的峰峰值,画成散点再插值:
import numpy as np
import pandas as pd
import wfdb
from scipy.interpolate import griddata
base = "https://physionet.org/files/kiel-cardio/1.0.0/data"
sid, stage = 1, "preprocessed"
tiles = []
for t in range(1, 26):
name = f"subject{sid}_{stage}_trial{t:02d}"
r = wfdb.rdrecord(f"{base}/{name}", physical=True)
chunk = r.p_signal[:12000] #-- 取前 60 秒
amp = chunk.max(axis=0) - chunk.min(axis=0) #-- 每路峰峰值
tiles.append((name, amp))
g = pd.read_parquet("grid.parquet")
g = g[(g.subject == sid) & (g.stage == stage)]
#-- 每个测点方向的峰峰值挂到该测次的传感器坐标上
pts, val = [], []
for t, (name, amp) in enumerate(tiles, start=1):
sub = g[g.trial == t].sort_values("sensor")
for k, s in enumerate(sub.itertuples()):
pts.append((s.x, s.z))
val.append(amp[k])
pts = np.array(pts, float)
val = np.array(val, float)
xi = np.linspace(pts[:, 0].min(), pts[:, 0].max(), 120)
zi = np.linspace(pts[:, 1].min(), pts[:, 1].max(), 120)
X, Z = np.meshgrid(xi, zi)
V = griddata(pts, val, (X, Z), method="cubic")
print(V.shape, float(np.nanmax(V)))
这段代码演示的是"把逐格数据拼成一张图"的最小路径,重点在流程本身,不在结果好不好看。有一个隐含的近似必须写进方法节:八路通道与四只探头并非一一对应,其中两路是同一探头的第二方向,上面的写法把它们都挂到探头坐标上,等于把两个方向的幅度放在同一张图里比较,量纲与物理含义都不严格。正式分析时应当按方向分开画两张图。
5.5 三种常见起跑姿势
推荐的第一步是只看形态:读一条 preprocessed,把八路波形画出来,花几分钟就能判断这份信号到底有没有心动周期、噪声底厚不厚。如果连形态都看不出周期,后面的工作都不会顺。第二步是做对照,取同名的 raw 与 preprocessed,比较两者的时长与频谱,这一步不需要全量下载,一条记录的两个版本就够,十几分钟能跑完。第三步才是建网格,跑 §5.3 的测点索引,再画 §5.4 的场图,需要较多下载与计算,适合已经确定要用这份数据做正式分析的人。
这三步的顺序不能颠倒,原因很实际:心磁的原始信号里,心动周期与噪声的幅度可能相差不大,如果在没有确认形态之前就投入建网格,很可能花了两小时下载与插值,最后发现某几个测次根本看不出周期。先看一条、再比两条、最后铺全市,是最省返工的走法。
5.6 六个最容易出错的地方
| 位置 | 错误写法 | 后果 | 正确做法 |
|---|---|---|---|
| 数据集定位 | 当作心电库套用心电流程 | 单位与量级全错 | 先确认单位是皮特斯拉 |
| 下载 | 只按清单取 | 只拿到一半,原始版缺失 | 把版本段换成 _raw_ 再补一遍 |
| 通道理解 | 当八导联做解剖映射 | 跨测次方向错位 | 每次读头文件的信号名 |
| 时长假设 | 假定每条正好 60 秒 | 切窗丢末尾十秒 | 用实际采样点除以采样率 |
| raw 对照 | 直接与 preprocessed 相减 | 时间轴未对齐,结果无意义 | 先重采样到同一刻度 |
| 坐标解析 | 按单空格切分 | 空串导致整型转换报错 | 用 split() 不加参数 |
第五行最隐蔽:两个版本时长一致,点数却差两个数量级,先入为主地以为"同一次采集直接减就行",减出来的只是两条不同分辨率上的抽样,既不是噪声也不是误差。
§6 与库内条目的关系
6.1 关系图谱
在心电与生理信号这一类资源里,它的位置不在"规模"轴,也不在"任务"轴,而在"模态"轴。库内相关词条测的都是电位,只有它测的是磁场。
| 资源 | 模态 | 与 Kiel Cardio 的关系 |
|---|---|---|
| ECG-ID | 单导联心电 | 同源异模态:电极测电位,光泵测磁场 |
| MIT-BIH 心律失常库 | 双导联心电 | 任务完全不同,仅共享 WFDB 读写工具 |
| INCART 十二导联库 | 十二导联心电 | 通道数相反,它是宽覆盖,本库是窄阵列 |
| PTB-XL 与 PTB-XL+ | 十二导联诊断 | 人群相反,它是患者,本库是健康志愿者 |
| MIMIC-IV 波形库 | 多参数床旁监护 | 同一格式家族,不同采集场景 |
| adfecgdb | 腹壁与直接胎心电 | 同属小众模态,都受采集条件高度限制定 |
| chfdb | 心衰长程心电 | 用途互补,它给病理时长,本库给空间分布 |
真正有参照价值的是第一行与第六行。与 ECG-ID 是"同源异模态":都记录心脏电活动,一个记电位一个记磁场,处理链路可以互相借,但单位、噪声结构与传感器响应完全不同。与 adfecgdb 是"同为受采集条件限制的小众模态":都是几十条记录、都需要专门设备,都适合方法验证而非统计。
6.2 检索路径
| 你要找的东西 | 检索词 | 会落到哪里 |
|---|---|---|
| 心磁的公开数据 | magnetocardiography dataset、MCG database |
§8.1 与 §6.1 |
| 光泵磁力仪的研究用数据 | OPM MCG、optically pumped magnetometer |
§3.1 |
| 心电算法向心磁迁移 | ECG delineation MCG |
§4.4 与 §7.4 |
| 磁场与电位的关系 | BSPM、body surface potential mapping |
§2.5 的对照列 |
| 许可与署名义务 | CC BY-SA 4.0、ShareAlike |
§9.3 |
| 心电同源参考 | ECG database、WFDB |
§6.1 表 |
6.3 与其他库的分工判据
| 任务 | 主粮仓该用什么 | 本库的位置 | 原因 |
|---|---|---|---|
| 心电诊断模型训练 | 带诊断标签的大规模心电库 | 不参与 | 无标签、无患者 |
| 心磁方法预研 | 心磁公开数据 | 主力 | PhysioNet 上唯一的同类 |
| 传感器与阵列评估 | 设备厂商数据或自采 | 可用作参照 | 四只同型号探头并行 |
| 磁场反演与源定位 | 阵列式心磁数据 | 有条件可用 | 逐格测量需自行对齐 |
| 心电与心磁联合分析 | 配对采集的数据 | 不适用 | 本版无心电 |
| 教学演示磁与电的差别 | 两类数据各一份 | 适合 | 同一平台、同一格式,便于并排 |
第二行与最后一行是它真正的落点。作为方法预研的起点,它的稀缺性几乎无法替代——没有第二份公开的心磁数据可换。作为教学的对照,它与心电库同用 WFDB 格式,学生可以在同一套代码里读两种模态,直接看到单位与波形的差异。真正的分工判据可以压缩成一句话:凡是需要"人多、有标签、有同步心电"的任务,它都不在候选名单里;凡是需要"真实心磁、带坐标、可比较滤波链路"的任务,它几乎没有替代品。
§7 质量评估与局限性
7.0 阅读本节前的一个前置校正
评价这份数据时最容易犯的误判,是拿它和心电库比规模,然后得出"七个人太少"的结论。这个比较的坐标轴本身选错了。心电采集的成本主要落在人身上——找受试者、排班、贴电极;心磁的成本主要落在设备和场地上——屏蔽室、探头、操作员。两者的瓶颈不在同一处,所以可公开的样本量天然差好几个数量级。
换成正确的坐标轴之后,评分才读得准。对心磁来说,七个人已是相当可观的一份公开数据。它的短板不在人数,而在没有任何标注、只有单一模态这两处,而这两处恰好都能由后续版本补上。
还需做一次口径区分:官方写受试者 22 到 50 岁,而 subject-info.csv 与头文件推出的实际年龄是 26 到 35 岁。前者是招募条件,后者是实际入组,写论文时应引实际数据。
7.1 五维评分
按 DAIMS 的常用维度打分,每项 1 到 5 分,锚定在"作为心磁方法研究数据"这个用途上:
| 维度 | 分数 | 理由 |
|---|---|---|
| 数据规模 | 3 | 七人在心磁里不算小,但绝对量仍偏低 |
| 标注质量 | 1 | 本版完全没有注释,官方明确说明 |
| 任务适配 | 4 | 逐格加坐标的结构独有,覆盖多种方法学需求 |
| 文档完整 | 4 | 方法、坐标、位移表、伦理与致谢都写全了 |
| 可获取性 | 4 | 免注册、CC BY-SA,但 6.5 GB 不是随手能下 |
合计 16 分(满分 25)。适配性与文档撑起一半,标注把总分拖下来。标注给 1 分是按本版事实给分,官方在用法说明里已写明本版不提供注释、定量评价须先人工标注。可获取性给 4 分是因为体积:免注册、许可清晰、下载方式齐全,但 6.5 GB 的压缩包不是"先下下来看看"的量级,需要先规划存储。
7.2 预处理链路的真实含义
官方的预处理写了四步:按灵敏度缩放、100 Hz 低通、1 Hz 高通、50 Hz 带阻。这四步决定了 preprocessed 版能用来做什么、不能用来做什么。
| 步骤 | 作用 | 可能损失 | 建议 |
|---|---|---|---|
| 灵敏度缩放 | 把电压换成皮特斯拉 | 无损失 | 直接用 |
| 100 Hz 低通 | 抑制高频噪声 | 高于 100 Hz 的成分不可恢复 | 研究高频成分时改用 raw |
| 1 Hz 高通 | 去掉基线漂移 | 低于 1 Hz 的慢变化被削 | 研究慢波时改用 raw |
| 50 Hz 带阻 | 抑制工频干扰 | 50 Hz 附近成分被挖空 | 做频谱分析时注意缺口 |
这四步不是"把信号洗干净",而是"把某段频带之外的成分删掉"。采样率 200 Hz,按奈奎斯特上限 100 Hz 正是能保留的最高频率,低通因此没有额外损失;真正有损失的是高通与带阻,1 Hz 以下与 50 Hz 附近被移除,而心磁的低频成分在源定位与慢波分析里是有意义的。
这也解释了 raw 版为何必须提供:官方把两个版本都放出来,等于把"要不要滤波、滤多狠"的决定交回使用者,§4.2 的案例正是为这个决定提供依据。对做源定位的人,这意味着一个具体的取舍:用 preprocessed 版省事,但 1 Hz 以下的慢变化已经被削掉,反演出来的源深度会偏;用 raw 版则要自己承担从电压到皮特斯拉的换算与全部噪声。两条路都能走通,差别在于你在论文里能不能说清自己删掉了哪一段频带。
7.3 已知的、可枚举的偏差
| 偏差 | 表现 | 影响 |
|---|---|---|
| 性别单一 | 七人全为男性 | 无法讨论性别差异 |
| 年龄集中 | 实际 26 到 35 岁 | 无法讨论年龄效应 |
| 健康人群 | 全部健康志愿者 | 无病理对照 |
| 单一机构 | 一间屏蔽室、一套探头 | 无法做跨中心验证 |
| 单一模态 | 本版只有心磁 | 无法做模态间联合 |
| 无标注 | 没有心搏或节律文件 | 无法直接做监督任务 |
| 时间不同步 | 相邻测点间隔数十秒 | 场图重建需自行对齐 |
| 位置离散 | 200 个测点来自五乘五网格 | 网格分辨率受位移表限制 |
| 清单不全 | RECORDS 只列预处理版 |
只按清单下载会漏一半 |
影响最大的不是"人少",而是"无标注"与"时间不同步"这两行。人少是显性限制,写论文的人都会承认;时间不同步是隐性限制,它不出现在任何一句官方描述里,只在位移表与"操作员移动夹具"这句话里透出来,没注意到的使用者会把 200 个测点当成同一时刻的场图,结果在物理上不成立。「清单不全」是操作层面的坑:RECORDS 一直是预处理版清单,把版本段当可替换字段而非相信清单的完备性,就能避开。位置上还有一个容易被忽略的偏差:五乘五网格的步长固定为 3 厘米,网格边界以外的磁场分布完全没有数据。若心脏的某个源恰好落在覆盖范围之外,插值会外推出一片看着合理、实际没有依据的区域。画场图时应把网格边界画出来,边界外的部分留白而不是补满。
7.4 外部验证矩阵
先要说清"外部验证"在这个库上意味着什么。它体量小、无标注、单机构,任何以它为训练集再在别处测试的研究都还不存在;目前能谈的只是别人拿它做什么,而不是它验证了别人什么。这层区分在评估这类小库时尤其重要,否则容易把"有人引用"误读成"已经通过外部检验"。
以 Europe PMC 检索,匹配到的工作只有一项,讨论强噪声下的心磁去噪:作者用本库的干净段作参照,构造基线漂移、1/f 噪声与白噪声合成的复合噪声,训练对抗式网络降噪。这恰好落在本库最有把握的位置上——提供干净的真实信号,而不是标注或诊断。
| 验证角色 | 典型做法 | 讲得通的地方 | 风险 |
|---|---|---|---|
| 去噪算法的参照源 | 用干净段作目标,合成噪声作输入 | 信号真实、条件可控 | 干净段的"干净"是相对于本库的采集环境 |
| 分割算法的迁移试跑 | 自己标注几个心搏后跑心电模型 | 同源异模态,形态可比 | 无官方标注,结果不可跨研究比较 |
| 传感器评估 | 比较四只探头的噪声与灵敏度 | 同一次采集内条件一致 | 只有一种型号 |
| 场图重建 | 200 个测点做插值 | 网格完整、坐标清晰 | 时间不同步被忽略时会失真 |
第一行是目前唯一有公开证据的用法,也最自然。第二行说得通但可比性差,各组自标的几个心搏标准不会一致。第三行的价值在于把设备层面的问题变得可讨论:同型号探头之间的差异在任何心磁实验里都存在,一份公开的同环境对照总是有用的。
7.5 它为何能持续:稀缺的是设备,不是意愿
它从 2023 年底上线至今没有新版,却仍有被引用的理由:PhysioNet 上第一份心磁数据。想做心磁又没有屏蔽室的人几乎只能从这里开始。这个位置不是靠采得好拿到的,而是靠"别人做不了"拿到的。
生存逻辑还有一层时间维度:官方说后续版本会补心电、磁共振与注释,所以当前版本更像一块地基而非成品。地基的价值在于它先立住了,后来者往上加东西时有个参照。只要心磁的设备门槛还在,这块地基就有存在的理由。
§8 生态位与历史
8.1 历史沿革
心磁的历史几乎与心电图一样长:上世纪六十年代首次在屏蔽室内测到人体心脏磁场,七十年代超导器件成熟后进入实验室常规手段,此后主战场一直是可以承担超导成本的少数中心,应用集中在胎儿心磁、心肌缺血与心律失常灶定位。根源始终同一处:设备贵、场地贵,能做的机构少。
基尔大学走的是传感器替代路线。他们所在的协作研究中心 CRC 1261 专注磁电传感器,主题是把复合材料的磁电效应用于生物磁诊断。光泵磁力仪在这条路线里是折中:比超导便宜、比磁电传感器成熟。用四只探头拼网格,本质上是在设备成本与覆盖范围之间找平衡,这个选择的痕迹留在每一个头文件里。
8.2 时间线
| 时间 | 事件 | 意义 |
|---|---|---|
| 2022 年 | 七名受试者完成采集 | 全部记录的实际年份 |
| 2023-08 | RECORDS 与 subject-info.csv 定型 |
目录结构的最后形态 |
| 2023-11 | README.md 定稿 |
说明文字不再变动 |
| 2023-12-09 | LICENSE.txt 落位 |
许可确定 |
| 2023-12-15 | 以 1.0.0 版上线 PhysioNet | 获得 DOI,进入可引用状态 |
| 待定 | 计划补入心电、磁共振与注释 | 官方声明,尚未发布 |
几个时间点都集中在 2023 年下半年,说明采集完成后整理上线用了约一年。版本号只有 1.0.0,发布说明只有一行"初始版本",没有修订记录,这对使用者是好事:没有版本漂移。也不必有"等新版本再动手"的想法,因为官方没有给出任何时间表;更稳妥的做法是现在就按 1.0.0 定下实验协议,若日后真有 1.1,再把它当作独立的第二份数据来复制同一套流程,而不是在同一份结果里混着两个版本。
8.3 生态位:唯一的一格
| 位置 | 代表 | 本库的角色 |
|---|---|---|
| 心电大数据 | 各类十二导联库与监护库 | 完全不同的模态,无竞争 |
| 心磁阵列数据 | 超导系统的一次成像 | 互补:它给空间分辨率,本库给时间序列 |
| 心磁单通道数据 | 零星发表的案例 | 本库覆盖更完整、可下载 |
| 心磁方法基准 | 此前没有公开基准 | 本库占据这一格 |
它的位置简单到一句话能说完:在公开可下载的心磁数据里,它是唯一一个既完整又带坐标的。这个"唯一"既是价值,也是风险——没有第二份可以对照,任何在它上面得到的结论都无法用它自己来验证。
8.4 谁在用它,用来做什么
使用者大致三类:信号处理研究者把它当干净参照,验证降噪或分割算法能否处理皮特斯拉级信号;设备与传感器研究者把它当同型号探头在屏蔽室内的性能标本,判断自家系统噪声底是否合理;研究者与学生把它当入门材料,理解磁与电的关系。
最小众的是第二类,但它恰好用到了最不可复制的部分:四只同型号探头、同一间屏蔽室、同一批受试者。三类人面对同一组限制——没有标注、没有心电、只有七个人,所以结论都要收窄到"这间屏蔽室、这套探头、这批健康男性",不能顺口写成"心磁的普遍规律"。这份数据规模小、条件干净,最容易让人产生"我看到的就是全部"的错觉。
§9 使用指引
9.1 三种角色的路径
| 角色 | 第一天 | 第一周 | 注意事项 |
|---|---|---|---|
| 信号处理研究者 | 读一条 preprocessed,画出八路波形 | 取同名 raw,比较滤波前后的频谱 | 时间轴需重采样后再对齐 |
| 设备与传感器研究者 | 取一条记录,看四只探头的噪声底 | 跨测次比较同一探头的稳定性 | 通道方向需每次从头部确认 |
| 教学人员 | 用 §4.2 的案例,两次测量的坐标并排 | 把心磁与心电库各取一条并排演示 | 强调单位是皮特斯拉 |
9.2 最短可用流程(第一步:取清单)
#-- 1. 取清单与受试者表
base=https://physionet.org/files/kiel-cardio/1.0.0
curl -sL "$base/RECORDS" -o RECORDS
curl -sL "$base/subject-info.csv" -o subject-info.csv
head -3 RECORDS
9.3 最短可用流程(第二步:读一条记录)
import wfdb
base = "https://physionet.org/files/kiel-cardio/1.0.0/data"
name = "subject1_preprocessed_trial01"
rec = wfdb.rdrecord(f"{base}/{name}", physical=True)
print(rec.fs, rec.sig_len, rec.units[0])
#-- 200 13964 pT
for i in range(4):
print(rec.sig_name[2 * i].strip(),
round(float(rec.p_signal[:, 2 * i].std()), 3))
#-- 四只探头的主方向标准差,逐行打印
按探头两两分组打印标准差是最直观的第一步;要看波形再画图,横轴用采样点除以 fs 换算成秒即可。若某一路形态明显不同于同组另一路,先确认这一路的方向,同一只探头的两个方向本来就可能形态不同。
9.4 引用方式
| 引用对象 | 内容 | 何时需要 |
|---|---|---|
| 数据集本体 | Engelhardt E, Frey N, Schmidt G. Kiel Cardio Database (version 1.0.0). PhysioNet. 2023. DOI 10.13026/q6r2-zz68 | 使用数据时必须 |
| 平台综述 | PhysioNet 平台论文,按官方页面惯例一并引用 | 按平台要求 |
| 资助 | 德国研究基金会(DFG)协作研究中心 CRC 1261 | 说明数据来源时可写 |
| 许可 | CC BY-SA 4.0,署名且同许可共享 | 再分发衍生数据时必须 |
署名之外还有一条容易被忽略的义务:ShareAlike。如果把这份数据加工成新的数据集并公开,新数据集必须用同一许可发布。这一点与很多 PhysioNet 库的 ODC-BY 不同,后者只要求署名,不要求传染。做衍生数据集之前要把许可想清楚,尤其是打算申请专利或走闭源路线的情况。还有一处细节值得在方法节里写明:受试者已按 GDPR 去标识,官方声明取得了在公共仓库共享去标识数据的明确知情同意,所以引用时不涉及额外的伦理审批,但涉及人体的部分仍应在方法节交代伦理批件编号。
§10 AI 使用声明
| 项目 | 声明 |
|---|---|
| 文本生成 | 本文由 AI 辅助撰写,结构与事实由编辑把关 |
| 数字来源 | 规模、结构、边界三类数字来自官方页面、README.md、RECORDS 与头文件 |
| 文件核验 | 逐个取回了 RECORDS、README.md、LICENSE.txt、subject-info.csv,并读取多条头文件原文 |
| 头文件核验 | subject1 的 trial01 与 trial02 两个头文件逐行核对,用于坐标与位移表的交叉验证 |
| 未核验内容 | 未下载 data 目录下的信号文件做逐条统计,采样点与时长以头文件声明的数值为准 |
| 论文信息 | Europe PMC 检索仅匹配到一篇引用本库的去噪研究,未获得官方独立论文 |
| 差异披露 | 官方写受试者 22–50 岁,subject-info.csv 推出 26–35 岁,两者分别对应招募条件与实际入组 |
| 图像 | 无配图;封面为生成式提示词,不含真实心磁波形 |
| 免责 | 本文不构成临床建议;数据使用须遵守 CC BY-SA 4.0 的署名与同许可条款 |
常见误读(避坑清单)
| 说法 | 实际 | 证据 |
|---|---|---|
| 「这是一个心电数据库」 | 存的是心磁图,单位皮特斯拉 | 头文件信号行单位写作 /pT,raw 版为 /V |
| 「每人是 25 个测点」 | 25 次测量,共 200 个测点 | 官方摘要写 200 个位置,位移表为五乘五 |
| 「八通道就是八个测点」 | 八路来自四只探头,其中两只有第二方向 | 头文件信号名为 Sensor 0 至 Sensor 3 加方向 |
| 「它就是 200 Hz 采的」 | 预处理版 200 Hz,raw 版采样点约三百三十万 | 两个头文件首行点数差两个数量级 |
| 「每条记录正好一分钟」 | 采样点除以采样率约 69 秒 | 13964 除以 200 得 69.82 |
| 「清单里的记录就是全部」 | RECORDS 只列预处理版,raw 版另有 350 条 |
清单文件名统一含 _preprocessed_ |
| 「它带心电和磁共振」 | 本版只有心磁,其余是官方计划 | 官方摘要写"未来版本将纳入" |
| 「它可以用来自动分割心搏」 | 无任何注释文件 | 官方用法说明要求先做人工标注 |
| 「四只探头位置每次都一样」 | 夹具内相对位置固定,绝对位置随测次变 | 位移表五乘五,x 与 z 各五档 |
| 「CC BY-SA 与 ODC-BY 差不多」 | 多一条同许可扩散义务 | LICENSE.txt 为 CC BY-SA 4.0 全文 |
FAQ
Q1:Kiel Cardio Database 是心电数据库吗?
不是。它存的是心磁图,用光泵磁力仪测心脏电活动产生的微弱磁场,单位是皮特斯拉,测量必须在磁屏蔽室内完成。它与心电图同源但不同模态:心电测体表电位差,心磁测体表磁场。
Q2:只有七个人,这个库还有用吗?
有用,但用途限定在方法与设备层面。心磁设备昂贵、需要屏蔽室,公开数据极少,所以它在心磁里的稀缺性远高于同等规模的心电库。它能支撑波形形态、噪声处理、等值线重建与传感器评估,但撑不起人群统计或诊断模型。
Q3:每人 25 次测量、200 个位置是怎么算出来的?
四只探头装在夹具里,夹具被操作员移动 25 次,位置由五乘五的偏移表决定。其中两只探头各记录两个方向,于是 25 次乘以 4 只探头得到 100 个探头位置,再乘以方向展开成 200 个测点。
Q4:能不能直接做心搏分类或心律失常检测?
不能。本版没有任何注释,官方在用法说明里明确写到做检测评测前必须先人工标注。受试者全是健康男性,即便标注完也没有病理类别可用。
Q5:raw 版与 preprocessed 版有什么区别?
raw 是原始电压、未滤波、采样点约三百三十万;preprocessed 是按灵敏度缩放为皮特斯拉并做 100 Hz 低通、1 Hz 高通、50 Hz 带阻后的版本,采样点约一万四千。两者时长一致,分辨率不同。
Q6:为什么清单里只有 350 条,目录里却有 700 组记录?
RECORDS 只列预处理版,原始版文件实际存在但不在清单里。要拿 raw 版,把文件名中的 _preprocessed_ 换成 _raw_ 即可。
Q7:这份数据能不能和心电做联合分析?
本版做不到。官方声明未来版本会补入心电与磁共振,但当前版本只有心磁,也没有任何配对信息。想做联合分析需另找来源或自行同步采集。
Q8:200 个测点是同一时刻的场图吗?
不是。每一次测量是一分钟独立记录,相邻测点之间隔着操作员挪动夹具的时间。要把它们拼成场图,必须先做时间对齐,取平均或以心搏为锚点叠加是常见做法。
Q9:这份数据允许商用吗?
允许,CC BY-SA 4.0 覆盖商业用途。条件是署名,且若把数据加工成衍生数据集再公开,衍生数据集须以同一许可发布。
Q10:它会不会有后续版本?
官方明确说计划补入心电、磁共振与注释,但没有给时间表。截至 1.0.0,版本说明只有一行初始发布。
Q11:受试者年龄到底是 22 到 50 岁还是 26 到 35 岁?
两个数字都对,含义不同。官方的 22 到 50 岁是招募条件,subject-info.csv 与头文件里的出生年推出的是实际入组的七个人,落在 26 到 35 岁之间。
Q12:为什么没有一篇正式的数据论文?
官方页面的引用栏直接指向 PhysioNet 上的数据集本身,DOI 是本库的版本 DOI,没有列出配套的期刊论文。相关的方法背景可以参考 CRC 1261 名下关于磁电传感器与心磁电流密度估计的几篇会议与期刊文章。
术语表
| 术语 | 解释 |
|---|---|
| 心磁图(MCG) | 测量心脏电活动产生的体表磁场,单位皮特斯拉 |
| 光泵磁力仪(OPM) | 利用激光与碱金属蒸气测量极弱磁场的传感器,室温工作 |
| 超导量子干涉器件(SQUID) | 另一种高灵敏度磁传感器,需液氦冷却 |
| 磁屏蔽室 | 用高磁导率材料包围的空间,隔绝地磁与环境磁噪声 |
| 皮特斯拉(pT) | 磁感应强度单位,一万亿分之一特斯拉 |
| 磁电传感器 | 利用磁致伸缩与压电效应测磁场的器件,CRC 1261 的研究主题 |
| 夹具 | 固定四只探头、保持相对位置不变的支架 |
| 测次(trial) | 一次一分钟的测量,夹具在测次之间被移动 |
| 测点 | 一只探头在一个位置上的一个测量方向 |
| 位移表 | 五乘五的偏移组合,决定 25 次测量的平面位置 |
| WFDB | PhysioNet 的波形数据库格式,含头文件与信号文件 |
| 格式 212 | WFDB 的 12 位打包存储格式 |
| 增益 | 每个整数单位对应的物理量,逐通道不同 |
| 基线 | 头文件增益后括号内的值,换算时的零点 |
| 带阻滤波 | 挖掉指定窄频段的滤波,本库用于 50 Hz 工频 |
| 等值线重建 | 由离散测点插值出连续场分布 |
| 时相叠加 | 以心搏为锚点把多段信号平均,用于观察形态 |
| DAIMS | 数据管理与分析框架,用于五维评分 |
| CRC 1261 | 德国研究基金会资助的协作研究中心,主题为磁电传感器 |
| KiRAT | 课题组自研的实时采集软件 |
| CC BY-SA 4.0 | 署名且同许可共享的国际知识共享许可 |
附录 A:核心数字核对表
| 项 | 值 | 来源 | 来源层级 |
|---|---|---|---|
| 受试者数 | 7 | 官方摘要;subject-info.csv 行数 |
官方页面 |
| 每人测次 | 25 | 官方方法节;文件名 | 官方页面 |
| 每人测点数 | 200 | 官方摘要 | 官方页面 |
| 清单记录数 | 350 | RECORDS 行数 |
官方文件 |
| 实际记录组数 | 700 | 目录内 .hea 计数 |
官方文件 |
| 单次通道数 | 8 | 头文件首行 | 官方文件 |
| 采样率 | 200 Hz | 官方页面;头文件首行 | 官方页面 |
| 单次采样点 | 约一万四千 | 头文件首行 | 官方文件 |
| 单次时长 | 约 69 秒 | 采样点除以采样率 | 官方文件派生 |
| 年龄(实际) | 26 至 35 岁 | subject-info.csv 出生年 |
官方文件派生 |
| 年龄(招募) | 22 至 50 岁 | 官方方法节 | 官方页面 |
| 性别 | 全部男性 | subject-info.csv;头文件 |
官方文件 |
| 采集年份 | 2022 | 官方方法节;头文件注释 | 官方页面 |
| 传感器型号 | QuSpin QZFM Gen 1 | 官方方法节 | 官方页面 |
| 传感器数量 | 4 | 官方方法节 | 官方页面 |
| 网格步长 | 3 厘米 | 位移表;官方方法节 | 官方页面 |
| 未压缩体积 | 6.8 GB | 官方文件区 | 官方页面 |
| 压缩包体积 | 6.5 GB | 官方下载按钮 | 官方页面 |
| 许可 | CC BY-SA 4.0 | 官方页面;LICENSE.txt |
官方页面 |
| 上线日期 | 2023-12-15 | 官方页面 | 官方页面 |
| DOI | 10.13026/q6r2-zz68 | 官方页面 | 官方页面 |
附录 B:数字的来源分层
第一层:官方页面与官方文件。 受试者人数、每人测次与测点数、传感器型号与数量、采集场景、坐标定义、位移表、预处理步骤、许可、日期与 DOI,都来自项目主页、README.md、LICENSE.txt 与头文件原文。记录清单的行数、目录内文件数量、subject-info.csv 的三列内容,是直接读取文件得到的。
第二层:官方文件的直接派生。 单次时长由采样点除以采样率得到,约 69 秒;全库累计时长由 25 次乘 7 人得到;网格步长由位移表的相邻差值得到;受试者实际年龄由 subject-info.csv 的出生年与采集年份相减得到。这些数字不是官方单独列出的,而是从官方数据算出来的,口径已在正文说明。
第三层:未核实。 信号文件逐条的实际采样点总量、四只探头在各测次的具体方向配置是否完全一致、raw 与 preprocessed 之间的精确重采样比例、受试者来源与招募方式、官方所称"后续版本"的时间表。这些官方未逐项公布,正文中标为未说明或计划。
附录 C:完整参考文献
| 编号 | 文献 | 链接 | 用途 |
|---|---|---|---|
| 1 | Kiel Cardio Database v1.0.0 | https://physionet.org/content/kiel-cardio/1.0.0/ | 规模、结构、边界数据来源 |
| 2 | 该库的 PhysioNet 文件目录 | https://physionet.org/files/kiel-cardio/1.0.0/ | RECORDS、README.md、头文件 |
| 3 | 数据集 DOI | https://doi.org/10.13026/q6r2-zz68 | 引用与版本定位 |
| 4 | 数据集官网 | https://biomagnetic-sensing.de/index.php/data-bases/datasets/kiel-cardio-database | 官方声明的更新版本入口 |
| 5 | PhysioNet 平台综述 | https://doi.org/10.1038/s44360-026-00096-z | 托管模式与引用规范 |
| 6 | Engelhardt E 等,磁电传感器心肌电流密度估计 | Current Directions in Biomedical Engineering, 2023 | §8.1 的技术背景 |
| 7 | Engelhardt E 等,心磁传感器系统质量分级 | Current Directions in Biomedical Engineering, 2022 | §7.2 的滤波与质量讨论 |
| 8 | LG-BiTCN 心磁去噪研究 | https://doi.org/10.1088/2057-1976/ae34b3 | §7.4 的外部用法 |
| 9 | Koch H 等,心电生理模型验证的参考数据集 | Biomedical Engineering Online, 2011 | §2.5 的同类对照 |
| 10 | ECG-ID 数据库(库内对照) | https://physionet.org/content/[ecgiddb](https://www.qianfanghub.com/ai-ready-dataset/ecgiddb/1488)/1.0.0/ | §6.1 的同源异模态对比 |
附录 D:任务代码
任务一:按受试者做留一交叉验证的数据打包
import os
import re
import numpy as np
import pandas as pd
import wfdb
DATA = "https://physionet.org/files/kiel-cardio/1.0.0/data"
def load_subject(sid, stage="preprocessed", win=12000):
rows = [wfdb.rdrecord(f"{DATA}/subject{sid}_{stage}_trial{t:02d}",
physical=True).p_signal[:win].astype("float32")
for t in range(1, 26)]
#-- 25 次测量的通道顺序一致,可直接堆成 (25, 8, win)
return np.stack([r.T for r in rows])
for sid in range(1, 8):
arr = load_subject(sid)
print(sid, arr.shape, float(arr.std()))
这段代码把每个受试者的 25 次测量堆成一个三维数组,形状是测次乘通道乘采样点。用固定长度 win 截断,是为了让 25 次能对齐;截断到一万二千点即前六十秒,丢掉的末尾十秒不属于同一段时相,不截反而更难处理。
任务二:四只探头的一致性检查
import numpy as np
import pandas as pd
import wfdb
DATA = "https://physionet.org/files/kiel-cardio/1.0.0/data"
rows = []
for t in range(1, 26):
r = wfdb.rdrecord(f"{DATA}/subject1_preprocessed_trial{t:02d}", physical=True)
names = [s.strip().split() for s in r.sig_name]
for k, (sensor, axis) in enumerate(names):
seg = r.p_signal[:12000, k]
rows.append({
"trial": t, "sensor": int(sensor[1]), "axis": axis,
"std_pT": float(seg.std()),
})
df = pd.DataFrame(rows)
print(df.groupby(["sensor", "axis"])["std_pT"].describe().round(3))
第二段代码回答的是"四只探头是不是同一水位"这个问题。同一只探头在不同测次里的标准差若出现数量级跳变,通常不是信号问题,而是那一次测量时探头没贴稳或者夹具移位没到位。这类检查在任何传感器阵列数据上都是第一步。
附录 E:如果只记五件事
| 序号 | 记住什么 | 为什么 |
|---|---|---|
| 1 | 它是心磁,不是心电,单位皮特斯拉 | 这一条决定了后面所有流程能不能照搬 |
| 2 | 七个人、两百个测点、每次一分钟 | 三个数字定住了它的规模上限 |
| 3 | 25 次测量来自五乘五位移表 | 空间网格是设计出来的,不是随机的 |
| 4 | 本版没有任何标注,也没有心电 | 想训练监督模型,得先自己标 |
| 5 | 清单只列预处理版,raw 需换名字补下 | 只按清单下载会漏掉一半数据 |
编辑说明
核对于 2026 年 10 月 28 日完成。核对方式为直接访问 PhysioNet 项目页与文件目录,取回 RECORDS、README.md、LICENSE.txt、subject-info.csv 全文,并逐行读取 subject1 的 raw 与 preprocessed 头文件、trial02 头文件与 subject7 首末测次头文件,用于交叉核对坐标、采样点与时长。未下载 data 下的信号文件做逐条统计,单时长与总时长均由头文件声明的采样点与采样率推算,属于对官方文件的派生。论文侧只做了 Europe PMC 检索,仅匹配到一篇引用本库的降噪研究,未获得官方独立数据论文。未覆盖的内容包括:四只探头在全部测次的完整方向配置、raw 与 preprocessed 的精确重采样比例、受试者的招募方式、以及官方所称后续版本的时间表。这些均标为未说明或计划。
相关数据集导航
以下为站内 AI-Ready 数据集百科中与本词条共享多个主题标签的相关数据集,按相关度降序排列:
- eye-tracking-ecg — 共享标签:生理信号 / 心电信号 / 多模态
- ephnogram — 共享标签:生理信号 / 心电信号 / 多模态
- deepfake-ecg — 共享标签:生理信号 / 心电信号 / 多模态
- ecg-spider-clip — 共享标签:生理信号 / 心电信号 / 多模态
- ninfea — 共享标签:生理信号 / 心电信号 / 多模态
- ucddb — 共享标签:生理信号 / 多模态
- qol-stress — 共享标签:生理信号 / 心电信号 / 多模态
- dreamer — 共享标签:生理信号 / 心电信号 / 多模态
- heartcycle — 共享标签:生理信号 / 心电信号 / 多模态
- vitaldb-arrhythmia — 共享标签:生理信号 / 多模态
导航说明:本章节由全站统一标签体系自动计算生成(标签重合度算法),双向可达;点击链接可跳转至对应数据集词条。

