录到死亡的二十三盘磁带 — SDDB 猝死长程心电库

23 段长程 Holter / 4–25 小时 250 Hz / 12 份审校心搏标注

来源 https://physionet.org/content/sddb/1.0.0/发布时间: 2026-10-29最后更新: 2026-10-29 阅读 4
录到死亡的二十三盘磁带 — SDDB 猝死长程心电库

信息速览

数据集名称录到死亡的二十三盘磁带 — SDDB 猝死长程心电库
数据类型时序信号,波形,人工标注,元数据
规模23 名患者 / 23 段记录
接入方式https://physionet.org/content/sddb/1.0.0/
AI 就绪度

心源性猝死最残酷的地方不是它致命,而是它几乎从不被完整记录。一个人在院外倒下,从窦性心律走到心室颤动往往只花几分钟;等急救人员到达、电极贴上、监护仪开机,记录下来的大多已经是心电静止,或者心肺复苏按压留下的大片伪迹。真正有科学价值的那段窗口——最后一次正常心搏之后,室性早搏怎样逐渐增多、怎样成对成串、怎样演变为室性心动过速、怎样蜕变为心室扑动与颤动、最后怎样停下来——在临床记录里几乎是空白。要拿到这一段,只可能靠一件事:患者倒下的那一刻,身上恰好戴着 Holter。

SDDB 就是一批"恰好"的带子。SDDB 猝死长程心电库(Sudden Cardiac Death Holter Database)由 PhysioNet 于 2004 年 7 月 2 日发布,版本 1.0.0,主体是 23 段完整的双通道长程心电记录,单段从 3 小时 56 分到 25 小时 8 分不等,采样率 250 Hz。全部 23 名患者都在记录期间发生了持续性室性心动过速,其中多数发生了真正的心脏骤停。这些数据主要采集于 1980 年代的波士顿地区医院,由当时在 MIT 的 Scott Greenwald 为室性心律失常研究而汇编。

它的代价与它的价值同样极端:只有 23 段、两通道、患者信息大量缺失、审校过的心搏标注只覆盖其中 12 段。它不是一个"规模够用"的训练集,而是一批在伦理与技术上都不可能重新采集的原始素材。一屏速览见下表。

维度 内容
全名 Sudden Cardiac Death Holter Database
发布方 PhysioNet(记录由 Scott Greenwald 在 MIT 期间采集并汇编)
首次发布 2004 年 7 月 2 日,版本 1.0.0
最近改动 仅一个版本,无后续修订记录
记录数 23 段,编号 30–52
患者数 23 名(官方未给出统一人口学统计)
单段时长 3:56:00(记录 41)至 25:08:30(记录 51)
通道数 2(头文件未标注导联名,两通道均标记为 ECG)
采样率与分辨率 250 Hz,格式 212 打包存储,12 位 ADC 分辨率
增益 多数记录 800 ADC 单位/毫伏;记录 39 与 47 为 200
原始来源 1980 年代波士顿地区医院的 Holter 记录
底层心律构成 18 例窦性(含 4 例间歇起搏)、1 例持续起搏、4 例心房颤动
标注规模 23 份未审校算法标注(.ari)+ 12 份审校参考标注(.atr)
标注生成方式 算法自动初标;其中 12 段经人工逐搏审校
文件格式 WFDB:.hea 头文件 / .dat 信号 / .ari 与 .atr 注释
总体积 未压缩 1.1 GB,共 110 个文件
许可 Open Data Commons Attribution License v1.0(ODC-BY 1.0),无需注册
DOI 10.13026/C2W306
典型用途 室颤检测与预警、室性心律失常演进分析、除颤算法评估、猝死前驱信号研究

§1 它要解决的具体麻烦

1.1 猝死研究的证据缺口:临床记录不到那段

心电数据的公开生态里,绝大多数库回答的是"如何识别已经发生的异常"。MIT-BIH 心律失常库回答的是心搏形态怎么分;房颤类库回答的是心房活动怎么判;ST 类库回答的是缺血怎么定。这些任务的共同前提是:异常已经出现在那段被公开的记录里,研究者只要学会认出它。

猝死研究面对的是另一个问题:异常还没发生,而你需要提前几分钟知道它要发生。这个问题在数据层面几乎无解,因为能用来监督训练的"正样本"必须是真实的、连续的、从稳定状态一路走到致死性心律失常的整段过程,而这类过程在临床上绝大多数没有被记录。院外骤停的患者身上没有电极;院内监护的患者往往已经在干预之下,心电形态被药物、起搏、按压改写。

于是出现了一个近乎悖论的处境:最能推动预警算法进步的数据,恰恰是最不可能被前瞻性采集的数据。SDDB 的存在依赖于一次纯粹的历史巧合——一批 1980 年代做的 Holter 检查,恰好碰上了患者在这次检查期间发生致死性事件。这不是设计出来的队列,是筛出来的幸存样本。

1.2 三条常见的错误期待

第一条,期待它有清晰的临床标签。官方页面明确说:患者信息有限,有时完全缺失,包括用药方案与剂量。它给的是一张 23 行的临床信息表,性别、年龄、病史、用药、底层心律五列,其中"Unknown"反复出现。想用它做"某种药物是否延长了室颤前驱期"这类研究,从一开始就没有数据支撑。

第二条,期待它是"室颤检测的标准基准库"。它确实常被拿来测室颤检测器,但它不适合当唯一基准:样本只有 23 段,且底线心律不齐(18 例窦性、4 例房颤、1 例起搏),不同底层心律下的检测难度差异极大。用它报一个总准确率,等于把异质的人群混成一个数字。

第三条,期待标注是完整的参考标准。官方在发布公告里写得很清楚:该库包含一套未经审校的心搏标注文件,以及一套不完整的审校标注文件,并公开邀请研究者参与补全。也就是说,23 段里只有 12 段有人工审校过的标注,剩下的 11 段只有算法初标。把 .ari 当金标准用,是把算法的错误当成监督信号。

1.3 它能给到的与给不到的

你的需求 它给的 够不够
致死性室性心律失常的完整演进过程 23 段连续长程记录,多数录到心脏骤停 够,这是它唯一无可替代的地方
室颤起始时刻的粗定位 20 段在头文件里带 #vfon 注释,给出室颤起始的已历时刻 够做对齐,不够做逐搏界标
心搏级别的形态分类 12 段有审校标注,23 段有算法标注 够做评测,不够做大规模训练
室颤检测算法的外部测试 真实发生的室颤,非模拟、非叠加 够,且是少数能提供真实终末事件的库
除颤决策算法的评估 长时程背景 + 真实终末事件 可做,但通道数只有 2,看不到导联间关系
猝死风险的前瞻性预测建模 有终末事件,但无随访、无对照组 不够,23 段全是"发生了"的病例,没有"没发生"的
药物与心律关系的分析 用药列大量标注为 Unknown 不够,官方明确说明剂量信息缺失
导联间差异或十二导联形态学研究 两通道,且无导联名 完全不够

1.4 你的处境与它能帮到的事

你的处境 它能帮你什么 下一步该做什么
你在做室颤检测,但现有测试集的室颤是人工标注的短片段 提供真实发生、连续演化到室颤的长记录 按 #vfon 前后切窗,分别报告预警提前量与误报率
你在做可植入或体外除颤器的放电决策逻辑 长程背景里混着起搏、房颤、室早、室速多种心律 把 40、42、49 三段(官方注明无室颤)当阴性对照
你想研究室颤前的自主神经或心率动力学前兆 单段最长超过 25 小时,室颤前有数十小时稳定期 用审校过的 12 段做,避免算法标注引入虚假心搏
你在写综述,需要说明猝死数据的稀缺程度 它是"这类数据全球公开量极小"的直接证据 引用官方页面的规模与限制描述,不要夸大
你想复现 1980 年代的室颤检测器结果 官方参考文献即 Greenwald 1986 年硕士论文 注意该论文用的是同批记录的半小时摘录,不是全集
你需要一批"噪声真实、基线漂移真实"的长程数据 1980 年代模拟磁带转录,噪声特性与现代数字记录不同 做鲁棒性评测是好材料,做绝对性能基准要注明来源年代

1.5 一句话判断

它不适合当"更大更好的训练集",而适合当"唯一能回答某个问题的证据":人从活着的心律走到致死性心律失常,中间那几十分钟到底长什么样。

1.6 不适合谁:四条边界

不适合做统计意义上的风险建模。 23 段全部是发生了事件的病例,库内没有对照组。任何基于它的"预测"都是在没有负样本的情况下拟合,得不出可外推的风险估计。

