近十九万次逐搏标注 — MIT-BIH 室上性心律失常库

78 段 30 分钟 / 双导联 128 Hz / 只标心搏不标节律

来源 https://physionet.org/content/svdb/1.0.0/发布时间: 2026-10-28最后更新: 2026-10-28 阅读 12
近十九万次逐搏标注 — MIT-BIH 室上性心律失常库

信息速览

数据集名称近十九万次逐搏标注 — MIT-BIH 室上性心律失常库
数据类型时序信号,波形,人工标注,元数据
规模78 段记录 / 受试者人数官方未公布
接入方式https://physionet.org/content/svdb/1.0.0/
AI 就绪度

心律失常的自动判读有两个难度完全不同的层次。第一个层次是找出 QRS 波群在哪儿,这一层在干净信号上早已做得不错。第二个层次是判断每一次搏动从哪儿来:窦房结、心房、房室交界区,还是心室。前三种都归入室上性,波形上往往只差几十毫秒的宽度和一次 P 波的有无,落到监护仪的屏幕上,就是一条几乎一样的窄波。

SVDB 就是为这第二个层次准备的一批原始素材。它的全名是 MIT-BIH Supraventricular Arrhythmia Database,直译是「MIT-BIH 室上性心律失常数据库」。SV 两个字母分别取自 supraventricular 一词,指起源在心室之上;它既不表示「突发」,也不表示某种以 SVT 命名的专病。库的官方说明只有一句话,说这批记录是为了补充 MIT-BIH 心律失常库里的室上性心律失常标本而挑选的。

它的形态和同门那些库都不一样:七十八段半小时记录,双导联,128 Hz,十八万八千余条逐搏标注,几乎没有一条节律标签。也就是说,它把全部标注力气都花在「这一拍是什么」上,而不在「这一段是什么」上。你要的是逐搏的类别真值,它就在这个位置;你要的是节律起止,它帮不上忙。一屏速览见下表。

维度 内容
全名 MIT-BIH Supraventricular Arrhythmia Database
中文常用名 MIT-BIH 室上性心律失常数据库
站点缩写 svdb(PhysioNet 项目路径名)
SV 的含义 supraventricular,室上性
发布方 PhysioNet(MIT Laboratory for Computational Physiology 托管)
首次发布 1999 年 8 月 3 日,版本 1.0.0(至今未改版)
引用文献 Greenwald SD,1990 年 Harvard-MIT 健康科学与技术分部博士论文
记录数 78 段(800–812、820–829、840–894 三段不连续编号)
受试者数 官方未公布
每段时长 30 分钟(230400 采样点)
导联数 2(记作 ECG1 与 ECG2,无导联位置)
采样率 128 Hz
标注层级 逐搏(心搏类型 + 信号质量),几乎无节律层
标注符号 全库出现 11 种
全库标注总量 187,877 条
压缩包体积 约 54.5 MB
许可 ODC-BY 1.0,免注册
DOI 10.13026/C2V30W
典型用途 心搏分类外部测试、室上性与室性误判分析、噪声鲁棒性评估

§1 它要解决的具体麻烦

1.1 监护仪真正分不清的,是窄波里的那几十毫秒

室性早搏好办。它宽、它怪、它提前,任何基于宽度和形态的判据都能抓住大半。真正难的是窄波之间的区别:窦性搏动、房性早搏、交界性早搏,三者的 QRS 几乎同形,区别藏在 P 波的有无与 PR 间期的长短里,而 P 波在监护导联上常常只有几十微伏,正好落在基线漂移与肌电噪声的量级上。

临床上这件事有后果。房性早搏本身良性,但频发房早是房颤的前驱信号;交界性心律提示房室结在接管起搏;把房早误判成室早,会触发一连串不必要的报警,让护士对报警失去信任。上世纪八十年代做自动判读的人最先撞上的就是这堵墙,而这个库正是那批工作的产物。

它的设计回答了一个很具体的问题:给定一段带噪声的连续心电,能不能把每一次窄波分到正确的来源类别上。为了回答这个问题,标注必须落到每一拍,信号必须保留真实的噪声,记录必须足够长,长到能装下不同心率、不同体位、不同干扰强度的片段。七十八段半小时,合起来三十九个小时,就是按这个要求攒出来的。

1.2 三条常见的错误期待

第一条,期待它专收室上性心动过速。库名里的 supraventricular 指的是起源位置,不是某一种快速心律。全库的标注主体是正常搏与零散的异位搏动,不是一段段持续发作的心动过速。想找持续的室上速发作段,这里凑不出多少。

第二条,期待它和心律失常库一样有节律层。心律失常库的注释里既有逐搏标签,也有节律改变标记;本库几乎只有前者。逐份读完全部注释文件,节律改变符号只出现一次——852 号记录第 876 秒处的一条 +,附加字符串写的是正常窦性心律。把它当节律检测的训练集,标签根本不存在。

第三条,期待它是从人群里随机抽的七十八个人。官方说得很清楚,这批记录是「挑选」出来的,目的是补齐心律失常库里稀缺的室上性标本。挑选意味着富集:带房早、交界性早搏、伪迹与信号质量切换的段落被优先留下。它的类别比例不代表任何人群,任何「房早占多少百分比」的结论都不能从这里推到病房里去。

1.3 它能给到的与给不到的

你的需求 它给的 够不够
逐搏心搏分类的外测集 七十八段、十八万余条带类别的心搏 够,且是全库最扎实的用途
室上性与室性早搏的混淆分析 S 与 V 两类在同一段信号里并存 够,能直接算混淆矩阵
节律检测与报警延迟评估 几乎没有节律区间标签 不够,换库
噪声鲁棒性测试 独立的质量改变与伪迹符号 够做定性切分,干扰不是人工注入
十二导联形态研究 两通道,且无导联位置 不够
高频成分分析(晚电位、QRS 碎裂) 128 Hz 采样,上限带宽约 64 Hz 不够,须换 360 Hz 以上的库
患者级泛化声明 人数未公布,人与记录的对应未知 不够,只能写记录级结论
教学演示与快速原型 全库五十余兆,几分钟取完 够,是目前最省事的入门心电库之一
与心律失常库做跨库迁移实验 同一套 WFDB 格式与符号体系,采样率不同 够,但须先统一采样率

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

你的处境 它能帮你什么 下一步该做什么
你训练的心搏分类网络在自建数据上 F1 很高,一换医院就掉,怀疑是室上性那几类没学好 提供一批逐搏标注的室上性异位搏动,且噪声形态真实 先只测 S 与 V 两类的召回,再谈总体指标
你在做监护仪报警去误报,房早被误报成室早是最常见的一类 提供大量正常搏与零散房早共处同一段的样本 把 S 类单独拉出来算误报率,别混进总体
你想验证一个 QRS 检测器在噪声下的稳定性 信号质量改变与伪迹有独立符号,可精确切段 用这些符号切出噪声段,单独报检出一致性
你要做跨库域适应,源域是 360 Hz 的心律失常库 目标域是另一个采样率、另一批记录、同一套符号 先重采样到同一频率,再固定符号映射表
你在教心电判读,需要带标准答案的练习素材 每拍都有类别,可以直接对答案 从 §4.3 的案例那条记录开始,它的类别跨度够宽
你在复现八十年代的自动判读工作 库的原始文献就是那篇讲噪声下上下文判读的博士论文 先确认原作用的标注口径与本库是否一致
你只需要一个能一次下完的小库做流水线联调 五十余兆,解压即用,格式统一 按 §9.2 的流程读一条记录,跑通读、画、算三步

1.5 一句话判断

它不是一本按节律编排的病例集,而是一份把每一次心跳都贴上类别标签的点名册;拿它去测节律检测是错位,拿它去校准「这一拍到底算哪一类」才是正用。

1.6 不适合谁:四条边界

不适合拿来做节律检测。 注释里没有节律区间这一层,只有心搏。任何以「室速从第几秒开始」为标签的任务,在这里找不到真值。

不适合拿来做高频形态分析。 128 Hz 的采样率把可用带宽压到 64 Hz 以下,QRS 的上升支被平滑,晚电位、碎裂 QRS 这类毫秒级特征无从谈起。要这些特征,得回到 360 Hz 或 1000 Hz 的库。

不适合拿来做人群结论。 没有年龄、性别、诊断、用药,连受试者人数都没有。你能说的是「在这七十八段记录上」,不能说的是「在房早患者中」。

不适合拿来做规模化预训练。 三十九小时、十八万拍,对传统信号处理与轻量模型是充裕的,对需要百万级样本的自监督预训练则太小。它的价值在标签质量与噪声真实性,不在体量。

§2 数据构成与规格

2.1 一段记录由三个必需文件构成

