信息速览
有一类数据集的稀缺性不在规模,而在「答案」:你能拿到一大堆输入,却只有极少数样本同时附了标准答案。腹壁胎儿心电就是这样的任务——把母亲肚皮上那几路混在一起的信号里属于胎儿的那一部分分离出来,是这个领域二十多年的核心问题,而绝大多数公开数据只给你混在一起的信号,不给你胎儿那一路的原始记录。
adfecgdb 是少数给了答案的。它由波兰西里西亚医科大学产科在产程中采集,5 名妊娠 38 到 41 周的产妇,每人一段五分钟,同时记录了四路腹壁差分导联和一路从胎儿头皮取得的直接心电。头皮那一路是真实胎儿心电本身,不含母体成分,所以它天然就是金标准。全部信号一千赫兹同步采样、十六位量化,以 EDF+ 格式发布,许可为 ODC-BY 1.0。
这份数据的全部内容装不满一张光盘:五条记录加起来约二十五分钟,压缩包不到十五兆字节。它撑不起一篇「我们训练了一个模型」的论文,却撑得起「我们的算法在这批真值上误差多少毫秒」的结论。一屏速览见下表。
| 维度 | 内容 |
|---|---|
| 中文名 | 腹壁与直接胎儿心电数据库 |
| 英文名 | Abdominal and Direct Fetal ECG Database |
| 发布方 | PhysioNet(MIT 计算生理学实验室托管) |
| 采集方 | 波兰西里西亚医科大学产科,扎布热 |
| 首发时间 | 2012 年 8 月 9 日,版本 1.0.0,此后未再升版 |
| 记录条数 | 5 条(r01、r04、r07、r08、r10) |
| 受试规模 | 5 名产妇、5 例胎儿,孕 38–41 周,均在产程中 |
| 总时长 | 每条 5 分钟,合计约 25 分钟 |
| 导联数 | 每条 5 路生理信号:1 路直接胎心电 + 4 路腹壁差分导联 |
| 采样率 | 1000 赫兹,全部通道同步 |
| 位深 | 16 位有效量化,EDF 文件按 24 位打包 |
| 带宽 | 1–150 赫兹,另有 50 赫兹工频与基线漂移的数字滤除 |
| 格式 | EDF+(波形)+ WFDB 注释(.qrs 逐搏真值) |
| 标注 | 胎儿 QRS 时刻,由系统在线检出、心内科医师离线核验 |
| 许可 | ODC-BY 1.0,署名即可商用 |
| 体积 | 未压缩 14.6 兆字节,单个 .edf 约 3 兆字节 |
| 引用 | Jezewski 等,Biomed. Tech. 2012;57(5):383-394 |
§1 它要解决的具体麻烦
1.1 腹壁上的胎儿心电小到几乎看不见
产科想回答的问题是胎儿缺氧没有。目前的常规手段是多普勒超声测胎心率,它给出的是一条心率曲线,而不是心电本身。心电能提供更多东西:波形形态、QRS 宽度、ST 段的趋势,这些都是心肌缺血与酸中毒的早期线索。要在产程中拿到这些,只能从母亲腹壁无创地记录。
问题在于物理层面的先天不利。腹壁电极贴在母亲身上,距离母亲心脏几十厘米内,距离胎儿心脏要先穿过羊水、子宫壁、皮下脂肪和皮肤。母体心电的幅度通常是腹壁记录里最大的成分,胎儿心电被压在下面,只剩一个数量级的差距还可能拉开。加上胎心电的高频成分被多层面组织低通衰减,剩下的那一点信号既小又钝。
于是这个领域的核心工艺成了「减掉母亲」:先估计母体 QRS 模板,从每一路腹壁信号中减去,再看剩下的残差里有没有周期性出现的胎儿心搏。二十多年来,减的办法换了一轮又一轮——模板相减、盲源分离、奇异值分解、自适应滤波、时空滤波,最近十年又加上了神经网络。这些方法都能在自己的数据上报出好看的数,但好看的数未必是真的对。
1.2 三条常见的错误期待
第一条期待是「拿到腹壁信号就能自动得到胎心电」。这是把混合信号当成了干净信号。四路腹壁导联里同时存在母体心电、胎儿心电、肌电噪声与运动伪迹,四路之间并不是简单重复,而是同一组源在不同投影方向上的叠加;任何只处理单路的做法,本质是在解一个欠定方程。理解这一点,才知道为什么这个领域执着于多导联同时处理。
第二条期待是「数据量大就能解决问题」。这个领域过去十年新增的公开集,多数是把腹壁记录做多做大,但真值仍然缺位。扩大没有答案的数据,只能让模型更像是一个会画出漂亮心电波形的生成器,不能让它更接近真实胎儿心搏。adfecgdb 的量很小,却是少数能验证「像」与「对」是否一致的地方。
第三条期待是「五分钟足够评估一个临床可用的算法」。五分钟包含的心搏数在数百量级,足以比较两种算法在同一批心搏上的误差分布,但不足以覆盖产程中会出现的场景切换:宫缩带来的运动伪迹、胎心减速、母体体位改变、母胎 QRS 的重叠与分离。论文里那句「方法对记录条件非常敏感」,说的正是这层意思。
1.3 它能给到的与给不到的
| 你的需求 | 它给的 | 够不够 |
|---|---|---|
| 知道「标准答案」长什么样 | 头皮螺旋电极的直接胎儿心电,逐点波形 | 够,这是它存在的理由 |
| 逐搏对齐时间的真值 | .qrs 注释给每个胎儿 QRS 的时刻,精度到毫秒 | 够,直接算检出误差 |
| 多导联合的空间信息 | 四路差分腹壁导联,同一参考、同一时刻 | 够,可做空间滤波与源分离 |
| 足够的样本训练深度模型 | 五条记录、约二十五分钟 | 不够,只能当测试集 |
| 覆盖不同孕周与人群 | 只有 38 到 41 周,且全部来自一家医院 | 不够 |
| 母体心电的独立参考 | 没有单独记录母体心电通道 | 不够,母体成分只能从腹壁信号里估 |
| 逐条的临床背景 | 无年龄、无孕次、无分娩结局 | 不够 |
| 宫缩、运动、体位等事件标签 | 无 | 不够 |
| 母胎 QRS 重叠的显式标注 | 无,需要自己按真值时刻推 | 需自行加工 |
| 与算法的直接对比基线 | 论文给了作者方法的误差分析,可作参照 | 部分可用 |
| 教学演示用的完整流程素材 | 五条记录、一千赫兹,够跑通全链路 | 够 |
| 产程长时程趋势分析 | 每条只有五分钟 | 不够 |
1.4 你的处境与它能帮到的事
| 你的处境 | 它能帮你什么 | 下一步该做什么 |
|---|---|---|
| 刚提出一种新的母体心电抑制方法,想在公开真值上报误差 | 提供逐搏真值,可算检出率与 RR 间期误差 | 固定评估协议,报告每条的误差而不是只报平均 |
| 想复现文献里的胎心率精度,但找不到原始数据 | 原始论文用的就是这批记录,结论可直接对照 | 按同样的预处理链路重跑,先对上作者的结果 |
| 手里有大批无真值的腹壁数据,想验证自己标注是否可靠 | 用它的真值校准你自己的标注工具与人工标注一致性 | 先在 adfecgdb 上跑标注工具,再推到大批数据 |
| 要写一份胎儿心电的综述或教学材料 | 提供唯一可展示「输入—真值—误差」三件套的公开例子 | 引用原始论文,不要只引 PhysioNet 页面 |
| 做产科监护设备,需要判断自家电极布局是否合理 | 四路脐周布局与直接参考都可观察,能对比自有记录 | 记录自己的布局参数,与它的失败区间对照 |
| 想训练一个端到端的 fECG 提取网络 | 五条记录只能当验证集,训练必然过拟合 | 另找大规模无真值数据预训练,用它做外部验证 |
| 做产程监测的临床研究,关心胎心减速这类事件 | 五分钟片段覆盖的事件太少,且没有事件标签 | 改找有长时程与临床标注的集合 |
1.5 一句话判断
这不是一个用来训练的数据集,是一个用来判分的数据集。它的价值在于让「胎儿心电提取」从「看起来像」变成「算得出来误差」,任何把它当成训练集扩大规模的努力,都会立刻撞上五条记录的墙。
1.6 不适合谁:四条边界
第一条边界是规模驱动的建模工作。如果你需要的是几百上千条记录来训练、调参、做消融,adfecgdb 帮不上。五条记录的训练集里,模型学到的是这五名产妇的电极位置、皮肤阻抗与胎位,不是胎心电本身。任何在这五条记录上报出的交叉验证分数,都只能说明模型记住了什么。
第二条边界是人群与场景的代表性研究。五名产妇全部来自波兰一家医院的产科,全部是孕 38 到 41 周、且头皮电极有临床指征的产程。人群偏高龄初产还是偏经产、剖宫产与阴道分娩的差别、不同国家的监护习惯,这些它一个都答不了。用它论证「我们的算法适用于所有孕妇」是站不住的。
第三条边界是需要母体心电独立通道的研究。数据没有单独记录母亲的心电导联,母体成分必须从腹壁信号里自己估。如果你的方法需要一块干净的母体参考来做自适应抵消,这里没有;你只能把某一路腹壁当参考,再承担两路共有成分带来的泄漏。
第四条边界是长时程与事件级分析。每条五分钟,覆盖不了整个产程;没有宫缩曲线、没有胎心减速的标注、没有分娩结局。做产程监护研究的人会很快发现,它缺的不是信号,而是信号之外的那一整套临床上下文。
§2 数据构成与规格
2.1 五条记录怎么来
官方页面给出的采集说明很短:五名产妇,孕 38 到 41 周,在产程中记录,每人一条五分钟的多通道胎儿心电;记录用的是 KOMPOREL 系统,这是波兰扎布热 ITAM 研究所研发的胎儿心电采集与分析系统。每条记录含四路取自母亲腹壁的差分信号,以及同步的、取自体表的直接胎儿心电参考。
电极布置写得很具体:四只电极围绕脐部放置,构成四路差分,一只参考电极放在耻骨联合上方,一只共模参考(带主动接地信号)放在左腿。为降低皮肤阻抗,Ag-AgCl 电极下方的皮肤做了打磨处理。头皮电极是临床需要才放的,所有产妇都同意参与研究。
2.2 字段、通道与文件的完整字典
EDF+ 的每个文件由三段组成:256 字节的固定主头、每个通道 256 字节的通道头、以及按记录帧排列的数据。adfecgdb 的文件头里,几项关键值如下表。
| 位置 | 字段 | 本数据集的值 | 含义与影响 |
|---|---|---|---|
| 主头 0–7 | 版本 | 0 |
无扩展保留,标准 EDF+ |
| 主头 8–87 | 患者标识 | r01 F X X |
记录名 + 性别 F + 两处占位 X,无年龄姓名 |
| 主头 88–167 | 记录标识 | Startdate X X X Komporel |
起始日期占位,设备名写在此处 |
| 主头 168–175 | 起始日期 | 01.01.11 |
占位值,非真实采集日 |
| 主头 176–183 | 起始时间 | 00.00.00 |
占位值 |
| 主头 184–191 | 头长度 | 1792 |
即 256 + 6×256 |
| 主头 192–235 | 保留区 | EDF+C |
声明为连续记录的 EDF+ |
| 主头 236–243 | 记录帧数 | 60 |
60 个记录帧 |
| 主头 244–251 | 每帧时长 | 5 |
每帧 5 秒,60 帧即 300 秒 |
| 主头 252–255 | 通道数 | 6 |
5 路生理信号 + 1 路注释 |
| 通道 1 | 标签 | Direct_1 |
头皮直接胎儿心电 |
| 通道 2 | 标签 | Abdomen_1 |
腹壁差分导联 1 |
| 通道 3 | 标签 | Abdomen_2 |
腹壁差分导联 2 |
| 通道 4 | 标签 | Abdomen_3 |
腹壁差分导联 3 |
| 通道 5 | 标签 | Abdomen_4 |
腹壁差分导联 4 |
| 通道 6 | 标签 | EDF Annotations |
EDF+ 要求的时间注释通道 |
| 所有生理通道 | 物理单位 | uV |
微伏 |
| 所有生理通道 | 物理最小值 | -3276.8 |
对应数字最小值 |
| 所有生理通道 | 物理最大值 | 3276.8 |
对应数字最大值 |
| 所有生理通道 | 数字最小值 | -32768 |
16 位有符号下限 |
| 所有生理通道 | 数字最大值 | 32767 |
16 位有符号上限 |
| 所有生理通道 | 每帧采样数 | 5000 |
5 秒 × 1000 赫兹 |
| 注释通道 | 每帧采样数 | 500 |
5 秒 × 100 赫兹,EDF+ 规定 |
| 所有生理通道 | 传感器类型 | AgAgCl Electrodes |
干电极在皮肤预处理后使用 |
| 所有生理通道 | 预滤波 | LP:150Hz, CombF:50Hz |
低通 150 赫兹,50 赫兹梳状滤波 |
文件名层面的构成如下表。五个波形文件加五个注释文件,外加三份清单。
| 文件 | 类型 | 字节数 | 作用 |
|---|---|---|---|
r01.edf |
EDF+ 波形 | 3,061,792 | 第一条记录的五路信号 |
r04.edf |
EDF+ 波形 | 同 r01 | 第二条 |
r07.edf |
EDF+ 波形 | 同 r01 | 第三条 |
r08.edf |
EDF+ 波形 | 同 r01 | 第四条 |
r10.edf |
EDF+ 波形 | 同 r01 | 第五条 |
r01.edf.qrs |
WFDB 注释 | 1,326 | 第一条的胎儿 QRS 时刻 |
r04.edf.qrs |
WFDB 注释 | 1,302 | 第二条 |
r07.edf.qrs |
WFDB 注释 | 1,292 | 第三条 |
r08.edf.qrs |
WFDB 注释 | 1,340 | 第四条 |
r10.edf.qrs |
WFDB 注释 | 1,336 | 第五条 |
RECORDS |
纯文本 | 40 | 五行,逐行一个波形文件名 |
ANNOTATORS |
纯文本 | 30 | 一行:qrs verified beat annotations |
SHA256SUMS.txt |
纯文本 | 899 | 十个文件的校验值 |
单个波形文件的字节数可以倒推校验:1792 字节头 + 60 帧 ×(5×5000 + 500)× 2 字节 = 1792 + 3,060,000 = 3,061,792。这个算式对五条记录全部成立。它的意义在于:如果你下载的文件不是这个大小,传输一定出了问题,不必怀疑数据本身被裁剪。
2.3 一条记录的完整解剖
以 r01 为例,一条记录在磁盘上是一段连续字节,读法有固定的偏移。下面这段 Python 只依赖标准库,从头到尾把 r01.edf 的结构拆开,输出的每一项都能与上一节的表对上。
#-- 解析一条 adfecgdb 记录的 EDF+ 头,只用标准库
import struct
PATH = "r01.edf"
with open(PATH, "rb") as fh:
head = fh.read(1792) #-- 主头 256 + 6 通道 × 256
def field(start, width, count=1):
return [head[start + i * width: start + (i + 1) * width].decode("latin1").strip()
for i in range(count)]
nsig = int(head[252:256])
assert nsig == 6, nsig
labels = field(256, 16, nsig)
p = 256 + 16 * nsig
units = field(p + 80 * nsig, 8, nsig) #-- 跳过 80 字节的传感器类型
pmin = field(p + 88 * nsig, 8, nsig)
pmax = field(p + 96 * nsig, 8, nsig)
nsamp = field(p + 216 * nsig, 8, nsig)
print("记录名 ", head[8:19].decode("latin1").strip())
print("帧数/秒 ", head[236:244].decode().strip(), head[244:252].decode().strip())
print("通道 ", labels)
print("单位 ", units)
print("量程 ", list(zip(pmin, pmax)))
print("每帧点数 ", nsamp)
print("理论字节 ", 1792 + 60 * (5 * 5000 + 500) * 2)
跑完之后你会确认三件事:五个生理通道的每帧点数都是 5000,注释通道是 500,文件总长度是三点零六一七九二兆的精确字节数。第三个数与上一节的算式一致。
信号本体按帧存,每帧 5 秒,五个生理通道各 5000 个 16 位整数首尾相接,最后是注释通道的 500 个字节。读数的方式是:先按帧切开,再按通道顺序切成五段,每段用 int16 小端解释,最后按「物理值 = 数字值 × 增益」换算。增益由物理上下限除以数字上下限得到,即 6553.6 / 65535,约 0.1 微伏每单位。
#-- 读第一帧的五路信号并换算成微伏
import numpy as np
with open("r01.edf", "rb") as fh:
fh.seek(1792)
frame = np.frombuffer(fh.read(60_000), dtype="<i2")
GAIN = 6553.6 / 65535 #-- 0.1 微伏 / 单位
sig = frame.reshape(5, 5000).astype(float) * GAIN
names = ["Direct_1", "Abdomen_1", "Abdomen_2", "Abdomen_3", "Abdomen_4"]
for name, x in zip(names, sig):
print(f"{name:10s} 极性 {x.mean():7.1f} uV 标准差 {x.std():6.1f} uV")
在 r01 上,这五行输出的标准差大致是:直接导联五十余微伏,四路腹壁导联在七到十三微伏之间。这个量级差不是笔误,恰恰是这份数据要处理的核心矛盾——腹壁上看到的波形,幅度上比真实胎心电小一个档,却还要从中分离出它。
注释文件 r01.edf.qrs 是另一套格式:WFDB 的 16 位注释。文件开头是若干 ## 开头的头部块,例如 ## time resolution: 1000,之后是连续的 16 位整数,每一个代表相对上一个心搏的时间增量,单位为毫秒。把增量累加,就得到每一个胎儿 QRS 的相对时刻。下一节的代码处理了这件事。
2.4 五条记录的规模分布
下表是从注释文件解出的逐条统计。心搏数是注释条数,首末时刻是相对记录起点的毫秒换算,中位 RR 是相邻心搏间隔的中位数。这些数字回答的问题是「这一条记录里有多少个可用样本」,而不是「这名胎儿的心率是多少」。
| 记录 | 波形字节 | 心搏数 | 首个心搏(秒) | 末个心搏(秒) | 中位 RR(毫秒) | 名义心率(次/分) |
|---|---|---|---|---|---|---|
| r01 | 约 3 MB | 644 | 18.688 | 7693.945 | 10747 | 约 5.6 |
| r04 | 约 3 MB | 632 | 27.136 | 6841.531 | 8955 | 约 6.7 |
| r07 | 约 3 MB | 627 | 14.336 | 5421.361 | 9211 | 约 6.5 |
| r08 | 约 3 MB | 651 | 12.800 | 8843.446 | 12283 | 约 4.9 |
| r10 | 约 3 MB | 649 | 23.296 | 9449.273 | 14331 | 约 4.2 |
中位 RR 一栏出现了两个必须交代清楚的问题。
第一,名义心率一列明显不合理,四到七次每分显然是错的。原因不在数据,在解码:这张表用的是「增量取绝对值再累加」的简化做法,也就是把每个有符号增量当作正数处理。五个文件里绝大多数增量本是负值,取绝对值之后,一次符号翻转就被记成了一次时间跳变。正确的解码必须在累加前处理符号,附录 D 给出的 wfdb 写法不存在这个问题。本表保留这两个不合理列,是为了让后来者一眼看出「粗解码会得到什么」——这也是 §4.3 案例里要被反复提起的第一课。
第二,末个心搏的时刻超过了 300 秒,有的到了 7000 秒甚至 9000 秒。同样来自解码错误,而不是记录时长。EDF+ 主头里 帧数 60、每帧 5 秒 是硬约束,任何超出 300 秒的「心搏时刻」都只能是累加过程里漂移出来的假值。表中心搏数一列受影响较小,因为它只数条数不数时间,可以作为规模的大致参考:五条记录合计约三千二百个心搏。
如果要用一个不依赖解码细节的方式估规模,更稳的算法是用波形本身:五分钟里,胎儿心率按每分钟一百二十到一百六十次计,一条记录大约六百到八百个心搏,五条合计三千到四千。这个区间与上表的心搏数一列落在同一量级,可以互相印证。
2.5 与同类资源的字段差异
把 adfecgdb 和同类公开的胎儿心电资源放在一起,差异集中在四列:有没有直接胎心电、有几路腹壁、有没有逐搏标注、给不给人口学信息。
| 资源 | 直接胎心电 | 腹壁导联 | 逐搏真值 | 规模量级 | 人群字段 |
|---|---|---|---|---|---|
| adfecgdb | 有,头皮螺旋电极 | 4 路差分 | 有,医师核验 | 5 条 × 5 分钟 | 无 |
| PhysioNet 的 Non-Invasive Fetal ECG 系列 | 无 | 多路(腹部与胸部混合布置) | 有母体与胎儿注释 | 数十条 | 无 |
| 各类竞赛型腹壁 fECG 挑战数据 | 无 | 单路到多路不等 | 多为专家在腹壁上标 | 数百到数千条 | 部分有 |
| 自建临床队列 | 视设计而定 | 视设计而定 | 常无独立第二路 | 视设计而定 | 常有 |
结论是:在「有没有真值」这一列上,adfecgdb 是少数几个能打勾的小样本集之一。它的规模劣势是明显的,但在腹部胎儿心电这个任务里,规模并不等价于可用性——没有真值的大数据集,只能用来做无监督或自监督的预训练,不能用来判分。§6 会讨论这两类资源如何配对使用。
§3 核心层 A:它为什么能被当成金标准
3.1 三路信号里的三种「真相」
一条腹壁记录里躺着三种东西:母亲的真实心电、胎儿的真实心电、以及两者叠加后透过母亲身体的那份投影。绝大多数数据集只记录第三种,因为它最好采、最安全、最便宜。adfecgdb 特殊的地方,是它同时记下了第二种。
定义上说,头皮螺旋电极贴在胎儿先露部位,电极与参考之间的电流路径几乎全部经过胎儿组织,因此记录到的电位变化主要是胎儿心脏产生的。母体心电要传到这里,必须穿过羊水与子宫壁再逆向传导,衰减极大。这就是为什么在产程监护里,直接胎心电一直被认为是胎心率的参考方法:它不受母体心电污染,也不受胎动影响。
把它当成金标准,需要接受两个前提。前提之一是电极确实贴在胎儿身上且接触良好;前提之二是胎儿的先露部位在记录期间没有大幅移动。这两条在五分钟尺度上通常成立,在长时程上会出问题。所以金标准这个说法,在这个数据集上的正确读法是「五分钟内的局部金标准」,而不是「整段产程的绝对真值」。
3.2 直接导联能回答的三个问题
有了这一路,很多原本只能靠猜的问题变成了可以算的。
第一个问题是「提取出来的胎儿 QRS 是不是真的对上了」。把算法在四路腹壁上的输出与直接导联的 QRS 时刻逐搏比对,可以分成三类:检出的、漏检的、误检的。漏检率与误检率都是可计算的量,而不是靠肉眼在图上挑毛病。
第二个问题是「叠在母体波形里的胎儿心搏会不会被吞掉」。母体 QRS 与胎儿 QRS 在时间上随机靠近,靠近到两者重叠时,腹壁上的胎儿成分会被母体成分的尾巴盖住,这类片段是检出率下降的主要来源。有一份独立真值,才能知道哪些位置是重叠的、重叠时算法有没有失手。
第三个问题是「胎心率的短时变异能不能复现」。胎心率变异是判断胎儿状态的重要指标,而变异的估计对逐搏误差极其敏感:一次漏检就会让相邻两个 RR 变成一个双倍间隔,一次误检则会插进一个极短间隔。有真值,才能把「算法误差」与「胎儿本身的变化」分开。
3.3 它没有被做成更大,原因在伦理而不是技术
五条记录这个数字会让第一次接触的人以为是偷懒。理解它为什么只有五条,需要知道头皮电极的代价。
头皮电极要经宫颈放到胎儿先露部位,这本身是一个侵入性操作:需要破膜、需要宫颈足够扩张、需要胎儿先露已经进入骨盆。临床上它只在有监护指征时使用,因为存在感染、胎儿头皮损伤与母体不适的风险。换句话说,不是为了研究才放电极,是因为临床已经决定要放,才有机会顺手记录。
在这个前提下,能同时满足「临床上要放电极」「产妇愿意签字」「设备在场」「记录质量合格」四条的产程并不常见。五条记录背后可能是数倍于五的筛选。任何一个做这个方向的人想扩大规模,都会立刻撞上同一堵墙:你没办法为了做数据集,去给不需要内监护的产妇放一只头皮电极。
这也解释了为什么这个领域到今天还在用这么小的数据集。不是没有人试过做大,而是代价不允许。
把这张「伦理账」摊开,会看到五个约束在同时收紧,任何一个单独松动都不足以让规模跳一级。
| 约束 | 具体内容 | 松动的后果 |
|---|---|---|
| 临床指征 | 头皮电极必须有监护指征才放 | 无指征放电极即伦理不通过 |
| 知情同意 | 产妇须在研究范围内单独签字 | 产程中紧急,签字窗口很短 |
| 破膜前提 | 电极经宫颈放置,通常需已破膜 | 未破膜的产程无法入组 |
| 设备在场 | 专用采集系统须在产房可用 | 设备不多时,能录到的产程有限 |
| 信号合格 | 电极接触、胎位、胎动都会毁掉记录 | 录了也可能用不了 |
五条约束叠加的结果是「能录到的窗口本来就窄」,而不是「录完挑剩五条」。这两件事的区别在于:前者意味着扩大规模要做的是流程改造,后者意味着扩大规模只要多录几次。事实是前者。
§4 核心层 B:质量与特色
4.1 波形质量:干净的代价是带宽受限
官方说明给出的采集链路是:带宽 1 到 150 赫兹,同步采样一千赫兹,十六位量化,另外做了 50 赫兹工频抑制与基线漂移去除。文件头的预滤波字段写的是 LP:150Hz, CombF:50Hz,与此一致。
这条链路的优点是可重复:滤波参数写在文件头里,任何人在任何机器上读到的都是同一份已经处理过的信号,不必担心「我这里用了一个不同的滤波器所以结果不一样」。缺点是低频被砍掉了:1 赫兹的高通意味着 ST 段这类缓变成分不在数据里。如果你的研究关心胎儿心肌缺血的 ST 段改变,这份数据帮不上——它保住了 QRS 的时间信息,代价是放弃了形态学的低频部分。
4.2 标注质量:两级核验
标注链路是两级的。第一级在采集端:KOMPOREL 系统在直接导联上在线检出 R 波位置,这是自动的。第二级在离线:一组心内科医师逐条复核这些位置,形成最终的参考标记。
两级结构的意义在于,自动检出提供了初稿,人工复核提供了纠错。相对纯粹的自动标注,它降低了系统性偏差;相对纯粹的人工标注,它把医师的工作量压到了「复核」而不是「从零标」。对一个五分钟、数百搏的记录,从零标与复核的差别可能不大;但对五条记录乘以若干年后的复现者来说,这套流程意味着标注口径是稳定的。
需要提醒的是,标注只针对胎儿 QRS。母体 QRS 的位置没有单独给出来。要得到母体心搏的真值,只能自己从腹壁信号里检,或者用在直接导联上看不到的大幅成分去反推。这对做母体抑制的研究者是一个不大不小的坑:你想评估「母体成分减掉了多少」,但你没有母体成分的真值。
4.3 案例:r01 前五秒里母与胎的强弱关系
把 r01 的第一帧单独拎出来看,可以把抽象的说法变成具体的数。
对五路信号各取五分钟里的第一帧,计算标准差:直接导联约五十余微伏,四路腹壁导联分别在七到十三微伏之间。再在直接导联上按阈值检出第一帧里的胎儿 R 波,能稳定找到五个峰,对应约每分钟六十次的检出率——这个数只是阈值法的粗结果,不代表真实心率,但足以证明直接导联里的胎儿心搏是清晰可辨的。
然后在四路腹壁信号上做同样的阈值检出,得到的峰数在六到十一个之间,且峰位与直接导联的胎儿峰位大部分不重合。这说明第一帧里腹壁上最显著的周期性成分并不是胎儿心搏。再往前一步,把腹壁信号幅度最大处的位置与直接导联的同刻振幅并列:腹壁上那个大到四十余微伏的波峰,在直接导联上对应的是接近于零的电位。两路在同刻一强一弱,最自然的解释是——腹壁上那个大波属于母亲,直接导联看不到母亲,所以那里是平的。
§4.3 的案例之所以值得反复引,是因为它用一个可以复算的小片段说明了三件事:直接导联里只有胎儿,腹壁导联里母亲占主导,两路的强弱关系在具体采样点上可以直接观察到。§7.0 的误判校正、§8.2 的算法演进、§9.2 的最短流程,都会回到这段片段。
4.4 特色与不可替代性
| 特色 | 具体表现 | 为什么不常见 |
|---|---|---|
| 有真值 | 头皮直接胎心电与腹壁同步 | 直接电极有创,只在高危产程放 |
| 有真值下的逐搏标注 | 医师复核的 QRS 时刻 | 需要直接导联才能标得准 |
| 多导联空间覆盖 | 四路脐周差分 | 多数公开集只有一两路 |
| 口径写入文件 | 滤波参数、单位、量程都在头里 | 很多集的预处理只在论文里写 |
| 完全开放 | ODC-BY 1.0,无需注册 | 部分产科数据集需要数据使用协议 |
| 体积极小 | 十四兆字节 | 适合教学与快速验证 |
| 版本冻结 | 2012 年后再未升版 | 复现性极好,但也意味着不再更新 |
最后一行既是优点也是缺点。版本冻结让你的结果三年后还能对上;也意味着数据本身的已知问题不会被修复,比如占位的日期字段、缺失的人口学信息。使用它的人必须接受这些是常量,而不是待更新的缺陷。
「不可替代性」这个词容易说得太满,所以把它拆成五个可以单独检验的判断。
| 判断 | 是否成立 | 检验方式 |
|---|---|---|
| 公开数据里没有第二路可对照的胎儿心电 | 大体成立 | 逐个核查同类集合的通道清单 |
| 没有它就无法计算逐搏误差 | 不完全 | 可自建,但要重走伦理流程 |
| 没有它就无法做算法比较 | 不完全 | 可在同一无真值集上横向比较,但无法判对错 |
| 它比自建数据更省事 | 成立 | 十四兆字节对三个月的伦理与采集 |
| 它比自建数据更可信 | 取决于场景 | 自建数据若有完整临床背景,可能更有代表性 |
第二、三条之所以写「不完全」,是为了避免把这份数据的价值说成唯一路径。它是捷径,不是唯一解;只不过这条捷径的维护成本几乎为零,而自建路径的维护成本要由每一个团队各自承担一次。
§5 核心层 C:取数、解码与最小闭环
5.1 三种取数方式
PhysioNet 给了三条路径,对应三种网络条件。
第一条是网页逐文件下载。目录浏览页 https://physionet.org/files/adfecgdb/1.0.0/ 列出全部十个文件与三份清单,点哪个下哪个。适合只想试一条记录的人。
第二条是打包下载。项目页给出的 ZIP 是十四兆字节,一次拿全。适合进了正式实验、需要保证所有记录版本一致的人。
第三条是命令行递归同步。官方给的两行是 wget -r -N -c -np 与 aws s3 sync --no-sign-request。前者走 HTTP,后者走 S3 开放桶,后者在同一区域内的速度通常更好。
#-- 方式一:整包下载(十四兆,任何网络都能在几分钟内完成)
curl -L -o adfecgdb-1.0.0.zip \
"https://physionet.org/content/adfecgdb/1.0.0/adfecgdb-1.0.0.zip"
#-- 方式二:只拿一条记录与它的注释
BASE="https://physionet.org/files/adfecgdb/1.0.0"
curl -L -o r01.edf "$BASE/r01.edf"
curl -L -o r01.edf.qrs "$BASE/r01.edf.qrs"
#-- 方式三:用 S3 开放桶(免签名)
aws s3 sync --no-sign-request \
s3://physionet-open/adfecgdb/1.0.0/ ./adfecgdb/
有一个与网络实现相关的细节值得写进来:用 curl -r 0-1791 取文件头时,PhysioNet 对 .edf 的字节范围请求并不总是按区间返回,有时直接回整个文件。这不会损坏数据,但会让「我只想读个头部」的脚本意外拉满三兆。要读头,用 Python 的 requests 加 stream=True 再 fh.read(1792),或者直接用 wfdb 库,都不存在这个问题。
5.2 用 wfdb 读波形与注释
wfdb 是 PhysioNet 官方的 Python 读库,pip install wfdb 即可。它能直接读 EDF+,也能直接读同名的 .qrs。
#-- 用 wfdb 读一条记录与它的 QRS 注释
import wfdb
import numpy as np
record = wfdb.rdrecord("r01", pn_dir="adfecgdb/1.0.0", physical=True)
ann = wfdb.rdann("r01", "qrs", pn_dir="adfecgdb/1.0.0")
print("导联名 ", record.sig_name)
print("采样率 ", record.fs, "赫兹")
print("时长 ", record.sig_len / record.fs, "秒")
print("单位 ", record.units)
print("心搏数 ", len(ann.sample))
rr = np.diff(ann.sample) / record.fs
print("中位 RR %.3f 秒 -> 胎心率 %.1f 次/分" % (np.median(rr), 60 / np.median(rr)))
这段代码跑通,就等于完成了这份数据最核心的一次读取:波形、采样率、单位、心搏时刻、由心搏时刻换算的心率。注意最后两行的输出才是有意义的心率,前一节表里那两个「名义心率」列正是没走 wfdb、自己解注释解错的结果。如果这里输出的是每分钟一百二十到一百六十之间,说明解码正确;如果输出个位数,说明注释顺序或符号处理有问题。
5.3 手工解码注释:一份可对照的实现
不用 wfdb 也能读,只要理解 WFDB 16 位注释的结构。文件开头是若干以 ## 开头的说明块,每个块以空字节结尾;之后就是连续的 16 位整数,每个整数是相对上一个心搏的毫秒增量。
#-- 手工解码 .qrs 注释(与 wfdb 的结果可互相对照)
import struct
import statistics
def read_qrs(path):
raw = open(path, "rb").read()
i = 0
#-- 跳过所有 ## 开头的头部块,每个块以 0x00 结尾
while raw[i:i + 2] == b"##":
i = raw.index(b"\x00", i) + 1
words = struct.unpack("<%dh" % (len(raw[i:]) // 2), raw[i: len(raw) - len(raw[i:]) % 2 + i])
return words
words = read_qrs("r01.edf.qrs")
print("前八个 16 位字 ", words[:8])
print("总字数 ", len(words))
打印结果里,前两个字通常是 -20, -1 这类控制项,之后才是增量序列。这里必须说清楚:把这段增量序列做「直接累加」还是「取绝对值累加」,会得到完全不同的结果,后者的末值会漂到数千秒。正确做法是按注释规范处理符号与溢出,而这件事最容易的方式是交给 §5.2 的 wfdb。手工解码的价值在于自检:如果两种方式给不出同一个心搏数,说明其中一种错了。
5.4 把腹壁与真值画在一起
要直观看到「母体压住胎儿」这件事,最省事的办法是画一段十秒的波形图,把直接导联与四路腹壁叠成两栏。
#-- 取 r01 第 60 秒起十秒,画直接导联与四路腹壁
import wfdb
import numpy as np
import matplotlib.pyplot as plt
rec = wfdb.rdrecord("r01", pn_dir="adfecgdb/1.0.0")
fs = rec.fs
a, b = 60 * fs, 70 * fs
direct = rec.p_signal[a:b, 0]
abd = rec.p_signal[a:b, 1:5]
fig, ax = plt.subplots(2, 1, figsize=(10, 5), sharex=True)
ax[0].plot(np.arange(a, b) / fs, direct, lw=0.8, color="#1f5f8b")
ax[0].set_ylabel("Direct_1 (uV)")
ax[1].plot(np.arange(a, b) / fs, abd, lw=0.6)
ax[1].set_ylabel("Abdomen 1-4 (uV)")
ax[1].set_xlabel("time (s)")
plt.tight_layout()
plt.savefig("r01_60_70s.png", dpi=150)
这张图通常一眼就能看出区别:上面那栏是干净、规则、幅度大的胎儿心搏;下面四栏波形更杂,主频往往与上面那栏不同。如果在下面四栏里找不到与上面同步的小尖峰,不代表数据有问题,而是这份信号里胎儿成分本来就被压得很低,需要先做母体抑制才能显形。
5.5 评估一个提取结果的最小协议
有了真值,评估可以写成固定的四步:对齐、配对、分类、统计。下面这段是最小实现,输入是算法给出的胎儿 QRS 时刻与注释给出的真值时刻,输出是检出率与 RR 误差。
#-- 与真值逐搏比对:容差 50 毫秒
import numpy as np
def score(detected, reference, fs, tol_ms=50):
tol = int(fs * tol_ms / 1000)
hit = 0
used = set()
for d in detected:
cand = [i for i, r in enumerate(reference)
if abs(int(r) - int(d)) <= tol and i not in used]
if cand:
best = min(cand, key=lambda i: abs(int(reference[i]) - int(d)))
used.add(best)
hit += 1
n_ref = len(reference)
n_det = len(detected)
recall = hit / n_ref
precision = hit / n_det if n_det else 0.0
f1 = 2 * recall * precision / (recall + precision) if recall + precision else 0.0
return dict(hit=hit, n_ref=n_ref, n_det=n_det,
recall=recall, precision=precision, f1=f1)
ref = np.array(ann.sample)
mine = ref + np.random.randint(-30, 30, len(ref)) #-- 占位:换成你自己的检出结果
print(score(mine, ref, fs=1000))
把 mine 换成真实算法的输出之后,这个函数的每一个返回值都能直接写进论文表格。容差的选择要写清楚:50 毫秒是一千赫兹下 50 个采样点,对 QRS 检测是常见口径,但如果你的算法输出的是滤波后的峰位,系统延迟会整体平移检出时刻,评估前必须先校正。
5.6 五条记录一起跑:把结果摊开看
五条记录的价值不在平均,而在方差。同一算法在五条上的表现如果差出两三倍,说明它对记录条件高度敏感,平均分会掩盖这个事实。
#-- 逐条评估,不做平均,先看离散度
import wfdb
import numpy as np
rows = []
for rec_id in wfdb.get_record_list("adfecgdb/1.0.0"):
name = rec_id.split(".")[0]
r = wfdb.rdrecord(name, pn_dir="adfecgdb/1.0.0")
a = wfdb.rdann(name, "qrs", pn_dir="adfecgdb/1.0.0")
rr = np.diff(a.sample) / r.fs
rows.append((name, len(a.sample), float(np.median(rr)), 60 / float(np.median(rr))))
for name, n, rr, hr in rows:
print(f"{name} 心搏 {n:4d} 中位RR {rr:.3f} s 心率 {hr:6.1f} 次/分")
五个心率如果不落在同一个窄带里,不必惊讶。五个胎儿处在产程的不同阶段,心率本来就不该一致。真正需要警惕的是同一名胎儿在五分钟内心率的剧烈跳动——那通常意味着一处漏检或误检,而不是胎儿状态突变。
把「摊开看」这件事拆成四个可以逐条勾选的检查项,会比一次性看五个数更可靠。
| 检查项 | 合格的样子 | 不合格说明什么 |
|---|---|---|
| 心搏数在合理区间 | 每条数百个 | 若差一个数量级,解码路径错 |
| 首搏时刻在前半分钟 | 通常十几到三十秒 | 若为零或数百秒,累加起点错 |
| 末搏时刻小于或等于 300 秒 | 略小于三百秒 | 若远超,累加时符号或溢出未处理 |
| 中位 RR 在 0.35–0.55 秒 | 对应每分钟百余次 | 若是个位数心率,走了绝对值路径 |
四项都过关,说明这条记录的读取链路是可信的;任何一项不过,先回去核对注释解码,再谈算法效果。附录 D 第三个工具的输出就是按这四项组织的,可以直接当自检报告用。
§6 与库内条目的关系
6.1 关系图谱
adfecgdb 在生理信号类目里的位置特殊:它是「有真值的评测集」,而不是「有规模的数据集」。这决定了它与库内其他词条的关系,多数是互补而不是替代。
| 库内词条类型 | 与之的关系 | 怎么配对使用 |
|---|---|---|
| 大规模单导联或双臂心电集 | 提供母体心电的形态多样性 | 用它们学母体 QRS 的分布,用 adfecgdb 判分 |
| 其他胎儿心电集(有腹壁无真值) | 提供规模与人群多样性 | 先在无真值集上预训练或自监督,再到 adfecgdb 做外部验证 |
| 胎儿超声影像集 | 提供同一时期的另一模态 | 做产前筛查与产时监护的任务区分,不要混为一谈 |
| 其他 PhysioNet 生理信号集 | 提供格式与工具链的通用性 | 统一用 wfdb 读取,减少工程差异 |
| 心电算法竞赛数据集 | 提供标准化评测协议 | 借它们的评估口径,但要重新说明容差与配对规则 |
一句话概括:大规模心电集回答「模型见没见过足够的母体心电」,adfecgdb 回答「模型在真值面前准不准」。两者缺一不可,但顺序不能颠倒——没有真值就没有判分,没有规模就没有泛化。
6.2 检索路径
在库里找与它相关的词条,有四个入口。
第一个是标签路径:生理信号 / 心电信号,加上 时序信号、波形、人工标注 三个数据标签。凡是同时带这四个标签的,都可视为同一任务族。
第二个是机构路径:PhysioNet。它是同一套发布规范、同一套 WFDB 工具链,任何 PhysioNet 上的心电集都可以用同一段代码读取。
第三个是任务路径:胎儿心电提取、母体心电抑制、胎心率估计。这三个词在这份数据集的论文与页面上反复出现,搜这三个词能直接命中它的引用链。
第四个是资源类型路径:评测基准。这一类词条的共同特点是小而精、有真值、有明确的评估协议。如果你在找的是「能判分的东西」,从这个类型往里筛,命中率更高。
§7 质量评估与局限性
7.0 阅读本节前的一个前置校正
在给任何分数之前,必须先校正一个几乎人人都会犯的误判:把「小」直接读成「差」。数据集的质量评估在这类小样本真值集上,不能沿用大数据集的维度权重——那边看重的是覆盖度与规模,这边看重的是真值是否可信、口径是否可复现、代价是否被诚实记录。
如果按覆盖度打分,adfecgdb 会在五条记录上被扣到底;如果按真值可信度打分,它反而是这一族里最靠前的。§4.3 的案例已经说明,它的每一条记录都能被独立复核:波形与注释自洽,头文件与官方描述一致,文件字节数与结构算式对得上。这些是「可以拿去当参照物」的品质,而不是「可以用来训练」的品质。
下面的评分表因此按「参考标准」而非「训练库」来设计权重。读的时候请把这一点放在前面,否则五维分数会被误读成「一个质量平平的小数据集」。
7.1 五维评分
| 维度 | 分数 | 理由 |
|---|---|---|
| 真值可信度 | 5 / 5 | 直接头皮电极 + 医师离线核验,双重保障 |
| 口径可复现 | 5 / 5 | 滤波、单位、量程、采样率全部写在文件头与页面上 |
| 规模与覆盖 | 1 / 5 | 五条记录、二十五分钟,且人群与机构高度单一 |
| 结构与工程 | 4 / 5 | EDF+ 与 WFDB 都是成熟标准,工具链齐全;扣分在注释需专用解码 |
| 文档完整性 | 3 / 5 | 采集方法写得很细,但缺人口学、缺事件标签、缺逐条临床背景 |
五维平均三点六。这个数放在库里不算高,但它测量的对象是「作为数据集好不好用」,而这个集合的正确角色是「作为参照准不准」。按角色匹配的评分是四点五,按用途错配的评分是一点五。差距这么大,正是 §7.0 那句校正要表达的意思。
分数之外还有一层「在不同任务下的折算」。同一份数据,换任务就换权重,分数自然不同。
| 任务 | 最看重的维度 | 折算分 | 说明 |
|---|---|---|---|
| 算法可行性验证 | 真值可信度 | 四点八 | 它几乎是为这件事设计的 |
| 算法横向比较 | 真值 + 口径 | 四点五 | 口径一致,比较公平 |
| 外部验证 | 结构与文档 | 四点零 | 格式通用,但缺临床背景 |
| 教学与复现 | 接入成本 | 四点七 | 体积极小,全流程半小时 |
| 模型训练 | 规模 | 一点零 | 五条记录无法训练 |
| 人群代表性研究 | 覆盖 | 一点二 | 单一机构、单一人群 |
| 长时程趋势 | 时长 | 一点零 | 每条五分钟 |
| 事件级分析 | 标注 | 一点五 | 只有逐搏,没有事件 |
这张表比单一总分更有用。它把「好不好」拆成了「对什么事好」,而这正是选数据集时真正要回答的问题。
7.2 它强在哪:真值、口径与接入成本
真值的存在本身是它最强的一条。在腹部胎儿心电这个任务上,这是一份罕见的、可以直接算误差的公开数据。任何提出新方法的人,只要想证明自己的提升是真的,就需要一份不依赖自建数据的判分集;adfecgdb 是少数几个可以拿出来的选项。
第三件是极低的接入成本。十四兆字节、两个成熟格式、一段二十行的读取代码,任何人半小时内就能把全流程跑通。对一个需要快速验证想法的研究者,这比一个需要申请三个月的数据集有用得多。
7.3 已知的、可枚举的偏差
| 偏差 | 表现 | 影响 | 能否在分析中校正 |
|---|---|---|---|
| 机构单一 | 五条全部来自波兰一家医院 | 设备与操作者效应与人群效应混淆 | 不能,只能承认 |
| 孕周集中 | 全部 38–41 周 | 无法外推到早产或足月前 | 不能 |
| 入组偏倚 | 头皮电极有临床指征才放 | 偏向需要内监护的高危产程 | 不能,但应写明 |
| 时间字段占位 | 五条都是 01.01.11 00:00 | 无法做跨记录的时间趋势 | 不能 |
| 人口学缺失 | 无年龄、孕次、分娩结局 | 无法做亚组分析 | 不能 |
| 事件标签缺失 | 无宫缩、无减速标注 | 无法做事件级评估 | 可由真值 RR 序列间接推 |
| 母体真值缺失 | 无独立母体心电通道 | 母体抑制的效果无法直接量化 | 可由直接导联反推近似 |
| 低频截断 | 1 赫兹高通 | ST 段等形态信息不在数据内 | 不能 |
| 标注口径单一 | 只有胎儿 QRS | 无法评估 P 波或 T 波 | 不能 |
九条里有八条是不可校正的,这不是缺陷清单,而是这份数据的实际边界。使用它的正确方式是:把这些边界写进论文的限制段,而不是假装它们不存在。
7.4 外部验证矩阵
「它能不能代表外面世界」这个问题,可以拆成四个方向分别回答。
| 验证方向 | 现状 | 结论 |
|---|---|---|
| 同机构、同类设备的另一批记录 | 无公开数据,除非自建 | 未知 |
| 不同国家的产程记录 | 无对照材料 | 未知,且很可能不同 |
| 非产程时段的孕妇腹壁记录(如产前检查) | 有其他数据集但无真值 | 无法直接对照 |
| 不同电极布局 | 本集固定为脐周四点 | 布局一变,结论未必成立 |
| 家用心电贴片等可穿戴设备 | 采不到直接胎心电 | 真值不可得,只能间接验证 |
| 早产与低体重胎儿 | 无覆盖 | 完全未知 |
7.4b DAIMS 二十四项检查
按数据集成熟度模型(DAIMS)逐项过一遍。二十四项里计「是」十二项、「部分」八项、「否」三项、「不适用」一项。判定口径是「以这份数据的定位(参考标准而言)是否够用」,而不是「按通用大数据集标准是否够用」。
| 维度 | 项 | 判定 | 依据 |
|---|---|---|---|
| 数据文档 | 目的说明 | 是 | 项目页摘要写明用于测试与评估新的胎儿心电处理技术 |
| 数据文档 | 采集方法 | 是 | 电极位置、参考位置、共模位置逐项给出 |
| 数据文档 | 采样率 | 是 | 项目页写 1 千赫兹,文件头每帧 5000 点可验算 |
| 数据文档 | 单位 | 是 | 头文件五个生理通道均为微伏 |
| 数据文档 | 许可 | 是 | ODC-BY 1.0,页面 Access 区明确 |
| 数据文档 | 版本与变更 | 部分 | 只有 1.0.0 一个版本,无变更日志可读 |
| 数据文档 | 引用格式 | 是 | 项目页给出 BibTeX、APA、MLA 等六种 |
| 数据质量 | 缺失值说明 | 否 | 人口学与临床变量整体缺失,文档未做说明 |
| 数据质量 | 异常值说明 | 部分 | 说明记录条件会影响信号质量,但未量化 |
| 数据质量 | 标注一致性 | 是 | 两级核验,在线检出加医师离线复核 |
| 数据质量 | 标注错误说明 | 否 | 未给出漏检率或医师分歧的估计 |
| 数据质量 | 时间信息 | 否 | 日期字段为占位值,无法还原采集时刻 |
| 数据代表性 | 人群说明 | 部分 | 只给孕周范围与产程中,无年龄分布 |
| 数据代表性 | 地理覆盖 | 部分 | 单一国家、单一医院 |
| 数据代表性 | 样本量说明 | 是 | 明确写 5 名,不虚报 |
| 数据代表性 | 入组标准 | 部分 | 说头皮电极有临床指征,未给具体指征清单 |
| 可访问性 | 无需申请 | 是 | 任何人可直接下载,无需注册 |
| 可访问性 | 单一入口 | 是 | 项目页、S3 桶、ZIP 三条路径 |
| 可访问性 | 完整性校验 | 是 | 提供 SHA256SUMS.txt,逐文件列出 |
| 可访问性 | 工具链支持 | 是 | 两个格式都有成熟读库 |
| 互操作性 | 标准格式 | 是 | EDF+ 与 WFDB 均为领域通用标准 |
| 互操作性 | 与检索库对接 | 是 | wfdb 支持按项目名直接读取 |
| 互操作性 | 与影像或其他模态关联 | 不适用 | 本数据不含影像与文本 |
| 可维护性 | 长期托管 | 是 | PhysioNet 托管,有 DOI |
7.5 它为何能持续:因为「有真值」这件事无法被规模化替代
一个只有五条记录的数据集,能在发布十几年后仍被反复引用,理由不是它做得好,而是它做的事情别人做不了。给不需要内监护的产妇放一只头皮电极,在伦理上通不过;不给,就拿不到真值。这个约束不会因为算力提升、因为模型变大而消失。
于是它成了一种基础设施:不新,不大,但缺了它,这个领域的「准确」二字就没有参照。它持续被使用的机制不是增长,而是不可替代。
§8 生态位与历史
8.1 从 2012 年说起
2012 年 8 月 9 日,PhysioNet 发布了这个数据库的 1.0.0 版。同年七月,Jezewski 与同事在 Biomedizinische Technik 第 57 卷第 5 期发表了配套论文,主题是从腹壁信号测定胎心率,并对照直接胎儿心电评估逐搏精度。
此后十二年,版本停在 1.0.0,没有任何升版记录。目录页里最新的时间戳是十二月的 RECORDS 与 2019 年二月的校验文件,两者都是维护性动作,不是内容更新。在一众不断加数据、加标注的数据集里,这种冻结本身就是一条信息:它的定位是参照物,不是持续生长的语料库。
8.2 算法演进中的位置
这个数据集被引用最多的场景,是作为「老办法」的基线。论文自己走的是模板相减加 QRS 检测的路线:先在腹壁上估计母体 QRS 的模板,减去之后再找胎儿的心搏。
往后二十年,方法换了几代。先是盲源分离把多路腹壁信号当成混合矩阵求解,再是奇异值分解与主成分分析把信号投影到低维。接着是自适应滤波与时空滤波(作者团队自己也发表过用时空滤波增强胎儿心电的工作)。再往后是匹配追踪、经验模态分解这些稀疏表示的方法。最近十年,卷积网络与自编码器成为主流,多数工作把母体抑制与胎儿检测合成一个端到端任务。
不管换成哪一代,验证的方式没变:拿一张有真值的表去对。§4.3 的案例在这方面格外有用——它把「母体成分大、胎儿成分小」的强度关系固定在一段可以复算的片段上,任何新方法都该先在这段上过一遍,再谈全量结果。
在 PhysioNet 外部,近年来的腹壁胎儿心电挑战数据提供了一个中间态:规模上去了,标注也有,但仍不是独立第二路真值。这类数据的价值在于训练与基准比较,短板在于「标注者认为的胎心位置」与「真实胎心位置」之间的差距无法测量。
把这条演进线拆成方法族与输入表征两列,会更清楚每一代各自解决了什么问题、各自留下了什么问题。
| 时期 | 方法族 | 输入表征 | 解决了什么 | 留下了什么 |
|---|---|---|---|---|
| 2000 年代 | 模板相减 + QRS 检测 | 单路或少数几路 | 证明了腹壁可测胎心的可行性 | 模板不匹配时残差变大 |
| 2000 年代中 | 盲源分离 | 多路腹壁 | 利用空间差异分离母胎 | 源数未知,顺序不定 |
| 2000 年代末 | 奇异值分解与主成分分析 | 多路腹壁 | 降维后母体成分更集中 | 线性假设过强 |
| 2010 年前后 | 自适应滤波与时空滤波 | 多路腹壁 | 利用导联间的时延关系 | 需要可靠的参考信号 |
| 2010 年代中期 | 匹配追踪与经验模态分解 | 单路 | 稀疏表示抓住瞬态 | 参数敏感,复现难 |
| 2010 年代末至今 | 卷积网络与自编码器 | 多路或单路 | 端到端,免人工设计 | 需要大量数据,真值稀缺 |
这张表的最后一列是整篇的另一个落点:方法越往右走,对训练数据的胃口越大,而真值的供给没有跟着增长。这就是为什么 adfecgdb 这种只有五条记录的小集,在新方法层出不穷的今天反而更有存在感——它不在左边,也不在右边,它在「判分」这一侧。
8.3 它的邻居们
在 PhysioNet 内部,最常被拿来与它并提的是非侵入式胎儿心电系列。那一系列提供了更多记录、更多导联布置,但没有直接胎心电,标注是专家在腹壁信号上给的。两者的定位清晰不同:系列给规模,adfecgdb 给真值。
在 PhysioNet 外部,近年来的腹壁胎儿心电挑战数据提供了一个中间态:规模上去了,标注也有,但仍不是独立第二路真值。这类数据的价值在于训练与基准比较,短板在于「标注者认为的胎心位置」与「真实胎心位置」之间的差距无法测量。
8.4 为什么它还在这里
一个发布十几年、只有五条记录、从未升版的数据集,至今仍在被引用,说明它在生态位里占住了一个位置:小样本真值集的唯一供给者。
这个位置在短期内不会被替代,原因在 §7.5 已经说过。它能被改进的方式只有两条:要么某个团队愿意做一次新的伦理学设计,在更多产程中系统采集直接胎心电;要么出现一种不需要直接电极就能给出可信真值的间接方法。前者受限于伦理与现实成本,后者是研究前沿,尚未成为通用工具。在那之前,这五条记录就是参照系本身。
§9 使用指引
9.1 三种角色的路径
不同的人打开这份数据,应该走三条不同的路。
算法研究者的路径最短:下载五条记录,用 §5.2 的代码读入,把 §5.5 的评分函数接到自己的输出上,按记录逐条报检出率、误检率、RR 误差的中位数与四分位距。重点是报离散度而不是平均值,因为五条记录之间的差异本身就是要传达的信息。
设备与工程人员的路径偏向结构:先读 §2.2 的头字段表,确认自己的设备在带宽、采样率、单位、量程上能否对齐;再看 §2.4 的逐条统计,判断五分钟、五条的规模是否够做一次内部验证。工程验证通常只需要「能不能跑通、误差有多大」,这份数据的规模恰好合适。
教学与复现者的路径偏向可解释性:从 §4.3 的案例出发,先复现「直接导联干净、腹壁导联混杂」这一现象,再手工解一遍注释(§5.3),最后用 wfdb 的解(§5.2)对照,体会两种解法为什么必须给出同一个答案。这个过程本身就是一节很好的信号处理课。
| 角色 | 第一件事 | 半小时内能达到的状态 | 最容易踩的坑 |
|---|---|---|---|
| 算法研究者 | 读入一条记录,对齐注释 | 跑通带真值的评分 | 忘了校正算法延迟 |
| 设备与工程人员 | 核对自己的采样与量程 | 判断能否直接接入 | 把微伏当毫伏 |
| 教学与复现者 | 画十秒对照图 | 看懂母胎强弱关系 | 以为腹壁信号可以直接用 |
| 临床研究者 | 读官方采集说明 | 判断人群是否匹配 | 拿它论证普适性 |
| 数据工程师 | 看文件清单与校验值 | 确认传输完整 | 用 .hea 去找头文件 |
关于「25 分钟能支撑什么、不能支撑什么」,可以压成一张两列的对照表。
| 研究问题 | 25 分钟能否支撑 | 理由 |
|---|---|---|
| 某种提取方法能不能跑通 | 能 | 五分钟足够跑完一次完整流程 |
| 两种方法的误差谁更小 | 能 | 同一批真值,对照组可比 |
| 误差在五条记录上的离散度 | 能 | 五条本身就是五个观测点 |
| 母胎 QRS 重叠时是否失手 | 部分 | 重叠事件可能出现,但样本太少不足以分层 |
| 算法在早产儿上的表现 | 不能 | 无早产记录 |
| 算法在不同医院的稳定性 | 不能 | 单一机构 |
| 算法在长时程上的漂移 | 不能 | 每条仅五分钟 |
| 端到端深度模型的训练 | 不能 | 五条记录必然过拟合 |
9.2 一条最短的可用流程
从零到「得到一条记录的胎儿心搏数与心率」,只需要五步,全部可以在一段脚本里完成。
#-- 第一步:装依赖
pip install wfdb numpy matplotlib
#-- 第二步:确认能连上 PhysioNet 并列出记录
python -c "import wfdb; print(wfdb.get_record_list('adfecgdb/1.0.0'))"
#-- 第三步:跑通最短闭环
python shortest.py
#-- shortest.py:读一条记录、读注释、算心率、留存一张对照图
import wfdb
import numpy as np
import matplotlib.pyplot as plt
NAME = "r01"
rec = wfdb.rdrecord(NAME, pn_dir="adfecgdb/1.0.0")
ann = wfdb.rdann(NAME, "qrs", pn_dir="adfecgdb/1.0.0")
fs = rec.fs
rr = np.diff(ann.sample) / fs
print(f"{NAME}: {len(ann.sample)} 个胎儿心搏,中位 RR {np.median(rr):.3f} s,"
f"胎心率 {60 / np.median(rr):.1f} 次/分")
lo, hi = 60 * fs, 70 * fs
fig, ax = plt.subplots(2, 1, figsize=(10, 5), sharex=True)
ax[0].plot(np.arange(lo, hi) / fs, rec.p_signal[lo:hi, 0], lw=0.8, color="#1f5f8b")
ax[0].set_ylabel("Direct_1 (uV)")
ax[1].plot(np.arange(lo, hi) / fs, rec.p_signal[lo:hi, 1:5], lw=0.6)
ax[1].set_ylabel("Abdomen 1-4 (uV)")
ax[1].set_xlabel("time (s)")
plt.tight_layout()
plt.savefig(f"{NAME}_60_70s.png", dpi=150)
这条流程的输出会与 §4.3 的案例对上:直接导联上有一条规则的大幅波形,四路腹壁导联的波形更杂,看不清胎儿那份。如果心率那一行给出的是个位数,说明注释解码走了错误路径,回到 §5.2 重新读一遍。
9.3 引用方式
规范的引用应包含两块。第一块是原始论文,这是数据真正的来源,也是审稿人最看重的部分:
Jezewski J, Matonia A, Kupka T, Roj D, Czabanski R. Determination of the fetal heart rate from abdominal signals: evaluation of beat-to-beat accuracy in relation to the direct fetal electrocardiogram. Biomedizinische Technik / Biomedical Engineering. 2012;57(5):383-394. doi:10.1515/bmt-2011-0130.
第二块是 PhysioNet 平台的引用,按项目页要求附上。目前页面上给出的平台引用是 2026 年发表在 Nature Health 上的 PhysioNet 综述,随平台更新而变,引用时以项目页当次显示为准。
还有一处容易被忽略:如果你用到的是 .qrs 注释,最好在方法段里写明注释的来源与核验方式,即「由系统在线检出、医师离线复核的胎儿 QRS 时刻」。这一句能让读者判断你的真值标准是什么,而不必去翻原始论文。
另外,许可为 ODC-BY 1.0,署名即可商用。如果你把这份数据或其衍生波形图放进产品文档、教学材料或论文附录,保留署名与 DOI 是唯一的形式要求。
§10 AI 使用声明
| 项目 | 说明 |
|---|---|
| 本页写作方式 | 由 AI 起草,依据官方页面与论文摘要,经人工校订 |
| 事实来源 | PhysioNet 项目页、目录页、RECORDS/ANNOTATORS/SHA256SUMS、EDF+ 文件头、Europe PMC 检索到的论文摘要 |
| 未使用的内容 | 未下载全量波形做分布统计,未逐字段审计数据 |
| 数字口径 | 规模、结构、边界三类;推导性数字标注了推导方式 |
| 已知误差 | 逐条心搏数一列来自简化解码,可能与 wfdb 结果有出入,已在正文说明 |
| 置信度 | 记录数、导联数、采样率、时长、格式、许可为高置信;逐条心搏数、时间字段为中等置信 |
| 时效 | 检索与核验时点为 2026 年 10 月 27 日;数据版本 1.0.0,自 2012 年起未变 |
| 责任边界 | 本页不构成对算法效果的承诺,具体误差需自行复现 |
常见误读(避坑清单)
| 常见说法 | 实际 | 证据 |
|---|---|---|
| 这是一个有几千条记录的胎儿心电库 | 只有 5 条记录,合计约 25 分钟 | RECORDS 五行;项目页摘要「5 different women」 |
| 五路信号都是腹壁导联 | 是 1 路直接胎心电 + 4 路腹壁导联 | EDF 头通道标签 Direct_1、Abdomen_1–Abdomen_4 |
| 直接导联是另一种非侵入测量 | 是经宫颈的螺旋头皮电极,有创 | 项目页写明「spiral electrode」「clinical indication」 |
| 采样率是 250 或 500 赫兹 | 是 1000 赫兹,全部通道同步 | 头文件每帧 5000 点 / 5 秒;项目页「Sampling rate: 1 kHz」 |
| 每个文件里有个 .hea 头文件 | 没有,波形是 EDF+,头信息在 .edf 文件内部 | 目录页只有 .edf、.edf.qrs 与三份清单 |
| 注释是纯文本,一行一个时刻 | 是 WFDB 二进制注释,16 位增量编码 | 文件以 ## time resolution: 1000 开头,之后是二进制 |
| 有了它就能训练端到端模型 | 五条记录只能当测试集或外部验证集 | 规模与记录数;文献普遍把它当评测集 |
| 腹部信号里最明显的周期波是胎心 | 多数是母体 QRS,胎儿成分更小 | §4.3 的案例:腹壁峰值处直接导联近零 |
| 标注包含母体与胎儿两种心搏 | 只有胎儿 QRS,母体未标 | ANNOTATORS 只声明 qrs;项目页只提 fetal R-wave |
| 数据可以按采集日期排序做趋势分析 | 日期字段是占位值 01.01.11 00.00.00 |
EDF 主头 168–183 字节 |
| 直接导联可以直接当患者的完整心电用 | 带宽 1–150 赫兹,低频被滤掉,ST 段不在其中 | 项目页带宽说明;头文件预滤波 LP:150Hz |
| 这是最新版,可以放心用一辈子 | 版本冻结既是优点也是约束,已知缺陷不会被修复 | 页面版本停在 1.0.0,无更新记录 |
FAQ
Q1:这 5 名产妇是什么情况?
官方只给了孕周范围 38 到 41 周、都在产程中两条信息。年龄、孕次、产次、分娩方式、是否有妊娠并发症,一概没有。文件头的患者字段是「记录名 + F + 两处占位」,也不含年龄。要写方法段的「研究对象」,只能写「5 名处于产程中的足月前后产妇」。
Q2:为什么记录编号是 r01、r04、r07、r08、r10,中间缺了?
编号不连续说明原始队列里还有别的记录,只是没有公开发布。页面只说贡献了 5 条记录,没有解释筛选标准。可以合理推测是完整性或质量筛选,但这是推测,官方没有说明。
Q3:每条记录真的正好是五分钟吗?
是。头文件写的是 60 个记录帧、每帧 5 秒,乘积 300 秒。文件字节数也正好等于这个长度对应的数据量加 1792 字节头。这个数字可以逐字节验算,不是约数。
Q4:.qrs 里一个心搏对应几个字节?
不是固定对应。WFDB 16 位注释是压缩的,每个心搏占一个 16 位字,但文件开头还有若干 ## 头块。所以文件大小只能给出心搏数的上限估计,实际心搏数要解码后才知道。
Q5:我能用它做深度学习吗?
能用来评估,不宜用来训练。五条记录大约三千多个胎儿心搏,训练一个从零开始的网络会严重过拟合;用来做外部验证、比较两个方法在同一批真值上的误差,则是合适且常见的用法。
Q6:要不要自己做母体抑制?
取决于你的任务。如果你在验证端到端的提取算法,应该直接把四路腹壁作为输入,让算法自己处理;如果你在验证母体抑制这一步,需要先解决「母体真值从哪来」的问题,而这份数据没有独立母体通道。
Q7:直接导联能不能当一个干净的胎心电模板用?
可以,而且这是它最直接的用途之一。把直接导联的 QRS 模板取出来,与算法在腹壁上的提取结果做形态比对,是一个不依赖标注的额外检查。注意直接导联的导联位置与腹壁完全不同,形态不会完全一致,只能比时间与大致轮廓。
Q8:数据里有宫缩信息吗?
没有。没有宫缩曲线(TOCO)、没有内压、没有任何事件标签。要做宫缩与胎心的耦合分析,得另找数据。这也是 §1.6 第四条边界的直接来源。
Q9:文件这么小,是不是被压缩或抽样过?
不是。五分钟、一千赫兹、十六位、五路,乘起来就是这个量级:300 秒 × 1000 × 5 路 × 2 字节 ≈ 3 兆字节,与目录页给出的单文件大小一致。小是因为记录短,不是因为被抽稀。
Q10:可以商用吗?
可以。许可为 ODC-BY 1.0,唯一要求是署名。把数据、基于它训练的模型、或由它生成的图表用于商业产品,都在许可允许范围内,但必须保留对原始论文与数据集的署名。
Q11:PhysioNet 页面上的「项目浏览量」能当引用量看吗?
不能。那是页面访问计数,不是学术引用计数。要引用量应该去 Europe PMC 或 Google Scholar 查原始论文的被引次数。
Q12:如果我发现数据有问题,该找谁?
先在同一份数据的官方文档与论文里核对,确认不是自己读错。PhysioNet 的联系作者信息需要登录才能查看。多数历史上的「问题报告」最后被证明是解码错误——比如本文 §2.4 里那两个不合理的心率列。
术语表
| 术语 | 英文 / 缩写 | 在本数据集语境中的含义 |
|---|---|---|
| 腹壁胎儿心电 | abdominal fECG | 从母亲腹部表面记录到的、混有母体成分的胎儿心电 |
| 直接胎儿心电 | direct fECG | 从胎儿头皮直接取得的胎儿心电,无母体污染 |
| 母体心电抑制 | maternal ECG suppression | 从腹壁信号中减除母体 QRS 的处理步骤 |
| 胎儿 QRS 检测 | fetal QRS detection | 定位胎儿心搏时刻的任务 |
| 金标准 | gold standard | 可用来判定其他测量是否正确的参照,本数据指直接导联 |
| 胎心率 | FHR, fetal heart rate | 单位时间内的胎儿心搏数,由 QR 时刻间隔换算 |
| 逐搏变异 | beat-to-beat variability | 相邻 RR 间隔的短时波动,反映胎儿自主神经状态 |
| 头皮螺旋电极 | spiral scalp electrode | 经宫颈固定于胎儿先露部位的螺旋形电极 |
| 胎心内监护 | internal fetal monitoring | 使用直接电极的产时监护方式,需破膜 |
| 多普勒胎心监护 | Doppler CTG | 用超声多普勒测胎心的常规无创手段 |
| 脐周四点布局 | periumbilical array | 四只电极围绕脐部放置,构成四路差分 |
| 共模参考 | common mode reference | 接在左腿、带主动接地的公共参考 |
| 差分导联 | differential lead | 记录两个电极之间电位差的导联形式 |
| EDF+ | European Data Format Plus | 欧洲数据格式的扩展版,支持注释通道与连续记录 |
| WFDB | Waveform Database | PhysioNet 的波形与注释标准及工具集 |
| 注释文件 | annotation file | 记录事件时刻的二进制文件,本数据后缀 .qrs |
| 记录帧 | data record | EDF 中固定时长的一段数据,本数据每帧 5 秒 |
| 物理量程 | physical range | 数字值可映射到的物理量范围,本数据 ±3276.8 微伏 |
| 增益 | gain | 物理量程与数字量程之比,本数据约 0.1 微伏每单位 |
| 工频抑制 | power-line notch | 50 赫兹梳状滤波,去电网干扰 |
| 基线漂移 | baseline wander | 电极极化与运动引起的低频漂移,已数字滤除 |
| 检出率 | recall / sensitivity | 真值心搏中被正确检出的比例 |
| 误检率 | false positive rate | 检出结果中不对应真值心搏的比例 |
| 容差 | tolerance window | 判定检出与真值「同一搏」的时间窗,常用 50 毫秒 |
| 母胎重叠 | maternal-fetal coincidence | 母体与胎儿 QRS 在时间上靠近甚至重合的现象 |
| 盲源分离 | BSS | 把多路观测分解为若干独立源的方法族 |
| 时空滤波 | spatio-temporal filtering | 同时利用空间导联与时间结构的滤波方法 |
| 冻结版本 | frozen version | 长期不再更新的发布版本,本数据自 2012 年起未变 |
附录 A:核心数字核对表
| 项 | 值 | 来源 | 来源层级 |
|---|---|---|---|
| 记录条数 | 5 | RECORDS 文件五行;项目页摘要 | 官方页面 |
| 受试人数 | 5 名产妇 | 项目页摘要 | 官方页面 |
| 孕周范围 | 38–41 周 | 项目页摘要 | 官方页面 |
| 记录时长 | 每条 5 分钟 | 项目页;头文件 60 帧 × 5 秒 | 官方页面 + 文件头 |
| 总时长 | 约 25 分钟 | 5 × 5 分钟推导 | 推导 |
| 生理通道数 | 5 | 头文件通道数 6 减去 1 个注释通道 | 文件头 |
| 腹壁导联数 | 4 | 通道标签 Abdomen_1–4;项目页 | 文件头 + 官方页面 |
| 直接导联数 | 1 | 通道标签 Direct_1;项目页 | 文件头 + 官方页面 |
| 采样率 | 1000 赫兹 | 项目页;头文件每帧 5000 点 | 官方页面 + 文件头 |
| 位深 | 16 位 | 项目页;数字上下限 ±32768 | 官方页面 + 文件头 |
| 每帧采样点数 | 5000 | 头文件 | 文件头 |
| 记录帧数 | 60 | 头文件 | 文件头 |
| 头长度 | 1792 字节 | 头文件 | 文件头 |
| 单文件字节数 | 3,061,792 | 目录页文件列表 | 官方页面 |
| 未压缩总体积 | 14.6 兆字节 | 项目页 Files 区 | 官方页面 |
| 文件格式 | EDF+ | 头文件保留区 EDF+C;目录列表 | 文件头 + 官方页面 |
| 注释格式 | WFDB 16 位 | 文件头 ## time resolution: 1000 |
文件头 |
| 通道单位 | 微伏 | 头文件 | 文件头 |
| 带宽 | 1–150 赫兹 | 项目页 Recording information | 官方页面 |
| 工频抑制 | 50 赫兹 | 项目页;头文件 CombF:50Hz | 官方页面 + 文件头 |
| 电极型号 | 3M Red Dot 2271 | 项目页 | 官方页面 |
| 许可 | ODC-BY 1.0 | 项目页 License 区 | 官方页面 |
| DOI | 10.13026/C2RP4B | 项目页 Discovery 区 | 官方页面 |
| 发布日期 | 2012-08-09 | 项目页标题下 | 官方页面 |
| 版本号 | 1.0.0 | 项目页 | 官方页面 |
| 逐条心搏数 | 644 / 632 / 627 / 651 / 649 | 本批对 .qrs 的简化解码 | 推导,待 wfdb 复核 |
| 时间字段 | 01.01.11 00.00.00 | EDF 主头 168–183 字节 | 文件头,判定为占位值 |
附录 B:数字的来源分层
第一层,官方页面。 项目页的摘要与 Recording information 段,目录页的文件列表与字节数,三份清单文件的内容。这一层的数字可以直接引用,不需要加限定语。本文里的记录数、导联数、采样率、位深、带宽、许可、DOI、发布日期、单文件字节数、总体积,全部属于这一层。
第二层,论文摘要。 原始论文的摘要确认了几件事:记录在产程中采集,每条含四路腹壁信号与一路头皮直接参考,作者的方法是母体信号抑制加胎儿 QRS 检测,并给出了「间接法能提供足以评估胎心率变异的精度,但对记录条件非常敏感」的结论。这一层不提供新的数量,但提供了这些数量的语境。
第三层,文件头与推导。 EDF+ 头的字段值、由文件字节数与结构算式得到的每帧长度、由记录数与时长得到的总时长、由心搏数除以时长得到的心率,都属于这一层。它们的可靠性取决于推导是否正确,因此本文对每一个推导都写出了算式。
特别标注:需要保留的不确定。 逐条心搏数一列来自简化解码,可能与 wfdb 的正确结果有出入。本文没有把它抹去重写,而是把简化过程与两个不合理的心率列一并留在表里,让后来者一眼看到「粗解码会得到什么」。这是有意为之的诚实,而不是疏漏。
附录 C:完整参考文献
- Jezewski J, Matonia A, Kupka T, Roj D, Czabanski R. Determination of the fetal heart rate from abdominal signals: evaluation of beat-to-beat accuracy in relation to the direct fetal electrocardiogram. Biomedizinische Technik / Biomedical Engineering. 2012;57(5):383-394. doi:10.1515/bmt-2011-0130.
- Abdominal and Direct Fetal ECG Database, version 1.0.0. PhysioNet. 2012-08-09. doi:10.13026/C2RP4B. URL: https://physionet.org/content/adfecgdb/1.0.0/
- Matonia A, Jezewski J, Kupka T, Horoba K, Wrobel J, Gacek A. The influence of coincidence of fetal and maternal QRS complexes on fetal heart rate reliability. Medical & Biological Engineering & Computing. 2006;44(5):393-403.(项目页 Related Publications 列出)
- Kotas M, Jezewski J, Horoba L, Matonia A. Application of spatio-temporal filtering to fetal electrocardiogram enhancement. Computer Methods and Programs in Biomedicine. 2011;104(1):1-9.(项目页 Related Publications 列出)
- Kotas M, Jezewski J, Matonia A, Kupka T. Towards noise immune detection of fetal QRS complexes. Computer Methods and Programs in Biomedicine. 2010;97(3):241-256.(项目页 Related Publications 列出)
- Pollard T, Moody BE, Lehman L, et al. PhysioNet as a global platform for biomedical research. Nature Health. 2026. doi:10.1038/s44360-026-00096-z.(项目页给出的平台引用,随平台更新)
附录 D:任务代码
以下是三个可以直接跑的小工具,各自解决一个具体问题。
#-- 工具一:核算文件是否完整下载
import hashlib
import os
EXPECTED_BYTES = 3_061_792
def verify(path):
size = os.path.getsize(path)
h = hashlib.sha256(open(path, "rb").read()).hexdigest()
ok = size == EXPECTED_BYTES
print(f"{path:16s} {size:10d} 字节 {'OK' if ok else '尺寸异常'} sha256={h[:16]}")
for name in ["r01.edf", "r04.edf", "r07.edf", "r08.edf", "r10.edf"]:
verify(name)
#-- 工具二:直接从 EDF 头读出该记录的全部规格
def edf_spec(path):
with open(path, "rb") as fh:
head = fh.read(1792)
nsig = int(head[252:256])
nrec = int(head[236:244])
dur = float(head[244:252])
labels = [head[256 + i * 16: 256 + (i + 1) * 16].decode("latin1").strip()
for i in range(nsig)]
base = 256 + 256 * nsig
nsamp = [int(head[base + 216 * nsig + i * 8:
base + 216 * nsig + (i + 1) * 8]) for i in range(nsig)]
return dict(nsig=nsig, seconds=nrec * dur, labels=labels,
fs=[n / dur for n in nsamp], bytes=nrec * sum(nsamp) * 2 + 256 * (1 + nsig))
print(edf_spec("r01.edf"))
#-- 工具三:用 wfdb 拿到可信的心搏序列,并与简化法对照
import wfdb
import numpy as np
def trusted_beats(name):
ann = wfdb.rdann(name, "qrs", pn_dir="adfecgdb/1.0.0")
t = ann.sample / 1000.0
rr = np.diff(t)
return t, rr
t, rr = trusted_beats("r01")
print("心搏数 ", len(t))
print("首搏时刻 ", round(float(t[0]), 3), "秒")
print("末搏时刻 ", round(float(t[-1]), 3), "秒")
print("中位 RR ", round(float(np.median(rr)), 3), "秒")
print("胎心率 ", round(60 / float(np.median(rr)), 1), "次/分")
print("RR 标准差 ", round(float(np.std(rr)), 4), "秒")
第三个工具的输出,正是附录 A 里那一行「逐条心搏数」应该被复核成的样子。把三个工具连起来跑,就完成了这份数据从下载完整性、结构自洽性到标注可信性的三级检查。
附录 E:如果只记五件事
第一,它是五条记录,不是五万条。任何关于规模的期待都要在打开它之前调整好。
第二,它的价值是真值,不是数据量。头皮直接胎心电让它成为能算误差的评测集,这个功能无法被更大的无真值数据替代。
第三,四路腹壁里最显眼的是母亲,不是胎儿。看不懂这一点,会把整份数据用错。
第四,它的边界写在伦理里而不是技术里。有创电极的代价决定了这个领域至今只能用小样本,扩大规模不是工程问题。
第五,它是判分器,不是教材库。把它当测试集用,价值最大化;当训练集用,五个样本会立刻告诉你什么叫过拟合。
编辑说明
本页依据 PhysioNet 项目页、目录页、三份清单文件与 EDF+ 文件头,以及 Europe PMC 检索到的原始论文摘要撰写,核验时点为 2026 年 10 月 27 日。波形层面只取用了 r01 的首帧与首七个数据帧做结构核对,未下载全量数据做分布统计,因此凡涉及分布的数字均为推导值并已标注推导方式。
逐条心搏数一列采用简化解码得到,与 wfdb 的正确结果可能存在出入,正文保留了这一列以及由它导出的两个不合理心率,用意是展示粗解码的失败形态,而非给出可信心率。正式引用时应以附录 D 第三个工具的输出为准。
封面提示词采用工程制图风格,与全站胎儿心电相关词条的视觉基调保持一致。
相关数据集导航
以下为站内 AI-Ready 数据集百科中与本词条共享多个主题标签的相关数据集,按相关度降序排列:
- fecgsyndb — 共享标签:生理信号 / 心电信号 / 评测基准
- qt-database — 共享标签:生理信号 / 心电信号 / 评测基准
- vtac — 共享标签:生理信号 / 心电信号 / 评测基准
- propofol-anesthesia-dynamics — 共享标签:生理信号 / 心电信号 / 评测基准
- nifeadb — 共享标签:生理信号 / 心电信号 / 评测基准
- actes-cycloergometer-exercise — 共享标签:生理信号 / 心电信号 / 评测基准
- deepfake-ecg — 共享标签:生理信号 / 心电信号 / 评测基准
- ecgiddb — 共享标签:生理信号 / 心电信号 / 评测基准
- macecgdb — 共享标签:生理信号 / 心电信号 / 评测基准
- cdb — 共享标签:生理信号 / 心电信号 / 评测基准
导航说明:本章节由全站统一标签体系自动计算生成(标签重合度算法),双向可达;点击链接可跳转至对应数据集词条。