不适合当心搏分类的主粮仓。 12 段审校标注的体量,对现代深度学习模型来说是几分钟就能记住的规模。它在这个任务上的角色是外部测试,不是训练来源。

不适合做药物、剂量、干预相关的任何分析。 官方原话是患者信息有限、有时完全缺失,包括用药方案与剂量。临床信息表里"Unknown"占了相当比例,这是官方承认的缺陷,不是数据整理疏漏。

不适合做导联相关的形态学研究。 只有两个通道,头文件里两个信号的描述字段都是 ECG,没有给出导联名。任何需要知道"这是哪个导联"的分析都无从下手。

§2 数据构成与规格

2.1 一段记录由四个文件组成

数据库采用 WFDB(Waveform Database)格式,这是 PhysioNet 自 1980 年代沿用至今的物理信号存储规范。每一段记录对应同名的一组文件:.hea 是纯文本头文件,声明采样率、信号条数、增益、初始值、校验和,并附带采集来源与室颤起始时刻的注释;.dat 是二进制信号本体,按采样点交错存放两个通道的整数值;.ari 是未经审校的算法心搏标注;.atr 是经人工审校的参考心搏标注,只有 12 段有。

目录里还有一个容易被忽略的 .hea-,23 段各一份。它是头文件的早期版本副本,正文与现行 .hea 只差最后一列:现行版两个信号的描述字段写的是 ECG,而 .hea- 里写的是 record 30, signal 0 与 record 30, signal 1。这个差别本身就在说明一件事——官方从未为这两个通道确认过导联身份。附带清单还有 RECORDS(23 行记录名)、ANNOTATORS(两行,说明两种注释扩展名的角色)、SHA256SUMS.txt(校验和)、vf-30.png(记录 30 的波形图)与两个 index 页面文件。

2.2 字段与信息的完整字典

需要强调:这里的"字段"不是表格列,而是 WFDB 头文件的关键字行、信号行与注释行。

信息项 所在位置 取值形态 含义 使用注意
记录名 .hea 第 1 行首字段 30–52 记录标识 纯数字,字面量就是文件名前缀
信号条数 .hea 第 1 行第 2 字段 2 通道数 全部 23 段均为 2
采样率 .hea 第 1 行第 3 字段 250 每秒采样点数 全部 23 段一致
采样点数 .hea 第 1 行第 4 字段 如 22099250 记录总长度 除以 250 即秒数
起始时刻 .hea 第 1 行第 5 字段 如 12:00:00 记录开始挂钟时间 多数为 12:00:00,少数是真实时刻
文件名 .hea 信号行第 1 字段 30.dat 信号存放位置 两通道共用同一个 .dat
存储格式 .hea 信号行第 2 字段 212 两通道 12 位打包 不是 16 位,也不是浮点
增益 .hea 信号行第 3 字段 800 或 200 ADC 单位/毫伏 记录 39、47 为 200,其余为 800
位分辨率 .hea 信号行第 4 字段 12 ADC 位数 与格式 212 配套
ADC 零值 .hea 信号行第 5 字段 0 零电平对应的整数值 换算时先减零值
初始值 .hea 信号行第 6 字段 如 51 首采样点整数值 用于校验读取是否对齐
校验和 .hea 信号行第 7 字段 如 -24065 采样点累加和 用于校验 .dat 完整性
块大小 .hea 信号行第 8 字段 0 每帧字节数 由 wfdb 按格式自动计算
信号描述 .hea 信号行第 9 字段 ECG 通道含义 两通道相同,无导联名
采集来源 .hea 注释行 #Produced by xform… 转录工具与起始偏移 xform 与 xform_new 两种
室颤起始 .hea 注释行 #vfon: 07:54:33 室颤起始的已历时刻 40、42、49 三段无此行
心搏位置 .ari / .atr 采样点序号 事件发生时刻 除以 250 得秒数
心搏类型 .ari / .atr 类型码 如 N、V、F 沿用 PhysioBank 标准定义
注释角色 ANNOTATORS 两行文本 ari 未审校 / atr 参考 决定该不该当金标准

心搏类型码沿用 PhysioBank 的标准定义。本库涉及的心律以室性为主,最常出现的几类如下:

类型码 含义 映射到 AAMI 五分类
N 正常心搏 N
L 左束支阻滞心搏 N
R 右束支阻滞心搏 N
A 房性早搏 S
a 伴差异性传导的房性早搏 S
J 交界性早搏 S
S 室上性早搏或异位搏动 S
V 室性早搏 V
r R-on-T 室性早搏 V
F 室性融合波 F
f 起搏与正常心搏融合 F
/ 起搏心搏 Q
Q 无法分类的心搏 Q
! 心室颤动波 通常单列,不进入五分类

最后一行值得单独说。室颤期间的心搏无法按常规方式逐搏定义,PhysioBank 用 ! 标记颤动波。如果你的流程把 ! 直接丢进 AAMI 五分类,会把一整段室颤压成若干"未知心搏",从而丢掉最关键的标签。

2.3 一条记录的完整解剖

以记录 30 为例。头文件第一行:

30 2 250 22099250 12:00:00

含义依次是:记录名 30,2 个通道,250 Hz,共 22099250 个采样点,起始挂钟时刻 12:00:00。22099250 ÷ 250 = 88397 秒,即 24 小时 33 分 17 秒——与官方表格里记录 30 的时长一栏完全一致。这种一致性是全库的普遍情况:头文件给出的采样点数除以 250,就是官方表格里的时长。

接下来两行信号声明:

30.dat 212 800 12 0 51 -24065 0 ECG
30.dat 212 800 12 0 145 21051 0 ECG

从右往左读:描述 ECG;块大小 0;校验和 -24065;初始值 51;ADC 零值 0;位分辨率 12;增益 800;存储格式 212;文件名 30.dat。第二通道除初始值 145 与校验和 21051 外完全相同。增益 800 意味着 800 个整数值对应 1 毫伏,约 1.25 微伏/单位。

最后两行注释给出它的身份与关键事件:

#Produced by xform_new from record 30, beginning at 26:35.000
#vfon: 07:54:33

第一行说明这段信号是用 xform_new 从原始磁带的第 26 分 35 秒开始转录的——也就是说,公开的记录起点不是原始 Holter 的起点,前面那段被截掉了。第二行是本库最重要的元数据:室颤起始于记录开始后的 7 小时 54 分 33 秒。换算成采样点,就是第 7132500 个采样点附近。

读取信号与标注的标准写法:

import wfdb

#-- 远程直读,无需先下载;pn_dir 指向 PhysioNet 上的库名
rec = wfdb.rdrecord('30', pn_dir='sddb')
ari = wfdb.rdann('30', 'ari', pn_dir='sddb')    #-- 未审校算法标注,23 段全有
atr = wfdb.rdann('30', 'atr', pn_dir='sddb')    #-- 审校参考标注,仅 12 段有

print(rec.fs, rec.sig_len, rec.sig_name)   #-- 250 22099250 ['ECG', 'ECG']
print(rec.p_signal.shape)                  #-- (22099250, 2) 已换算成毫伏
print(rec.comments)                        #-- 采集来源与 #vfon 注释
print(len(ari.sample), len(atr.sample))

p_signal 是已按增益与零值换算过的浮点毫伏值;需要原始整数用 d_signal。注意 rec.sig_name 返回的是 ['ECG', 'ECG'],不是导联名——这一点在写论文的"数据"一节时必须如实说明。

2.4 记录与标注的映射:23 对 12

这是本库最容易出事的一处结构。23 段记录各有 .ari,但只有 12 段另有 .atr:30、31、32、34、35、36、41、45、46、49、51、52。剩下 11 段(33、37、38、39、40、42、43、44、47、48、50)没有审校标注。

标注扩展名 段数 覆盖的记录 官方定义 可否当金标准
.ari 23 全部 30–52 unaudited beat annotations 不可,算法初标未过人工
.atr 12 30、31、32、34、35、36、41、45、46、49、51、52 reference beat annotations 可,但仍需注意室颤段的心搏定义
无 11 33、37、38、39、40、42、43、44、47、48、50 无 需自行标注或只用信号

ANNOTATORS 文件只有两行,把这件事写得很直白:ari 是 unaudited beat annotations,atr 是 reference beat annotations。官方在发布公告里的措辞是"一套未经审校的心搏标注文件,以及一套不完整的审校标注文件",并公开征集研究者参与补全。

这个结构决定了两种完全不同的用法。做心搏分类评测,只应该用那 12 段;做室颤检测或长时程演化分析,23 段都可以用,因为这类任务依赖的是信号本身与室颤起始时刻,而不是逐搏标签。混淆这两者是本库最常见的误用。

2.5 与同类资源的字段差异