数据库沿用 PhysioNet 的 WFDB 格式。每段记录对应三个同名文件:.hea 是纯文本头文件,声明采样率、采样点数、信号条数、增益、ADC 零值、初始值与校验和;.dat 是二进制信号本体,按 212 格式把两个 12 位采样点打包进三个字节;.atr 是二进制注释文件,存放每一个心搏的位置与类别符号。

目录里另有三类附属文件。.hea- 是历史版本的头文件,每条记录各附一份。.xws 是给旧版波形显示工具用的脚本,只含记录名与地址模板,不含数据。.atr- 是旧版注释,七十八段里只有二十四段有。这三类文件都不影响读取,但 .hea- 与 .atr- 容易让人误以为同一段记录被重复收录。

这套结构的直接后果是:只拿 .dat 无法还原毫伏值,因为增益在 .hea 里;只拿 .atr 无法知道这些时刻落在什么波形上,因为采样率也在 .hea 里。把库转成 CSV 或 NumPy 数组是有损操作,除非把增益与零值一起搬过去。§4.3 的案例会用一条具体记录演示这件事在代码里长什么样。

2.2 头文件字段与心搏符号的完整字典

先看头文件。SVDB 的头文件短到只有三行,第一行描述记录,后两行各描述一条导联:

行 字段位置 示例值 含义
1 记录名 800 与文件名一致
1 信号条数 2 双通道
1 采样率 128 每秒一百二十八个采样点
1 采样点数 230400 每条记录固定,等于 1800 秒乘 128
2 文件名 800.dat 两条导联共用同一个信号文件
2 存储格式 212 两个 12 位采样点打包进三字节
2 增益 200 每毫伏二百个整数单位
2 ADC 零值 0 零电平对应的整数
2 初始值 -101 第一条导联首采样点的整数
2 校验和 -25183 全段采样点累加和
2 导联名 ECG1 只有序号,没有导联位置
3 各字段 800.dat 212 200 10 0 123 10510 0 ECG2 第二条导联,结构与第二行相同

再看注释符号。符号体系沿用 PhysioBank 的心搏注释码,全库出现的符号共十一种:

符号 含义 在库里的角色
N 正常搏动 构成绝大多数标注,是类别基线
S 室上性异位搏动 全库的入选主题
V 室性异位搏动 与 S 构成主要混淆对
F 融合搏动 室上与室性同时激动心室
Q 无法归类的搏动 判读人员也拿不准的样本
J 交界性早搏 起源在房室交界区
a 差异性传导的房性早搏 伴室内差异传导,形态偏宽
B 束支传导阻滞搏动 形态宽,但传导路径固定
` ` 孤立伪迹
~ 信号质量改变 标出质量转折点
+ 节律改变 全库只有一条

这张表里有两处细节值得单独指出。一是 S 是一个上位类别,不是单一的房性早搏。凡是起源于心室以上的异位搏动都归入 S,包括房性早搏与部分交界性搏动;真正只属于交界性的另有 J,伴差异传导的另有 a。把 S 直接翻译成「房早」,会把三类搏动压成一类,也会让类别定义与官方符号表对不上。

二是 ~ 与 | 不是心搏类别,是信号状态的标记。它们的采样点往往落在一个正常心搏上,只是顺带说明「从这里起信号质量变了」或「这里有一段不是心搏的伪迹」。做心搏分类时必须先把这两类剔出去,否则它们会被当成两个稀有类别学进去。

2.3 一条记录的完整解剖

取 800 号记录为例。它是全库第一个编号,标注量略低于全库中位。把它的三个文件读进来:

import wfdb

rec = wfdb.rdrecord('800', pn_dir='svdb')
ann = wfdb.rdann('800', 'atr', pn_dir='svdb')

print(rec.fs, rec.sig_len, rec.sig_name, rec.units)
#-- 128 230400 ['ECG1', 'ECG2'] ['mV', 'mV']
print(rec.adc_gain, rec.adc_zero, rec.fmt)
#-- [200.0, 200.0] [0.0, 0.0] ['212', '212']
print(len(ann.sample), sorted(set(ann.symbol)))
#-- 1921 ['F', 'N', 'S', 'V', '|', '~']
print(ann.sample[:5], [round(s / 128, 2) for s in ann.sample[:5]])

读出来的四个事实,构成了这个库的基本形状。

第一,采样率是 128 Hz,不是心律失常库的 360 Hz。同一段三十分钟,这里的采样点只有那边的三分之一多一点。波形看上去更「干净」,其实是高频被削掉了;这一点在做形态学比较时会造成系统差异。

第二,两条导联的名字是 ECG1 与 ECG2。官方给了序号,没给位置。这比完全匿名的写法好一点——至少两个通道能稳定区分——但仍然不能声称第一条是肢体导联、第二条是胸导联。

第三,标注是逐搏的。一千九百多条标注分布在三十分钟里,平均不到一秒一条。第一节标注落在第 162 个采样点,换算过来是第 1.27 秒,说明记录起点就是一次完整的心搏周期,没有被截断在半拍上。

第四,符号集合里同时出现了 N、S、V、F 与两种状态标记。这说明单条记录内部就足以构成一次小规模的分类实验:正常、室上性、室性、融合四类齐全,外加噪声与伪迹两类干扰。§4.3 的案例会把这条记录完整走一遍。

2.4 七十八段记录的结构对照

下表按官方 RECORDS 逐一列出七十八段记录的可核对结构信息。所有记录的采样点数、导联数、采样率、增益完全一致,这正是它适合做批量流水线的原因:

记录 采样点数 导联 采样率 增益 逐搏标注
800 230400 2 128 200 有
801 230400 2 128 200 有
802 230400 2 128 200 有
803 230400 2 128 200 有
804 230400 2 128 200 有
805 230400 2 128 200 有
806 230400 2 128 200 有
807 230400 2 128 200 有
808 230400 2 128 200 有
809 230400 2 128 200 有
810 230400 2 128 200 有
811 230400 2 128 200 有
812 230400 2 128 200 有
820 230400 2 128 200 有
821 230400 2 128 200 有
822 230400 2 128 200 有
823 230400 2 128 200 有
824 230400 2 128 200 有
825 230400 2 128 200 有
826 230400 2 128 200 有
827 230400 2 128 200 有
828 230400 2 128 200 有
829 230400 2 128 200 有
840 230400 2 128 200 有
841 230400 2 128 200 有
842 230400 2 128 200 有
843 230400 2 128 200 有
844 230400 2 128 200 有
845 230400 2 128 200 有
846 230400 2 128 200 有
847 230400 2 128 200 有
848 230400 2 128 200 有
849 230400 2 128 200 有
850 230400 2 128 200 有
851 230400 2 128 200 有
852 230400 2 128 200 有
853 230400 2 128 200 有
854 230400 2 128 200 有
855 230400 2 128 200 有
856 230400 2 128 200 有
857 230400 2 128 200 有
858 230400 2 128 200 有
859 230400 2 128 200 有
860 230400 2 128 200 有
861 230400 2 128 200 有
862 230400 2 128 200 有
863 230400 2 128 200 有
864 230400 2 128 200 有
865 230400 2 128 200 有
866 230400 2 128 200 有
867 230400 2 128 200 有
868 230400 2 128 200 有
869 230400 2 128 200 有
870 230400 2 128 200 有
871 230400 2 128 200 有
872 230400 2 128 200 有
873 230400 2 128 200 有
874 230400 2 128 200 有
875 230400 2 128 200 有
876 230400 2 128 200 有
877 230400 2 128 200 有
878 230400 2 128 200 有
879 230400 2 128 200 有
880 230400 2 128 200 有
881 230400 2 128 200 有
882 230400 2 128 200 有
883 230400 2 128 200 有
884 230400 2 128 200 有
885 230400 2 128 200 有
886 230400 2 128 200 有
887 230400 2 128 200 有
888 230400 2 128 200 有
889 230400 2 128 200 有
890 230400 2 128 200 有
891 230400 2 128 200 有
892 230400 2 128 200 有
893 230400 2 128 200 有
894 230400 2 128 200 有

七十八行里没有一行的结构是特殊的:没有更高的采样率,没有单导联记录,没有缺失注释。这一点比它的规模更有价值——解析代码写一次就能跑全库,不需要为每条记录写例外分支。

第二张表是文件类型的构成,说明下载时会看到什么:

文件后缀 每段数量 全库数量 作用 是否必需
.hea 1 78 头文件 必需
.dat 1 78 双通道信号本体 必需
.atr 1 78 逐搏标注 必需
.hea- 1 78 头文件历史版本 仅对照用
.xws 1 78 旧版显示脚本 可忽略
.atr- 0 或 1 24 旧版注释 仅对照用
RECORDS — 1 记录名清单,78 行 建议
ANNOTATORS — 1 标注类型说明,一行 建议
SHA256SUMS.txt — 1 校验和清单 建议

