信息速览
MIT-BIH ST Change Database 在 PhysioNet 上只有一行简介、两张表格和二十八个文件名。缩写成 stdb 之后,它最容易被读成「ST 段数据库」——这个读法方向没错,落点却偏了:库名里的 ST 确实是 ST 段(S-T segment),Change 指这一段在记录过程中的移动,而不是注释文件里有 ST 改变事件。
它属于 MIT-BIH 系列里最早那一批记录,编号从 300 排到 327,共 28 条。官方说明写得很克制:这些记录长度不一,多数在运动负荷试验中采集,表现一过性 ST 下移;末尾五条(323 至 327)是长时程心电记录的摘录,表现 ST 抬高。紧接着还有一句更关键的话——注释文件只含心搏标签,不含 ST 改变标注,并特意点出这与 European ST-T Database 的做法不同。
于是这个库的实际形态与名字给人的印象之间有一道缝:信号里有 ST 改变,标注里没有 ST 改变。理解这条缝,基本就理解了这个库能做什么、不能做什么(§1.2)。一屏速览见下表。
| 维度 | 内容 |
|---|---|
| 官方全名 | MIT-BIH ST Change Database |
| 缩写 | stdb |
| ST 的确切所指 | ST 段(S-T segment),非「标注有 ST 事件」 |
| 作者 | Paul Albrecht(Cambridge Heart, Bedford, MA) |
| 托管平台 | PhysioNet,Open Access 栏目 |
| 版本 | 1.0.0,1999 年 8 月 3 日发布 |
| DOI | 10.13026/C2ZW2H |
| 记录数 | 28 条,编号 300 至 327 连续 |
| 两段构成 | 300–322 为负荷试验段;323–327 为长时程摘录 |
| 通道数 | 18 条双通道,10 条单通道 |
| 采样率 | 360 Hz,每样本 12 位 |
| 单条时长 | 约 13 分钟至 67 分钟 |
| 注释内容 | 仅心搏标签,无 ST 事件 |
| 许可 | ODC-BY 1.0 |
| 未压缩体积 | 约 42 MB |
§1 它要解决的具体麻烦
1.1 一句话结论:它是「有 ST 改变却没标 ST 改变」的信号源
这个库卖的不是标注,是信号本身。二十八条记录里,ST 段确实在动——负荷试验中随心率上升而逐渐下移,长时程摘录里则呈现抬高。但要把「哪一刻开始下移、下移多少毫米、何时回到基线」变成机器可用的标签,这一步官方没有做。
这个定位决定了它的使用方式:它适合做信号级的工作,比如基线漂移抑制、J 点定位、ST 测量算法的前端处理,以及运动伪迹下的 QRS 检出;它不适合做事件级的工作,比如训练一个「这段是不是缺血」的分类器——后者需要 European ST-T Database 或 ltstdb 那种逐事件标注。
大多数介绍性文字会把这个库写成「MIT-BIH 的 ST 段版本」,听起来像是 MIT-BIH 心律失常库的姊妹库。实际上两者的关系更接近「同一批人、相近年代、不同目的」:心律失常库关注心搏类别,这个库关注那段被压低或被抬高的等电位线。
1.2 三条常见的错误期待
第一条是把库名当成标注清单。stdb 里的 S 与 T 是波形上的位置,不是注释里的符号。打开 .atr 文件,看到的是一个个心搏位置,而不是「ST 事件开始」「ST 事件结束」这样的段落标记。若拿它去训练事件检测器,标签得自己造。
第二条是以为它覆盖长时程。「Change」这个词在临床语境里天然带「随时间变化」的味道,容易让人联想到 Holter。全库确实有五条来自长时程记录,但那五条是摘录,单条最长不到四十三分钟,而且官方明说它们表现的是抬高而非下移。真正的长时程 ST 库是 ltstdb。
第三条是以为二十八条记录就是二十八个人。官方的措辞是「二十八条记录」,从未说过对应多少人。头文件里也没有受试者标识字段,只有记录号。当一条记录被切成两段或一人被记了两条时,从文件本身无法分辨。
1.3 它能给到的与给不到的
| 你的需求 | 它给的 | 够不够 |
|---|---|---|
| 带 ST 下移的真实心电信号 | 二十余条负荷试验记录,ST 段确有下移 | 够,而且是运动条件下少见的素材 |
| 逐事件的 ST 标注 | 完全没有,注释只标心搏 | 不够,得自己算或换库 |
| 常模人群的静息心电 | 没有;多为运动负荷条件 | 不够,去看 nsrdb |
| 长时程动态心电 | 仅五条摘录,且是抬高 | 不够,换 ltstdb |
| 双通道同步记录 | 十八条双通道,十条单通道 | 部分够,用之前先看头文件 |
| 心律失常多样性 | 有少量室性与室上性异位搏动标注 | 部分够,但不能替代标注更细的库 |
| 现代数字设备下的信号 | 上世纪八十年代初的采集条件 | 不够,只能作历史对照 |
| 教学演示 ST 段形态 | 体量小、下载快、形态典型 | 够,这是它最好用的场景之一 |
1.4 你的处境与它能帮到的事
| 你的处境 | 它能帮你什么 | 下一步该做什么 |
|---|---|---|
| 要验证自己写的 ST 测量代码是否跟得上运动中的基线漂移 | 提供真实的负荷试验信号,漂移形态比合成信号复杂得多 | 先用短记录跑通,再用最长的 306 号压测 |
| 论文需要一个「ST 段改变」的公开引用 | 提供可署名引用的 DOI 与 1983 年硕士论文 | 引用时说明它只有心搏标注,避免审稿人误读 |
| 想做一个缺血事件分类器 | 只能提供无事件标签的正例信号 | 换 European ST-T Database 或 ltstdb 拿事件标签 |
| 教学里要展示 ST 下移与 ST 抬高 | 两种形态都有,且可以并排演示 | 从 300–322 段取下移、从 323–327 段取抬高 |
| 只想快速跑通 WFDB 读取流程 | 全库几十兆,下载与读入几乎无成本 | 用 300 号当第一个示例 |
| 要做人群层面的 ST 发生率的结论 | 记录按目的挑选,不是人群抽样 | 放弃这个结论,换队列型数据 |
1.5 一句话判断
它是一个信号可靠、标签单薄的运动负荷心电切片:能验证你的 ST 测量前端,不能替你判断哪里是事件。
1.6 不适合谁:四条边界
不适合需要事件标签的人。 如果你的任务定义里出现「缺血段起点」「ST 事件持续时间」这类字段,这个库一次都给不出。它给出的只有心搏位置,事件必须由你在信号上重新计算并自行定义阈值,而阈值一旦自定义,跨论文比较就失去共同口径。
不适合做长时程研究的人。 五条长时程摘录加起来不到三小时,且只呈现抬高。凡涉及昼夜节律、睡眠期 ST 变化、二十四小时负荷这类问题,样本量与结构都不支持。这一类需求应转向 ltstdb,那里每条记录本身就是二十一至二十四小时。
不适合追求人群代表性的人。 记录因「有 ST 改变」而被收入,进来的人本来就是负荷试验中出现异常的那一批。任何「多少人会出现 ST 下移」的推断,都被这个入组条件截断。
不适合要求现代设备条件的人。 采集年代在上世纪八十年代初,滤波器、电极与记录介质都与今天的十二导联数字心电不同。把它当作设备无关的基准,会把旧设备的频率响应一起学进去。
§2 数据构成与规格
2.1 一条记录由三件文件构成
每条记录在目录下占三件核心文件:.hea 是纯文本头文件,第一行写记录名、通道数、采样率与样本总数;其后每行描述一个通道的格式、增益、基线与初始值;.dat 是二进制数据体,按通道交错存放 12 位样本;.atr 是注释文件,记录每个心搏的样本位置与类别符号。
目录里还能看到两类附带文件。.hea- 是头文件的旧版本备份,时间戳统一为 1992 年 7 月 31 日;.xws 是 PhysioNet 早期的波形显示侧文件,只有几十字节,内容是三行参数,如今读取已不需要。这些文件的存在本身就是年代证据——它们记录了这个库从本地工作站迁到网络平台过程中留下的痕迹。
2.2 字段与文件的完整字典
头文件是理解这个库的唯一入口,其余文件都由它派生。
| 文件/字段 | 位置 | 含义 | 容易卡住的点 |
|---|---|---|---|
| 记录名 | .hea 第一行首字段 |
三位数字,300 至 327 | 编号连续,不代表同一受试者 |
| 通道数 | .hea 第一行第二字段 |
1 或 2 | 全库 18 条为 2、10 条为 1 |
| 采样率 | .hea 第一行第三字段 |
全库统一 360 | 单位是每秒样本数 |
| 样本总数 | .hea 第一行第四字段 |
该记录总样本点 | 除以 360 得秒数 |
| 文件名 | 通道行首字段 | 数据体文件名,均指向同名 .dat |
多通道共用同一个数据体 |
| 格式码 | 通道行第二字段 | 212 表示 12 位、双样本打包 | 不是简单的 16 位小端 |
| 增益 | 通道行第三字段 | 每毫伏对应的数字单位 | 换算物理量必须用 |
| 位分辨率 | 通道行第四字段 | 12 | 与格式码配套 |
| 基线 | 通道行第五字段 | 零电位对应的数字值 | 求物理值要先减基线 |
| 初始值 | 通道行第六字段 | 第一个样本的数字值 | 读取时可用于校验 |
| 校验和 | 通道行第七字段 | 全通道样本和 | 用来确认数据体没坏 |
| 块大小 | 通道行第八字段 | 0 表示默认 | 多数记录都是 0 |
| 描述 | 通道行末字段 | 一律写作 ECG | 不区分导联位置 |
| 注释符号 | .atr |
心搏类别,如 N、V、S、~ | 不含任何 ST 事件符号 |
这张表里最需要留意的是最后两行。通道描述一律写成 ECG,没有标注这是哪一个导联——是肢体导联还是胸前导联、具体哪个位置,头文件不说,官方页面也不说。注释符号同理,只承载心搏类别,不承载波形段落状态。
2.3 一条记录的完整解剖
以 300 号为例,头文件只有三行,读完就能算清这条记录的一切。
300 2 360 536976
300.dat 212 296 12 0 40 3141 0 ECG
300.dat 212 300 12 0 -5 427 0 ECG
第一行说:记录名 300,两个通道,采样率 360,共 536,976 个样本。第二行与第三行分别是两个通道的参数:格式 212、增益 296 与 300、12 位分辨率、基线 0、初始值 40 与 -5、校验和 3141 与 427,描述均为 ECG。
由这四行可以直接推出三个数:时长约 24.9 分钟(536976 ÷ 360 ÷ 60);两个通道共用同一个 1.5 MB 左右的数据体;整条记录只覆盖一次检查。
import wfdb
#-- 读取头文件,不下载数据体
h = wfdb.rdheader("300", pn_dir="stdb/1.0.0")
print(h.record_name, h.n_sig, h.fs, h.sig_len)
print(h.sig_name, h.adc_gain, h.baseline)
#-- 换算物理量需要的两个系数
print("时长(秒)", h.sig_len / h.fs)
这段代码的关键在于 rdheader:只取头文件,几百字节,就能在下载整库之前先看清一条记录的规格。对二十八条记录逐条跑一遍,得到的就是下面那张表。
2.4 二十八条记录的规模结构
全库样本点相加约为一千七百四十八万个,按 360 Hz 折算约十三余小时。这个总量不大,但它分布在长度差异明显的二十八条记录上。
| 记录号 | 通道数 | 时长(分钟) | 所属段 |
|---|---|---|---|
| 300 | 2 | 24.9 | 负荷试验段 |
| 305 | 2 | 13.1 | 负荷试验段 |
| 306 | 2 | 67.2 | 负荷试验段,全库最长 |
| 312 | 2 | 27.9 | 负荷试验段 |
| 313 | 1 | 23.2 | 负荷试验段 |
| 318 | 2 | 27.1 | 负荷试验段 |
| 322 | 1 | 13.2 | 负荷试验段,该段最短 |
| 323 | 1 | 42.9 | 长时程摘录,全库唯一单通道长记录 |
| 325 | 2 | 21.2 | 长时程摘录 |
| 327 | 2 | 19.9 | 长时程摘录 |
上表是抽样展示,完整二十八行的规律可以这样概括:负荷试验段(300 至 322)合计约六百五十八分钟,长时程段(323 至 327)合计约一百五十一分钟、折合约二点五小时。单条最短十三分钟出头,最长一小时零七分钟。双通道记录十八条第、单通道十条,两段内部都有单双通道混排。
2.5 与 ltstdb 的结构差异
同族的 ltstdb 也讲 ST,但两者的表结构几乎不重叠。
| 维度 | stdb | ltstdb |
|---|---|---|
| 记录数 | 28 条 | 86 条 |
| 受试者 | 官方未单列 | 80 名 |
| 单条时长 | 13 至 67 分钟 | 21 至 24 小时 |
| 采样率 | 360 Hz | 250 Hz |
| 导联 | 一至两路,未注明位置 | 双三导联轴体系 |
| 采集条件 | 多数为运动负荷试验 | 日常动态监护 |
| ST 事件标注 | 无 | 有,且分缺血与非缺血 |
| 未压缩体积 | 约 42 MB | 数吉字节量级 |
这张表的用法很直接:只要你的问题里出现「事件」「几小时」,就该去 ltstdb;只要你的问题里出现「运动中」「J 点」「漂移」,stdb 才有优势。
§3 它是谁的二十八段心跳:一个 1983 年的硕士课题
3.1 谁在建这个库
官方把署名给了 Paul Albrecht,隶属单位写作 Cambridge Heart, Bedford, MA。PhysioNet 页面上的作者简介只列了这一条隶属信息,没有更细的分工说明。
引用格式指向的是 Albrecht 1983 年在麻省理工学院电气工程与计算机科学系完成的硕士论文,题为《S-T segment characterization for long-term automated ECG analysis》。标题里的两个词值得留意:「characterization」说明重点在刻画这段波形的形态,「long-term automated」说明目标场景是长时程自动分析——也就是说,这个库的原始动机不是给负荷试验做诊断,而是为长时程自动判读提供 ST 段形态的参考素材。
这一点解释了一个表面上的矛盾:一个以长时程自动分析为动机的课题,产出的主体却是负荷试验记录。原因是长时程记录里 ST 事件稀疏,要让算法学会识别,需要先有大量形态明确、变化可控的样本,而负荷试验恰好能在几十分钟内把 ST 段从正常推到明显下移。
3.2 时间线
| 时间 | 事件 | 证据来源 |
|---|---|---|
| 1983 年 | 硕士论文完成,库的主题与形态在此定型 | 官方引用记录 |
| 1983 年前后 | 信号采集与心搏标注 | 官方描述「多数在负荷试验中采集」未给年份 |
| 1992 年 7 月 31 日 | 数据体与注释文件的文件时间戳 | 目录页逐文件时间 |
| 1999 年 8 月 3 日 | PhysioNet 发布 1.0.0 版 | 官方页面版本信息 |
| 1999 年 12 月 12 日 | .xws 侧文件时间戳 |
目录页逐文件时间 |
| 2008 年 4 月 5 日 | 头文件时间戳 | 目录页逐文件时间 |
| 至今 | 仍为 1.0.0,未再发新版 | 官方页面仅列一个版本 |
三个时间戳讲了一个迁移故事:1992 年的数据体说明这批记录在进入 PhysioNet 之前已经在某种本地介质上归档;1999 年的发布与 .xws 文件说明它赶上了平台建设的第一波;2008 年的头文件时间戳说明后来做过一次格式整理,但版本号没有随之变动。
3.3 采集场景:一次负荷试验里的四十分钟
把 300 至 322 这一段当成一个整体看,它描述的是同一种场景:受试者在跑台或踏车上运动,心电电极贴在胸前,随呼吸与躯体摆动,信号在几十分钟内经历静息、运动、恢复三个阶段。
负荷试验对信号处理提出的难题与静息心电完全不同。心率在几分钟内从六十余次升到一百多次,QRS 形态随体位与呼吸改变,基线随电极位移缓慢漂移,肌电噪声在运动峰值处最强。ST 段恰好在这种条件下发生下移——也就是说,要观察的目标信号,埋在噪声最强的时段里。
长时程摘录那五条则是另一种场景:受试者日常活动,记录设备随身,信号里出现的是抬高而非下移。两种场景共用同一套读取流程,却对应不同的临床含义,混在一起使用时必须先按号段分开。
3.4 一个记录的来源层次
从文件层面看,一条记录的信息来源可以分成三层,层次之间并不总是对齐。
| 层 | 承载什么 | 由谁写 | stdb 里是否完整 |
|---|---|---|---|
| 头文件层 | 通道、采样、增益、基线、长度 | 数字化与格式整理环节 | 完整,但不含受试者信息 |
| 数据体层 | 波形本身 | 采集设备 | 完整,但采集条件未记 |
| 注释层 | 心搏位置与类别 | 人工标注 | 只有心搏,没有 ST |
| 文档层 | 库的整体说明与引用 | 平台与作者 | 简短,一句话交代来源 |
第四层是最薄的一层。官方对全库的描述只有两句话,一句讲构成,一句讲注释的局限。剩下的细节,只能从文件里读出来。
3.5 判读流程:本库停在了哪一步
把 ST 分析拆成步骤,可以看出 stdb 覆盖到哪里。
| 步骤 | 做什么 | stdb 是否提供 |
|---|---|---|
| 1 心搏检出 | 定位每个 QRS | 提供,.atr 里已有 |
| 2 心搏分类 | 区分正常与异位 | 部分提供,符号有 N、V、S 等 |
| 3 等电位线估计 | 以 PR 段定基线 | 不提供,需自算 |
| 4 J 点定位 | QRS 结束点 | 不提供,需自算 |
| 5 ST 幅度测量 | J 点后若干毫秒的偏移 | 不提供,需自算 |
| 6 事件判定 | 连续偏移是否构成事件 | 不提供,需自定义 |
| 7 事件类型 | 缺血与否、抬高与否 | 不提供 |
这套七步里,stdb 只完成了前两步的一小部分。后五步是使用者的工作,而第 6 步的阈值定义恰恰是各家论文分歧最大的地方。§4.4 的案例会展示,同样一条记录,阈值取不同,结论会从「全程负例」变成「一段明显事件」。
§4 它最独特的东西:把 ST 改变留在信号里,不给标签
4.1 无标注本身就是一种设计选择
在公开心电库里,ST 改变通常以两种形式出现:一是像 European ST-T Database 那样,逐个事件标注起止、幅度与类型;二是像 ltstdb 那样,给出一套三级判定,并保留中间测量值。stdb 走的是第三条路:波形给你,心搏给你,事件判定留给你。
这个选择放在 1983 年的语境里是合理的。当时的自动 ST 分析还处在形态刻画阶段,算法要学的是「这一段像不像下移」,而不是「这一段属于哪一类事件」。标注事件需要一套临床判读标准与多位判读医师,而刻画形态只需要准确的定位与测量。
代价也很清楚:四十年后,当绝大多数下游任务都需要事件级标签时,这个库只能作为信号源,不能作为监督源。
4.2 两段构成对应两种 ST 形态
全库的 ST 形态分成两类,分界线在 323 号。
| 号段 | 条数 | ST 形态 | 采集场景 | 时长特征 |
|---|---|---|---|---|
| 300–322 | 23 | 一过性下移 | 运动负荷试验 | 13 至 67 分钟 |
| 323–327 | 5 | 抬高 | 长时程记录摘录 | 20 至 43 分钟 |
第一段的下移是「随运动出现、随恢复回落」的动态过程,适合研究 ST 随时间的变化率;第二段的抬高是长时程记录里被摘出来的一段,适合研究抬高形态本身,但不适合推断抬高在一天中的分布——摘录已经把这个信息切掉了。
4.3 心搏符号是唯一的标注产品
打开任意一个 .atr,得到的是心搏位置与类别符号。以 300 号为例,符号集合是 N 与 V 两类;305 号包含 N、V、S 三类;319 号还出现了一个 ~。这些符号沿用 MIT-BIH 系列的约定,N 是正常心搏,V 是室性早搏,S 是室上性早搏,~ 表示形态变化但未细分的搏动。
需要强调的是:异位搏动的存在会影响 ST 测量。一个室性早搏之后的 ST 段与正常心搏之后的 ST 段不可直接比较,若不加区分地对全部心搏做 ST 测量,结果会混入由复极异常造成的假性下移。这也解释了为什么 .atr 虽然不含 ST 事件,却是这个库不可省略的部分——它是 ST 测量的前置过滤器。
import wfdb
from collections import Counter
#-- 逐条统计符号集合,判断这条记录能不能直接用于 ST 测量
for r in ["300", "305", "319", "324"]:
a = wfdb.rdann(r, "atr", pn_dir="stdb/1.0.0")
c = Counter(a.symbol)
print(r, dict(c), "首个样本", a.sample[0])
4.4 案例:305 号这条记录为什么适合当第一条
305 号是全库最短的两条记录之一,十三分钟出头,双通道,符号集合里同时有 N、V、S 三类——这使它成为观察「一个库的全部要素如何叠在一起」的最小样本。
先看它的规模位置。全库最短为十三分钟出头,305 与 322 并列在这个下限附近;最长的 306 是一小时零七分钟。305 短,但包含的要素齐全:双通道、三类心搏符号、负荷试验条件下的连续记录。
再看它的符号构成。N 是主体,V 的数量在全库中属于靠前的一档,S 只有极少数几个。这个组成本身就说明了三件事:记录里确有异位搏动,异位搏动在时间上并不均匀分布,正常心搏仍占绝对多数。做 ST 测量时,把 V 与 S 排除后剩下的 N 序列才是干净的测量对象。
再看它的时序结构。V 类心搏在记录中连续出现,跨度几乎覆盖全程,说明这不是偶发单个早搏,而是一段持续存在的异位节律。对 ST 测量来说,这恰恰是麻烦所在:如果直接用全部心搏求 ST 曲线,这段异位节律会把曲线拉出一段与缺血无关的偏移。
最后看它对使用者的实际影响。把 305 号当作第一条上手记录,好处是三分钟内就能跑完读取、绘制与符号统计;代价是它的异位节律会让人误以为「ST 曲线本来就这么抖」。因此它适合当过滤前的样本,不适合当基线干净度的样本——后者该去看 306 号,那是一条一小时零七分钟、几乎全是正常心搏的记录。
§4.4 的案例在后面的章节还会用到:§5.5 会用它演示阈值选择如何改变结论,§7.2 会用它说明标注稀疏对评测的影响,§9.2 会把它作为最短流程的第一步。
4.5 这条记录与 ltstdb 的同号记录容易混淆
两个库都用三位数字编号,而且号段有重叠。stdb 的 300 至 327 与 ltstdb 的部分编号在字面上可能相同,但内容是两份完全不同的东西:采样率一个是 360 Hz、一个是 250 Hz,时长一个是几十分钟、一个是二十余小时。
实际使用中最常见的错误是只按记录名去读文件。若用同一段代码对两个库循环,而没有在库名上区分,就会把 ltstdb 的某条长记录误当成 stdb 的一条。规避办法很简单:读取时始终带上库路径 stdb/1.0.0,不要只传记录名。
§5 怎么拿到:从清单到一条可复现的 ST 曲线
5.1 目录结构与下载面
目录下只有二十八组文件,没有子目录。获取方式有三种:从项目页下载整包、用 wget 递归同步目录、用 aws s3 sync 从公开桶拉取。三种方式拿到的是同一批文件。
#-- 整包下载(约 42 MB)
wget -r -N -c -np https://physionet.org/files/stdb/1.0.0/
#-- 或者只取记录清单,先看有哪些记录
curl -s https://physionet.org/files/stdb/1.0.0/RECORDS
清单返回二十八行,从 300 到 327 逐个排列,没有表头。这个顺序就是官方认可的顺序,也是做训练集划分时最稳妥的枚举依据。
5.2 用官方接口按需读取
PhysioNet 支持按库名直接读取,不必先下载整包。这种方式适合只取某几条记录做验证的场景。
import wfdb
#-- 直接按库路径读,不落地整包
rec = wfdb.rdrecord("306", pn_dir="stdb/1.0.0")
print(rec.p_signal.shape, rec.fs, rec.sig_name)
print("首样本", rec.p_signal[0])
rdrecord 会同时下载头文件与数据体,并把 12 位样本按头文件里的增益与基线换算成毫伏。返回值里的 p_signal 形状是「样本数 × 通道数」,列顺序与头文件通道行一致。
5.3 按段读取与内存控制
306 号是全库最长的一条,一次性读入约占用一成多的内存峰值,若要批量处理则需要分段。
import wfdb
#-- 分段读,每次三十秒
rec = wfdb.rdrecord(
"306", pn_dir="stdb/1.0.0",
sampto=360 * 30,
physical=True,
)
print(rec.p_signal.shape)
sampto 限定读取样本数,配合循环即可把长记录切成等长窗口。切窗时要注意窗口边界不要落在心搏中间,最简单的方式是先用注释文件里的心搏位置确定窗口起点。
5.4 从信号到 ST 曲线的四个必要步骤
由于官方不给 ST 标注,这条曲线必须自己算。四个步骤缺一不可。
import numpy as np
import wfdb
rec = wfdb.rdrecord("305", pn_dir="stdb/1.0.0")
ann = wfdb.rdann("305", "atr", pn_dir="stdb/1.0.0")
fs = rec.fs
x = rec.p_signal[:, 0]
#-- 1 只保留正常心搏,异位搏动的复极段不能与正常心搏混算
beats = ann.sample[np.isin(ann.symbol, ["N"])]
#-- 2 以每个心搏前若干毫秒的段作为等电位参考
pre = 60
base = np.array([np.median(x[b - pre:b]) for b in beats])
#-- 3 取 R 峰后固定偏移处的样本作为 J 点近似
off = int(0.06 * fs)
j = np.array([x[min(b + off, len(x) - 1)] for b in beats])
#-- 4 差值即 ST 幅度(毫伏)
st = j - base
print(len(st), round(float(np.mean(st)), 4), round(float(np.min(st)), 4))
这四步里的每一个选择都会影响结果:参考段取多长、J 点偏移取多少毫秒、是否对基线再做一次高通、是否剔除运动伪迹段。官方不规定这些,是因为它本来就不提供事件标签,任何固定选择都只是使用者自己的口径。
5.5 构造训练样本时的三个选择
把 ST 曲线变成训练样本,要回答三个问题,每个问题都有两种常见答案。
| 问题 | 选项一 | 选项二 | 对结果的影响 |
|---|---|---|---|
| 正负例怎么定义 | 以固定毫伏阈值切分 | 以基线相对变化切分 | 前者跨记录可比、后者跨个体更稳 |
| 样本长度怎么定 | 以心搏为中心取窗 | 以固定秒数切窗 | 前者心搏对齐、后者节律信息完整 |
| 段间是否打乱 | 按记录划分训练与测试 | 混记录随机划分 | 前者不泄漏、后者分数虚高 |
第三个选择最容易被忽略。若把同一条记录的不同片段同时放进训练集与测试集,模型会记住这条记录特有的基线漂移与电极噪声,测试分数会明显高于真实泛化能力。由于全库只有二十八条记录,按记录划分后每组只有十几条,这个代价必须接受。
5.6 六个最容易出错的地方
| 错误 | 后果 | 规避 |
|---|---|---|
| 把 300–322 与 323–327 混作一类 | 下移与抬高被当成同一任务的正负例 | 先按号段分组 |
| 用全部心搏求 ST 曲线 | 异位搏动的复极异常被当成缺血 | 先按符号过滤 |
直接读 .atr 找 ST 事件 |
找不到任何事件,误以为文件损坏 | 记住注释只含心搏 |
| 忽略 212 格式的打包方式 | 读出的波形整体错位 | 用官方库读取,不手写解析 |
| 以为通道描述 ECG 就是指某个导联 | 无法对齐到标准导联体系 | 接受「未注明」这个事实 |
| 只传记录名不带库路径 | 可能读到 ltstdb 的同名记录 | 始终带 stdb/1.0.0 |
5.7 与派生数据目录的取舍
PhysioNet 上另有若干以 MIT-BIH 为名的派生集合,其中一些把多个库的记录合并重编号。使用派生集合的便利是格式统一、可能附带额外标签;代价是记录号可能与源头不一致,按号段区分的规则会失效。
稳妥的做法是以 stdb 官方目录为准,派生集合只在明确知道其重编号规则时使用。若引用时需要说明某条记录的来源,用官方的 300 至 327 号段最不容易引起歧义。
§6 与库内条目的关系
6.1 关系图谱
stdb 在心电类目里处在最轻的一端:记录少、时长短、标注薄,但它的「轻」使它成为入门与历史对照的合适入口。
| 维度 | stdb | ltstdb | ltdb | macecgdb | nsrdb |
|---|---|---|---|---|---|
| 主题 | ST 改变 | ST 事件分层 | 长时程心电 | 运动伪迹 | 正常窦性心律 |
| 记录数 | 28 | 86 | 7 | 单人多段 | 18 |
| 单条时长 | 13 至 67 分钟 | 21 至 24 小时 | 二十余小时 | 数分钟级 | 24 小时 |
| 采样率 | 360 Hz | 250 Hz | 360 Hz | 不同 | 128 Hz |
| 导联 | 一至两路 | 双三导联轴 | 两路 | 多路 | 两路 |
| ST 事件标注 | 无 | 有,三级 | 无独立事件层 | 无 | 无 |
| 连续监测 | 否,多为负荷试验 | 是 | 是 | 否 | 是 |
| 主要用途 | 信号前端与形态研究 | 缺血检测器评测 | 长时程节律 | 运动伪迹抑制 | 正常节律基线 |
把这张表读成一句话:**stdb 与 ltstdb 不是同一主题的长短两版,而是「有 ST 改变的信号」与「有 ST 事件标签的库」两件不同的东西。**前者回答「ST 段长什么样」,后者回答「哪一段算事件」。
与 ltdb 的区隔在另一个轴上。ltdb 是七条二十余小时的长时程记录,采样率同为 360 Hz,但它关注的是长时程节律与噪声,没有 ST 事件层。stdb 与它在采样率上一致,在时长上完全不同,两者不能互相替代。
与 macecgdb 的区隔在场景。macecgdb 把运动伪迹作为主题,记录的是一个人在多段活动中的心电;stdb 的运动伪迹是负荷试验的副产品,不是研究对象。若研究目标是伪迹抑制算法,macecgdb 的主题更直接。
与 nsrdb 的区隔在人群。nsrdb 是十八名健康受试者的二十四小时正常窦性心律,用于建立正常基线;stdb 的记录因存在 ST 改变而被收入,两者在「正常」这个维度上正好相反。
6.2 检索路径
从需求出发,路径可以这样走。
| 起点关键词 | 先看 | 再看 | 理由 |
|---|---|---|---|
| ST 段、下移、抬高 | stdb | ltstdb | 先看形态,再看事件标签 |
| 缺血事件、事件检测 | ltstdb | stdb | 事件标签只在 ltstdb |
| 运动负荷、跑台 | stdb | macecgdb | 前者是诊断场景,后者是伪迹场景 |
| 长时程、Holter | ltstdb、ltdb | stdb | stdb 只有摘录 |
| 正常节律基线 | nsrdb | — | stdb 不是正常人群 |
| 导联体系、十二导联 | 无库内直接对应 | ltstdb 的双三导联轴 | stdb 未注明导联位置 |
6.3 与三导线、十二导联体系的距离
心电导联体系是理解这个库边界时绕不开的一层。标准十二导联把心脏电活动投影到十二个不同方向,其中六个来自肢体、六个来自胸前;缺血改变在哪些导联上明显,直接决定判读的可靠性。ltstdb 虽然也不是十二导联,但它明确给出的是三条轴构成的组,导联之间的空间关系是可复述的。
stdb 在这一点上停得更早。头文件把两条通道都写作 ECG,没有方向信息。这意味着无法判断同一条记录的两个通道是不是正交、是不是相邻、间隔几厘米。对只关心「两路信号各自怎么漂」的算法,这没有影响;对任何涉及导联投影、空间重构或跨记录对齐的工作,这就是一道硬墙。
墙的存在有一个副作用值得说明:它反而降低了误用为临床判读的风险。因为无法把记录拼成一份可判读的十二导联心电图,使用者只能把它当作信号处理素材,而不是诊断材料。从这个角度说,信息缺失在这里起到了一种保护作用。
6.4 与更晚的 ST 类资源的代际差
把 stdb 与它之后出现的 ST 类资源排成一条线,可以看到三个代际的动作差别。
| 代际 | 代表资源 | 主要动作 | 产出形态 |
|---|---|---|---|
| 第一代 | stdb | 刻画形态,标心搏 | 信号加心搏位置 |
| 第二代 | European ST-T | 判读事件,标起止 | 信号加事件段落 |
| 第三代 | ltstdb | 分层判定并保留中间测量 | 信号加多层标签 |
三代之间不是覆盖关系。第一代解决的问题是「这段波形怎么被准确描述」,后两代解决的是「这段波形属于哪一类事件」。前者是后者的必要条件——若 ST 幅度本身测不准,事件判定就无从谈起。所以即使标准已经推进到第三代,第一代的素材仍有独立价值:它检验的是测量环节,而不是判定环节。
这条代际线也解释了为什么 stdb 的规模远小于后两代。第一代的产出单位是「一条能看清 ST 形态的记录」,不需要长、不需要多;后两代的产出单位是「一个带事件的完整周期」,必须以小时计。
§7 质量评估与局限性
7.0 阅读本节前的一个前置校正
评价这个库之前,要先拆掉一个默认框架:把它当成「小号的 ltstdb」。这个框架一旦成立,所有缺项都会被读成缺陷——记录太少、时长太短、没有事件标签、没有受试者信息。
正确的框架是把它当成一份信号档案。信号档案的评价标准不是标签丰富度,而是波形是否真实、定位是否准确、读取是否可复现。按这三条衡量,它的表现并不差:波形来自真实的负荷试验与长时程记录,心搏位置由人工标注且与波形对齐良好,格式统一为 WFDB、四十年后仍能原样读出。
最容易发生的误判是把「无标注」读成「不可用」。无标注只意味着它不能直接作为监督信号,不意味着它没有价值——恰恰相反,正因为没有预定义的阈值与事件边界,它才适合用来检验别人定义的阈值是否站得住。校正之后的尺度应该是:在形态刻画与信号质量上,它够硬;在事件标签与人群代表性上,它没有证据。
7.1 五维评分
按 DAIMS 的常用维度打分,每项 1 至 5 分,针对「作为 ST 测量算法与信号前端的验证素材」这个用途。
| 维度 | 分数 | 理由 |
|---|---|---|
| 数据规模 | 2 | 28 条记录、十三余小时,够验证不够训练 |
| 标注质量 | 2 | 心搏标注可用,ST 事件完全缺失 |
| 任务适配 | 3 | 形态研究与前端验证适配,事件检测不适配 |
| 文档完整度 | 2 | 官方说明只有两句,受试者与导联信息缺失 |
| 可复现性 | 5 | 格式标准、体量小、许可清晰、四十年后仍可读 |
这张表的低分集中在标注与文档,高分集中在可复现性。这个分数结构说明它适合当「对照组」而不是「主材料」。
7.2 标注稀疏对评测意味着什么
用这个库做评测,最大的约束不是记录数,而是标注层只有心搏。
假设要评测一个 ST 下移检测器。常见做法是人工读一遍信号,标出下移段的起止,再与算法输出比对。这时评测的其实是两件事的叠加:算法能力,以及标注者自己的判读口径。由于库本身没有给出官方事件边界,任何评测结果都缺少一个可以对外复述的基准。
§4.4 的案例在这里说明了具体后果:305 号那段持续存在的异位节律,若标注者把它读成缺血,就会得到一个正例段;若读成复极异常,就是负例。两种读法都不算错,但结论相反。当二十八条记录都由使用者自行判读时,跨论文比较就没有共同分母。
替代方案有两条:一是只在信号质量可判、且 ST 改变形态典型的少数记录上做小规模对照,明确写出判读口径;二是改用带事件标签的库做主评测,把 stdb 作为外部补充。
7.3 已知的、可枚举的偏差
| 偏差 | 来源 | 影响范围 |
|---|---|---|
| 入组偏差 | 因存在 ST 改变而被收入 | 任何发生率结论 |
| 场景偏差 | 多数为负荷试验 | 静息与日常活动场景 |
| 时长偏差 | 多为十几至几十分钟 | 昼夜与长期趋势 |
| 人群偏差 | 受试者信息未记录 | 年龄性别分层 |
| 设备偏差 | 上世纪八十年代初采集 | 现代设备迁移 |
| 标注偏差 | 只有心搏,无事件 | 事件级任务 |
| 号段偏差 | 末五条来源与形态均不同 | 混用时的分类正确性 |
七条里前四条是结构性的,无法通过子集筛选消除;后三条可以通过使用规范规避。
7.4 外部验证矩阵
把它放到几个常见的外部参照里对照,可以看出各自能补什么。
| 外部参照 | 补什么 | stdb 自身的短板 |
|---|---|---|
| European ST-T Database | 逐事件 ST 标注与判读标准 | 事件层的空缺 |
| ltstdb | 长时程与三级事件判定 | 时长与事件 |
| ltdb | 长时程连续记录 | 连续监测 |
| nsrdb | 正常人群基线 | 正常对照 |
| macecgdb | 运动伪迹的专题数据 | 伪迹的受控条件 |
| 十二导联标准库 | 导联位置体系 | 导联未注明 |
这张矩阵的结论是:stdb 几乎每一项都有替代者,但它有两项不容易被替代——体量极小的快速上手,以及同时包含下移与抬高两种形态的并排演示。
7.5 它为何能持续:小到可以原样留着
一个只有四十二兆、二十八条记录、二十七年没发过新版的库,按理早该被更完整的资源取代。它还留着,原因恰恰在「小」:维护成本接近于零,读取依赖只有 WFDB 这一套标准,许可清晰不需要逐个协商。
更实际的原因是引用惯性。1983 年的硕士论文是一份可以追溯的原始出处,任何讨论「ST 段形态刻画」的文献都可以指向它。库的价值在这里从数据转向了出处——它记录的是这个问题在最早被系统处理时留下的样本,而不是今天最好的样本。
7.6 一个可执行的局限性清单
把前几节的偏差落成一张自查表,使用前逐条确认,可以避免大部分返工。
| 检查项 | 若答案为否 | 后果 |
|---|---|---|
| 任务是否只需要信号,不需要事件 | 转向 ltstdb | 标签缺失无法补救 |
| 是否能接受负荷试验条件 | 转向静息类资源 | 基线漂移被当成信号特征 |
| 是否能接受单条几十分钟 | 转向长时程库 | 昼夜问题无解 |
| 是否能接受导联信息缺失 | 转向有导联体系的库 | 空间分析无法开展 |
| 是否按记录而非按片段划分数据 | 重新划分 | 测试分数虚高 |
| 是否在混用前按号段分组 | 先分组 | 下移与抬高混淆 |
| 是否在测 ST 前过滤异位搏动 | 先过滤 | 假性偏移混入 |
七项里前四项是关于资源选择的,后三项是关于使用方式的。前者决定要不要用,后者决定用得对不对。
§8 生态位与历史
8.1 历史沿革
这个库的起点是一篇硕士论文,不是一次数据库建设计划。1983 年的课题要回答「长时程自动心电分析里,ST 段该怎么被刻画」,为了回答它,作者采集了一批 ST 改变明确的记录,并逐个标出心搏位置。
此后十余年,这批记录以本地介质形式存在。1992 年 7 月的文件时间戳说明当时做过一次归档整理;1999 年 8 月进入 PhysioNet 并定版 1.0.0;2008 年 4 月的头文件时间戳说明后来重写过头部格式。三次动作都没有改变内容,只改变了容器。
8.2 与 European ST-T、MIT-BIH 心律失常库的分工
三个库经常被放在一起提,但各自承担不同角色。
| 库 | 承担什么 | 与 stdb 的关系 |
|---|---|---|
| European ST-T | 事件级 ST 标注的标准参考 | 官方明确对照,stdb 缺事件层 |
| MIT-BIH 心律失常库 | 心搏类别标注的标准参考 | 符号体系同源,主题不同 |
| stdb | ST 改变信号的早期样本 | 本体 |
官方那句「注释不含 ST 改变标注,与 European ST-T Database 不同」,本身就是一次分工声明:这个库不打算做事件标注,需要事件的人应该去别处。
8.3 生态位:入门样本与历史对照
在今天的工具链里,stdb 的位置有两个。一个是入门:全库几十兆,几分钟下完,用它可以最快跑通 WFDB 读取、绘图、心搏统计的完整流程。另一个是历史对照:当需要说明「四十年前的 ST 形态研究用的是什么素材」时,它是少数还在线的原始样本。
这两个位置都不显眼,但都稳定。做算法的人偶尔会回来取一条记录验证前端,做教学的人会拿它演示运动中的基线漂移。
8.4 谁在用它,用来做什么
按官方 Topics 标签,它归在运动、负荷、心电三个词下。这个归类说明平台对它的定位是「负荷试验心电」,而不是「缺血数据库」。
从库的结构推断,主要使用者有三类:验证 ST 测量前端的算法工程师、需要演示运动条件下心电变化的教学者、以及整理心电数据谱系的研究者。前两类用它取信号,第三类用它取出处。
8.5 平台侧的三次整理与内容的不变
从文件时间戳能读出平台侧的整理节奏,而这个节奏恰好说明内容从未变过。
1992 年的数据体与注记说明这批记录在进入网络平台之前已经成型;1999 年的发布把容器换成 WFDB 并补了显示侧文件;2008 年重写头文件,把格式细节规整到当时的标准。三次动作分别对应归档、上线、格式对齐,没有一次触及波形与心搏标注。
这种只换容器的维护方式在数据资源里并不常见。多数库会在每次整理时顺手扩一点内容,于是版本号与内容同时变化,使用者无法判断某个差异来自版本还是来自数据。stdb 的做法让版本号与内容严格对应:1.0.0 就是 1983 年前后那批记录的 1.0.0,没有第二个含义。
§9 使用指引
9.1 三种角色的路径
| 角色 | 第一步 | 第二步 | 第三步 |
|---|---|---|---|
| 算法工程师 | 读 306 号验证前端 | 读 300 至 322 段做批量 | 用 323 至 327 测抬高形态 |
| 教学者 | 取 300 号演示下移 | 取 323 号演示抬高 | 用 305 号演示异位搏动干扰 |
| 数据整理者 | 核对 RECORDS 二十八行 | 核对头文件三行结构 | 记录号段与通道分布 |
三条路径的共同点是不需要事件标签。凡路径里需要事件的地方,都应该转向 ltstdb。
9.2 一条最短的可用流程
以下五步可以在一条命令里跑完,输出能直接判断这条记录是否适合 ST 测量。
python3 - <<'PY'
import wfdb
import numpy as np
from collections import Counter
rec = wfdb.rdrecord("305", pn_dir="stdb/1.0.0")
ann = wfdb.rdann("305", "atr", pn_dir="stdb/1.0.0")
print("通道", rec.n_sig, "采样率", rec.fs, "样本", rec.sig_len)
print("时长分钟", round(rec.sig_len / rec.fs / 60, 1))
print("符号", dict(Counter(ann.symbol)))
print("正常心搏占比", round(float(np.mean(np.isin(ann.symbol, ["N"]))), 3))
PY
四行输出对应四个判断:通道数决定可用信息量,时长决定能否覆盖进与出,符号构成决定是否需要过滤,正常心搏占比决定过滤之后还剩多少可用样本。§4.4 的案例里那个「异位节律持续存在」的结论,就是这四行输出里第三行读出来的。
9.3 引用方式
官方要求的引用有两部分。第一部分是原始出处:Albrecht P. S-T segment characterization for long-term automated ECG analysis. M.S. thesis, MIT Dept. of Electrical Engineering and Computer Science, 1983。第二部分是平台引用,按 PhysioNet 的统一格式给出,当前推荐引用为 Pollard 等 2026 年发表于 Nature Health 的平台综述。
若在论文中描述这个库,建议同时写明三件事:记录数为二十八、注释只含心搏、末五条为长时程摘录。这三句话能避免绝大多数审稿误读。
9.4 把它放进 AI 流程的哪个位置
在一个完整的 ST 分析流水线里,stdb 最适合的位置是前端验证,而不是训练或测试主干。
| 流水线环节 | stdb 能承担吗 | 说明 |
|---|---|---|
| 数据清洗与格式转换 | 能 | 格式标准,适合验证读取与单位换算 |
| 心搏检出 | 部分能 | 有标注可对照,但记录少 |
| 心搏分类 | 不宜 | 符号种类有限,类别分布不均 |
| 基线漂移抑制 | 能 | 负荷试验漂移形态真实 |
| ST 幅度测量 | 能 | 这是它最合适的位置 |
| 事件判定 | 不能 | 无事件标签 |
| 模型训练 | 不宜 | 规模与标签都不够 |
| 模型外部验证 | 部分能 | 可作跨设备鲁棒性补充 |
落在「ST 幅度测量」这一行,是因为这一步只依赖信号与心搏位置,而这两样恰好都是它给得最完整的。至于心搏分类那一行的「不宜」,理由不是标注错了,而是可用的类别太少——二十八条记录里绝大多数心搏都是正常搏动,异位搏动零散分布,无法构成可训的分类样本。
9.5 一份可复述的三分钟口头介绍
如果要在组会上用三分钟讲清这个库,可以按下面五句话的顺序说。
第一句交代身份:这是 PhysioNet 上 MIT-BIH 系列里的 ST 改变库,二十八条记录,编号从三百到三百二十七。第二句交代来源:多数来自运动负荷试验,末尾五条是长时程记录的摘录。第三句交代形态:前一段是一过性下移,后一段是抬高。第四句交代局限:注释只标心搏,不标 ST 事件。第五句交代用法:它适合验证 ST 测量的前端,不适合训练事件检测器。
五句话里第四句最关键。省掉它,听者会以为这是一个带标签的 ST 数据库,之后的讨论都会建在错误前提上。
§10 AI 使用声明
| 项目 | 声明 |
|---|---|
| 文本生成 | 本文由 AI 辅助撰写,结构与事实由编辑把关 |
| 数字来源 | 规模、结构、边界三类数字来自 PhysioNet 官方页面与文件目录 |
| 文件核验 | 记录清单经直接访问确认为二十八行,编号 300 至 327 连续 |
| 头文件核验 | 二十八条头文件的首行均已直接访问,用于确认通道数、采样率与样本总数 |
| 注释核验 | 部分记录的注释符号集合经 WFDB 读取确认 |
| 统计口径 | 未做心跳间期分布、未做 ST 幅度直方图、未做符号频次排序表 |
| 论文信息 | 1983 年硕士论文仅见官方引用记录,未获取全文 |
| 未核验 | 受试者人数、年龄性别、导联体表位置、采集年份、判读人员构成 |
| 免责 | 本文不构成临床建议;使用须遵守 ODC-BY 1.0 署名要求 |
常见误读(避坑清单)
| 说法 | 实际 | 证据 |
|---|---|---|
| 「stdb 里有 ST 事件标注」 | 注释只含心搏标签,无任何 ST 事件 | 官方 Data Description 末句 |
| 「它和 ltstdb 是同一个库的新旧版」 | 两个独立库,记录数、采样率、时长、标注层全不同 | 两库各自项目页 |
| 「二十八条记录就是二十八个人」 | 官方只给记录数,未给人数 | 官方页面无受试者字段 |
| 「末五条也是负荷试验」 | 末五条是长时程记录摘录,表现为抬高 | 官方明写 323 至 327 |
| 「通道描述写了 ECG 就知道导联」 | 描述一律写作 ECG,未注明位置 | 二十八条头文件通道行 |
| 「它能做缺血发生率的研究」 | 因存在 ST 改变而被收入,不是人群抽样 | 库的入组条件 |
| 「它比 ltstdb 小所以更旧」 | 两者目标不同,体积差来自时长与记录数 | 两库规格对照 |
| 「可以手写解析 212 格式」 | 双样本打包易错位,应使用官方读取库 | 头文件格式码 212 |
| 「心搏类别可以直接忽略」 | 异位搏动会让 ST 测量产生假性偏移 | §4.4 的案例 |
| 「有 DOI 就说明近年发布」 | DOI 对应 1999 年的 1.0.0 版,内容来自 1983 年前后 | 版本与引用记录 |
FAQ
问:库名里的 ST 到底指什么?
答:指 ST 段,即 QRS 波群结束到 T 波开始之间那段本应贴近等电位线的区间。库名里的 Change 指这段区间在记录过程中的移动,不是注释文件里的事件类别。
问:为什么它没有 ST 事件标注?
答:这个库的原始目标是 ST 段的形态刻画,而不是事件判读。事件标注需要临床判读标准与多位判读医师,1983 年的课题没有走这条路,官方在页面上明确说明了这一局限。
问:那我还能用它做缺血检测吗?
答:可以做信号前端的工作,比如基线漂移抑制、J 点定位、ST 幅度测量。做事件级检测需要自己定义阈值并标注,而自定义阈值会使跨论文比较失去共同口径。
问:和 ltstdb 该怎么选?
答:看问题里有没有「事件」和「几小时」。有,选 ltstdb;没有,且需要运动条件下的信号,选 stdb。
问:五条长时程摘录能当长时程数据用吗?
答:不能。它们是被截取的片段,最长的不到四十三分钟,而且只呈现抬高。长时程研究应使用 ltstdb 或 ltdb。
问:全库有多大?
答:官方写明未压缩约四十二兆。全量下载解压后可以直接装进内存,这是它最大的实用优势之一。
问:通道描述里的 ECG 是哪个导联?
答:头文件只写 ECG,不注明导联位置。官方页面也没有给出对应关系。做导联相关的研究时,这是一个无法绕过的限制。
问:记录长度是怎么分布的?
答:最短十三分钟出头,最长一小时零七分钟,多数落在二十到四十分钟之间。本文不给直方图,因为决定用法的只是两个端点和号段归属。
问:可以商用吗?
答:可以。ODC-BY 1.0 允许包括商用在内的使用,条件是署名。署名需引用 1983 年硕士论文并同时引用 PhysioNet 平台。
问:为什么版本停在 1.0.0 不动?
答:内容没有再扩充的需要,格式只需跟随 WFDB 标准。2008 年重写过头文件但未升版本号,说明维护动作限于容器层面。
问:这个库有教学价值吗?
答:有,而且可能是它最稳的用途。体量小、两种 ST 形态都有、心搏标注齐全,适合演示运动中的基线漂移与复极变化。
问:如果只下载一条,选哪条?
答:看目的。验证读取流程选 300;验证前端稳定性选最长的 306;看异位搏动如何干扰 ST 测量选 305。
术语表
| 术语 | 含义 |
|---|---|
| ST 段 | QRS 结束到 T 波开始之间的区间,正常应贴近等电位线 |
| ST 下移 | 该区间相对基线向下偏移,负荷试验中常见 |
| ST 抬高 | 该区间相对基线向上偏移,长时程摘录中这五条表现为此 |
| J 点 | QRS 波群结束、ST 段开始的交界点 |
| 等电位线 | 参考基线,通常取 PR 段或 TP 段 |
| 负荷试验 | 让受试者在跑台或踏车上运动以诱发心电改变 |
| 一过性 | 出现后在短时间内自行恢复 |
| WFDB | 波形数据库的通用文件格式与读取工具集 |
.hea |
头文件,描述通道、采样率、增益与长度 |
.dat |
二进制数据体,存放 12 位样本 |
.atr |
注释文件,记录心搏位置与类别符号 |
| 212 格式 | 每字节装两个 12 位样本的打包方式 |
| 增益 | 每毫伏对应的数字单位,换算物理量必需 |
| 基线 | 零电位对应的数字值 |
| 心搏符号 N | 正常心搏 |
| 心搏符号 V | 室性早搏 |
| 心搏符号 S | 室上性早搏 |
| 心搏符号 ~ | 形态变化但未细分的搏动 |
| 室性早搏 | 起源于心室、形态宽大的提前搏动 |
| 复极异常 | 心室复极过程改变,可造成非缺血性的 ST 偏移 |
| 基线漂移 | 低频的整段波形上下浮动 |
| 运动伪迹 | 电极与皮肤相对运动造成的噪声 |
| 长时程记录 | 连续记录二十小时以上的动态心电 |
| 摘录 | 从长记录中截出的一段 |
| DAIMS | 数据资产管理与使用的一组成熟度评估维度 |
| ODC-BY | 开放数据署名许可,允许商用但须署名 |
| DOI | 数字对象标识,用于稳定引用 |
附录 A:核心数字核对表
| 项 | 值 | 来源 | 来源层级 |
|---|---|---|---|
| 记录数 | 28 | 官方页面;RECORDS 逐行 |
官方页面+直接访问 |
| 记录号范围 | 300 至 327 | RECORDS 逐行 |
直接访问 |
| 负荷试验段条数 | 23 | 由号段划分 | 官方页面 |
| 长时程摘录条数 | 5 | 官方明写 323 至 327 | 官方页面 |
| 采样率 | 360 Hz | 二十八条头文件 | 直接访问 |
| 位分辨率 | 12 | 头文件格式码 212 | 直接访问 |
| 双通道记录 | 18 条 | 二十八条头文件首行 | 直接访问 |
| 单通道记录 | 10 条 | 二十八条头文件首行 | 直接访问 |
| 总样本数 | 约 1748 万 | 二十八条头文件样本数相加 | 直接访问 |
| 折算总时长 | 约 13.5 小时 | 总样本数除以采样率 | 推算 |
| 单条最短 | 约 13 分钟 | 305 与 322 号 | 直接访问 |
| 单条最长 | 约 67 分钟 | 306 号 | 直接访问 |
| 未压缩体积 | 约 42 MB | 官方页面 | 官方页面 |
| 受试者人数 | 官方未给出 | 官方页面无此字段 | 未核实 |
| 许可 | ODC-BY 1.0 | 官方页面 | 官方页面 |
| DOI | 10.13026/C2ZW2H | 官方页面 | 官方页面 |
附录 B:数字的来源分层
| 层级 | 包含哪些数字 | 处理方式 |
|---|---|---|
| 官方页面 | 记录数二十八、两段划分、末五条为抬高、注释只含心搏、体积四十二兆、许可、DOI、版本与发布日期 | 直接引用 |
| 直接访问文件 | 通道数分布、采样率、样本总数、单条时长、符号集合 | 由头文件与注释文件读出 |
| 推算 | 折算总时长、两段各自时长合计 | 明写为推算,不当作官方口径 |
| 未核实 | 受试者人数、年龄性别、导联位置、采集年份区间、判读人员 | 正文标「官方未给出」 |
附录 C:完整参考文献
| 序号 | 文献 | 类型 |
|---|---|---|
| 1 | Albrecht P. S-T segment characterization for long-term automated ECG analysis. M.S. thesis, MIT Dept. of Electrical Engineering and Computer Science, 1983 | 原始出处 |
| 2 | MIT-BIH ST Change Database v1.0.0,PhysioNet,1999-08-03,DOI 10.13026/C2ZW2H | 数据集主页 |
| 3 | Pollard T, Moody BE, Lehman L, et al. PhysioNet as a global platform for biomedical research. Nature Health, 2026 | 平台引用 |
| 4 | European ST-T Database,PhysioNet,作为事件级标注的对照 | 对照资源 |
| 5 | Long-Term ST Database(ltstdb),PhysioNet,作为长时程事件标注的对照 | 对照资源 |
附录 D:任务代码
两个最常用的脚本:一是判断哪些记录适合直接做 ST 测量,二是按号段拆分训练与测试。
import wfdb
import numpy as np
#-- 逐条给出可用性判断
for i in range(300, 328):
r = str(i)
h = wfdb.rdheader(r, pn_dir="stdb/1.0.0")
a = wfdb.rdann(r, "atr", pn_dir="stdb/1.0.0")
normal = float(np.mean(np.isin(a.symbol, ["N"])))
seg = "负荷试验" if i <= 322 else "长时程摘录"
print(r, h.n_sig, round(h.sig_len / h.fs / 60, 1), seg, round(normal, 3))
第三列的时长与第五列的正常心搏占比合起来决定这条记录能不能直接用。占比接近一说明几乎没有异位搏动,适合当基线干净的样本;占比明显偏低则必须先过滤。
#-- 按号段划分,避免同源泄漏
train, test = [], []
for i in range(300, 328):
(train if i <= 315 else test).append(str(i))
print("训练", len(train), "测试", len(test))
这里用 315 号作切分点,让两段都包含两种通道数,避免某一侧全是单通道。
附录 E:如果只记五件事
| 序号 | 记住什么 | 为什么 |
|---|---|---|
| 1 | 二十八条记录,300 至 327 | 一切用法从这个编号范围开始 |
| 2 | 注释只有心搏,没有 ST 事件 | 决定了它只能做信号源 |
| 3 | 300–322 是下移,323–327 是抬高 | 混用会把两种形态当成一类 |
| 4 | 与 ltstdb 是两个库,不是两版 | 采样率、时长、标注层都不同 |
| 5 | 全库约四十二兆 | 下载与试错的成本几乎为零 |
编辑说明
本篇的核验时间为 2026 年 10 月 28 日。核对方式为直接访问 PhysioNet 项目页与文件目录:项目页返回正常,据此确认全名、作者、两段构成、注释局限、体积、许可与 DOI。记录清单经单独访问确认为二十八行,首行为 300、末行为 327,连续无缺号。二十八条头文件的首行已逐条访问,用于确认通道数、采样率与样本总数;十九位的样本总数相加后再除以采样率,得到折算总时长,本文标为推算而非官方口径。注释符号集合经 WFDB 库读取部分记录确认,未对全库逐条统计符号频次,也未做心跳间期分布。受试者人数、年龄性别、导联体表位置、采集年份区间与判读人员构成在官方页面与头文件中均无记载,正文凡涉及处均未给出数值。1983 年硕士论文仅见官方引用记录,未获取全文,未引用其正文内容。
相关数据集导航
以下为站内 AI-Ready 数据集百科中与本词条共享多个主题标签的相关数据集,按相关度降序排列:
- wctecgdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
- ahadb — 共享标签:生理信号 / 心电信号 / 心血管疾病
- chfdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
- crisdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
- cudb — 共享标签:生理信号 / 心电信号 / 心血管疾病
- ltdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
- ltstdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
- iafdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
- mvtdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
- nsrdb — 共享标签:生理信号 / 心电信号 / 心血管疾病
导航说明:本章节由全站统一标签体系自动计算生成(标签重合度算法),双向可达;点击链接可跳转至对应数据集词条。