对比项 SDDB MIT-BIH 恶性室性心律失常库 MIT-BIH 心律失常库 长期 ST 库 INCART
记录数 23 22 48 86 75
单段时长 3:56–25:08 约 30 分钟 约 30 分钟 21–24 小时 30 分钟
通道数 2 2 2 2–3 12
采样率 250 Hz 250 Hz 360 Hz 250 Hz 257 Hz
终末事件 持续性室速,多数心脏骤停 恶性室性心律失常 各类心律失常 短暂心肌缺血 冠心病相关心律失常
心搏标注 23 段算法标注 + 12 段审校标注 有 有 有 有
标注审校 不完整,官方征集补全 完整 完整 完整 自动加人工修正
临床信息 23 行表,大量 Unknown 有限 有限 详细临床摘要 逐患者诊断
许可 ODC-BY 1.0 ODC-BY 1.0 ODC-BY 1.0 ODC-BY 1.0 ODC-BY 1.0

这张表要说清的只有一件事:SDDB 在"终末事件真实性"这一列上唯一性地突出,在"规模"“标注完整度”"临床信息"三列上都不占优。它的定位不是替代任何一个库,而是补上别人补不了的那一行——真实发生的死亡。

2.6 两个通道分别测的是什么

官方没有给出导联名,这一点要反复强调。从 .hea- 的旧版描述 record 30, signal 0 与 record 30, signal 1 可以看出,官方自己也只把它们当作"第 0 通道"与"第 1 通道"。但双通道 Holter 的常规配置仍有规律可言,理解这些规律有助于判断某段信号能不能用于某个分析:

通道 常规 Holter 配置下的可能角色 常见失真来源 对分析的影响
通道 0 多为模拟 V1 或 V5 位置的胸导联 电极贴合度、呼吸起伏 幅度随体位变化大,绝对幅度不可靠
通道 1 多为模拟 II 或 V5 位置的第二路 肌电干扰、上肢活动 QRS 主波方向可能与通道 0 相反
两通道共同 共享同一时间轴与同一放大器 磁带转录引入的抖晃 时间轴误差是相关的,不能靠互相校正消除

上表是双通道 Holter 的通用配置推断,不是官方声明。它的价值在于提示两件事:第一,不要假设其中一个是 II 导联;第二,两通道来自同一次放大与同一盘磁带,噪声在时间上相关,做"用一路去噪另一路"的实验时这个相关性会让结果虚高。

§3 它是谁的数据:一批 1980 年代的 Boston 磁带

3.1 贡献者与机构

官方页面没有列出作者栏,发布公告与参考文献共同指向同一个人:Scott D. Greenwald。他在 MIT 电气工程与计算机科学系做硕士期间,为研究心室颤动检测器而采集并汇编了这批 Holter 记录,1986 年的硕士论文《Development and analysis of a ventricular fibrillation detector》是官方指定的引用文献。论文全文托管在 MIT 的 DSpace(handle 1721.1/92988)。

数据后来由 PhysioNet 承接托管,2004 年 7 月 2 日以 “Sudden Cardiac Death Holter Database” 之名正式发布。官方页面把它标注为 Open Access,访问政策是"任何人都可以访问文件,只要遵守指定许可的条款"。从捐献方式看,它是典型的 PhysioNet 早期模式:一位研究者把已经完成的历史资料交给平台,平台负责格式规范化与长期托管,没有基金持续投入,因此也几乎没有后续更新。

3.2 时间线

时间 事件 意义
1980 年代 波士顿地区医院采集 Holter 记录 原始采集,模拟磁带
1985 Greenwald 等发表心律失常检测器性能置信限研究 方法学基础
1986 Greenwald 硕士论文完成,成为官方指定引用 数据集的学术出处
1988 Goldberger 等基于本批数据发表心率振荡与分岔研究 首次用于非线性动力学分析,基于 16 例窦性心律者
1989 半小时摘录以 MIT-BIH 恶性室性心律失常库之名开放 子集先行公开
1989 Courtemanche 等的复杂心律失常建模研究引用记录 47 个案层面的使用
2004-07-02 完整 23 段在 PhysioNet 发布,版本 1.0.0 全集首次公开
2004 官方同期发布征集公告,邀请补全标注与扩充记录 标注不完整的官方说明
2008 被列为 PhysioNet/CinC 2008 T 波电交替挑战赛的候选来源库 进入挑战赛视野

最后一行属于使用侧的观察而非官方版本变更。它的意义在于说明:SDDB 长期处于"被引用但不被维护"的状态,二十年没有出过版本 1.0.1。

3.3 采集场景:为室性心律失常研究而汇编

官方原话是:这些记录主要采集于 1980 年代的波士顿地区医院,后来被汇编为室性心律失常研究的一部分。这句话包含两个关键限定。第一是"主要"——不是全部,说明来源机构不止一家,采集规范可能不一致。第二是"汇编"——不是为这项研究专门采集的,而是从既有临床 Holter 里挑出来的。

由此可以推出它的人群画像:记录期间发生持续性室性心动过速,多数发生心脏骤停;底层心律 18 例窦性(其中 4 例间歇起搏)、1 例持续起搏、4 例心房颤动。临床信息表还给出了部分患者的病史,包括心力衰竭、冠状动脉旁路移植、二尖瓣置换、心脏手术、急性髓系白血病、肥厚型心肌病伴猝死家族史、冠心病、陈旧性心肌梗死合并室速史等,最年轻的一例 17 岁,最年长的一例 89 岁。相当比例的性别、年龄、病史、用药四列为 Unknown。

官方对这批数据的自我判断相当克制:由于是回顾性汇编,存在重要局限;患者信息有限,有时完全缺失,包括用药方案与剂量;这些病例未必能代表自发性猝死事件,因为受试者群体很可能高度异质。这段话应该被原文引用,而不是被改写成更乐观的表述。

3.4 数据来源的三个层次

理解这份数据要先分清三层:原始 Holter 磁带(1980 年代,未公开,且多半已不存在)、转录后的双通道信号(公开的基本单位,起点是转录偏移点而非原始起点)、心搏标注(公开的监督信号,两层质量)。

第一层不可得,意味着转录时丢失的信息无法追回,也无法验证。第二层的起点偏移值得注意——记录 30 的头文件写着 beginning at 26:35.000,说明公开信号从原始磁带的第 26 分 35 秒开始;记录 47 甚至是 beginning at 44:10.000。这意味着不同记录的起点对齐到挂钟时间的口径并不统一,做跨记录的时刻对比时要小心。第三层的两层质量已在 §2.4 说明。

§4 它最独特的东西:把死亡录了下来

4.1 为什么这件事不可复制

SDDB 的稀缺性不是"采得精细",而是"不可能再采"。要复现它,你需要一批患者恰好在做 24 小时 Holter 的当天发生致死性心律失常,还需要这些记录被完整保存、转录、捐赠。任何前瞻性研究都设计不出这样的队列——伦理上不能等着患者死,技术上也无法预知谁会在哪一天出事。

于是它的稀缺性来自一次历史窗口的巧合:1980 年代 Holter 检查刚开始普及,模拟磁带是唯一载体,而记录下来的东西在几十年后被数字化并公开。这个窗口已经关闭。现代的数字 Holter 理论上能采到同样的事件,但数据分散在各家医院的商业系统里,公开意愿与合规成本都完全不同。

所以它的价值判断标准也和别的库不一样。别的库可以问"够不够大"“标注够不够准”;它只能问"还有没有第二份"。答案目前是没有。

4.2 与恶性室性心律失常库的关系:全集与半小时摘录

官方在发布公告里明确说:这些记录中,半小时摘录自 1989 年起就以 MIT-BIH Malignant Ventricular Ectopy Database 之名向研究者开放,且这个库继续存在。站内对应的 VFDB 词条就是这份摘录集,DOI 为 10.13026/C22P44。

对比项 SDDB(本库) MIT-BIH 恶性室性心律失常库(VFDB)
关系 全集 从同批记录中切出的半小时摘录
记录数 23 段 22 段
单段时长 3:56–25:08 约 30 分钟
覆盖的事件 完整演进过程,含室颤前数十小时 围绕事件的半小时窗口
适合的任务 长时程前兆分析、预警提前量评估 事件片段的分类与检测
不适合的任务 需要对照组的统计推断 室颤前的长程动力学分析
DOI 10.13026/C2W306 10.13026/C22P44

这个关系带来一个实用提醒:如果一篇论文声称"使用了 MIT-BIH 恶性室性心律失常库",它用的是半小时窗口;如果它要研究室颤之前几十小时发生了什么,必须用 SDDB。反过来,如果你的模型只需要围绕事件的一段固定长度输入,VFDB 更省事,也不必处理 1.1 GB 的体积。