单文件最大的是 .dat,每段约 675 KB,与三十分钟双通道 128 Hz、两采样点三字节的算法吻合。全库压缩包约 54.5 MB,解压后信号部分接近五十三兆,其余是注释与附属文件。

2.5 与同类资源的字段差异

把 SVDB 与库内几份同域资源放在一起看结构字段,差异立刻显现:

资源 记录数 每段时长 采样率 导联与命名 标注层级
SVDB 78 30 分钟 128 Hz 2 导联,ECG1/ECG2 仅逐搏
MIT-BIH 心律失常库 48 30 分钟 360 Hz 2 导联,多为 MLII 与 V1 逐搏 + 节律
MIT-BIH 恶性室性异位搏动库 22 30 分钟 250 Hz 2 导联,均记作 ECG 仅节律
CU 室性快速心律失常库 35 约 8.5 分钟 250 Hz 1 导联 仅室颤段起止
自发性室速库 135 对序列 不等 由设备导出 无波形 逐搏 RR 间期
长时程 ST 库 86 数小时 不等 2–3 导联 逐搏 + ST 事件
MIT-BIH ST 改变库 28 不等 不等 2 导联 仅逐搏

SVDB 在这张表里的位置很特别:它的记录数最多,采样率最低,标注层级最单纯。记录数最多意味着它比同门任何一个库都更适合做统计意义上的外测;采样率最低意味着它不适合做形态细节研究;标注层级最单纯意味着它的用途边界最清楚。

§3 它是谁的数据:一篇博士论文撑起的一个库

3.1 名字里的三个词各管一件事

MIT-BIH 是一段机构史。它指的是 MIT 与贝斯以色列医院(Beth Israel Hospital)在 1970 年代末建立的合作实验室,那个实验室在上世纪八十年代产出了一批今天仍在被引用的心电库。名字里的连字符不是修饰,是出处:这段数据来自那套采集与整理流程。

Supraventricular 是任务。它限定了这批记录的入选理由——为心律失常库补齐室上性标本。这个限定同时是优点与局限:优点是室上性样本密度远高于自然分布,做小样本学习时不必为几十个正例发愁;局限是它不再代表任何人群。

Database 是形态。它是数据库,不是挑战赛数据集,没有训练集与测试集的官方划分,也没有排行榜。谁想用,自己划。

三个词连起来读,这个库的定位就出来了:一套出自特定实验室、按特定任务富集、需要使用者自己划分的逐搏心电语料。

3.2 SV 两个字母:一个容易被误读的缩写

公开讨论里,svdb 常被读成「室上速库」。这个读法把 supraventricular 的后半截丢掉了:supraventricular 是形容词,修饰的是整个心律失常家族,包括房性早搏、交界性早搏、房性心动过速、心房扑动等;tachycardia 才是「心动过速」,而全名里根本没有这个词。

另一类误读来自字母的巧合。SV 在某些语境里是「突发」「每搏」的缩写,在心电语境里都不成立。判断依据只有一条:看官方全名,不要看路径名。

这条误读的代价是实打实的。有人按「室上速发作段」的预期下载,打开发现全是正常窦性心律夹着零散早搏,于是判它名不副实。其实名实相符,只是名字里的那个词比想象中宽。

3.3 时间线

时间 事件 依据
1980 年代 MIT-BIH 合作实验室持续采集长时程心电 平台公开资料
1990 年 Greenwald 完成关于噪声心电上下文判读的博士论文 官方引用项
1990 年代前期 记录转为 WFDB 格式并逐搏标注 注释与头文件结构
1999 年 8 月 3 日 作为版本 1.0.0 上线 PhysioNet 官方页面
至今 仍为版本 1.0.0,未再改版 官方版本列表仅一项

时间线里有一处值得注意的落差:官方要求引用的文献是 1990 年的博士论文,而上线是 1999 年,中间隔了九年。这九年间数据在实验室内部使用,直到 PhysioNet 建立统一的 WFDB 分发体系才公开。这个滞后解释了为什么它的采样率停留在 128 Hz——那是八十年代监护设备的常见输出,而不是九十年代末的水平。

3.4 采集与判读中的空白

官方对采集方式的描述只有一句话:这批记录是为补充心律失常库里的室上性心律失常标本而选。没有说明用的是 Holter、床旁监护仪还是别的记录方式,没有说明电极位置与滤波设置,没有说明判读由几个人完成、是否互盲、分歧如何裁决。

这些空白决定了这个库能被用来说明什么。如果判读只有一个人,标注一致性就无从估计;如果电极位置不统一,通道间的形态差异里就混进了装联差异;如果滤波设置未记录,128 Hz 采样带来的带宽上限就无法与前置滤波区分开。§4.3 的案例里,这些问题会以具体的形式出现:一条记录开头的心率、信号质量标记出现的位置、以及那唯一一条节律标记落在哪一段。

值得注意的是目录里那份 ANNOTATORS 文件,它只有一行内容,说明 .atr 里放的是「参考心搏与信号质量标注」。这一行是对标注性质的官方界定,也是判断它没有节律层的最硬证据。

§4 它最独特的东西:逐搏、室上性、带噪声

4.1 为什么"室上性"这一类最难标

心搏分类的常规四分类是正常、室上性异位、室性异位、无法归类。前两类与后两类的边界相对清楚:宽窄、形态、代偿间歇。真正模糊的是正常与室上性异位之间:一次房性早搏的 QRS 与窦性搏动几乎同形,区别在于它提前了、并且前面有一个形态异常的 P 波。

在 128 Hz 的采样率上,P 波常常只剩几个采样点。判读人员要在一个被平滑过的波形上,靠 PR 段的细微倾斜来定夺。这就是为什么 Q(无法归类)这个符号存在:有些拍子,专业判读人员也只能认输。

这个困难直接塑造了库的用法。它不适合做「干净的二分类」训练,因为类别边界本身带噪声;它非常适合做「模型与人类判读的一致性」研究,因为你能看到人类在哪些拍子上也犹豫。

4.2 十一种符号背后的四组

十一种符号可以粗分成四组,这个分法不是官方给的,是看懂库的用途所必需的:

组别 符号 作用
基线 N 正常窦性搏动,构成绝大多数样本
目标异位 S、J、a 室上性起源,库的入选主题
对照异位 V、F、B 室性起源或形态偏宽,构成混淆对
状态标记 Q、` 、~、+`

这个分法解释了为什么这个库适合做鉴别任务而不适合做检测任务。目标组与对照组都是「一拍一拍」的事件,天然对齐;而状态标记组不是心搏,必须剔除。四组之间的关系,就是「拿一批带标签的拍子,去分辨哪些是室上性、哪些是室性」。

a 这一项值得单独说。它的含义是伴室内差异传导的房性早搏:起源在心室以上,但因为传导路径异常,QRS 变宽,形态接近室性早搏。这是临床上误判率最高的一类,也是最考验模型的一类。它同时属于「室上性起源」与「宽 QRS 形态」,两个属性相互矛盾,正是特征工程与深度模型都要面对的死角。

4.3 案例:800 号记录的三十分钟

800 号是全库第一个编号,也是理解「一条记录 = 一串带类别的心搏」这个结构最合适的一条。整段记录有 1921 条标注,符号集合覆盖正常、室上性、室性、融合与两种状态标记。

读它的注释,会看到一串时刻与符号。把时刻换算成秒,取开头十个心搏看间隔:

import wfdb

ann = wfdb.rdann('800', 'atr', pn_dir='svdb')
fs = 128
beats = list(zip(ann.sample, ann.symbol))

for i in range(1, 11):
    prev_s, prev_c = beats[i - 1]
    s, c = beats[i]
    print(f'{i:02d} {c} 第 {s / fs:7.2f} 秒,距上一拍 {(s - prev_s) / fs:5.2f} 秒')

输出的前半段会让一个事实浮出水面:开头十拍的间隔在 1.19 到 1.33 秒之间,对应每分钟四十五到五十次。这不是一段典型的心动过速记录,而是偏慢的窦性心律——室上性标本在这里以「慢背景加零散早搏」的形态出现。

第二件事是记录的时间跨度。最后一条标注落在第 230292 个采样点,换算过来是第 1799.2 秒,距记录末尾不到一秒。也就是说,标注者从头标到尾,没有留下未标注的尾巴。这对做序列模型的人是好消息:输入长度与标签长度严格对齐。

第三件事是那条融合搏。它在第 68270 个采样点,约第 8.9 分钟,是整个三十分钟里唯一的一次。一条记录里只出现一次的事件,任何按比例划分训练集的脚本都会把它分到某一侧,然后另一侧永远学不到这一类。§7.3 会把这条列进偏差清单。

