信息速览
胎心监护有三条互不相同的物理路径。多普勒超声打一束高频声波进去,听反射回来的频移;胎心电在腹壁上拾取胎儿心脏除极产生的微弱电位;胎心音则什么也不发射,只是把听诊器贴在小腹上,听那颗隔着羊水、子宫肌层和母体脂肪传来的机械搏动。三条路里,听诊是最老的一条,也是公开数据最少的一条。
IIScFHSDB 补的就是这个缺口。印度科学学院产品设计与制造中心的 Amrutha Bhaskaran 与 Manish Arora,在班加罗尔圣约翰医院的产前门诊与产房,用一支电子听诊器接了 Biopac 采集系统,给 60 名孕 31 到 40 周的单胎孕妇各录了一条下腹部心音,增益 500 倍,采样 2 千赫兹,平均每条八分钟,2022 年 9 月以 ODC-BY 1.0 许可放上 PhysioNet。
它的稀缺之处不在规模,在场景:官方把「嘈杂」写进了目标,明说数据来自拥挤、缺单人病房的临床环境,用途就是给去噪与胎心率提取算法当磨刀石。它的局限也同样直白——没有同步参考通道,参考心率靠人耳。一屏速览见下表。
| 维度 | 内容 |
|---|---|
| 全名 | Indian Institute of Science Fetal Heart Sound Database(IIScFHSDB) |
| 中文名 | 印度科学学院胎心音数据库 |
| 发布方 | PhysioNet,2022 年 9 月 15 日,版本 1.0 |
| 采集机构 | 印度科学学院产品设计与制造中心;采集地点为班加罗尔圣约翰医院 |
| 作者 | Amrutha Bhaskaran、Manish Arora |
| 记录数 | 60 条音频 |
| 受试者 | 60 名孕妇,单胎,无已知母体并发症 |
| 孕周 | 附表 31–40 周(均值 37±2.0);摘要写 30–40 周;方法写大于 30 周 |
| 年龄 | 附表 18–37 岁(均值 25±3.7);摘要写 18–27 岁 |
| 传感器 | 电子听诊器 SS30LA,贴于下腹部,位置由受训医生指定 |
| 采集链路 | Biopac MP36,增益 500 倍,内置工频陷波 |
| 采样率 | 2 千赫兹 |
| 平均时长 | 约 8 分钟 |
| 文件格式 | wav 音频,另有 Records.csv、example_code.m、LICENSE.txt、SHA256SUMS.txt |
| 体积 | 未压缩 377.2 MB,ZIP 128.3 MB |
| 参考心率 | 两名观察者人工聆听;部分受试者另有病历抄录值 |
| 许可 | ODC-BY 1.0,开放获取,无需注册 |
| DOI | 10.13026/9vvw-cx05(v1.0) |
§1 它要解决的具体麻烦
1.1 最老的一条路,公开数据却最少
1816 年 Laennec 用纸卷成筒听心音,此后一百多年,产科听诊一直是判断胎儿存活的床边手段。它的物理基础简单:胎儿心脏收缩时瓣膜关闭与血流冲击产生振动,经羊水、子宫壁、母体腹壁层层衰减,到体表只剩微伏到毫伏量级的位移;转成电信号放大几百倍,就是一条可画出的波形。这条链路不发射能量,不需要电极与皮肤良好接触,也不需要把超声探头压在肚子上找角度。它唯一的要求是安静。
安静恰恰最稀缺。资源受限的产科病房里几个产妇共用一间,家属走动、谈话、器械推车、隔壁床的监护仪报警全落在同一段录音里。母体自己的心音也在里面,而且通常更响——母体心脏离听诊器只有几厘米,胎儿心脏隔着一层羊水与几厘米组织。呼吸造成的低频摆动、肠鸣、胎动的瞬时冲击叠加,把信噪比压得很低。
所以技术核心从来不是能不能录到,而是录到之后能不能稳定数出胎心率。2022 年那篇论文把问题拆成三步:包络检测找候选心音成分,自相关估周期,再加一道基于前窗有效心率与功率谱密度的峰值校验剔除异常估计。加校验后平均绝对误差从 11.50 降到 7.54 次/分,正一致率从 81% 升到 87%。这两个数字衡量的是算法与人耳判读的一致性。
这批数据的意义是把「嘈杂临床环境」固定成常量,让不同算法在同一组难例上比较。没有它,每个课题组自录几十条,噪声条件各异,结果无法横向对照。
1.2 三条常见的错误期待
第一条,把它当成高质量胎心音图库。它不是。官方明说除内置工频陷波外没有前置滤波,也没筛掉噪声大的片段。论文把记录分成好中差三档,说明质量差异被承认并保留,不是被清理掉。
第二条,把它当成带同步金标准的评测集。它不是。参考心率是两名观察者听出来的,属于人耳判读,不是独立物理量测。任何算法与它比较,比的都是与人耳判读的一致性,而不是与真实胎儿心搏的一致性。
第三条,把它当成可做母体胎儿分离的多通道数据。它不是。全库只有一路音频,没有多导联、没有参考通道、没有胸壁同步录音。母体心音抑制只能用单通道盲分离或模板减除,没有第二路可对照验证。
1.3 它能给到的与给不到的
| 你的需求 | 它给的 | 够不够 |
|---|---|---|
| 在真实噪声下评测胎心率提取算法 | 60 条临床现场录音,噪声未被清理,附人工判读心率 | 够,这是它最主要的用途 |
| 训练一个端到端的胎心音深度学习模型 | 60 个受试者、总计约八小时音频 | 不够,样本量偏小,需预训练或强增广 |
| 做心音分割(S1/S2 定位) | 原始波形,无逐拍标注 | 可做无监督或弱监督,需自建标注 |
| 验证算法在人耳判读面前的一致性 | 论文给出两名观察者的参考值,另有 MAE 与正一致率口径 | 够,且可直接与论文数字对齐 |
| 做母体心音与胎心音的盲分离 | 单通道混合信号 | 只能做单通道方法,无多导联对照 |
| 与其他模态(胎心电、多普勒、CTG)做同步对照 | 无同步参考通道 | 不够,这是它最硬的边界 |
| 覆盖早孕期或全程孕期 | 仅孕 31–40 周附近 | 不够,早孕期胎心音极难拾取,本库未覆盖 |
| 覆盖不同国家、不同设备的人群 | 单一中心、单一设备型号 | 不够,跨域泛化无从评估 |
1.4 你的处境与它能帮到的事
| 你的处境 | 它能帮你什么 | 下一步该做什么 |
|---|---|---|
| 你在做低资源地区的家用胎心监测设备,样机在安静实验室里表现很好,一到病房就崩 | 提供 60 条同样来自拥挤病房的录音,噪声类型与你的现场接近 | 先用 §5.2 的流程建基线,再把你自己的录音按同一口径评估,比较掉分幅度 |
| 你写了一个基于自相关的胎心率算法,想找公开数据证明它比基线好 | 论文给出了明确的基线数字(MAE 7.54、正一致率 87%),可直接对标 | 严格照搬论文的评估口径,特别是参考值取两名观察者的哪一个、如何配窗 |
| 你在做心音分割,缺真实临床录音做预训练 | 八小时连续音频,S1/S2 节律天然存在,适合自监督预训练 | 用无标注的周期一致性做预训练目标,再在小规模标注集上微调 |
| 你要给医学生讲"为什么听诊难" | 同一条录音里可以同时听到母体心音、胎心音、肠鸣与说话声 | 截取一段做课堂对比,注意不要把它当成诊断级证据 |
| 你在做多模态融合,想把声音与胎心电拼起来 | 声音这一路有了,但时间上无法与任何公开胎心电库对齐 | 放弃逐样本融合,改做模态级的表征迁移 |
| 你需要一个能快速下载、快速跑通的小库 | 压缩包 128.3 MB,解压 377.2 MB,一条命令下完 | 先跑通 example_code.m 的读取与梳状滤波,再谈建模 |
1.5 一句话判断
它是一把专门用来量"噪声下还剩多少"的尺子:六十条现场录音把临床环境的脏固定成常量,让不同算法在同一个脏度上比出高低;但它量不了"准不准",因为尺子本身的刻度是人耳。
1.6 不适合谁:四条边界
不适合拿它训练大模型。 六十个受试者、约八小时音频,对参数量上千万的端到端模型来说,样本量连一个 epoch 的记忆都撑不住。做完增广与迁移之后勉强可用,单靠它从零训练必然过拟合。
不适合拿它当诊断级证据。 录音没有同步的胎心电或超声对照,也没有逐拍的临床结论。它能支持"这个算法在这批录音上与人耳判读吻合多少",不能支持"这个算法诊断胎儿窘迫的灵敏度是多少"。
不适合研究早孕期或全程孕期。 孕周集中在中晚孕的 31 到 40 周。早孕期胎心音被盆骨与组织遮蔽,信号极弱,本库完全没有覆盖。任何声称覆盖全孕期的结论都不能从这份数据推出来。
不适合做跨中心、跨设备的泛化研究。 单一医院、单一型号电子听诊器、单一采集系统。换一支听诊器、换一间病房,频响与噪声谱都会变,而这份数据里没有第二个中心可以用来度量这种变化。
§2 数据构成与规格
2.1 一个压缩包里的五类文件
解压后的目录结构极浅,没有嵌套子目录。六十个音频文件平铺在根目录,文件名是 subject_01.wav 到 subject_60.wav,两位数字补零,保证按字典序排列时与编号顺序一致。另外四个文件分别是:Records.csv 是受试者元数据表;example_code.m 是官方的 MATLAB 示例,演示如何读 wav 并做梳状滤波;LICENSE.txt 是 ODC-BY 1.0 的全文;SHA256SUMS.txt 是全部文件的校验和清单。
这种平铺结构的好处是零学习成本,坏处是没有分组。六十条记录没有按质量、按孕周、按采集地点(产前门诊还是产房)分层,全部混在一起。官方的论文里提到把记录分成好、中、差三档,但分档结果没有作为文件或列发布。想做分层分析,只能自己听完再标,或者用算法质量指标反推。
| 文件 | 类型 | 作用 | 是否必需 |
|---|---|---|---|
subject_01.wav … subject_60.wav |
二进制音频 | 胎心音波形本体 | 必需 |
Records.csv |
文本 CSV | 受试者人口学、临床情况、病历胎心率 | 强烈建议 |
example_code.m |
MATLAB 脚本 | 读取与梳状滤波示例 | 可选 |
LICENSE.txt |
文本 | ODC-BY 1.0 全文 | 合规必需 |
SHA256SUMS.txt |
文本 | 校验和 | 可选 |
2.2 字段/记录的完整字典
Records.csv 一共九列,六十行数据行,第一行是表头。九列里有两列是自由文本,其余是数值或短横线占位。理解这张表的关键是分清"哪几列是采集时记录的"与"哪几列是从病历抄来的"——后者才是所有误用的源头。
| 列名 | 含义 | 类型 | 取值范围(官方附表) | 缺失表示 | 备注 |
|---|---|---|---|---|---|
Subject |
受试者编号 | 整数 | 1–60 | 无 | 与 wav 文件名一一对应 |
Gestational age (weeks) |
孕周 | 整数 | 31–40 | 无 | 摘要写 30–40,方法写大于 30 |
Age |
孕妇年龄 | 整数 | 18–37 | 无 | 摘要写 18–27,与附表不一致 |
Weight (kg) |
体重 | 整数 | 49–103 | 空 | 单位千克,未说明测量时点 |
Height (cm) |
身高 | 整数 | 144–171 | 空 | 单位厘米 |
Gravida |
孕次 | 整数 | 1–4 及以上 | 短横线 | 表示既往妊娠次数 |
Para |
产次 | 整数 | 0–2 及以上 | 短横线 | 表示既往分娩次数 |
Clinical Conditions |
临床情况 | 文本 | 见 §2.4 | 空 | 自由文本,拼写不完全统一 |
FHR (bpm) from medical file |
病历胎心率 | 整数 | 130–156 等 | 空或短横线 | 非同步测量,时刻不明 |
表里有三处需要特别当心。第一,孕次与产次用短横线占位,不是数字零;短横线可能表示"未记录",也可能表示"初产妇",官方没有区分说明,直接转数值会把两种含义混成一种。第二,临床情况列是自由文本,同一类情况可能有不同拼写,比如"Abdominal and backpain"中间没有空格,机器解析时不能按空格切词。第三,也是最重要的一处,最后一列的胎心率来自病历,官方的表述是"在可得时提供",这意味着它既不同步于录音,也不保证与录音当次的状态一致。
2.3 一条记录的完整解剖
一条记录的全部内容就是一段单声道音频加 CSV 里的一行。音频里没有任何嵌入式元数据字段被官方承诺,采样率可以从文件头读出(官方说明为 2 千赫兹),位深与声道数官方页面没有说明。下面这段代码把一条记录的三个层面——文件层、表行层、波形层——一次性摊开。
#-- 读取一条记录的三层信息:文件、表行、波形
import wave
import numpy as np
import pandas as pd
base = "fetalheartsounddata/1.0"
sid = 7
wav_path = f"{base}/subject_{sid:02d}.wav"
with wave.open(wav_path, "rb") as w:
n_ch = w.getnchannels()
samp_w = w.getsampwidth()
fs = w.getframerate()
n_frames = w.getnframes()
print(f"声道 {n_ch} 位宽 {samp_w * 8} 位 采样率 {fs} Hz 帧数 {n_frames}")
print(f"时长 {n_frames / fs / 60:.2f} 分钟")
meta = pd.read_csv(f"{base}/Records.csv")
row = meta.loc[meta["Subject"] == sid].iloc[0]
print(row.to_dict())
跑完之后会得到三件事:这条录音的实际时长(官方只给平均值,逐条要自己读文件头)、这条录音的实际位深与声道(官方未公布),以及附表里这一行的全部字段。三者放在一起,才构成"一条记录"的完整画像。
音标本体是原始电压经放大后的数字化序列。500 倍增益是一个关键参数:它意味着进入采集卡的信号在放大前幅度极小,放大后仍然可能只占满量程的一小部分。这不是设计失误,而是胎心音的物理属性决定的——腹壁表面的振动幅度本来就远小于心电电极上的电位差,也远小于听诊器放在胸壁上听到的成人心音。增益给得高,底噪也被一起放大,所以录音里的本底嘶声是链路固有的,不可能靠后处理消除。
2.4 官方给出的受试者画像
官方页面用一张表给出了 60 名受试者的四项体格指标,另有方法段的文字说明人群构成。把这些官方数字集中起来,能看出这份数据的人群边界在哪里。
| 指标 | 均值 ± 标准差 | 范围 | 说明 |
|---|---|---|---|
| 年龄(岁) | 25 ± 3.7 | 18–37 | 摘要另称 18–27 岁,与附表冲突 |
| 孕周(周) | 37 ± 2.0 | 31–40 | 摘要写 30–40,方法写大于 30 |
| 体重(千克) | 68.3 ± 10.9 | 49–103 | 体重跨度大,与腹壁厚度直接相关 |
| 身高(厘米) | 155 ± 7.3 | 144–171 | 身高影响听诊器到胎心的距离 |
四项指标里,体重与身高的组合最能解释信号质量的个体差异。腹壁厚的受试者,胎心音要多穿过几厘米脂肪与肌肉,高频成分衰减更明显,录到的信号偏低频、偏闷;体型瘦的受试者,胎心音相对清晰,但母体肠鸣与主动脉搏动也更容易串进来。这两种情况在库里都存在,体重从 49 千克到 103 千克,跨度超过一倍。
临床情况列是自由文本,官方附表里出现的内容包括血压偏高、血压偏低、胎儿体重偏轻、头痛与视物模糊、腹部与背部疼痛、羊水过多、下腹疼痛、胎动减少、血小板偏低、妊娠期糖尿病。这些内容混杂了症状、体征与诊断三类粒度,不能直接当标签用。想要一个干净的合并症标签,必须自己归并,而归并规则由使用者承担,不是数据发布方的承诺。
2.5 与同类资源的字段差异
把这份数据和库内已有的胎心类资源放在一张表里比字段,差异会非常清楚地浮现:它少的不是数量,而是"第二路信号"和"逐拍标注"。
| 字段 / 能力 | IIScFHSDB | adfecgdb(腹壁 + 头皮胎心电) | CTU-UHB(产时 CTG) | NIFEA(胎儿心电) |
|---|---|---|---|---|
| 模态 | 声学(心音) | 电学(胎心电) | 机械/多普勒(CTG 曲线) | 电学(腹壁胎心电) |
| 传感器 | 电子听诊器,单点 | 4 路腹壁电极 + 1 路头皮电极 | 多普勒探头 + 宫缩压力探头 | 腹壁电极 |
| 通道数 | 1 | 5 | 2(胎心率 + 宫缩) | 多路腹壁 |
| 原始波形 | 有,2 千赫兹 | 有,1 千赫兹 | 无原始波形,只有提取后的曲线 | 有 |
| 同步参考 | 无 | 有,头皮直接胎心电 | 无独立参考 | 部分有标注 |
| 逐拍标注 | 无 | 有 | 无 | 有节律标注 |
| 记录数 | 60 | 5 | 552 | 26 |
| 时长量级 | 每条约 8 分钟 | 每条 5 分钟 | 每条约 60 分钟 | 每条数十分钟 |
| 采集场景 | 产前门诊 + 产房 | 产房产程中 | 产房产程中 | 门诊 |
| 许可 | ODC-BY 1.0 | ODC-BY 1.0 | ODC-BY 1.0 | 见原库说明 |
这张表最重要的一行是"同步参考"。adfecgdb 之所以在胎儿心电领域不可替代,就是因为它有头皮电极那一路真值;IIScFHSDB 在这一行是空的,这直接决定了它的评估结论只能停在"与人耳一致"的层面。这一差别在 §6.1 会再展开一次,因为它是所有跨模态误用的根源。
§3 声学模态的物理身份
3.1 心音是机械振动,不是电
先把它放回物理层面。心肌收缩是机械运动,机械运动推动血液,血液冲击瓣膜与血管壁,产生可听频段的振动;振动以压力波在体内传播,到体表表现为皮肤表面的微小位移。听诊器先把位移转成腔体内的气压变化,再把气压变化转成电压。胎心电走另一条链:心肌细胞除极产生动作电位,电位差在体表形成可测的电压分布,电极把它取出来,不需要介质振动,只需要电极与皮肤之间稳定的离子—电子转换界面。
两条链的差别带来三个后果。频带不同:心音主能量在几十到几百赫兹;胎心电 QRS 主能量在十到四十赫兹,诊断需保留到一百赫兹以上。干扰源不同:心音怕环境声、母体心音、肠鸣、胎动;胎心电怕母体 QRS、肌电、基线漂移、接触噪声。采样率不同:心音要 2 千赫兹,胎心电 250 赫兹到 1 千赫兹通常够。三者叠加,两种数据的算法传统几乎没有交集。
| 维度 | 胎心音(本库) | 胎心电(adfecgdb 等) | 多普勒超声 | CTG 曲线 |
|---|---|---|---|---|
| 物理量 | 体表机械振动 | 体表电位差 | 血流散射的频移 | 设备内部推算的心率 |
| 主频带 | 数十至数百赫兹 | 十至百余赫兹 | 发射频段内 | 不适用 |
| 典型采样 | 2 千赫兹 | 250 赫兹–1 千赫兹 | 内部高速采样后降采样 | 每 0.25 秒一点 |
| 是否发射能量 | 否 | 否 | 是 | 是 |
| 主要干扰 | 环境声、母体心音、胎动、肠鸣 | 母体 QRS、肌电、接触噪声 | 探头位置、母体血流 | 探头移位、信号丢失 |
| 输出形态 | 连续波形 | 多通道连续波形 | 心率曲线 | 心率与宫缩两条曲线 |
3.2 心音与噪声的成分谱
胎心音的能量分布不是平的。第一心音(S1)由房室瓣关闭与心室收缩早期血流加速产生,频率偏低而能量集中;第二心音(S2)由半月瓣关闭产生,频率略高、持续略短。胎儿心率快,孕晚期常在每分钟 110 到 160 次之间,一个心动周期只有四百到五百毫秒,两个心音的间隔比成人短得多,在时域上更容易混叠。
母体心音也在同一段录音里。成人静息心率常在每分钟 60 到 90 次,与胎心率有明显频率差,但母体心音的幅度通常更大。自相关方法能在同一条信号里找出两个周期,再用心率范围把母体那一个排除掉——前提是两者不落在同一个倍数关系上。当母体心率接近胎心率的一半或两倍时,自相关会出现倍频误判,这是这类算法的经典失效模式。
| 成分 | 来源 | 相对幅度 | 频段倾向 | 对算法的意义 |
|---|---|---|---|---|
| 胎心 S1 | 胎儿房室瓣关闭 | 中 | 偏低 | 主要计数对象 |
| 胎心 S2 | 胎儿半月瓣关闭 | 中低 | 偏高 | 辅助确认周期 |
| 母体 S1/S2 | 母体心脏 | 高 | 与胎心重叠 | 最强的混淆源 |
| 胎动 | 胎儿肢体运动 | 不定 | 宽带,突发 | 瞬时冲击,破坏周期 |
| 肠鸣 | 胃肠蠕动 | 不定 | 低频 | 低频漂移 |
| 环境声 | 谈话、器械、走动 | 不定 | 宽带 | 可掩盖整段 |
| 工频 | 供电 | — | 50 赫兹 | 由内置陷波压制 |
3.3 S1 与 S2 在胎心音里为什么分不开
成人听诊时 S1 与 S2 的间隔清晰,医生靠它判断收缩期与舒张期。胎儿心率快,一个心动周期只有四百到五百毫秒,两个心音之间只剩一百多毫秒;加上经腹壁传播时高频衰减更多,两个心音都变得更闷更宽,在时域上互相吞并。
后果是这份数据适合数周期、不适合分心音:数出每分钟多少次搏动可行,把每次搏动拆成 S1 与 S2 则困难,两者边界在噪声里经常消失。论文选自相关加包络而不是心音分割,正是绕开这个难点。要做分割任务,只能拿它当无标注预训练素材,标注得自建,而两个人听同一段录音,切出的 S1 起点可能差几十毫秒。
3.4 500 倍增益与 2 千赫兹采样率的取舍
500 倍增益是个不寻常的数字。常规心电放大器在 1000 倍量级,因为心电信号在毫伏级;胎心音在体表产生的信号更弱,需要更高放大倍数才能用满采集卡动态范围。但增益不是越高越好:倍数越高,前级本底噪声被放大得越多,信噪比不会因此改善。
2 千赫兹对应 1 千赫兹的奈奎斯特上限。心音主能量在几百赫兹以内,这个上限够用且留有余量。选 2 千赫兹而不是 8 千赫兹,是在文件体积与信息保留之间取折中:六十条八分钟单声道音频,未压缩总量 377.2 MB,对 2022 年的公开数据集来说合适。
| 参数 | 取值 | 为什么是这个值 | 代价 |
|---|---|---|---|
| 增益 | 500 倍 | 胎心音体表幅度弱,需放大到采集卡可用范围 | 前级底噪同步放大 |
| 采样率 | 2 千赫兹 | 覆盖心音主频带,留有奈奎斯特余量 | 无法分析 1 千赫兹以上成分 |
| 前置滤波 | 仅内置工频陷波 | 保留原始噪声,符合"嘈杂场景"目标 | 低频漂移与宽带噪声全部留在数据里 |
| 导出格式 | wav | 通用、无损、工具链成熟 | 体积大于压缩格式 |
3.5 为什么"听"比"电"更难做算法
同样是估计胎心率,胎心电的经典路线是模板减除:先用母体导联估计母体 QRS 模板,从腹壁信号里减掉,剩下的就是胎儿成分,再做峰值检测。这条路有明确的物理模型,减除效果可以直接看残差。
胎心音的路线没有这样的模型。声音在体内传播经过多层介质,每层的阻抗与衰减都不同,传播路径也不唯一,导致同一个心音在体表表现为一段有时间展宽、有混响的波形,而不是一个尖锐的脉冲。母体心音与胎心音在同一条通道里叠加,没有第二路信号可以估计母体成分,盲分离的可辨识性也成问题。
这就是为什么胎心音的算法传统偏向"从周期性入手"而不是"从波形入手":不去分离成分,直接找重复的周期。自相关、倒谱、谱熵、包络自相关,都是这一类思路。它们的共同弱点是对周期性破坏敏感——一次胎动、一段说话,就能让某个窗口的估计彻底跑偏。峰值校验那一步(用前窗的有效心率与功率谱密度筛掉异常值)就是针对这个弱点加的补丁,效果是把平均绝对误差从 11.50 降到 7.54。
§4 质量与特色
4.1 噪声在这里是采集目标,不是缺陷
大多数数据集把噪声当成要清理的东西,这份数据反过来,把噪声当成要保留的东西。官方背景段写得很直白:某些资源受限场景的外部噪声更大,原因是拥挤与缺少单人病房;数据库的目标是提供"在嘈杂临床环境下录到的胎心音",用于去噪算法与胎心率提取算法的开发与评估。
这个定位决定了三件事。第一,没有做质量筛选:质量差的录音照样入库,因为差录音才是难例。第二,没有做前置滤波:除了内置陷波,原始噪声全部保留(§3.4)。第三,没有标注噪声段:官方不告诉你哪一段被说话声污染,因为这正是要算法自己解决的问题。
理解了这一点,就不会把"噪声大"当成数据缺陷来抱怨。它是这份数据的产品定义。
4.2 现场声学剖面
采集地点有两处:产前门诊与产房。门诊相对安静,但有候诊人群走动与交谈;产房更嘈杂,有监护仪报警、器械操作、医护交流,还可能有其他产妇的声音。官方没有按地点分层发布,从文件名看不出某条录音来自哪里。
这个缺失的实际影响是:要做噪声类型的分层分析,只能靠听或靠信号特征反推。噪声的声学特征还算有辨识度——人声集中在几百赫兹且有语调变化,器械碰撞是短促宽带瞬态,监护仪报警是固定频率周期音。逐条标注六十条的工作量不小。
| 噪声来源 | 声学特征 | 出现的场景 | 对胎心率估计的影响 |
|---|---|---|---|
| 人声交谈 | 数百赫兹,有语调起伏 | 门诊候诊、产房 | 宽带覆盖,可整段掩盖 |
| 器械与推车 | 短促宽带瞬态 | 产房 | 瞬时冲击,破坏单窗周期 |
| 监护仪报警 | 固定频率周期音 | 产房 | 可能被误判为节律成分 |
| 母体心音 | 与胎心音重叠的周期成分 | 全程 | 自相关倍频误判的主因 |
| 母体呼吸 | 低频缓慢摆动 | 全程 | 基线漂移 |
| 肠鸣 | 低频不规则 | 全程 | 低频干扰 |
| 胎动 | 突发宽带 | 不定 | 局部信噪比骤降 |
| 工频 | 50 赫兹窄带 | 全程 | 已由内置陷波压制 |
4.3 案例:subject_07 的一段八分钟
把 subject_07 单独拿出来看,能具体说明"一条记录里到底发生了什么"。附表里这一行的孕周是 38 周,年龄 26 岁,体重 103 千克,是全部受试者里体重最高的一档;临床情况写的是头痛与视物模糊,病历胎心率记为 156 次/分。文件大小 9.3 MB,是库里偏大的一条,说明时长接近或超过平均的八分钟。
从物理条件推断,这条录音应该属于偏难的一类:体重 103 千克意味着腹壁脂肪层厚,胎心音传播路径上的衰减更大,高频成分损失更多,录到的信号会更偏低频、更闷。同时母体心音的相对幅度会更高,因为它离听诊器更近,而胎心音被额外几厘米组织削弱。病历记录的 156 次/分属于偏快的胎心率,与母体心率(假定 70 到 90)的比值接近二比一,这正是自相关算法最容易出现倍频误判的区间。
这条记录因此适合当"难例基准":如果某个算法在 subject_07 上能稳定给出接近 156 的估计,说明它的峰值校验确实起了作用;如果在 78 附近给出估计,那就是把胎心率的一半当成了胎心率,典型的倍频错误。
需要说明的是,上面这段推断的每一步都建立在官方公布的字段上——体重、临床情况、病历心率都是附表里的原始值,文件大小是目录列表里的原始值。但"因此信号更难"这一步是物理推断,不是官方结论。官方没有对任何单条记录给出质量评级,论文里的好中差三档也没有逐条公布。所以 subject_07 只能当"按公开字段推断出的难例",不能当"官方认定的难例"。
这一点在 §7.2 的评分里会再提到:这份数据缺少逐条的质量标签,是所有二次分析都要面对的第一个障碍。
4.4 参考心率的两个来源,强度完全不同
评估胎心率算法需要一个参考值。这份数据提供了两个来源,但可信度不在一个层级上。
第一个是论文里的两名观察者:60 条录音由两人逐条人工分析得到参考心率,这是人耳判读,可靠性取决于经验与录音质量。论文用正一致率而不是简单相关系数,说明作者清楚参考值本身有不确定性。第二个是附表最后一列,从病历抄录:列名就带 from medical file,不是每条都有,测量时刻与录音时刻不保证对齐,测量方法未说明。三重不确定性叠在一起。
| 参考来源 | 产生方式 | 时间对齐 | 覆盖范围 | 适合的用法 |
|---|---|---|---|---|
| 两名观察者判读 | 人工聆听音频 | 与录音同一时段 | 论文称 60 条全部分析 | 算法评估的主参考 |
| 病历胎心率 | 临床常规测量后抄录 | 不保证对齐 | 部分受试者 | 粗校验、量级 sanity check |
正确的用法是:主评估用观察者判读值,病历值只用来做量级校验——比如算法输出 300 次/分,而病历写 140,这就是明显的失败,不需要精细对齐就能发现。反过来,用病历值算逐窗平均绝对误差,会得到一个既包含算法误差又包含时间错位误差的数字,不可解释。
4.5 论文给出的算法基线与三个质量档
原始论文给出的数字不多,但每一个都可复现。方法是用包络检测找候选峰,用自相关估周期,再用基于前窗有效心率与功率谱密度的峰值校验剔除异常。两个版本的对比是这篇论文最实用的部分。
| 指标 | 无校验版本 | 加校验版本 | 提升 |
|---|---|---|---|
| 平均绝对误差(次/分) | 11.50 | 7.54 | 降低约 3.96 |
| 正一致率 | 81% | 87% | 提高 6 个百分点 |
这两个数字给后来者提供了明确的对标点。如果你的算法在这份数据上算出的平均绝对误差明显优于 7.54,要么是你的方法确实更好,要么是你的评估口径与论文不同——后者更常见。常见的口径差异包括:参考值取两名观察者中的哪一位、如何配窗(逐窗比还是整段比)、异常窗是否剔除、以及是否用了病历值做补充。
论文还把记录分成好、中、差三档,用来观察算法在不同质量下的表现。这个分层对使用者很有价值,但分层结果没有随数据发布。想做同样的分析,只能自己重做分层,而分层标准(用什么指标定义好中差)论文里给了思路但没有给出可执行的阈值表。这是复现时的一个实际障碍。
§5 取数与处理
5.1 三条获取路径
PhysioNet 提供三种取数方式:网页下载 ZIP、wget 递归镜像、AWS S3 同步。三者内容一致,区别只在速度与是否可断点续传。对这份 128.3 MB 的库来说,任何一种都够快。
#-- 方式一:直接下 ZIP(需要先在网页上接受许可)
curl -L -o iiscfhsdb.zip \
"https://physionet.org/content/fetalheartsounddata/get-zip/1.0/"
#-- 方式二:wget 递归镜像整个 1.0 目录
wget -r -N -c -np https://physionet.org/files/fetalheartsounddata/1.0/
#-- 方式三:AWS 开放数据桶,无需凭证
aws s3 sync --no-sign-request \
s3://physionet-open/fetalheartsounddata/1.0/ ./fetalheartsounddata/1.0/
第一种方式在部分网络环境下会因为重定向与 cookie 校验失败,返回一个 HTML 页面而不是 ZIP。判断方法是看文件头:真正的 ZIP 前两个字节是 PK,如果下载下来的文件用 file 命令识别成 HTML,就是失败了。第二种与第三种方式没有这个问题,适合脚本化。
5.2 下载后的完整性核对
SHA256SUMS.txt 是这个库唯一的完整性凭据。它列出每个文件的校验和,下载后应该逐条比对。这一步在批量处理前值得做一次,因为音频文件损坏不一定报错,可能只是解码出半段静音。
#-- 进入数据目录后逐条校验
cd fetalheartsounddata/1.0
sha256sum -c SHA256SUMS.txt
#-- 只看失败的行
sha256sum -c SHA256SUMS.txt 2>/dev/null | grep -v ': OK$'
#-- 统计音频文件数量与总体积
ls -1 subject_*.wav | wc -l
du -sh .
第一条命令会逐行输出"文件名: OK"或"文件名: FAILED"。第二条把通过的过滤掉,剩下的就是问题文件。第三条的两个数字可以用来核对官方公布的口径:六十个音频文件,未压缩总量 377.2 MB。如果数量或体积对不上,说明下载不完整。
5.3 用 Python 读一条录音
官方的示例是 MATLAB 脚本,用 audioread 读 wav,再用 iircomb 做梳状滤波。Python 侧用标准库的 wave 或 soundfile 都能读,区别是 wave 只支持 PCM 编码,soundfile 支持更多格式。这份数据的 wav 是 PCM,两者都行。
#-- 读取并画出前 10 秒,观察胎心音的周期性
import wave
import numpy as np
import matplotlib.pyplot as plt
path = "fetalheartsounddata/1.0/subject_07.wav"
with wave.open(path, "rb") as w:
fs = w.getframerate()
n = w.getnframes()
raw = w.readframes(n)
x = np.frombuffer(raw, dtype=np.int16).astype(np.float32)
if x.size == 2 * n:
x = x.reshape(-1, 2).mean(axis=1) #-- 若是双声道则混单
t = np.arange(x.size) / fs
seg = slice(0, min(10 * fs, x.size))
fig, ax = plt.subplots(figsize=(12, 3))
ax.plot(t[seg], x[seg], lw=0.4)
ax.set_xlabel("time (s)")
ax.set_ylabel("amplitude (ADC)")
plt.tight_layout()
plt.savefig("subject_07_head.png", dpi=150)
这段代码有一个防御性设计:位深按 16 位有符号整数读取,但如果实际是 8 位或 24 位,frombuffer 会得到错误长度。判断方法是看解出的数组长度是否等于帧数,或者等于帧数的两倍(双声道)。更稳妥的做法是先读 getsampwidth() 再决定 dtype,官方没有公布位深,所以这一步不能省。
5.4 预处理链:陷波、带通、包络
官方的示例只做了梳状滤波。实际做胎心率估计时,常见的预处理链更长:先陷波去工频残留,再带通到心音主频带,然后取包络,最后在包络上做自相关。每一步的参数都会影响结果,而这些参数没有官方推荐值,只能自己调。
#-- 一条最小可用的预处理链:陷波 -> 带通 -> 包络
import numpy as np
from scipy.signal import butter, filtfilt, iirnotch, hilbert
def preprocess(x, fs, mains=50.0, band=(20.0, 400.0)):
b, a = iirnotch(mains, Q=35.0, fs=fs)
y = filtfilt(b, a, x)
lo, hi = band
bb, ab = butter(4, [lo / (fs / 2), hi / (fs / 2)], btype="band")
y = filtfilt(bb, ab, y)
env = np.abs(hilbert(y))
return y, env
Q 值取 35 与官方示例里的 35 一致,带宽因此大约是 50/35 赫兹,即不到两赫兹,只压掉很窄的一条。带通的下限取 20 赫兹是为了去掉呼吸与体动造成的低频漂移,上限取 400 赫兹是因为胎心音在更高频段的能量已经很弱,留着只会引入高频噪声。这两个数不是官方给的,是工程上的常用值,换一组参数结果会变。
包络用希尔伯特变换的模,这是解析信号的标准做法。也可以用平方后低通,效果类似但更粗糙。包络的作用是把双向振荡的波形变成单向的、以心音出现时刻为峰的信号,便于后续的峰值检测与自相关。
5.5 与元数据表对齐
把音频与 Records.csv 对齐的唯一键是编号。音频文件名是 subject_XX.wav,表里是整数 Subject,需要做一次字符串到整数的转换。这一步看起来简单,实际有两个坑:编号补零的位数(01 而不是 1)、以及 CSV 里可能有前后空格。
#-- 建立编号到文件路径与元数据的索引
import re
from pathlib import Path
import pandas as pd
root = Path("fetalheartsounddata/1.0")
meta = pd.read_csv(root / "Records.csv")
meta.columns = [c.strip() for c in meta.columns]
def sid_from_name(p):
m = re.search(r"subject_(\d+)\.wav$", p.name)
return int(m.group(1)) if m else None
files = {sid_from_name(p): p for p in sorted(root.glob("subject_*.wav"))}
joined = meta.assign(path=meta["Subject"].map(files))
missing = joined[joined["path"].isna()]
print(f"音频 {len(files)} 条,表 {len(meta)} 行,未匹配 {len(missing)} 行")
跑完之后应该看到音频六十条、表六十行、未匹配零行。如果不是这个结果,说明编号格式与预期不同,需要先打印几个文件名看看实际格式。这个检查在写任何批处理脚本之前都值得做一次,因为编号错位是这类批量任务最常见的静默错误——不会报错,只是所有结果都串了一行。
5.6 复现论文的评估口径
要复现论文的 7.54 次/分,需要把评估口径拆到可执行的程度。论文用的是逐窗比较,窗口长度与步长需要从论文正文确认(摘要未给出)。参考值取两名观察者的一致性结果,具体是取平均还是取一致的那个,也需要看正文。
在没有全文的情况下,能做的是搭一个"结构正确"的评估框架,把关键参数留成可配的,等拿到正文再填。
#-- 评估骨架:逐窗估计 vs 参考值,参数留空待填
import numpy as np
def windowed_fhr(env, fs, win_s, hop_s, fmin=60.0, fmax=200.0):
win = int(win_s * fs)
hop = int(hop_s * fs)
out = []
for start in range(0, len(env) - win, hop):
seg = env[start:start + win] - env[start:start + win].mean()
ac = np.correlate(seg, seg, mode="full")[win - 1:]
lo = int(fs * 60.0 / fmax)
hi = int(fs * 60.0 / fmin)
if hi >= len(ac):
continue
lag = lo + int(np.argmax(ac[lo:hi]))
out.append((start / fs, 60.0 * fs / lag))
return out
这段代码给的是"能跑"的下限,不是"能复现论文"的上限。它缺三样东西:峰值校验、异常窗剔除、以及参考值的对齐。前两样是论文的核心贡献,第三样是评估的关键。把这三样补齐,才谈得上复现。
§6 与库内条目的关系
6.1 关系图谱
IIScFHSDB 在库内的位置可以用一句话定位:它是胎心监测这一族里唯一的声学模态成员。这个唯一性决定了它与其它词条的关系——不是竞争,是互补;不是替代,是补位。
| 库内词条 | 模态 | 与本库的关系 | 怎么配合使用 |
|---|---|---|---|
| adfecgdb | 腹壁 + 头皮直接胎心电 | 同一临床问题、不同物理量 | 用它的真值研究"胎心电能做到多准",用本库研究"声音能做到多准",两者结论不可互换 |
| CTU-UHB | 产时 CTG 曲线 | 同一场景、不同抽象层级 | CTG 是设备算完的心率曲线,本库是原始声音;前者可直接做分类,后者要先估心率 |
| NIFEA | 腹壁胎心电 | 同为非侵入、不同模态 | 可作为"电学 vs 声学"在同一任务上的对照,注意人群与孕周不同 |
| UCI CTG | CTG 特征表 | 特征级 vs 波形级 | 前者是已提取的二十余个特征,后者是原始波形,粒度差两个层级 |
| 各类胎儿超声影像集 | 影像 | 任务不同,仅共享"胎儿"这个前缀 | 不要混为一谈:影像看结构,本库看节律 |
| 心音类数据集(成人) | 声学 | 同一模态、不同对象 | 可借用成人心音的分割与分类方法,但胎儿的频率与周期特性不同,不能直接迁移 |
最关键的一行是 adfecgdb。这两个库经常被放在一起讨论"非侵入胎儿监护",但它们的物理基础完全不同:adfecgdb 记录的是电,IIScFHSDB 记录的是声。电学方法有清晰的传播模型(容积导体),声学方法没有(多层介质、路径不唯一)。电学方法有头皮电极做真值,声学方法只有人耳。这两条差异决定了:在 adfecgdb 上验证过的胎心电算法,一行代码都不能直接搬到 IIScFHSDB 上;反过来也一样。
第二关键的是 CTU-UHB。它给的是产时 CTG 曲线,也就是设备已经算好的胎心率序列,每 0.25 秒一个点。IIScFHSDB 给的是原始声音,胎心率要自己算。两者的关系是"上游"与"下游":本库是 CTG 设备内部那一步的输入,CTG 是那一步的输出。想做端到端的"从声音到曲线",理论上可以用本库训练、用 CTG 库做对照,但两者的采样场景(产前门诊 vs 产房产程)与人群不同,直接拼接会引入场景偏差。
6.2 检索路径
在库里找与它相关的词条,有四个入口。
第一个是标签路径:生理信号 加上心音类标签,数据标签是 时序信号、波形、元数据、人工标注。带这套标签的词条不多,因为心音这个模态在公开数据里本来就稀缺。
第二个是机构路径:PhysioNet。同一套发布规范、引用格式、目录约定,取数流程与校验方式高度相似,可以复用同一套脚本。
第三个是任务路径:胎心率估计、胎心监护、非侵入胎儿监测、产科筛查。搜胎心率会同时命中本库、CTG 类库与胎心电类库,需要按模态再筛。
第四个是模态路径:声学。这是最窄也最准的筛法。全库里带声学模态的词条屈指可数,胎心音只有这一个。
§7 质量评估与局限性
7.0 阅读本节前的一个前置校正
在给任何分数之前,必须先校正一个几乎人人都会犯的误判:把"没有同步真值"直接读成"数据质量差"。这两件事不是一回事。质量讲的是数据本身是否可信、是否自洽、是否被诚实描述;真值讲的是能不能给算法判分。一份数据可以质量很高但没有真值,也可以有真值但采集粗糙。
按"评测基准"的维度打分,IIScFHSDB 会在"参考信号"一项上大幅失分,因为它确实没有同步通道。但按"现场数据集"的维度打分,它反而靠前:噪声被如实保留、采集链路被完整披露、每个参数都能在官方页面找到出处、参考心率的来源被明确写成人耳判读而不是含糊其辞。这种诚实本身就是质量的一部分。
下面的评分表因此按"临床现场声学数据集"来设计权重,而不是按"评测基准"来设计。读的时候请把这一点放在前面,否则分数会被误读成"一个没有真值所以不及格的小库"。
7.1 五维评分
按 DAIMS 的常用维度打分,每项 1 到 5 分,分数针对"作为胎心音算法研究数据"这个用途:
| 维度 | 分数 | 理由 |
|---|---|---|
| 文档完备度 | 4 | 采集设备、增益、采样率、伦理批件、引用方式全部披露;扣分在孕周与年龄口径不一致、位深未公布 |
| 数据自洽性 | 4 | 文件名与编号一一对应,附表与目录可核对;扣分在临床情况列拼写不统一、短横线含义未定义 |
| 参考信号强度 | 2 | 只有人耳判读,无同步物理参考;这是最弱的一维 |
| 规模与覆盖 | 2 | 六十个受试者、约八小时、单一中心、单一设备;对训练不够,对评测够用 |
| 可复现性 | 4 | 全部参数公开、示例代码随附、校验和随附;扣分在三档质量标签未发布 |
五维加起来十九分,满分二十五。这个分数放在"评测基准"类目里偏低,放在"现场声学数据集"类目里属于中上。分数本身没有意义,有意义的是每一维的扣分理由——它们精确地指出了使用时的四个注意事项。
7.2 分维度展开
文档完备度四分:设备型号、采集系统、软件、增益、采样率、导出格式、伦理批件号、采集地点、听诊器放置位置全部披露;扣分在孕周与年龄口径不一致、位深未说明。
数据自洽性四分:六十个文件名与六十行表能一一对上,编号格式统一,校验和可用;扣分在临床情况是自由文本、拼写不统一,孕次与产次的短横线未定义。
参考信号强度两分,是最硬的短板:人耳判读无法回答算法是否比人耳更准,因为人耳就是标尺。
规模与覆盖两分:六十个受试者对跨人群泛化偏少,每人八分钟覆盖不了孕周与状态的变异。
可复现性四分:参数可查、示例可跑、校验和可验;扣分在三档质量标签未随数据发布。
§4.3 的案例正好说明这五维里的前两维为何给四分:单条记录的全部公开字段都自洽,缺的是官方对它的质量判定。
7.3 已知的、可枚举的偏差
下面这份清单只列能用官方文字或公开事实支撑的偏差,不做推测。
| 偏差 | 具体表现 | 影响 | 可缓解方式 |
|---|---|---|---|
| 单中心偏倚 | 全部来自班加罗尔圣约翰医院 | 设备型号、病房噪声、人群特征都被固定 | 跨库外部验证只能换中心,不能在本库内做 |
| 单设备偏倚 | 只用 SS30LA 一种电子听诊器 | 频响特性被固定,换设备后分布会变 | 记录自己的设备型号,做频响校准 |
| 孕周集中 | 31–40 周,集中在晚孕 | 早孕与中孕早期完全缺失 | 明确声明适用范围,不外推 |
| 年龄口径冲突 | 摘要 18–27,附表 18–37 | 人群描述不确定 | 引用时以附表为准并注明冲突 |
| 参考非独立 | 人耳判读,无物理参考 | 算法上限不可测 | 表述为"与人耳一致性"而非"误差" |
| 无逐条质量标签 | 论文分档未发布 | 无法直接做分层评估 | 自建质量指标,如分段信噪比估计 |
| 临床列粒度混杂 | 症状、体征、诊断混在一列 | 不能直接当标签 | 自定义归并规则并公开 |
| 无逐拍标注 | 只有连续音频 | 心音分割需自建标注 | 弱监督或半自动标注 |
7.4 外部验证矩阵
一份数据的外部验证能力,取决于它能与多少其它数据形成对照。把 IIScFHSDB 与库内其它胎心类资源的可对照性列成矩阵,能清楚看出它在哪些方向上可验证、哪些方向上不可验证。
| 对照方向 | 可对照的资源 | 是否可行 | 障碍 |
|---|---|---|---|
| 同模态、不同人群 | 库内暂无第二个胎心音库 | 不可行 | 声学模态在公开数据里稀缺 |
| 同任务、不同模态 | adfecgdb、NIFEA | 部分可行 | 只能比"胎心率估计精度"这个抽象指标,不能比波形 |
| 同场景、不同抽象层 | CTU-UHB、UCI CTG | 部分可行 | 场景不同(门诊 vs 产时),需分层说明 |
| 同模态、成人 vs 胎儿 | 成人心脏听诊数据集 | 可行 | 频率与周期不同,只能借方法不能借参数 |
| 时间上的稳定性 | 本库内部按孕周分层 | 可行 | 孕周范围窄,分层后每组样本很少 |
| 设备上的稳定性 | 无第二设备 | 不可行 | 单设备是硬边界 |
| 与临床结局的关联 | 无结局变量 | 不可行 | 附表只有临床情况文本,无分娩结局 |
这张矩阵的结论是:它能做的外部验证非常有限。这不是它的过错,而是整个声学胎心监测领域的现状——公开数据太少,少到无法形成互相验证的网络。任何一个声称"在多个胎心音库上验证"的论文,都值得追问一句:另外几个库是什么?
7.5 它为何能持续:唯一性比规模更能抵抗时间
公开数据集的生命力通常来自规模,但这份数据的生命力来自唯一性。胎心音这个模态在公开数据里极度稀缺,而临床需求一直存在——低资源地区的产前筛查需要便宜、被动、不需要耗材的设备,听诊器符合全部三条。只要这个需求还在,只要没有第二个公开的胎心音库出现,这份六十条的小数据就会一直被引用。
它的另一个持续因素是采集条件的诚实。很多数据集在发布时会把噪声清理掉,让数据"看起来更好",代价是失去了真实场景的代表性。这份数据反过来,把噪声留在里面,把采集链路写清楚,让后来者能判断"我的场景和它像不像"。这种可判断性比规模更难被替代。
§8 生态位与历史
8.1 胎心听诊的两百年
1816 年 Laennec 发明听诊器,最初用于成人胸部。胎心听诊在 19 世纪逐步进入产科,成为判断胎儿存活的主要床边手段。20 世纪初 DeLee 与 Hillis 等人把胎心听诊规范化,提出用听诊器计数一分钟作为常规产程监测。这套方法一直用到 20 世纪 70 年代,没有本质变化。
转折是电子监护。1960 年代后期胎心宫缩监护进入临床,用多普勒超声连续记录胎心率,用压力传感器记录宫缩。它连续、可存档、可报警,很快成为产房标准配置。听诊退到门诊与资源受限场景,成为没有设备时的替代方案。这个轨迹解释了为什么胎心音公开数据这么少。
8.2 胎心音图研究的三次起落
胎心音图作为研究课题经历过三次起落。
第一次在 1970 到 1980 年代,电子听诊器与模拟滤波器成熟,一批研究尝试用 fPCG 替代多普勒。受限于当时的计算能力,只能做简单带通与过零检测,效果不稳定,未进入临床。
第二次在 1990 到 2000 年代,数字信号处理普及,自相关、倒谱、小波被引入。这一阶段建立了基本算法框架,也出现若干商用尝试,都因噪声鲁棒性不足而未成规模。
第三次从 2010 年代开始,低功耗芯片与机器学习让 fPCG 重新被视为低资源筛查的可行路径。特征是从追求替代多普勒转向追求在特定场景下够用:不要求诊断级精度,只要求在没有超声设备的地方筛出需要转诊的孕妇。
8.3 本库在这个谱系里的位置
把三次起落与本库的位置对上,能看出它的定位:它不是算法的提出者,是算法的试金石。第一次起落缺的是算力,第二次缺的是鲁棒性,第三次缺的是可比较的公开难例。本库补的是第三样。
这个定位也解释了它的规模为什么这么小。作为试金石,六十条足够暴露算法的失效模式;作为训练集,六十条远远不够。发布者显然清楚这一点,所以官方页面从头到尾没有提"训练"这个词,只提"开发与评估"。
8.4 同类资源编年
| 年份 | 资源 | 模态 | 规模 | 与本库的关系 |
|---|---|---|---|---|
| 2012 | adfecgdb | 腹壁 + 头皮胎心电 | 5 条 | 电学真值,与本库互补 |
| 2013 | CTU-UHB | 产时 CTG | 552 例 | 下游曲线,与本库上下游相关 |
| 2017 | Ibrahim 等的 fPCG vs CTG 对比研究 | 声学 vs 机械 | 研究论文 | 提供了 fPCG 与 CTG 可比性的早期证据 |
| 2022 | IIScFHSDB | 胎心音 | 60 条 | 本库 |
| 2022 | Amrutha 等的心率估计算法 | 声学 | 算法论文 | 本库的配套论文,给出基线数字 |
这张表里最值得注意的是 2017 年那篇对比研究。它比较了从胎心音图与 CTG 估计的胎心率,结论是两者在多数情况下可比,但在信号质量差时分歧明显。这个结论为本库的存在提供了临床合理性:如果 fPCG 永远无法与 CTG 可比,那么建一个 fPCG 库就没有意义。
§9 使用指引
9.1 三种角色的路径
不同的使用者拿到这份数据,第一步该做的事完全不同。
算法研究者先跑通基线,不要一上来上深度模型:用官方梳状滤波加自相关跑一遍,看能不能接近 7.54。跑不通说明预处理链有问题。第二步做失效分析,把误差最大的窗口挑出来听一遍,看是母体心音、胎动还是环境声。§4.3 的案例提供了一个可复用的排查顺序。
设备工程师先评估场景匹配度:把样机录音与库里录音放在同一套指标下比噪声谱、信噪比、频响。差得远说明现场不是一回事,直接套结论会误导。第二步做鲁棒性测试,按不同信噪比加噪,找算法开始失效的阈值。
临床与教学人员先听,挑几条不同质量的录音建立直觉;再做对比教学,同一条录音里母体心音与胎心音的节律差异是好素材。这份数据不能用于诊断教学。
| 角色 | 第一步 | 第二步 | 常见误区 |
|---|---|---|---|
| 算法研究者 | 跑通官方基线 | 失效分析,逐窗听 | 直接上深度模型,没有对照 |
| 设备工程师 | 评估场景匹配度 | 加噪鲁棒性测试 | 把库里的平均误差当成自己产品的指标 |
| 临床与教学 | 听不同质量的录音 | 做母体与胎心的节律对比 | 把数据当诊断级证据使用 |
| 数据工程师 | 核对文件与表的一致性 | 建立批处理管线 | 忽略编号补零与短横线占位 |
9.2 一条最短的可用流程
从下载到算出第一条录音的胎心率,最短的路径是五步。下面这段代码把五步串起来,可以直接跑。
#-- 最短流程:读一条 -> 预处理 -> 包络 -> 自相关 -> 心率
import wave
import numpy as np
from scipy.signal import butter, filtfilt, iirnotch, hilbert
def load_wav(path):
with wave.open(path, "rb") as w:
fs = w.getframerate()
n = w.getnframes()
raw = w.readframes(n)
x = np.frombuffer(raw, dtype=np.int16).astype(np.float64)
return x, fs
def band_env(x, fs, lo=20.0, hi=400.0, mains=50.0):
b, a = iirnotch(mains, 35.0, fs)
y = filtfilt(b, a, x)
bb, ab = butter(4, [lo / (fs / 2), hi / (fs / 2)], btype="band")
y = filtfilt(bb, ab, y)
return np.abs(hilbert(y))
def fhr_from_env(env, fs, fmin=60.0, fmax=200.0):
seg = env - env.mean()
ac = np.correlate(seg, seg, mode="full")[len(seg) - 1:]
lo = int(fs * 60.0 / fmax)
hi = int(fs * 60.0 / fmin)
lag = lo + int(np.argmax(ac[lo:hi]))
return 60.0 * fs / lag
x, fs = load_wav("fetalheartsounddata/1.0/subject_07.wav")
env = band_env(x, fs)
print(f"采样率 {fs} Hz,估计胎心率 {fhr_from_env(env, fs):.1f} 次/分")
这段代码在一整条八分钟录音上做单次自相关,得到的是一个全局平均心率,不是逐窗估计。它的用途是快速 sanity check:如果输出落在 60 到 200 之外,说明预处理或读取有问题;如果落在 78 附近而病历写 156,说明遇到了倍频误判(§4.3 讨论的正是这种情况)。要做正经的评估,必须改成逐窗加峰值校验。
9.3 引用方式
PhysioNet 页面明确要求两条引用同时给。第一条是数据本身,第二条是配套论文,第三条是 PhysioNet 平台的标准引用。三条的关系是:数据来自第一条,方法基线来自第二条,平台归属来自第三条。
Bhaskaran, A., & Arora, M. (2022). Indian Institute of Science Fetal Heart
Sound Database (IIScFHSDB) (version 1.0). PhysioNet.
https://doi.org/10.13026/9vvw-cx05
Amrutha, B., Sidhesh Kumar, J., George, S., & Arora, M. (2022).
Heart rate estimation and validation algorithm for fetal phonocardiography.
Physiological Measurement. https://doi.org/10.1088/1361-6579/ac7a8c
只引数据不引论文,读者无法知道参考心率是怎么来的;只引论文不引数据,读者无法复现。两条都给,才构成完整的引用链。
§10 AI 使用声明
| 项目 | 说明 |
|---|---|
| 数据来源 | 全部描述来自 PhysioNet 项目页、Records.csv 与 Europe PMC 的论文摘要 |
| 未使用生成式方法造数 | 本文不含任何合成的波形、图像或统计量 |
| 数字口径 | 只写规模、结构、边界三类,分布类统计一律未做 |
| 未核实项 | wav 位深、声道数、逐条时长、三档质量标签的具体划分 |
| 官方口径冲突 | 孕周与年龄在摘要、方法、附表间不一致,已如实并列 |
| 建议的复核方式 | 下载后运行 §5.2 的校验和核对与 §5.5 的编号对齐检查 |
| 适用边界 | 结论不外推到早孕期、其它设备、其它国家的人群 |
| 引用要求 | 数据 DOI 与论文 DOI 须同时给出 |
常见误读(避坑清单)
| 说法 | 实际 | 证据 |
|---|---|---|
| 这是胎心电数据集 | 是胎心音,声学模态 | 官方标题为 Fetal Heart Sound Database,采集用电子听诊器 |
| 它有同步的超声或胎心电参考 | 没有任何同步参考通道 | 官方页面只提到人耳判读与病历抄录 |
| 60 条就是 60 个独立样本,可以随便切分训练测试 | 是 60 个受试者各一条,按受试者切分才对 | 文件名与 Subject 列一一对应,每人一条 |
| 平均 8 分钟意味着每条都是 8 分钟 | 8 分钟是平均值,逐条时长要看文件 | 官方只给平均值,目录里文件大小从 1.2 MB 到 9.9 MB 不等 |
| 采样率 2 千赫兹意味着能分析到 2 千赫兹 | 奈奎斯特上限是 1 千赫兹 | 采样定理,官方未声明抗混叠滤波器特性 |
| 病历里的胎心率就是金标准 | 不同步、覆盖不全、方法未说明 | 列名明确写 from medical file,官方称仅可得时提供 |
| 数据已经去过噪,可以直接做特征 | 只做了内置工频陷波,其余噪声全保留 | 官方方法段写明无其它前置滤波 |
| 六十条足够训练一个端到端模型 | 样本量对深度模型明显不足 | 60 个受试者、总计约八小时,官方定位是开发与评估 |
| 它和 CTG 数据可以直接拼接 | 场景不同(门诊 vs 产时),抽象层级不同 | 本库是原始声音,CTG 是设备算好的曲线 |
| 孕周是 30 到 40 周 | 三个口径并存:30–40、大于 30、31–40 | 摘要、方法段、附表各写一种 |
FAQ
Q1:这份数据到底叫什么?为什么有两个名字?
全名是 Indian Institute of Science Fetal Heart Sound Database,缩写 IIScFHSDB。PhysioNet 的 URL 里用的短名是 fetalheartsounddata。两个名字指同一个东西,缩写出现在页面标题与论文里,短名只出现在网址与文件路径中。
Q2:为什么说它没有同步参考信号?论文里不是有参考心率吗?
论文的参考心率是两名观察者听音频听出来的,属于人耳判读,不是独立的物理测量。同步参考指的是与录音同一时刻、用另一种物理原理测得的信号,比如同步的多普勒超声或同步的胎心电。本库没有这样的通道。
Q3:它的噪声真的有代表性吗?
官方明确说数据来自产前门诊与产房,且背景段提到资源受限场景的噪声更大是因为拥挤与缺单人病房。这两个地点覆盖了临床听诊的主要场景。但它是印度单家医院的噪声,不能代表所有地区,尤其是安静的单人病房或家庭环境。
Q4:60 条录音够做什么?
够做算法评测、失效分析、预训练素材、教学示范。不够做端到端训练、跨人群泛化研究、临床结局关联分析。判断标准是任务而不是模型大小。
Q5:文件是 wav,位深是多少?
官方页面没有说明位深与声道数,只说明采样率是 2 千赫兹、格式是 wav。读取时应该先用 getsampwidth() 与 getnchannels() 探测,不要假设是 16 位单声道(§5.3)。
Q6:为什么文件大小差这么多?
因为录音时长不同。官方只给平均值约 8 分钟,没有逐条时长表。目录里最小的文件 1.2 MB,最大的 9.9 MB,差异反映的是时长差异,不是质量差异。
Q7:它和 adfecgdb 有什么本质区别?
模态不同。adfecgdb 记录的是电,用腹壁电极加头皮电极,有头皮那一路做真值;本库记录的是声,用电子听诊器,没有真值。两者的算法传统、干扰源、评估方式都不同,不能互相替代(§6.1)。
Q8:能拿它训练心音分割模型吗?
可以拿它做无标注预训练,但不能直接做有监督训练,因为没有逐拍的 S1/S2 标注。要做有监督,得自己标注,而胎心音里 S1 与 S2 在时域上容易混叠,标注一致性是个难题(§3.3)。
Q9:为什么论文的误差是 7.54 次每分,这个数字好吗?
这个数字要放在临床背景里看。胎心率监测关注的是基线、加速、减速,误差在 5 到 10 次每分通常被认为可接受用于筛查,但不足以做诊断。7.54 是加校验后的结果,无校验时是 11.50。
Q10:我想复现论文的结果,最可能卡在哪一步?
最可能卡在评估口径,§4.3 的案例里那两处推断也不能当结论用。参考值取两名观察者中的哪一个、窗口长度与步长、异常窗是否剔除、是否用了病历值补充——这四点论文正文里应该有,摘要里没有。不把这四点对齐,算出的数字不可比。
Q11:它有没有伦理批件?
有。官方页面写明研究经班加罗尔圣约翰医院机构伦理委员会批准,批件号 07/2018,数据在获得知情同意后采集。
Q12:这份数据会被更新吗?
截至核验时只有版本 1.0,2022 年 9 月 15 日发布,之后没有新版本。官方也没有承诺后续扩充。以六十条的规模判断,短期内大幅扩充的可能性不大。
术语表
| 术语 | 英文 | 含义 |
|---|---|---|
| 胎心音图 | fetal phonocardiography, fPCG | 用传感器记录胎儿心音得到的波形 |
| 胎心率 | fetal heart rate, FHR | 单位时间内的胎儿心搏次数,常用次/分 |
| 电子听诊器 | electronic stethoscope | 把体表振动转成电信号并放大的听诊设备 |
| 心音 | heart sound | 心脏瓣膜关闭与血流冲击产生的可听振动 |
| 第一心音 | S1 | 房室瓣关闭与心室收缩早期产生的心音 |
| 第二心音 | S2 | 半月瓣关闭产生的心音 |
| 包络检测 | envelope detection | 提取信号幅度包络的方法,常用希尔伯特变换 |
| 自相关 | autocorrelation | 信号与自身延迟版本的相关性,用于找周期 |
| 梳状滤波 | comb filter | 在基频及其谐波处形成陷波的滤波器 |
| 陷波器 | notch filter | 压制某一窄带频率的滤波器,常用于去工频 |
| 工频干扰 | power line interference | 供电系统引起的 50 或 60 赫兹干扰 |
| 奈奎斯特频率 | Nyquist frequency | 采样率的一半,可无混叠表示的最高频率 |
| 增益 | gain | 放大器的输出与输入之比,本库为 500 倍 |
| 信噪比 | signal-to-noise ratio, SNR | 有用信号功率与噪声功率之比 |
| 正一致率 | positive percent agreement | 算法与参考均判定为阳性的比例 |
| 平均绝对误差 | mean absolute error, MAE | 估计值与参考值绝对差值的平均 |
| 倍频误判 | octave error | 把周期估成真实值的两倍或一半 |
| 腹壁胎心电 | abdominal fECG | 从孕妇腹壁电极拾取的胎儿心电 |
| 直接胎心电 | direct fECG | 从胎儿头皮电极拾取的胎心电,可作真值 |
| 胎心宫缩监护 | cardiotocography, CTG | 连续记录胎心率与宫缩的临床监护方法 |
| 多普勒超声 | Doppler ultrasound | 利用频移测血流与胎心的超声技术 |
| 单胎妊娠 | singleton pregnancy | 一次妊娠只有一个胎儿 |
| 孕次 | gravida | 既往妊娠次数,含本次 |
| 产次 | para | 既往分娩次数 |
| 开放数据许可 | ODC-BY | 允许使用与再分发、要求署名的数据许可 |
附录 A:核心数字核对表
| 项 | 值 | 来源 | 来源层级 |
|---|---|---|---|
| 记录数 | 60 | 官方摘要与数据描述段 | 官方页面 |
| 受试者数 | 60 | 官方数据描述段 | 官方页面 |
| 孕周范围 | 31–40 周 | 官方附表的范围行 | 官方页面 |
| 孕周均值 | 37 ± 2.0 周 | 官方附表的均值行 | 官方页面 |
| 年龄范围 | 18–37 岁 | 官方附表的范围行 | 官方页面 |
| 年龄均值 | 25 ± 3.7 岁 | 官方附表的均值行 | 官方页面 |
| 体重范围 | 49–103 千克 | 官方附表的范围行 | 官方页面 |
| 身高范围 | 144–171 厘米 | 官方附表的范围行 | 官方页面 |
| 采样率 | 2 千赫兹 | 官方摘要与方法段 | 官方页面 |
| 增益 | 500 倍 | 官方摘要与方法段 | 官方页面 |
| 平均时长 | 约 8 分钟 | 官方摘要与数据描述段 | 官方页面 |
| 未压缩体积 | 377.2 MB | 官方文件区 | 官方页面 |
| 压缩包体积 | 128.3 MB | 官方文件区 | 官方页面 |
| 基线平均绝对误差 | 7.54 次/分 | 论文摘要 | 论文摘要 |
| 基线正一致率 | 87% | 论文摘要 | 论文摘要 |
| wav 位深 | 官方未公布 | — | 未核实 |
| 逐条时长 | 官方未公布 | — | 未核实 |
| 三档质量标签划分 | 官方未公布 | — | 未核实 |
附录 B:数字的来源分层
第一层:官方页面直接给出。 记录数 60、受试者数 60、采样率 2 千赫兹、增益 500 倍、平均时长 8 分钟、体积 377.2 MB 与 128.3 MB、四项体格指标的均值与范围、伦理批件号、DOI、许可类型。这些数字可以在项目页或 Records.csv 里逐字找到。
第二层:论文摘要给出。 平均绝对误差从 11.50 降到 7.54、正一致率从 81% 升到 87%、两名观察者逐条分析 60 条录音、记录被分为好中差三档。这些数字来自 Europe PMC 的摘要,未读全文,正文里可能有更细的分层结果。
第三层:未核实或官方未公布。 wav 的位深与声道数、逐条录音的确切时长、三档质量标签的具体划分标准与逐条归属、参考心率的具体数值表、附表缺失单元格的确切含义(空与短横线是否等价)。这些内容官方页面没有说明,本文一律标为未核实,不做推测。
附录 C:完整参考文献
- Bhaskaran A, Arora M. Indian Institute of Science Fetal Heart Sound Database (IIScFHSDB), version 1.0. PhysioNet. 2022. DOI: 10.13026/9vvw-cx05.
- Amrutha B, Sidhesh Kumar J, George S, Arora M. Heart rate estimation and validation algorithm for fetal phonocardiography. Physiological Measurement. 2022. DOI: 10.1088/1361-6579/ac7a8c.
- Ibrahim EA, et al. A comparative study on fetal heart rates estimated from fetal phonography and cardiotocography. Frontiers in Physiology. 2017;8:764.
- Jezewski J, et al. Abdominal and direct fetal electrocardiogram database(adfecgdb). PhysioNet. 2012.
- Chudáček V, et al. CTU-UHB Intrapartum Cardiotocography Database. PhysioNet. 2014.
- Pollard T, Moody BE, Lehman L, et al. PhysioNet as a global platform for biomedical research. Nature Health. 2026;1(8):792–795.
附录 D:批量扫描的代码
上面 §5 给的是单条记录的读取与估计。实际做研究时要扫全库,下面这段代码把六十条录音全部跑一遍,输出每条的单窗估计值,并与附表对齐。
#-- 批量扫描:六十条录音逐条估计,与附表并排输出
import re
import wave
from pathlib import Path
import numpy as np
import pandas as pd
from scipy.signal import butter, filtfilt, hilbert, iirnotch
ROOT = Path("fetalheartsounddata/1.0")
def read_i16(path):
with wave.open(str(path), "rb") as w:
fs, n, ch, sw = w.getframerate(), w.getnframes(), w.getnchannels(), w.getsampwidth()
raw = w.readframes(n)
if sw != 2:
raise ValueError(f"{path.name} 位宽 {sw * 8} 位,非 16 位")
x = np.frombuffer(raw, dtype=np.int16).astype(np.float64)
if ch == 2:
x = x.reshape(-1, 2).mean(axis=1)
return x, fs
def estimate(x, fs):
b, a = iirnotch(50.0, 35.0, fs)
y = filtfilt(b, a, x)
bb, ab = butter(4, [20.0 / (fs / 2), 400.0 / (fs / 2)], btype="band")
y = filtfilt(bb, ab, y)
env = np.abs(hilbert(y))
env = env - env.mean()
ac = np.correlate(env, env, mode="full")[len(env) - 1:]
lo = int(fs * 60.0 / 200.0)
hi = int(fs * 60.0 / 60.0)
lag = lo + int(np.argmax(ac[lo:hi]))
return 60.0 * fs / lag
rows = []
for p in sorted(ROOT.glob("subject_*.wav")):
sid = int(re.search(r"(\d+)", p.stem).group(1))
x, fs = read_i16(p)
rows.append({
"Subject": sid,
"fs": fs,
"minutes": len(x) / fs / 60.0,
"fhr_est": estimate(x, fs),
})
est = pd.DataFrame(rows)
meta = pd.read_csv(ROOT / "Records.csv")
meta.columns = [c.strip() for c in meta.columns]
out = est.merge(meta, on="Subject", how="left")
out.to_csv("fhr_scan.csv", index=False)
print(out[["Subject", "minutes", "fhr_est", "FHR (bpm) from medical file"]].head(10))
这段代码会打印出前十条的时长、估计心率与病历心率。要看的是三件事:时长分布是否与"平均八分钟"一致、估计值是否大面积落在 60 到 200 之外(说明预处理有问题)、以及与病历值的偏差是否有系统性的两倍关系(说明倍频误判)。三件事都是诊断性的,不是结论性的——发现了异常,还要回到录音去听。
附录 E:如果只记五件事
| 序号 | 记住什么 | 为什么 |
|---|---|---|
| 1 | 60 条胎心音,每条约 8 分钟,2 千赫兹,500 倍增益 | 这四个数字定义了它的一切用法与限制 |
| 2 | 它是声学模态,不是胎心电 | 与 adfecgdb 等库不能互换,算法传统完全不同 |
| 3 | 没有同步参考通道,参考心率靠人耳 | 评估结论只能表述为"与人耳一致",不能说"误差" |
| 4 | 噪声是产品定义的一部分,不是缺陷 | 它的用途就是在难例上做去噪与心率提取的评测 |
| 5 | 单一中心、单一设备、晚孕期 | 任何外推都要先声明这三条边界 |
编辑说明
本文的核验时间为 2026 年 10 月 28 日。核对方式为直接 GET 项目页 HTML 与文件目录,读取 Records.csv 的表头与前若干行,抓取 example_code.m 全文,并用 Europe PMC 的 REST 接口取回论文摘要;未下载音频本体,未读论文全文。官方页面在孕周与年龄上存在三处口径不一致(摘要 30–40 周与 18–27 岁、方法大于 30 周、附表 31–40 周与 18–37 岁),本文并列写出,未做取舍判断。wav 的位深、声道数、逐条时长与三档质量标签的具体划分均未公布,文中一律标为未核实。分布类统计按要求一律未做。
相关数据集导航
以下为站内 AI-Ready 数据集百科中与本词条共享多个主题标签的相关数据集,按相关度降序排列:
- cdb — 共享标签:生理信号 / 时序数据 / 评测基准
- shanghai-t1dm-t2dm-cgm — 共享标签:生理信号 / 时序数据 / 评测基准
- cinc-2018-sleep-arousal — 共享标签:生理信号 / 时序数据 / 评测基准
- cpap-data-canterbury — 共享标签:生理信号 / 时序数据
- mmgdb — 共享标签:生理信号 / 时序数据
- perg-ioba-dataset — 共享标签:生理信号 / 时序数据
- ieeepg — 共享标签:生理信号 / 时序数据 / 评测基准
- sisfall — 共享标签:生理信号 / 时序数据 / 评测基准
- wisdm — 共享标签:生理信号 / 时序数据 / 评测基准
- mimic-iv-waveform-legacy — 共享标签:生理信号 / 时序数据
导航说明:本章节由全站统一标签体系自动计算生成(标签重合度算法),双向可达;点击链接可跳转至对应数据集词条。