还有一处需要留意:SDDB 23 段,VFDB 22 段,两者并不一一对应。官方没有逐条给出对应关系,因此不能假定 VFDB 的每一段都能在 SDDB 里找到母记录。

4.3 案例:记录 30 的二十四小时与第七小时五十四分

取记录 30。它是全库信息最完整的一段之一:24 小时 33 分 17 秒,起始挂钟时刻 12:00:00,转录自原始磁带第 26 分 35 秒之后,室颤起始于记录开始后 7 小时 54 分 33 秒,同时拥有未审校标注 .ari 与审校标注 .atr。

把这三个数字放在一起,就能算出一件很关键的事:这段记录里,室颤之前有将近八小时的连续稳定期,室颤之后还有十六个多小时的余下记录。这是 SDDB 相对任何摘录集最本质的优势——它给了你"之前"和"之后",而不只是"之中"。

用 §2.3 的代码读出信号后,取室颤起始前后的固定窗口做对照:

import wfdb
import numpy as np

rec = wfdb.rdrecord('30', pn_dir='sddb')
fs = rec.fs

#-- 从头文件注释里解析室颤起始时刻(时:分:秒 -> 秒)
vfon = None
for c in rec.comments:
    if c.lower().startswith('vfon'):
        h, m, s = [int(x) for x in c.split(':')[1:]]
        vfon = h * 3600 + m * 60 + s
print('室颤起始秒:', vfon)

def window(center_sec, half=10):
    #-- 取中心前后各十秒的片段,返回两通道毫伏值
    lo = max(0, int((center_sec - half) * fs))
    hi = min(rec.sig_len, int((center_sec + half) * fs))
    return rec.p_signal[lo:hi]

before = window(vfon - 600)      #-- 室颤前十分钟处
after  = window(vfon + 60)       #-- 室颤后一分钟处
print(before.shape, after.shape)
print('前:', round(float(np.ptp(before[:, 0])), 3), 'mV 峰峰值')
print('后:', round(float(np.ptp(after[:, 0])), 3), 'mV 峰峰值')

这段代码的用途不是下结论,而是建立一个可复现的观察点。官方只给了室颤起始的已历时刻,没有给结束时刻,也没有给转复或终止方式的标注,所以"之后"的解读必须自己看波形,不能靠注释。

把这类观察整理成表,就成了后续讨论的支点:

观察位置 头文件能给的 头文件给不了的
室颤起始之前 已历时刻(#vfon)、连续信号、心搏标注 前驱期的定义、何时算"预警成功"
室颤起始瞬间 一个时刻点,精确到秒 起始判定的依据与判读者
室颤持续期间 连续信号 室颤的终止时刻、是否自行终止
室颤之后 连续信号(本段还有十六小时) 结局、是否复苏成功、临床处理

这张表最有用的是最后一列。它说明:用 SDDB 做研究时,绝大部分"标签"要自己定义,而定义的口径必须写进方法节,否则结果不可复现。

4.4 标注的两层:算法初标与人工审校

ANNOTATORS 用两行把层次说清楚了。.ari 是 unaudited beat annotations,23 段全有,由算法生成后没有过人工。.atr 是 reference beat annotations,只有 12 段有,是审校过的参考标注。

官方对标注难度的说明也很直接:标注本库的任务特别困难,因为所包含的心律非常复杂。这句话的实际含义是——在一段走向室颤的记录里,心搏形态会从规整的窦性,经过频发的室性早搏、成对室早、短阵室速、多形性室速,一直到形态完全失去周期性。算法在这一整条链条上的表现并不均匀:在规整段很准,在形态剧烈变形的段落会系统性失效。

这对使用者是实打实的约束。如果你在 .ari 上统计室性早搏的时序模式,那么算法在"快要室颤"那一段的表现最差,而你恰恰最关心那一段。这不是可以通过增加样本量解决的问题,因为它是一个与状态相关的偏差,样本越多,偏差越稳定。

用途 用 .ari 的风险 用 .atr 的风险 建议
心搏分类评测 算法错误被当作金标准 只有 12 段,样本小 只用 .atr,并在论文里写明段数
室性早搏负荷统计 高,形态变形段漏标 中,室颤段心搏定义本身就模糊 限定在室颤起始之前、形态尚规整的窗口
室颤检测与预警 低,因为不依赖心搏标签 低 主要用信号与 #vfon,标注只做辅助
心率变异性 高,RR 序列直接受影响 中,同样受室颤段影响 先自行检测 R 峰再做对齐
长时程节律趋势 中,趋势级结论对个别漏标不敏感 低 两者都可用,但不要混用

4.5 边界条件:什么情况下它不再适用

条件 是否适用 判断依据
研究室颤前的长程前兆 适用,且几乎无可替代 单段最长超过 25 小时,多数含数十小时稳定期
评估除颤或预警算法的提前量 适用 20 段带室颤起始时刻,可定义预警窗口
做心搏形态分类的外部测试 适用,但只能用 12 段 审校标注只覆盖 12 段
作为阴性对照 部分适用 40、42、49 三段官方注明无室颤,可作对照
做猝死风险的统计预测 不适用 全库均为发生事件者,无对照组
做药物或剂量相关分析 不适用 官方说明用药方案与剂量信息缺失
做导联间差异或十二导联研究 不适用 两通道且无导联名
做现代数字 Holter 的绝对性能基准 谨慎 1980 年代模拟磁带转录,噪声谱与现代设备不同
做多中心泛化验证 不适用 来源集中在波士顿地区医院
做儿科或青少年心电模型 不适用 已知年龄最小 17 岁,且多数年龄未知

这张表最有用的两行是第一行与倒数第三行。第一行是它的立身之本;倒数第三行提醒的是一件常被忽略的事:从它上面得到的绝对性能指标,不能直接外推到今天的数字记录设备,因为噪声来源完全不同——模拟磁带带来的是抖晃与磁带噪声,现代设备带来的是量化噪声与运动伪迹。

§5 怎么拿到:从目录树到可训练张量

5.1 目录结构与下载面

PhysioNet 的文件目录是扁平的:根目录下直接放 23 组文件,加上几个附属清单,没有按患者或日期分的子目录。全库未压缩 1.1 GB,共 110 个文件,官方提供了整库 ZIP(1.1 GB)。

路径 内容 数量 大小量级
/files/sddb/1.0.0/RECORDS 23 行记录名 1 数十字节
/files/sddb/1.0.0/ANNOTATORS 注释扩展名与角色 1 两行
/files/sddb/1.0.0/SHA256SUMS.txt 全部文件的校验和 1 数千字节
/files/sddb/1.0.0/vf-30.png 记录 30 的波形图 1 数十 KB
/files/sddb/1.0.0/NN.hea 头文件 23 约 200 字节
/files/sddb/1.0.0/NN.hea- 旧版头文件副本 23 约 250 字节
/files/sddb/1.0.0/NN.dat 双通道信号 23 十数 MB 至 60 余 MB
/files/sddb/1.0.0/NN.ari 未审校心搏标注 23 数十 KB 至 250 余 KB
/files/sddb/1.0.0/NN.atr 审校心搏标注 12 数十 KB 至 260 余 KB

单段体积差异很大:记录 30 的信号文件是 63.2 MB,而记录 41(3 小时 56 分)只有十数 MB。规划磁盘时按整库 1.1 GB 准备最省心;只想做方法验证的话,先拿记录 30 一段就足够跑通全流程。

5.2 批量下载

#-- 整库 ZIP,一次拿全 1.1 GB
wget -O sddb.zip https://physionet.org/content/sddb/get-zip/1.0.0/

#-- 或者用官方命令行工具
physionet download sddb --version 1.0.0

#-- 或者用 S3 免签名同步
aws s3 sync --no-sign-request s3://physionet-open/sddb/1.0.0/ ./sddb

#-- 只取清单,先确认 23 条记录名
curl -sL https://physionet.org/files/sddb/1.0.0/RECORDS | tr -s '\n' ' '

四条路径里,ZIP 最省事但一次性落盘 1.1 GB;S3 同步支持断点续传,适合网络不稳的环境;physionet 命令行工具会顺带校验。只做流程验证时,建议先只下记录 30 的四个文件,跑通后再决定要不要全量。

5.3 用 wfdb 直接流式读取

import wfdb
from collections import Counter

names = wfdb.get_record_list('sddb')
print(len(names))            #-- 23

#-- 逐段读标注,注意 atr 不是每段都有
for name in names[:5]:
    ari = wfdb.rdann(name, 'ari', pn_dir='sddb')
    try:
        atr = wfdb.rdann(name, 'atr', pn_dir='sddb')
        n_atr = len(atr.sample)
    except FileNotFoundError:
        n_atr = 0            #-- 11 段没有审校标注
    print(name, len(ari.sample), n_atr)

get_record_list 从 RECORDS 解析,不需要本地磁盘,代价是每段重新走网络。全库 1.1 GB,全部走网络读取会很慢,正式实验建议先落盘。

5.4 转成通用的表结构

下游若是 PyTorch 或 TensorFlow 的常规管线,通常需要切成定长片段。切窗时建议以室颤起始时刻为锚点,而不是从头等距切:

import wfdb
import numpy as np
import pandas as pd

FS = 250
WIN = 10 * FS        #-- 十秒一窗

def vfon_sec(name):
    #-- 从头文件注释里取室颤起始秒;无则 None
    h = wfdb.rdheader(name, pn_dir='sddb')
    for c in h.comments:
        if c.lower().startswith('vfon'):
            hh, mm, ss = [int(x) for x in c.split(':')[1:]]
            return hh * 3600 + mm * 60 + ss
    return None

rows = []
for name in ['30', '31', '32']:
    rec = wfdb.rdrecord(name, pn_dir='sddb')
    vf = vfon_sec(name)
    if vf is None:
        continue
    ari = wfdb.rdann(name, 'ari', pn_dir='sddb')
    for w in range(0, rec.sig_len // WIN):
        lo, hi = w * WIN, (w + 1) * WIN
        t_end = hi / FS                      #-- 该窗结束时的已历秒数
        #-- 以室颤起始为界:之前记 0,之后记 1,并留出灰区
        label = 0 if t_end < vf - 60 else (1 if t_end >= vf else -1)
        if label < 0:
            continue                         #-- 起始前后一分钟为灰区,丢弃
        rows.append({'record': name, 'win': w, 'label': label,
                     'ch0': rec.p_signal[lo:hi, 0].astype('float32'),
                     'ch1': rec.p_signal[lo:hi, 1].astype('float32')})
df = pd.DataFrame(rows)
print(df.groupby(['record', 'label']).size())

这段代码只用三段演示口径。上正式实验时有四处必须改:一是灰区宽度要写进方法节,它直接决定正负样本边界;二是要不要把室颤之后的十几小时全部标为正样本,需要明确——多数研究只取室颤前的一段与室颤后的一小段;三是 label 在这里是逐窗的,与心搏级标注不同源,不要混用;四是只用了 .ari,如果是心搏级任务必须换到审校过的 12 段。

5.5 注释读取与 AAMI 映射

import wfdb

AAMI = {'N': 'N', 'L': 'N', 'R': 'N', 'B': 'N',
        'A': 'S', 'a': 'S', 'J': 'S', 'S': 'S',
        'V': 'V', 'r': 'V',
        'F': 'F', 'f': 'F',
        'e': 'Q', 'j': 'Q', 'n': 'Q', 'E': 'Q', '/': 'Q', 'Q': 'Q'}

ann = wfdb.rdann('30', 'atr', pn_dir='sddb')     #-- 审校标注,12 段之一
sym = [s for s in ann.symbol if s in AAMI]
print(len(ann.symbol), len(sym), len(ann.symbol) - len(sym))

最后打印的差值是被映射表排除的类型数。这个值值得看一眼:它通常包含 !(室颤波)以及各类非心搏注释。如果差值很大,说明你取的窗口落在了室颤段里,而不是稳定段里。

映射表不是本库独有的,它来自心电算法评价的通行分组:束支阻滞与正常心搏并作 N,室上性与房性并作 S,室性与 R-on-T 并作 V,融合波作 F,其余作 Q。做跨库对比时必须用同一张表,否则数字不可比。

5.6 五个最容易出错的地方

位置 错误写法 后果 正确做法
取标注 默认每段都有 .atr 11 段会抛文件不存在错误 先检查 RECORDS 里是否有对应 .atr,或捕获异常
取标注 把 .ari 当参考标注用 算法错误进入监督信号 只有 .atr 是 reference beat annotations
幅度换算 直接用整数喂模型 39、47 两段增益是 200,其余是 800,幅度不可比 用 p_signal 或按 .hea 的增益归一
时间定位 把 #vfon 当作记录内的绝对采样点 单位错,差 250 倍 先按 时:分:秒 解析成秒,再乘 250
通道命名 假设通道 0 是 II 导联 论文里写出没有依据的导联结论 头文件描述字段只有 ECG,如实写"双通道,导联未标注"

§6 与库内条目的关系

6.1 关系图谱

SDDB 在心电类内容里的位置,可以用"时长 × 事件严重度"两个轴摆出来:

条目 时长 事件性质 与 SDDB 的关系
MIT-BIH 恶性室性心律失常库 约 30 分钟 恶性室性心律失常 同源:它是本库半小时摘录的版本
MIT-BIH 心律失常库 约 30 分钟 各类心律失常 对照:同为短片段,无终末事件
长期 ST 库 21–24 小时 短暂心肌缺血 对照:同为长时程,事件性质不同
INCART 30 分钟 冠心病相关心律失常 对照:十二导联,但无终末事件
噪声压力测试库 数分钟至数十分钟 纯噪声 工具:叠加到本库做鲁棒性评测
欧洲 ST-T 库 约 2 小时 缺血性 ST 改变 对照:同为长程,事件为缺血而非致死性心律失常
本库 3:56–25:08 持续性室速、心脏骤停 唯一以真实致死性事件为终点

这条关系线的意义在于:如果你要论证一个预警算法有效,只用短片段库说服力有限,因为短片段库没有"之前",只有"之中";SDDB 提供的是事件之前的连续时间轴,而这正是预警任务的全部前提。

6.2 检索路径

你要找的东西 检索词 会落到哪里
同批记录的半小时摘录 VFDB、Malignant Ventricular Ectopy §4.2 的关系表
心搏类型码的标准定义 PhysioBank annotation、MIT-BIH §2.2 的类型码表,多个库通用
长时程缺血对照 Long-Term ST、European ST-T §6.1 表
噪声叠加的来源 NSTDB、noise stress §4.5 的边界表与 §6.1
十二导联长时程对照 INCART §2.5 与 §6.1
除颤与可电击节律识别 shockable rhythm、AED §1.4 的处境表
挑战赛来源 CinC 2008、T-wave alternans §8.2

6.3 与其他库的分工判据

选数据集时最实际的问题不是"哪个最好",而是"哪个负责哪一段"。下面把常见的心电任务逐项拆开,看 SDDB 该站在哪一格:

任务 主粮仓该用什么 SDDB 的位置 原因
心搏形态分类 大体量短片段库 外部测试(仅 12 段) 审校标注不完整,规模太小
房颤检测 长时程房颤库 辅助 本库只有 4 例房颤,且都是终末事件病例
室颤与可电击节律识别 混合多库 主力之一 唯一提供真实终末事件的公开来源
室颤前兆与预警 无可替代 主力 需要事件前的连续时间轴
长时程心率动力学 长时程大库 辅助 只有 23 段,但事件真实
噪声鲁棒性 噪声库加任一长时程库 主力之一 模拟磁带噪声真实且与现代设备不同
缺血与 ST 分析 长期 ST 库、欧洲 ST-T 库 不适用 本库事件性质不同,无 ST 标注
十二导联形态学 十二导联长时程库 不适用 只有两个通道

这张表的前四行是大多数人的真实处境:他们已经有主粮仓,缺的是一个不撒谎的裁判。被高估的用法是第五行及之后的所有行——把 SDDB 当通用长时程库用的人不少,但真正需要它的场景集中在"致死性事件的演进"这一格。

§7 质量评估与局限性

7.0 阅读本节前的一个前置校正

先纠正一个常见的误判:把"样本少、标注不全"当成"质量差"。SDDB 的 23 段不是采集能力不足,而是这类事件本来就不可前瞻性采集(§4.1)。评价它的时候不能套用"越大越好"的尺子,而应该问:在它能回答的那个问题上,还有没有第二份数据?

这个校正会改变五维评分的读法。规模与标注完整度两项它拿不到高分,但在"任务唯一性"上它几乎无可替代。把这两件事混在一起看,就会得出"不值得用"的错误结论。

7.1 五维评分

按 DAIMS 的常用维度打分,每项 1–5 分,分数针对"作为致死性心律失常研究数据"这个用途:

维度 分数 理由
数据规模 2 23 段、23 名患者,长时程但样本数少
标注质量 2 23 段算法标注未审校,仅 12 段有审校标注
任务适配 5 唯一公开提供真实致死性事件演进过程的长程库
文档完整 4 官方把规模、限制、征集意图写得很清楚,但无逐条临床摘要
可获取性 4 免注册、ODC-BY、有整包下载,但 1.1 GB 体积偏大

五项合计 17 分(满分 25)。这个分数结构说明它是明显的"偏科生":任务适配拉满,规模与标注拖后腿。用它的人必须清楚自己要的是哪一科。

7.2 标注质量的两层

第一层是类型对不对。.atr 经过人工审校,是 reference beat annotations;.ari 是算法输出,官方标为 unaudited。两者不应该混用,也不应该互相补充——把审校段的 .atr 和未审校段的 .ari 拼起来训练,等于在同一个模型里混了两种标注标准。

第二层是心搏定义在室颤段是否成立。室颤期间心电活动失去周期性,"心搏"这个概念本身就模糊。PhysioBank 用 ! 标记颤动波,但室颤的起止边界、颤动波是否逐条标出,官方页面没有说明。因此任何涉及室颤段内部的心搏级统计都要非常谨慎。

用途 建议用哪套标注 风险
心搏分类评测 .atr,12 段 样本小,结论不稳
室性早搏时序分析 .atr,限定在室颤前的规整段 形态变形段算法漏标
室颤检测与预警 不用标注,只用信号与 #vfon 标签口径需自建并公开
心率变异性 自行检测 R 峰 室颤段与频发早搏段会污染 RR 序列
长时程趋势 两者皆可,但不要混用 跨段标准不一致

7.3 已知的、可枚举的偏差

偏差 表现 影响
选择偏差 全部为发生致死性事件的病例,无对照组 无法做统计意义上的风险预测
回顾性汇编 官方明确说明患者信息有限、有时完全缺失 用药、剂量、既往史大量未知
时代偏差 1980 年代模拟磁带转录 噪声谱与现代数字记录不同
地域集中 波士顿地区医院 人群与设备单一,不代表其他人群
起点偏移 各记录的转录起点不同(0 至 44 分不等) 跨记录的时刻对齐需谨慎
标注不完整 11 段无审校标注 心搏级任务只能用 12 段
增益不一致 39、47 两段为 200,其余为 800 整数幅度跨段不可比
通道语义缺失 两通道描述均为 ECG 无法做导联相关分析

7.4 外部验证矩阵

SDDB 最常被引用的方式,是当"真实终末事件"的来源。这类用法可以从公开论文的摘要里看出轮廓。

验证角色 做法 讲得通的地方 风险
室颤检测器的测试集 在别的库上训练,本库上测灵敏度 事件真实,非人工构造 样本只有 23 段,置信区间宽
除颤决策算法评估 用长程背景评估误放电 背景心律复杂,接近真实难度 无临床结局,无法评估决策的临床后果
去噪算法的压力测试 叠加噪声后看检测性能 本底噪声真实 1980 年代噪声谱与现代不同
综述中的稀缺性论据 引用其规模说明数据缺口 官方页面自述限制 不应被改写成"代表性队列"

值得注意的是第二行。除颤决策不只是"识别出可电击节律",还包括"不该放电时不放电"。SDDB 里有起搏、房颤、频发室早等大量"不该放电"的心律,这确实是好的阴性材料;但它没有给出任何临床处理与结局,所以算法做出"放电"判断之后会发生什么,无法用它评估。

反过来也要防止把外测成绩当作绝对标准。23 段里每一段的时长差异巨大(最短 3 小时 56 分,最长 25 小时 8 分),按段平均会把一段 25 小时的记录和一段 4 小时的记录等权处理。合理的做法是显式声明是按段还是按时间加权,并在结果里分别报告。

7.5 它为何能持续:稀缺的不是数据量,是那件事本身

它没有更新、没有扩版、标注至今不完整,却仍然被引用,原因只有一个:它占着一个别人没法再占的坑——真实发生的死亡被连续记录了下来。官方在 2004 年的发布公告里公开征集更多记录与标注贡献,二十多年过去仍是版本 1.0.0,这本身就说明补充这类数据有多难。只要这个前提不变,它作为证据的价值就不会被新库替代。

§8 生态位与历史

8.1 历史沿革

SDDB 的诞生路径与后来大多数捐赠型数据库不同。它不是一个机构决定公开一批数据,而是一位研究者的个人资料在近二十年后被平台承接。1986 年 Greenwald 的硕士论文完成,1989 年这批记录的半小时摘录以恶性室性心律失常库之名开放,2004 年 PhysioNet 才把完整 23 段作为独立数据集发布。

这条路径解释了它身上几个"不像现代数据集"的特征:没有统一的采集协议文档,没有伦理审查编号的公开说明,没有逐条临床摘要,标注也不完整。它是历史资料的数字化,不是按现代标准建设的数据资产。把这些当成缺陷是对的,但把它们当成"可以修好的缺陷"就错了——原始磁带与纸质病历大概率已经不存在。

8.2 与挑战赛的关系

PhysioNet/CinC 2008 的 T 波电交替挑战赛把本库列为候选来源数据库之一。该挑战赛页面对本库的描述是:23 段完整的双通道 Holter 记录,每段 7 至 25 小时,来自记录期间发生持续性室性心动过速与心脏骤停的患者;信号以 250 Hz 数字化;其中 12 段经过逐搏精心标注,其余有算法生成的心搏标注;没有临床对照信息。

这段描述与官方表格有一处需要说明的差异:挑战赛页面写"7 至 25 小时",而官方记录表里最短的一段是记录 41 的 3:56:00。两处都以官方发布为准,最短时长应按官方表格的 3 小时 56 分理解;挑战赛页面的表述属于当时的概略描述。挑战赛页面另外确认了两件事——250 Hz 与"12 段精心标注",这两点与现行文件目录完全一致。

需要强调的是:本库只是候选来源之一,挑战赛最终采用的记录与公开库并不等同。想研究室颤演进,必须用原始库,不能把挑战赛数据当成它的替身。

8.3 生态位:证据而不是粮仓

角色 主力粮仓 证据
典型用法 大规模训练、预训练 特定问题的唯一可用材料
需要的前提 数据量大、标签细 事件罕见且不可复现
代表库 心律失常库、短片段大库十二导联库 本库
失败模式 过拟合、标签噪声累积 样本少导致结论不稳、标签口径自建

SDDB 坐在右边这一列。把证据当粮仓用,会立刻遇到规模瓶颈;把粮仓当证据用,会立刻遇到"问题根本没被回答"的尴尬。两者不能互换。

8.4 谁在用它,用来做什么

从公开文献的摘要看,使用者集中在三类:做致死性心律失常检测的信号处理组(把它当真实事件的测试集)、做除颤与监护设备的工程组(把它当长程复杂背景的评测材料)、做心电脑电去噪的组(把它当真实噪声来源)。近年也有综述类文章把它列为心电算法评估的常用公开资源之一。第一类最少,但正是它最不可替代的位置。

§9 使用指引

9.1 三种角色的路径

角色 第一天 第一周 注意事项
猝死机制研究者 读官方页面与临床信息表,跑通 §5.3 的读取 按 #vfon 建立事件前后窗口,定义前兆口径 口径必须写进方法节(§4.3)
设备工程师 用记录 30 跑通全流程 把 40、42、49 三段作阴性对照,评估误报 报告按段与按时间分别给(§7.4)
算法研究者 只用审校过的 12 段做评测 建立与短片段库的跨库对照 不要混用 .ari 与 .atr(§5.5)

9.2 一条最短的可用流程

#-- 1. 取记录清单,确认 23 条
curl -sL https://physionet.org/files/sddb/1.0.0/RECORDS -o RECORDS
tr -s '\n' ' ' < RECORDS

#-- 2. 确认哪些段有审校标注(.atr),只有 12 段
for r in $(cat RECORDS); do
  code=$(curl -s -o /dev/null -w '%{http_code}' \
         "https://physionet.org/files/sddb/1.0.0/${r}.atr")
  [ "$code" = "200" ] && echo "$r atr" || echo "$r -"
done > atr_availability.txt

#-- 3. 抽出全部头文件里的室颤起始时刻
for r in $(cat RECORDS); do
  echo -n "$r "
  curl -sL "https://physionet.org/files/sddb/1.0.0/${r}.hea" \
    | grep '^#vfon' || echo "(no VF onset)"
done > vfon.txt
import wfdb

#-- 4. 只取有审校标注的段,读信号与参考标注
names = wfdb.get_record_list('sddb')
for name in names:
    h = wfdb.rdheader(name, pn_dir='sddb')
    print(name, h.fs, h.sig_len, h.comments)

上面 bash 段的第二步会发起 23 次请求。想省事可以直接看官方记录表里"Audited Annotations"一列的空格——那 11 个空格就是没有 .atr 的段。第三步同理:官方表格里 40、42、49 三行的 VF Onset 列写的不是时间,而是 (paced, no VF) 与 (no VF)。

9.3 引用方式

PhysioNet 的惯例是引用数据集本身加平台:

引用对象 内容
数据集 Sudden Cardiac Death Holter Database, version 1.0.0. PhysioNet. 2004. doi:10.13026/C2W306
原始出处 Greenwald SD. Development and analysis of a ventricular fibrillation detector. M.S. thesis, MIT Dept. of Electrical Engineering and Computer Science, 1986. https://dspace.mit.edu/handle/1721.1/92988
平台 PhysioNet 平台综述论文(2026 年发表于 Nature Health),按官方页面的 Cite 按钮生成
许可 Open Data Commons Attribution License v1.0,署名要求以官方许可全文为准

写论文时建议同时注明四点:使用的版本号(1.0.0);用的是 .ari 还是 .atr,以及涉及哪几段;室颤起始时刻是从头文件 #vfon 注释解析的;标签口径(灰区宽度、正负样本定义)是自己定义的。

§10 AI 使用声明

项目 声明
文本生成 本文由 AI 辅助撰写,编辑把关结构与事实
数字来源 规模、结构、边界三类数字来自 PhysioNet 官方页面与官方文件目录
文件核验 RECORDS、ANNOTATORS、23 份 .hea 头文件、30.hea-、39.hea- 经直接访问确认
不一致说明 挑战赛页面写"7 至 25 小时",官方记录表最短为 3:56:00,已在 §8.2 说明并以官方表为准
论文信息 仅参考公开摘要与官方参考文献列表,未读全文
未核验内容 各心搏类型的具体条数、.atr 的逐条审校范围、室颤终止时刻、23 段与 VFDB 22 段的对应关系
图像 无配图;封面为生成式提示词,不含真实心电图
免责 本文不构成临床建议;数据使用须遵守 ODC-BY 1.0 署名要求

常见误读(避坑清单)

说法 实际 证据
「23 段都有审校标注」 只有 12 段有 .atr,其余 11 段只有未审校的 .ari ANNOTATORS 两行定义;官方公告写"不完整的审校标注集"
「.ari 是参考标注」 ari 官方定义为 unaudited beat annotations ANNOTATORS 文件内容
「两通道是 II 导联和 V1」 头文件描述字段两个通道都是 ECG,无导联名 23 份 .hea 的信号行第 9 字段
「增益都是 800」 记录 39 与 47 的增益是 200 39.hea、47.hea 信号行第 3 字段
「它是 25 小时一段的标准长程库」 单段 3:56:00 至 25:08:30,差异很大 官方记录表的 Signal Duration 列
「23 段都发生了室颤」 40、42、49 三段官方注明无室颤(其中两段为起搏心律) 官方记录表的 VF Onset 列
「它有完整的临床信息」 官方明确说明患者信息有限、有时完全缺失,含用药与剂量 官方 Data Description 段
「可以拿它做猝死风险预测」 全库均为发生事件者,无对照组 官方描述"全部患者有持续性室性心动过速,多数心脏骤停"
「记录起点就是 Holter 起点」 转录起点各不相同,记录 47 从原始磁带第 44 分 10 秒开始 47.hea 的 #Produced by 注释
「它和 VFDB 一一对应」 SDDB 23 段,VFDB 22 段,官方未给出逐条对应关系 两库官方记录表规模不同

FAQ

Q1:SDDB 到底有多少段记录?有多少段有审校标注?
23 段,编号 30 至 52,一段一名患者。审校标注(.atr)只有 12 段:30、31、32、34、35、36、41、45、46、49、51、52。全部 23 段都另有未审校的算法标注(.ari)。

Q2:.ari 和 .atr 到底能不能混用?
不能。ANNOTATORS 文件把两者分别定义为 unaudited beat annotations 与 reference beat annotations。混用等于在同一个模型里掺入两种标注标准,评测结果失去意义。

Q3:室颤起始时刻在哪里找?
在头文件的注释行里,格式是 #vfon: 07:54:33,含义是记录开始后的已历时刻。40、42、49 三段没有这一行,官方表格对应位置写的是 (no VF) 与 (paced, no VF)。

Q4:两个通道分别是什么导联?
官方没有给。头文件信号行的描述字段两个通道都是 ECG。论文里应如实写"双通道,导联未标注",不要凭猜测写成具体导联。

Q5:为什么记录 39 和 47 的波形看起来幅度不一样?
这两段的增益是 200 ADC 单位/毫伏,其余 21 段是 800。直接用整数值比较幅度会差四倍。用 wfdb 的 p_signal 或按头文件增益归一后再比较。

Q6:它能用来训练一个室颤检测模型吗?
可以,但要清楚限制:23 段、无对照组、标签口径自建。更合适的定位是外部测试与验证,而不是训练集。做训练时建议按段划分而非随机切窗,避免同一段的相邻窗落在两侧。

Q7:它和 MIT-BIH 恶性室性心律失常库是什么关系?
后者是从同批记录切出的半小时摘录,1989 年就已开放,至今仍然存在。SDDB 是全集,包含事件之前的数十小时。两者记录数不同(23 对 22),官方未给出逐条对应关系。

Q8:体积有多大,能一次下完吗?
未压缩 1.1 GB,共 110 个文件,官方提供整库 ZIP。只想跑通流程的话,先下记录 30 的四个文件即可,它同时有 .ari 与 .atr,信息最完整。

Q9:患者信息有多全?
不全,这是官方承认的局限。临床信息表有性别、年龄、病史、用药、底层心律五列,相当比例标为 Unknown;官方明确说包括用药方案与剂量在内的信息有时完全缺失。

Q10:底层心律是怎么分布的?
官方写明:18 例窦性心律(其中 4 例间歇起搏)、1 例持续起搏、4 例心房颤动,合计 23 例。全部患者都有持续性室性心动过速,多数发生了心脏骤停。

Q11:许可允许商业使用吗?
ODC-BY 1.0 允许商业使用,条件是署名。引用时要写清数据集名称、版本与来源,具体条款以官方许可全文为准。

Q12:为什么二十多年只有一个版本?官方有扩版计划吗?
官方在 2004 年的发布公告里公开征集更多记录与标注贡献,但至今仍是版本 1.0.0,页面没有给出扩版时间表。从数据性质看,这类事件不可能前瞻性采集(§4.1),扩充只能依赖其他机构捐赠历史资料。

术语表

术语 解释
Holter 便携式长时程心电监护,患者随身携带记录仪生活,通常记录 24 小时以上
心源性猝死 因心脏原因导致的突然死亡,多由持续性室性心动过速或心室颤动引发
室性心动过速 起源于心室的快速心律,可分为单形性与多形性
心室扑动 介于室速与室颤之间的极快而相对规整的室性心律
心室颤动 心室电活动完全失去组织,无法有效泵血,是猝死最常见的直接原因
心脏骤停 心脏有效搏出停止的临床状态
持续性室性心动过速 持续存在而非短暂发作的室速
R-on-T 室性早搏落在前一心搏 T 波上,易诱发室颤
起搏心律 由人工起搏器驱动的心律
心房颤动 心房电活动紊乱,心室率绝对不规则
逐搏标注 对每一次心搏标出位置与类型
WFDB PhysioNet 使用的波形数据库格式,含头文件、信号、注释三类文件
.hea 纯文本头文件,声明采样率、增益、采样点数与注释
.hea- 头文件的早期版本副本,描述字段写作 record N, signal M
.dat 二进制信号文件,本库用 212 格式打包两路 12 位数据
.ari 未经人工审校的算法心搏标注
.atr 经人工审校的参考心搏标注
格式 212 WFDB 的双通道 12 位打包存储格式
增益 每毫伏对应的 ADC 整数值,换算物理量时使用
校验和 采样点累加和,用于检测文件是否完整
AAMI 五分类 心电算法评价的通行分组:N、S、V、F、Q
可电击节律 除颤器应当放电的心律,主要指室颤与无脉性室速
阴性对照 不含目标事件的记录,用于评估误报
ODC-BY 开放数据共享署名许可
PhysioNet 由 MIT 等机构维护的生物医学信号数据平台

附录 A:核心数字核对表

项 值 来源 来源层级
记录数 23(编号 30–52) 官方页面;RECORDS 逐行 官方页面
患者数 23 官方页面"23 complete Holter recordings" 官方页面
审校标注段数 12 官方记录表 Audited Annotations 列;目录文件计数 官方页面与官方文件
未审校标注段数 23 官方记录表 Unaudited Annotations 列 官方页面
单段时长范围 3:56:00(记录 41)–25:08:30(记录 51) 官方记录表 Signal Duration 列 官方页面
通道数 2 全部 23 份 .hea 第 1 行第 2 字段 官方文件
采样率 250 Hz 全部 23 份 .hea 第 1 行第 3 字段 官方文件
存储格式 212,12 位 全部 23 份 .hea 信号行第 2、4 字段 官方文件
增益 800(21 段);200(记录 39、47) 全部 23 份 .hea 信号行第 3 字段 官方文件
室颤起始时刻覆盖 20 段带 #vfon,3 段(40、42、49)无 全部 23 份 .hea 注释行;官方记录表 官方文件
底层心律构成 18 窦性(4 间歇起搏)、1 持续起搏、4 房颤 官方 Data Description 段 官方页面
文件总数 110 官方文件清单 官方页面
总体积 未压缩 1.1 GB 官方页面 Files 段 官方页面
许可 ODC-BY 1.0 官方页面 Access 栏与许可页 官方页面
DOI 10.13026/C2W306 官方页面 Discovery 栏 官方页面
发布日期 2004-07-02 官方页面版本列表 官方页面
引用文献 Greenwald 1986 硕士论文 官方页面 Citation 栏 官方页面
关联库 DOI 10.13026/C22P44(半小时摘录集) 官方发布公告 官方页面

附录 B:数字的来源分层

第一层:官方页面与官方文件。 记录数、患者数、时长范围、通道数、采样率、存储格式、增益、室颤起始时刻的覆盖范围、底层心律构成、文件总数、总体积、许可、DOI、发布日期。这些数字来自项目主页的数据描述段与记录表,以及 23 份头文件、RECORDS、ANNOTATORS 的直接访问。

第二层:其他官方页面。 CinC 2008 挑战赛页面对本库的描述(250 Hz、12 段精心标注、无临床对照信息)。它属于 PhysioNet 站内页面,但描述口径与现行记录表略有出入,已在 §8.2 说明。

第三层:未核实。 各心搏类型的具体条数、.atr 的逐条审校范围与审校者、室颤的终止时刻、23 段与 VFDB 22 段之间的记录对应关系、两名通道的具体解剖位置。这些需要下载全量并逐条比对,正文中凡涉及处均只做定性表述。

附录 C:完整参考文献

编号 文献 链接 用途
1 Sudden Cardiac Death Holter Database v1.0.0 https://physionet.org/content/sddb/1.0.0/ 全部规模、结构、边界数据的来源
2 该库的 PhysioNet 文件目录 https://physionet.org/files/sddb/1.0.0/ RECORDS、ANNOTATORS、23 份头文件
3 Greenwald SD. Development and analysis of a ventricular fibrillation detector. M.S. thesis, MIT EECS, 1986 https://dspace.mit.edu/handle/1721.1/92988 官方指定引用文献
4 Greenwald SD, Albrecht P, Moody GB, Mark RG. Computers in Cardiology 1985;12:383-386 官方参考文献列表 检测器性能置信限方法
5 Goldberger AL, Rigney DR, Mietus J, Antman EM, Greenwald S. Experientia 1988;44:983-987 官方参考文献列表 基于 16 例窦性心律者的非线性动力学分析
6 Courtemanche M, Glass L, Rosengarten MD, Goldberger AL. Am J Physiol 1989;257:H693-H706 官方参考文献列表 记录 47 的个案建模
7 PhysioNet/CinC Challenge 2008(T 波电交替)来源页 https://physionet.org/content/challenge-2008/1.0.0/ §8.2 的候选来源描述
8 该库的 ODC-BY 1.0 许可全文 https://physionet.org/content/sddb/view-license/1.0.0/ 许可条款
9 MIT-BIH 恶性室性心律失常库(同源摘录集) https://physionet.org/content/vfdb/ §4.2 的关系说明
10 PhysioNet 平台综述(2026,Nature Health) https://doi.org/10.1038/s44360-026-00096-z 托管模式与引用规范

附录 D:任务代码

任务一:按室颤起始时刻建立事件前后的对照窗口

import wfdb
import numpy as np

FS = 250
PRE, POST = 3600, 600        #-- 室颤前一小时 / 后十分钟

def vfon_sec(name):
    h = wfdb.rdheader(name, pn_dir='sddb')
    for c in h.comments:
        if c.lower().startswith('vfon'):
            hh, mm, ss = [int(x) for x in c.split(':')[1:]]
            return hh * 3600 + mm * 60 + ss
    return None

def segments(name):
    rec = wfdb.rdrecord(name, pn_dir='sddb', physical=True)
    vf = vfon_sec(name)
    if vf is None:
        return None
    lo = int(max(0, vf - PRE) * FS)
    hi = int(min(rec.sig_len / FS, vf + POST) * FS)
    return rec.p_signal[lo:hi], vf - lo / FS

for name in ['30', '31', '32']:
    seg, rel = segments(name)
    print(name, seg.shape, '室颤位于片段内第', round(rel), '秒')

任务二:检查标注覆盖并只在审校段上做心搏统计

import wfdb
from collections import Counter

AAMI = {'N': 'N', 'L': 'N', 'R': 'N', 'B': 'N', 'A': 'S', 'a': 'S',
        'J': 'S', 'S': 'S', 'V': 'V', 'r': 'V', 'F': 'F', 'f': 'F',
        'e': 'Q', 'j': 'Q', 'n': 'Q', 'E': 'Q', '/': 'Q', 'Q': 'Q'}

#-- 先用官方记录表确认这 12 段有 .atr,不要靠 try/except 猜
AUDITED = ['30', '31', '32', '34', '35', '36',
           '41', '45', '46', '49', '51', '52']

for name in AUDITED:
    ann = wfdb.rdann(name, 'atr', pn_dir='sddb')
    mapped = Counter(AAMI.get(s, 'other') for s in ann.symbol)
    total = sum(mapped.values())
    kept = total - mapped['other']
    print(name, total, dict(mapped), '排除非心搏注释', mapped['other'])

第二段代码里 AUDITED 这个列表是从官方记录表的 Audited Annotations 列直接抄下来的,不是靠遍历试错得到的。这一点很重要:如果靠 try/except 去猜哪些段有 .atr,一旦官方补全了标注,脚本行为会静默改变。

附录 E:如果只记五件事

序号 记住什么 为什么
1 23 段长程双通道 250 Hz 心电,录到真实致死性事件 这是它唯一无可替代的地方
2 只有 12 段有审校标注,其余 11 段是算法初标 心搏级任务只能用那 12 段
3 两通道导联未标注,描述字段都是 ECG 任何导联相关分析都无从下手
4 39、47 两段增益是 200,其余是 800 幅度跨段不可比,必须换算
5 无对照组,无随访,临床信息大量缺失 不能做风险预测,只能做事件演进分析

编辑说明

本文的核验时间为 2026 年 10 月 29 日。核对方式为直接访问 PhysioNet 项目页、版本页、许可页与文件目录,逐一确认 RECORDS、ANNOTATORS、23 份 .hea 头文件、30.hea-、39.hea- 的可访问性与内容;挑战赛相关描述取自 PhysioNet 站内 CinC 2008 来源页。文中所有数字限于规模、结构、边界三类,未自行计算任何分布性统计。未覆盖的内容包括:各心搏类型的具体条数、.atr 的逐条审校者与审校范围、室颤的终止时刻、23 段与 VFDB 22 段的记录对应关系、两个通道的解剖位置。这些需要下载全量后逐条比对,本文按要求只写可追到官方页或官方文件的数字。


相关数据集导航

以下为站内 AI-Ready 数据集百科中与本词条共享多个主题标签的相关数据集,按相关度降序排列:

  • vfdb,共享标签:生理信号 / 心电信号 / 心血管疾病 / 急危重症
  • incartdb,共享标签:生理信号 / 心电信号 / 心血管疾病 / 挑战赛数据集
  • nstdb,共享标签:生理信号 / 心电信号 / 元数据
  • edb,共享标签:生理信号 / 心电信号 / 心血管疾病
  • cdb,共享标签:生理信号 / 心电信号 / 心血管疾病
  • ptbdb,共享标签:生理信号 / 心电信号 / 心血管疾病
  • svdb,共享标签:生理信号 / 心电信号 / 心血管疾病
  • twadb,共享标签:生理信号 / 心电信号 / 心血管疾病
  • cinc-2020,共享标签:生理信号 / 心电信号 / 心血管疾病
  • ltafdb,共享标签:生理信号 / 心电信号 / 心血管疾病

导航说明:本章节由全站统一标签体系自动计算生成(标签重合度算法),双向可达;点击链接可跳转至对应数据集词条。

返回 AI-Ready 数据集