§4.3 的案例还能说明标注密度与临床节奏的关系。1921 拍分布在 1800 秒里,平均每秒 1.07 拍;按五分钟一段切开,各段拍数在两百多到四百多之间浮动。这个浮动本身就是心率变异与异位搏动共同作用的结果,而在 128 Hz 的采样率下,它只能被粗略地还原。

4.4 双导联,但导联只有序号

两条导联记作 ECG1 与 ECG2。这比完全匿名的写法好一点:至少两个通道能稳定区分,代码里按列索引取不会取错。但它仍然不告诉你电极贴在哪里。

后果有三条。第一,公开模型里硬编码导联名的预处理会失效:按 MLII 取通道会报错,按 V1 取会得到空数组。第二,跨库迁移时无法做「同导联对齐」,只能做「同通道序号对齐」,而两个库的通道序号未必对应同一位置。第三,临床解释受限:你不能说「V1 上的 P 波」,只能说「第二通道上的 P 波」。

对算法验证来说,这个限制的影响是可控的。双导联的主要价值是冗余:当一路被伪迹污染时,另一路还在。只要不把导联身份带进结论,用它做通道数消融是成立的。

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

当你的任务是节律检测时。 没有节律区间标签,训练信号为零。

当你的模型依赖 P 波细节时。 128 Hz 下 P 波只剩几个采样点,任何以 P 波形态为主特征的模型在这里都会被采样率卡住。

当你要评估除颤或起搏事件时。 库里没有这类设备事件的标注,也没有对应的符号。

当你要做患者级泛化声明时。 人数未知,人与记录的对应未知。任何「在多少名患者上验证」的表述都缺乏依据。

当你要做长时连续监护的误报累积分析时。 每段只有三十分钟,且是挑选出来的片段,不能代表连续数日的运行状态。

§5 怎么拿到:从五十四兆压缩包到可用的张量

5.1 目录结构与下载面

官方文件目录是扁平的,没有子目录。打开 https://physionet.org/files/svdb/1.0.0/ 会看到六类文件排在一起,按记录编号排序。全库压缩包约 54.5 MB,解压后略大一些。

这个体量意味着你可以整包下载,也可以在 CI 里每次重新拉一遍。它不是那种需要分片续传、对象存储同步的大库。

有一点需要注意:.hea- 与 .atr- 文件名末尾的连字符是名字的一部分,不是笔误。在某些 shell 里直接写 800.hea- 会被当成参数,需要加 ./ 前缀或引号。同理,.xws 里的地址模板含服务端嵌入指令,用浏览器打开会显示原始文本而不是波形。

#-- 先看目录里有什么,确认六类文件都在
curl -sL https://physionet.org/files/svdb/1.0.0/ \
  | grep -o 'href="[^"]*"' | sed 's/href="//;s/"//' \
  | awk -F. 'NF>1{print $NF}' | sort | uniq -c | sort -rn

5.2 三种下载方式

最短的是整包下载,解压即用:

#-- 整包下载(约 54.5 MB)
curl -L -o svdb.zip https://physionet.org/content/svdb/get-zip/1.0.0/
unzip -q svdb.zip -d svdb
ls svdb | head

#-- 只取记录清单,先确认条数
curl -sL https://physionet.org/files/svdb/1.0.0/RECORDS | tee RECORDS | wc -l

如果要做版本固定与增量更新,用 wget 递归更稳:

#-- 递归镜像,已存在则跳过,不追上级目录
wget -r -N -c -np -q \
  https://physionet.org/files/svdb/1.0.0/ \
  -P ./svdb_mirror

#-- 确认七十八段记录的三类必需文件都在
cd svdb_mirror/physionet.org/files/svdb/1.0.0
for f in *.hea; do r=${f%.hea}; [ -f "$r.dat" ] && [ -f "$r.atr" ] || echo "缺文件: $r"; done
echo '结构检查完成'

云上环境用开放桶同步会快很多,但要注意它不支持按记录过滤,只能整目录同步:

#-- 无需凭证的公共桶
aws s3 sync --no-sign-request \
  s3://physionet-open/svdb/1.0.0/ ./svdb_s3/

#-- 只同步头文件与注释,先做结构检查
aws s3 sync --no-sign-request --exclude '*.dat' \
  s3://physionet-open/svdb/1.0.0/ ./svdb_meta/
ls svdb_meta | wc -l

5.3 用 wfdb 直接流式读取

不必先下载。pn_dir 参数会让 wfdb 按需向 PhysioNet 取文件:

import wfdb

names = wfdb.get_record_list('svdb')
print(len(names), names[:3], names[-3:])
#-- 78 ['800', '801', '802'] ['892', '893', '894']

rec = wfdb.rdrecord('894', pn_dir='svdb')
print(rec.fs, rec.sig_len, rec.sig_name, rec.units)
#-- 128 230400 ['ECG1', 'ECG2'] ['mV', 'mV']

ann = wfdb.rdann('894', 'atr', pn_dir='svdb')
print(len(ann.sample), sorted(set(ann.symbol)))

get_record_list 读的就是 RECORDS。注意它返回的是字符串列表,不是整数;800 与 0800 在文件系统里是两个不同的名字,拼接路径时不要自作聪明补零。

流式读取的代价是每次都要走网络,而且信号本体有六百多 KB,批量现场读会很慢。批量处理时应先落盘再读:

import wfdb
import os

#-- 只下载七十八段的三类必需文件,不含历史头文件、旧版注释与显示脚本
wfdb.dl_database('svdb', dl_dir='svdb_local', keep_subdirs=False)

print(len([f for f in os.listdir('svdb_local') if f.endswith('.hea')]))
#-- 78

5.4 把注释读成心搏表

这是这个库最实用的一段代码:把一条记录读成一张「心搏表」,每行是一个心搏的时刻、类别与到上一拍的间隔。间隔是后面所有分析的基础,因为绝大多数心搏分类特征都要靠它来算。

import wfdb
import csv

def beat_table(name, fs=128):
    ann = wfdb.rdann(name, 'atr', pn_dir='svdb')
    rows, prev = [], None
    for s, c in zip(ann.sample, ann.symbol):
        rows.append({
            'record': name,
            'sample': int(s),
            'sec': round(float(s) / fs, 3),
            'symbol': c,
            'rr_sec': round(float(s - prev) / fs, 3) if prev is not None else '',
        })
        prev = s
    return rows

rows = beat_table('800')
with open('svdb_800_beats.csv', 'w', newline='', encoding='utf-8') as f:
    w = csv.DictWriter(f, fieldnames=list(rows[0]))
    w.writeheader()
    w.writerows(rows)
print(len(rows), rows[1])

表里第一行的 rr_sec 为空,是因为它前面没有心搏。不要把它填成零,否则第一条 RR 间期会把平均值拉低。同理,~ 与 | 这两类状态标记也在这张表里占一行,它们的时间间隔没有生理意义,做 RR 统计前要按符号过滤掉。

5.5 单位与时间的六个陷阱

对齐项 常见错法 后果 自检
单位 对 p_signal 再除增益 幅值缩小两百倍 看 R 波峰峰值是否接近一毫伏
时间 把采样点当秒 事件时刻偏早一百二十八倍 事件时刻应落在零到一千八百秒之间
采样率 沿用 360 Hz 的换算 所有时刻偏小三倍 一律从头文件读 fs,不要写死
类别 把 ~ 与 ` ` 当心搏类别 多出两类不存在的搏动
类别 把 S 直接当房早 类别定义与官方符号表不符 S 是上位类,含房性与交界性
通道 按名字取 MLII 报错或取到空数组 按列索引取,不用名字

5.6 三条路线的取舍

路线 适合谁 优点 成本
wfdb.dl_database 研究者做批量实验 一条命令拉全库,路径规范 需要能访问外网
整包 ZIP 离线环境、教学演示 一次解压,五秒可用 每次都要重下全量
流式 pn_dir 临时抽查几条记录 不占本地磁盘 每次读都走网络,单段六百多 KB

对绝大多数使用场景,第一条就够了。这个库小到不存在下载管理的必要性,「先落盘再读」是最省事的选择。

§6 与库内条目的关系

6.1 关系图谱

在千方医数集已收录的心电资源里,SVDB 的位置可以由三对相互独立的轴定出来。第一对轴是「室上性还是室性」,第二对轴是「逐搏标注还是节律或序列级标注」,第三对轴是「有波形还是没有波形」。三对轴交叉,库内几份同域资源就各归其位:

资源 目标心律 标注粒度 有无波形 采样率与时长 记录数 与 SVDB 的关系
SVDB 室上性异位搏动 逐搏 有,双导联 128 Hz × 30 分钟 78 本库
MIT-BIH 恶性室性异位搏动库 室速、室扑、室颤 序列级(节律区间) 有,双导联 250 Hz × 30 分钟 22 同门镜像:同作者体系、同三十分钟,但一个标室性节律、一个标室上性心搏
MIT-BIH 心律失常库 室性早搏为主,含少量室上性 逐搏 + 节律双层 有,双导联 360 Hz × 30 分钟 48 母库:本库是为补充它的室上性标本而选,格式同源、采样率不同
CU 室性快速心律失常库 室颤 序列级(仅段起止) 有,单导联 250 Hz × 约 8.5 分钟 35 同域最窄的邻居:只关心一种节律,只有一路信号
自发性室速库 室速与室颤 序列级(RR 间期) 无波形 由设备导出 135 对 方向相反:有逐搏精度但没有可回看的波形
长时程 ST 库 心肌缺血(ST 改变) 逐搏 + ST 事件 有,2–3 导联 数小时 86 同属逐搏层,但目标是缺血而不是异位搏动
MIT-BIH ST 改变库 运动负荷下的 ST 改变 仅逐搏 有,双导联 不等 28 同批上线、同样只有心搏标签,任务完全不同

五点区隔值得逐条讲清。

与 MIT-BIH 恶性室性异位搏动库的区隔:一个标节律,一个标心搏。 这两份数据出自同一批人的学术脉络,官方引用的都是 Greenwald 的学位论文,一份是 1986 年的硕士论文,一份是 1990 年的博士论文。形态上它们也像:都是半小时、都是双导联、都叫 MIT-BIH。但标注方式正好相反。恶性室性异位搏动库的注释文件里符号全是同一种,真正的信息写在一串以左括号开头的附加字符串里,内容是节律名称;SVDB 的注释是实打实的逐搏符号,一个字符就是一次心跳的类别。前者回答「这一段是什么节律」,后者回答「这一拍是什么」。想用前者训练心搏分类器,标签不存在;想用后者测报警延迟,边界不存在。§4.3 的案例里那条记录一千九百多条标注,在这份镜像库里对应的记录可能只有几十条标记。

与 MIT-BIH 心律失常库的区隔:母库与增补本。 官方说明写得很直白,本库是为补充心律失常库里的室上性标本而选的。这句话同时说明了两件事:一是两者的符号体系同源,解析代码可以复用;二是本库的室上性样本密度被人为抬高,不能当作心律失常库的自然延伸。字段层面还有两处硬差异:采样率 128 Hz 对 360 Hz,导联命名 ECG1/ECG2 对带位置的导联名。做跨库迁移时,这两处差异会先于模型差异显现出来。

与 CU 室性快速心律失常库的区隔:宽度与粒度。 后者只回答「室颤段从哪到哪」,单导联、八分半、两种状态。SVDB 回答的是每一次心跳的类别,双导联、三十分钟、十一种符号。前者是一把窄而深的刀,后者是一张宽而平的网。两者唯一的共同点是都用 WFDB 格式,别的一概不同。

与自发性室速库的区隔:有没有波形。 后者的每一行是一对 RR 间期序列,来自植入式设备的探测通道,逐搏精度很高,但完全没有原始波形——你无法回看那个间期为什么突然缩短。SVDB 相反:有双导联波形可以回看每一次判断的依据,但只有心搏类别,没有设备视角的间期序列。要做「设备怎么看到这一拍」的研究,两者得串起来用。

与两份 ST 库的区隔:任务不同,粒度相近。 长时程 ST 库与 MIT-BIH ST 改变库都带逐搏标签,后者甚至与本库同日上线,标注也「只有心搏」。区别在于目标现象:ST 库关心的是 ST 段的抬高与压低,标注服务的是缺血事件;SVDB 关心的是每一次搏动的起源。一个人如果只想找「带逐搏标签的心电库」,这三份都会被检索到,选错的概率不低——判断依据是看注释表里有没有 S 这一类,有 S 的才是本库。

6.2 检索路径

按需求找库,比按名称找库更有效。下面几条路径都通向 SVDB:

你要做的事 检索词 为什么指向本库
找带室上性早搏标注的公开心电 supraventricular premature beat, PAC annotation 官方全名与 S 符号都指向这里
找逐搏标注、无节律层的老库 beat annotation only, no rhythm labels 全库节律标记只有一条
找 128 Hz 的低采样率心电库 128 Hz ECG, resampled MIT-BIH 全库统一 128 Hz,同门里罕见
找带信号质量标注的心电 signal quality annotation, artifact marker ~ 与 `
找样本量最大的 MIT-BIH 系列库 MIT-BIH 78 records 七十八段是同门里最多的
找可做跨库迁移的配对语料 MIT-BIH transfer, 360 Hz to 128 Hz 与心律失常库构成天然的采样率对照

6.3 与其他库的分工判据

选库时最好先问三个问题,答案会直接把人推向不同的库。

第一个问题:你的标签是「每一拍」还是「每一段」?要每一拍,留在这里;要每一段,去恶性室性异位搏动库或心律失常库的节律层。

第二个问题:你要的异常是室上性还是室性?室上性留在这里;室性去心律失常库或恶性室性异位搏动库。两者都要,用心律失常库,它是唯一同时覆盖两类的逐搏库。

第三个问题:你的模型吃不吃高频?吃高频就去 360 Hz 的库,128 Hz 会先吃掉你的特征;只做节律与类别判断,128 Hz 完全够用,而且文件小、读得快。§4.3 的案例在这里可以再被引用一次:那条记录里 P 波只剩几个采样点,凡是依赖 P 波形态的方法,在这份数据上都会先天吃亏。

§7 质量评估与局限性

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

看这一节之前,需要先放下一个默认假设:数据集的标注越细越好,类别越多越好。按这个假设,SVDB 会被判为不完整——没有节律层,没有起搏与除颤事件,没有导联位置,连人数都没有。

但如果换一个评价轴,结论会反过来。它的目标不是「把一段三十分钟的临床过程讲清楚」,而是「把每一次心跳的类别钉死,供人对照」。在这个轴上,缺失的节律层不是缺陷,是取舍:节律标签需要判读人员对整段做全局判断,成本高、边界模糊;心搏标签是局部判断,成本低、可复核。把力气全押在心搏上,是这个库的理性选择。

用错轴去评分,就会把一个专用工具误判成残缺数据。公开讨论里常见两类抱怨:一类说它不能做节律检测,一类说它的采样率太低。两条都成立,但都不是缺陷报告,是用途错位。下面五维评分按「心搏分类与室上性鉴别研究数据」这个用途给分。

7.1 五维评分

按 DAIMS 的常用维度打分,每项 1–5 分,分数针对「作为心搏分类与室上性鉴别的研究数据」这个用途:

维度 分数 理由
数据规模 4 七十八段、三十九小时、十八万余拍,逐搏库中偏大
标注质量 4 逐搏标注完整、类别定义清楚,但无判读协议与一致性数据
任务适配 5 室上性与室性同段并存,天然构成鉴别任务
文档完整 2 官方说明只有一句话,采集与判读流程几乎全空白
可获取性 5 免注册、五十余兆、ODC-BY,下载与校验都极简

合计 20 分(满分 25)。分数的形状很说明问题:规模、适配、可获取性都高,唯独文档垫底。这意味着它是一份「数据比说明书厚」的资源——你几乎所有的使用约束都得自己从文件里读出来,而不是从官方页面读到。

7.2 标注质量的两层

第一层是心搏定位。每一条标注对应一个 QRS 波群的判读位置,通常落在 R 波峰附近。官方没有说明定位规则是取峰、取起点还是取质心,也没给出定位误差的估计。对分类任务,这个误差可以忽略;对需要毫秒级对齐的任务(比如计算 QRS 时限),它会直接进入结果。

第二层是类别判定。符号表定义了十一种类别,但类别之间的边界依赖判读人员的判断,尤其是 S 与 N、a 与 V 这两对。前者靠提前量与 P 波形态,后者靠宽窄与起始向量。128 Hz 的采样率让这两组判据都变得更勉强。

用途 受哪一层影响 建议
心搏分类评估 类别判定 可用,但要把 Q 与状态标记剔除或单列
QRS 检测评估 心搏定位 可用,容差给到几十毫秒
QRS 时限测量 心搏定位 谨慎,128 Hz 下量化误差约八毫秒
节律检测 两层都不够 不可用,没有节律标签
信号质量研究 状态标记 可用,~ 与 `

7.3 已知的、可枚举的偏差

