两千赫兹的胎心录音 — IIScFHSDB 心音库

60 名孕妇 / 孕 31–40 周 / 2 kHz 电子听诊器

来源 https://physionet.org/content/fetalheartsounddata/1.0/发布时间: 2026-10-28最后更新: 2026-10-28 阅读 15
两千赫兹的胎心录音 — IIScFHSDB 心音库

信息速览

数据集名称两千赫兹的胎心录音 — IIScFHSDB 心音库
数据类型时序信号,波形,元数据,人工标注
规模60 名孕妇 / 60 条记录
接入方式https://physionet.org/content/fetalheartsounddata/1.0/
AI 就绪度

胎心监护有三条互不相同的物理路径。多普勒超声打一束高频声波进去,听反射回来的频移;胎心电在腹壁上拾取胎儿心脏除极产生的微弱电位;胎心音则什么也不发射,只是把听诊器贴在小腹上,听那颗隔着羊水、子宫肌层和母体脂肪传来的机械搏动。三条路里,听诊是最老的一条,也是公开数据最少的一条。

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:完整参考文献

  1. Bhaskaran A, Arora M. Indian Institute of Science Fetal Heart Sound Database (IIScFHSDB), version 1.0. PhysioNet. 2022. DOI: 10.13026/9vvw-cx05.
  2. 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.
  3. Ibrahim EA, et al. A comparative study on fetal heart rates estimated from fetal phonography and cardiotocography. Frontiers in Physiology. 2017;8:764.
  4. Jezewski J, et al. Abdominal and direct fetal electrocardiogram database(adfecgdb). PhysioNet. 2012.
  5. Chudáček V, et al. CTU-UHB Intrapartum Cardiotocography Database. PhysioNet. 2014.
  6. 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 — 共享标签:生理信号 / 时序数据

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

返回 AI-Ready 数据集