偏差 表现 影响
选择偏倚 按室上性标本富集挑选,不是随机抽样 类别比例不代表任何人群
人群空白 无年龄、性别、诊断、用药 无法做亚组分析或公平性评估
人数空白 不知七十八段对应多少人 无法做严格的患者级划分
记录编号断裂 800–812、820–829、840–894 三段不连续 空缺段来历官方未说明
采样率偏低 128 Hz,带宽上限约 64 Hz 高频形态特征被削平
导联匿名 只有 ECG1 与 ECG2 不能做带位置的临床解释
判读协议缺失 未说明标注人数与复核方式 类别一致性无法量化
稀有类别稀疏 融合搏、交界性早搏在个别记录里只出现一次 按比例划分时容易被整类划走
旧版注释并存 24 段附 .atr- 用了哪个版本会影响可复现性
无阴性对照库 全部记录都因室上性标本入选 特异度只能在库内成立

稀有类别稀疏这一条值得展开。§4.3 的案例里,整段三十分钟只有一次融合搏。如果按记录划分训练集与测试集,这次融合搏要么在训练侧,要么在测试侧,另一侧就永远见不到这一类。合理的做法是按心搏分层抽样,并且明确报告哪些类别在测试侧样本过少、指标不可解释。

7.4 外部验证矩阵

这个库在文献里的角色,多数是「心搏分类的外部测试集」或「噪声鲁棒性评估集」,很少是唯一的训练集。原因很直接:类别定义清楚但边界模糊,适合检验模型与人类判读的一致性,不适合当作绝对真值。

验证角色 做法 讲得通的地方 风险
跨库心搏分类 在心律失常库上训练,本库外测 采样率与人群都换了一次 采样率差异会与模型差异混在一起
室上性误判分析 单看 S 类的召回与混淆 S 类密度高,样本充足 类别边界本身带判读噪声
噪声鲁棒性测试 用 ~ 与 ` ` 切出噪声段单独评估 噪声是真实发生的,不是人工注入
轻量模型可行性 在双导联 128 Hz 上跑嵌入式推理 采样率接近监护设备实际输出 记录数虽多,人数未知
判读一致性研究 比较模型与符号的差异分布 有 Q 这个「人类也犹豫」的类别 没有双人标注,无法算一致性系数
域适应研究 与 360 Hz 库联合训练与测试 格式与符号体系一致 批次差异未量化

外部研究里常见的表述是「在 MIT-BIH Supraventricular Arrhythmia Database 上评估」,但很少给出患者级置信区间,因为人数本身未知。看到这类结果时,应把它当作方向性证据,而不是可复现的绝对指标。

7.5 它为何能持续:稀缺的是带噪声的逐搏真值,不是波形

这个库从 1999 年上线至今没有扩版,也没有被更大的库取代。原因不在平台,而在供给:能同时满足「连续三十分钟」「每一拍都有人判过」「噪声没被滤掉」「机构愿意公开」四个条件的记录,至今仍然不多。今天的公开心电库体量比它大两个数量级,但绝大多数是单导联、短片段、标签来自报告文本而非逐搏判读。

它的另一层稀缺在于噪声。现代采集链路会把基线漂移与肌电干扰滤得很干净,干净对分类有利,对评估不利——模型在干净数据上学到的边界,一进真实监护环境就崩。这份数据保留的是八十年代的原始干扰,恰好是今天最缺的那一类负样本。只要心搏分类还要面对真实噪声,这七十八段就仍有位置。

§8 生态位与历史

8.1 历史沿革

SVDB 的源头是一篇博士论文,不是一个数据集项目。1990 年,Greenwald 在 Harvard-MIT 健康科学与技术分部完成论文,题目大意是《用上下文信息改进噪声污染心电中的心律失常检测与分类》。论文要解决的问题很具体:单看一拍分不清的类别,能不能靠前后若干拍的上下文来定夺。

这个思路决定了数据的形态。要做上下文判读,样本必须是连续的长带,标签必须落到每一拍,噪声必须保留。三段要求合起来,就是七十八段半小时、逐搏标注、不做强滤波的记录。

1990 年代前期,这批记录被转成 WFDB 格式并整理标注。1999 年 8 月,它与另外几份 MIT-BIH 老库一起以版本 1.0.0 上线 PhysioNet,获得独立 DOI。此后再未改版,官方版本列表只有一项。

8.2 与 PhysioNet 其他库的关系

PhysioNet 的心电库可以粗分为三代。第一代是 1980 年代为算法开发采集的库,MIT-BIH 心律失常库、CU 室性快速心律失常库、恶性室性异位搏动库与 SVDB 都属于这一代,特点是样本小、事件真、标注围绕特定任务。第二代是 2000 年代为挑战赛整理的库,规模变大、格式统一、标注规范化。第三代是 2010 年代之后的超大库与可穿戴库,强调规模与多样性。

SVDB 站在第一代的末端,与心律失常库同源。它没有经历第二代的标注规范化,所以符号体系里仍保留了 a、J、B 这些细分类别——规范化之后,这些类别通常会被合并进更大的桶里。也没有进入第三代的规模竞赛,所以至今只有七十八段。这不是停滞,是定位:它的任务从来不需要更大的体量。

8.3 生态位:逐搏点名册而不是节律轨迹

角色 节律轨迹型 逐搏点名册型
代表库 恶性室性异位搏动库、CU 室性快速心律失常库 SVDB、心律失常库、ST 改变库
提供的核心信息 节律从哪一刻变成了什么 每一次搏动属于哪一类
典型任务 报警时刻评估、过渡分析、误报分析 心搏分类、鉴别诊断、检出评估
失败模式 样本太少、无阴性对照 类别不平衡、判读边界模糊
不可替代性 较高,同类库少 中等,同类库多但这份的噪声与规模组合少见

把它放错列,就会得到两种典型错误:拿它做节律检测,找不到边界;拿节律库做心搏分类,找不到标签。两种错误都很常见,因为库名里的 database 让人以为它们可以互换。

8.4 谁在用它,用来做什么

从公开文献的使用方式看,主要有三类。第一类是做心搏分类与室上性鉴别的人,把它当外部测试集,检验模型换一批记录、换一个采样率之后还能不能分开 S 与 V。第二类是做信号质量与噪声鲁棒性的人,利用 ~ 与 | 两个符号切出噪声段,评估算法在干扰下的表现。第三类是做心电教学与算法复现的人,用它做带标准答案的练习素材。

第三类最少,但最贴近这个库的本意。它的原始论文关心的是「上下文能不能救回那些单拍分不清的类别」,而要看懂这件事,必须能同时看到波形与逐拍标签——也就是 §4.3 的案例所展示的那种记录。

§9 使用指引

9.1 三种角色的路径

角色 第一天 第一周 注意事项
算法研究者 跑通 §5.3 的读取,画出 800 号全段双导联波形 建立心搏表,算基线模型的四类混淆矩阵 先剔掉 ~ 与 `
设备工程师 确认 128 Hz 与设备采样率的差异,做重采样 在单路与双路上做阈值法与轻量模型对比 不要按导联名取通道,按列索引
教学与复现 挑三条类别跨度大的记录做成练习 把符号表翻成中文对照,逐拍对答案 讲清 S 是上位类,不是房早

9.2 一条最短的可用流程

#-- 1. 取一条记录(含头、信号、注释)
python3 - <<'PY'
import wfdb
wfdb.dl_database('svdb', dl_dir='svdb_one', records=['800'], keep_subdirs=False)
PY

#-- 2. 确认文件齐全
ls svdb_one

#-- 3. 打印前二十拍的类别与间隔
python3 - <<'PY'
import wfdb
ann = wfdb.rdann('svdb_one/800', 'atr')
for s, c in list(zip(ann.sample, ann.symbol))[:20]:
    print(c, round(float(s) / 128, 2))
PY
import wfdb
import numpy as np

rec = wfdb.rdrecord('svdb_one/800')
x, fs = rec.p_signal[:, 0], rec.fs
ann = wfdb.rdann('svdb_one/800', 'atr')

#-- 只保留真正的心搏符号,剔掉质量与伪迹标记
BEAT = {'N', 'S', 'V', 'F', 'Q', 'J', 'a', 'B'}
pairs = [(int(s), c) for s, c in zip(ann.sample, ann.symbol) if c in BEAT]
print(f'时长 {len(x) / fs / 60:.1f} 分钟,心搏 {len(pairs)} 个')

rr = np.diff([s for s, _ in pairs]) / fs
print(f'RR 中位数 {np.median(rr):.3f} 秒,约 {60 / np.median(rr):.0f} 次每分')

#-- 看 S 类出现的位置,确认它们不是集中在某一段
s_at = [s / fs / 60 for s, c in pairs if c == 'S']
print(f'S 类 {len(s_at)} 个,首个在 {min(s_at):.1f} 分钟' if s_at else '本段无 S 类')

这段流程的价值是让你在几分钟内看到真实波形与真实标签。看到之后,多数关于「这个库能不能用」的疑问会自己消失:能用在哪,一眼就清楚。

9.3 引用方式

官方要求引用原始学位论文,而不是只引用平台:

引用对象 内容
数据集 MIT-BIH Supraventricular Arrhythmia Database, version 1.0.0. PhysioNet. 1999. DOI: 10.13026/C2V30W
原始论文 Greenwald SD. Improved detection and classification of arrhythmias in noise-corrupted electrocardiograms using contextual information. Ph.D. thesis, Harvard-MIT Division of Health Sciences and Technology, 1990.
平台 PhysioNet 平台综述(2026 年发表于 Nature Health),按官方页面的 Cite 按钮生成

写论文时应注明版本号与采样率。这个库的 128 Hz 与心律失常库的 360 Hz 经常被混为一谈,明确写出采样率能省掉后续的复现争议。

9.4 接进来之后最先撞上的三个卡点

卡点一:类别不平衡。 正常搏占绝大多数,室上性与室性都是零散出现。直接训练会得到一个「全判正常」也有很高准确率的模型。可行的做法是分层采样或按类别加权,并且报告每一类的召回,而不是只报总体准确率。

卡点二:状态标记混进标签。 ~ 与 | 在注释里与心搏混排,很多现成的解析脚本会把它们当成两个类别。结果是类别数从四类变成六类,指标看上去更差,实际上只是标签没洗干净。

卡点三:复现别人对不上。 同一个库、同一篇论文,你算出的召回与原文差几个百分点,原因往往有三:采样率换算写死成 360、状态标记没剔、或者 S 与 J、a 的合并方式不同。下载后先确认这三件事,再开始算。

卡点 表面症状 根因 处理
类别不平衡 全判正常也高分 室上性与室性占比低 分层采样,分类别报召回
标签没洗 类别数比预期多两类 ~ 与 ` ` 被当心搏
时刻错位 事件时刻偏小三倍 沿用 360 Hz 换算 从头文件读 fs
稀有类丢失 融合搏在测试侧为零 按记录划分 改按心搏分层
版本不一 与他人结果差几个百分点 用了 .atr- 而非 .atr 锁版本、锁文件名

§10 AI 使用声明

项目 声明
文本生成 本文由 AI 辅助撰写,编辑把关结构与事实
数字来源 规模、结构、边界三类数字来自 PhysioNet 官方页面与官方文件
文件核验 RECORDS 共七十八行、七十八份头文件、七十八份注释文件经直接访问确认
记录数 官方页面与 RECORDS 均为七十八条,一致
受试者数 官方未公布,本文未做推断
论文信息 原始论文信息取自官方页面的引用项,未读学位论文全文
未核验内容 逐条记录的类别构成、各段的确切异位搏动数、.atr- 与 .atr 的差异
图像 无配图;封面为生成式提示词,不含真实心电图
免责 本文不构成临床建议;使用须遵守 ODC-BY 1.0 署名要求

常见误读(避坑清单)

说法 实际 证据
「SV 是室上速,库里全是心动过速发作」 SV 指室上性,指起源位置而非心率;主体是正常搏与零散早搏 官方全名与数据说明句
「它和心律失常库一样有节律标签」 只有逐搏标签,节律改变符号全库一条 注释文件符号统计与 ANNOTATORS 说明
「采样率和心律失常库一样是 360 Hz」 128 Hz,采样点 230400 七十八份头文件全部一致
「78 段就是 78 名受试者」 人数官方未公布,不能假定一一对应 官方只说为补充标本而选
「导联是 MLII 和 V1」 只记作 ECG1 与 ECG2,无位置信息 头文件第 2、3 行
「S 就是房性早搏」 S 是室上性上位类,含房性与交界性;交界性与差异传导另有符号 符号表 S、J、a 分列
「~ 和 ` ` 是两种罕见心搏」 是信号质量改变与伪迹标记,不是心搏
「它可以直接训练节律检测模型」 无节律区间标签,训练信号为零 注释符号统计
「78 段是随机抽的人群样本」 按室上性标本富集挑选 官方数据说明「chosen to supplement」
「它从 1999 年后一直在更新」 版本始终是 1.0.0,官方版本列表只有一项 官方版本区

FAQ

Q1:SV 这两个字母到底代表什么?
代表 supraventricular,室上性。全名 MIT-BIH Supraventricular Arrhythmia Database,主题是起源于心室以上的异位搏动。它不代表「突发」,也不代表某个以 SVT 命名的专病库。

Q2:它到底有多少条记录?
七十八条。编号分三段:800 到 812、820 到 829、840 到 894。官方页面摘要与 RECORDS 文件两处一致,这个数字从 1999 年上线至今没有变过。

Q3:它有多少名受试者?
官方没有公布。数据说明只写这批记录是为补充心律失常库里的室上性标本而选,没有给出人数,也没有说明一段记录是否对应一个人。做实验划分时应把这一点写进限制。

Q4:它和 MIT-BIH 心律失常库是什么关系?
官方说是「补充」关系:心律失常库里室上性标本偏少,本库专门挑了一批补上。两者格式与符号体系同源,但采样率、导联命名、记录数都不同,不能当成同一个库的两个分片。

Q5:它有节律标签吗?
基本没有。注释文件按逐搏方式标注心搏类别,节律改变符号在全库只出现一次,在 852 号记录第 876 秒附近,内容是正常窦性心律。要节律区间,去看恶性室性异位搏动库或心律失常库的节律层。

Q6:为什么采样率只有 128 Hz?
官方没有解释。合理推断是它沿用八十年代监护设备的输出,那批设备常见 128 Hz;1999 年上线时也没有做重采样升级。后果是带宽上限约 64 Hz,够做节律与类别判断,不够做高频形态分析。

Q7:两条导联分别是什么位置?
官方没有说明,只记作 ECG1 与 ECG2。你可以做通道间的形态比对,但不能在论文里声称它们是某个具体导联,也不能把公开模型的固定导联假设直接搬过来。

Q8:S 和房性早搏是一回事吗?
不是。S 是室上性异位搏动的上位类别,涵盖房性与部分交界性搏动;真正只属于交界性的有 J,伴室内差异传导的房早有 a。把 S 等同于房早,会让类别定义与官方符号表对不上。

Q9:~ 和 | 要不要删掉?
做心搏分类要删,或至少单列。它们是信号状态标记,不是心搏类别,采样点往往落在一个正常心搏上。做信号质量研究则要留,它们提供了现成的噪声切分点。

Q10:全库有多大?下载要多久?
压缩包约 54.5 MB。任何能上网的环境都能在一分钟内下完,适合放进 CI 做每次构建的回归测试。

Q11:许可允许商业使用吗?
ODC-BY 1.0 允许商业使用,条件是按许可要求署名。署名时应同时引用数据集与 Greenwald 的博士论文,具体条款以许可全文为准。

Q12:能不能用它做十二导联研究?
不能。它只有两个通道,且没有导联位置。要做多导联,得换库;要做逐搏室上性鉴别,这里的样本密度是它最大的优势。

术语表

术语 解释
室上性 起源在心室之上,包括窦房结、心房与房室交界区
室上性异位搏动 起源于心房或交界区的提前搏动,符号 S
房性早搏 起源于心房的提前搏动,P 波形态与窦性不同
交界性早搏 起源于房室交界区的提前搏动,符号 J
室内差异传导 室上性冲动在心室内的传导路径异常,QRS 变宽
融合搏动 室上与室性激动同时抵达心室形成的混合波形,符号 F
束支传导阻滞 束支传导受阻导致 QRS 增宽,符号 B
无法归类搏动 判读人员也无法确定起源的搏动,符号 Q
信号质量改变 标注信号由好转坏或由坏转好的转折点,符号 ~
孤立伪迹 形态类似 QRS 但不是心搏的干扰,符号 `
节律改变标记 标注某段节律起点的标记,本库几乎不出现,符号 +
逐搏标注 对每一次心搏给位置与类别,本库的标注属于此类
序列级标注 对一段连续区间给属性,本库没有
WFDB PhysioNet 使用的波形数据库格式,含头、信号、注释三类文件
212 格式 每两个 12 位采样点打包进三个字节的存储方式
增益 每毫伏对应的整数单位数,本库为 200
ADC 零值 零电平对应的整数,换算物理量时先减
校验和 全段采样点累加和,用于检测文件完整性
采样率 每秒采样点数,本库 128,决定可用带宽上限
奈奎斯特频率 采样率的一半,本库为 64 Hz
上位类别 涵盖若干子类的粗分类,如 S 涵盖房性与交界性
类别不平衡 各类样本量差距悬殊,本库正常搏占绝对多数
患者级划分 同一患者的所有记录只进训练或只进测试,本库无法严格做到
ODC-BY 开放数据共享署名许可
DOI 数字对象标识符,用于长期定位数据集

附录 A:核心数字核对表

项 值 来源 来源层级
记录数 78 官方页面;RECORDS 逐行 官方页面
记录编号 800–812、820–829、840–894 RECORDS 官方文件
每段时长 30 分钟 官方页面 官方页面
每段采样点 230400 七十八份头文件全部一致 官方文件
采样率 128 Hz 官方页面;头文件 官方页面
导联数 2 头文件信号条数 官方文件
导联名 ECG1、ECG2 头文件第 2、3 行 官方文件
增益 200 七十八份头文件全部一致 官方文件
存储格式 212 头文件 官方文件
标注层级 逐搏,几无节律 官方 ANNOTATORS;注释符号统计 官方文件
标注符号数 11 种 七十八份注释文件并集 官方文件
标注总量 187,877 条 七十八份注释文件求和 官方文件
全库时长 39 小时 78 × 30 分钟 推算
压缩包体积 54.5 MB 官方下载端点响应头 官方文件
许可 ODC-BY 1.0 官方页面 官方页面
DOI 10.13026/C2V30W 官方页面 官方页面
首次发布 1999-08-03 官方页面 官方页面
版本号 1.0.0(唯一版本) 官方版本区 官方页面

附录 B:数字的来源分层

第一层:官方页面与官方文件。 记录数、编号、时长、采样率、导联数与导联名、增益、存储格式、标注层级、标注符号集合、标注总量、体积、许可、DOI、发布日期,全部来自项目主页的数据说明段,以及 RECORDS、ANNOTATORS、SHA256SUMS.txt 与七十八份头文件、七十八份注释文件。这一层的数字可以直接引用。

第二层:论文摘要与引用条目。 原始学位论文的出处、作者、年份与题目来自官方页面的引用项;论文所属机构同为官方页面所载。没有读到学位论文全文,因此不引用论文里的任何具体数字。

第三层:未核实。 受试者人数、年龄、性别构成、每条记录的类别构成、各段异位搏动的确切数量、24 份 .atr- 与现行 .atr 的差异、记录编号三段空缺的来历。这些需要逐条比对或查阅实验室档案才能得到,正文中凡涉及处均写为「官方未公布」或只做定性表述。

附录 C:完整参考文献

编号 文献 链接 用途
1 MIT-BIH Supraventricular Arrhythmia Database v1.0.0 https://physionet.org/content/svdb/1.0.0/ 全部规模、结构、边界数据
2 该库文件目录 https://physionet.org/files/svdb/1.0.0/ RECORDS、头文件、注释、ANNOTATORS
3 Greenwald SD,噪声心电上下文判读博士论文,1990 https://dspace.mit.edu/handle/1721.1/29206 原始采集与分析背景
4 PhysioNet 平台综述(2026) https://doi.org/10.1038/s44360-026-00096-z 托管模式与引用规范
5 PhysioBank 注释码定义 https://physionet.org/physiobank/annotations.shtml N、S、V 等符号含义
6 MIT-BIH 心律失常库(母库对照) https://physionet.org/content/mitdb/ §2.5 与 §6.1 对比
7 恶性室性异位搏动库(镜像对照) https://physionet.org/content/vfdb/ 节律级与逐搏级的对照
8 CU 室性快速心律失常库(对照) https://physionet.org/content/cudb/ 单导联窄任务对照
9 MIT-BIH ST 改变库(对照) https://physionet.org/content/stdb/ 同为仅逐搏标注的老库

附录 D:任务代码

任务一:全库心搏表

import wfdb
import pandas as pd

BEAT = {'N', 'S', 'V', 'F', 'Q', 'J', 'a', 'B'}

def full_table(library='svdb'):
    rows = []
    for name in wfdb.get_record_list(library):
        ann = wfdb.rdann(name, 'atr', pn_dir=library)
        for s, c in zip(ann.sample, ann.symbol):
            rows.append({'record': name, 'sample': int(s), 'symbol': c,
                         'is_beat': c in BEAT})
        print(name, len(ann.sample), '条标注')
    return pd.DataFrame(rows)

df = full_table()
print(df.shape, df['symbol'].nunique())
print(df[df['is_beat']].groupby('symbol').size().sort_values(ascending=False))

这段代码的价值在于把「是不是心搏」显式成一列。is_beat 为假的行是状态标记,做分类前过滤掉即可,不要删掉——做信号质量研究时它们正是切分点。

任务二:四类混淆矩阵骨架

import wfdb
import numpy as np

#-- 官方符号到四分类的映射,S 与 J、a 合并为室上性
MAP = {'N': 'N', 'S': 'S', 'J': 'S', 'a': 'S',
       'V': 'V', 'F': 'V', 'B': 'V'}

def load(name, fs=128):
    rec = wfdb.rdrecord(name, pn_dir='svdb')
    ann = wfdb.rdann(name, 'atr', pn_dir='svdb')
    x = rec.p_signal[:, 0]
    idx = [(int(s), MAP[c]) for s, c in zip(ann.sample, ann.symbol) if c in MAP]
    return x, idx, fs

def window(x, center, fs, before=0.25, after=0.45):
    a = max(0, center - int(before * fs))
    b = min(len(x), center + int(after * fs))
    seg = x[a:b]
    return seg if len(seg) == b - a else None

for name in ['800', '801', '802']:
    x, idx, fs = load(name)
    segs = [window(x, s, fs) for s, _ in idx]
    ok = sum(1 for s in segs if s is not None)
    print(name, len(x), '拍', ok, '段可用窗口')

窗口长度按 128 Hz 取,前后共零点七秒,覆盖一个完整 QRS 与部分 T 波。阈值与模型都不在里面,这段代码只负责把「对齐好的张量」交出来——真正的分类器该怎么写,取决于你要回答的问题。

任务三:噪声段与心搏的相邻关系

import wfdb

def quality_context(name, fs=128):
    ann = wfdb.rdann(name, 'atr', pn_dir='svdb')
    smp = list(ann.sample)
    sym = list(ann.symbol)
    out = []
    for i, c in enumerate(sym):
        if c not in ('~', '|'):
            continue
        prev = sym[i - 1] if i else None
        nxt = sym[i + 1] if i + 1 < len(sym) else None
        gap = (smp[i] - smp[i - 1]) / fs if i else None
        out.append({'record': name, 'sec': round(smp[i] / fs, 1),
                    'mark': c, 'prev': prev, 'next': nxt,
                    'gap_sec': round(gap, 2) if gap else None})
    return out

for n in ['800', '801', '820']:
    for r in quality_context(n):
        print(r)

输出的 gap_sec 告诉你质量标记落在一次心搏之后多久。若它总是紧跟在一拍之后,说明标记是「事后补记」;若它落在两拍之间较远处,说明标注者是在实时判断信号状态。这个差别会影响你怎么用这些标记做切分。

附录 E:如果只记五件事

序号 记住什么 为什么
1 78 段、每段 30 分钟、双导联、128 Hz 这四个数决定了它的全部能力边界
2 只有逐搏标签,几乎没有节律标签 想做节律检测的人可以立刻离开
3 SV 指室上性,不是室上速 找错库的人多半在这里停下
4 它是心律失常库的增补本,不是随机人群样本 任何比例类结论都不能外推
5 十八万余拍的逐搏真值加真实噪声,是它最稀缺的地方 拿它做外测,比拿它做训练更有价值

编辑说明

本文的核验时间为 2026 年 10 月 28 日。核对方式为直接访问 PhysioNet 项目页与文件目录,确认 RECORDS 共七十八行、编号分三段不连续,逐份读取七十八个 .hea 头文件(采样率 128 Hz、采样点数 230400、双导联记作 ECG1 与 ECG2、增益 200、格式 212 全库一致),并读取七十八份 .atr 注释文件,确认符号集合共十一种、节律改变符号仅出现一条、ANNOTATORS 文件仅一行且说明为「参考心搏与信号质量标注」。论文侧只依据官方页面给出的引用项,未读 Greenwald 的学位论文全文,因此不引用其中的任何数字。未覆盖的内容包括:受试者人数与人口学构成、逐条记录的类别构成、各段异位搏动的确切数量、24 份旧版注释与现行注释的差异、编号空缺段的来历。库内检索确认此前没有 svdb 词条;与 vfdb、cudb、mvtdb、mitdb、ltstdb、stdb 的区隔已在 §2.5 与 §6.1 写明,其中与 vfdb 的区隔按「室上性对室性、逐搏对节律、128 Hz 对 250 Hz」三条轴逐项对齐。


相关数据集导航

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

  • wctecgdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
  • ahadb — 共享标签:生理信号 / 心电信号 / 心血管疾病
  • chfdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
  • crisdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
  • cudb — 共享标签:生理信号 / 心电信号 / 心血管疾病
  • ltdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
  • ltstdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
  • iafdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
  • mvtdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
  • nsrdb — 共享标签:生理信号 / 心电信号 / 心血管疾病

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

返回 AI-Ready 数据集