HLS-CMDS

HLS-CMDS — 临床模拟人心肺音数据集 AI-Ready Wikipedia | 千方病案医数集

来源 McMaster University, Mohawk IAHS url: https://data.mendeley.com/datasets/8972jxbpmp发布时间: 2026-08-10最后更新: 2026-08-10 阅读 2

信息速览

数据集名称HLS-CMDS
数据类型 约 38 MB, 535 条录音, CC BY 4.0 开放许可, 免费直接下载, 配对 Ground Truth
规模535 条录音
接入方式McMaster University, Mohawk IAHS url: https://data.mendeley.com/datasets/8972jxbpmp
AI 就绪度

INFOBOX

数据集名称 HLS-CMDS
英文全称 Heart and Lung Sounds Dataset Recorded from a Clinical Manikin using Digital Stethoscope
别名 / 简称 HLS-CMDS、Manikin Cardiopulmonary Sounds Dataset
疾病分类 多类别覆盖。心音:BC01–BC9Z 心血管疾病(心脏杂音、心律失常、心音异常);肺音:CA40–CA4Z 呼吸系统疾病(喘息、爆裂音、干啰音、胸膜摩擦音)
SNOMED CT 448370001 Murmur (finding) / 67782005 Atrial fibrillation (disorder) / 86650006 Tachycardia (finding) / 248254009 Wheeze (finding) / 409629000 Crackles (finding) / 94310008 Rhonchi (finding)
数据模态 音频(心音/肺音/混合心肺音录音,WAV 格式)
AI 任务类型 音频分类、声源分离(盲源分离/监督分离)、多任务学习、域适应
样本总数 535 条录音(50 孤立心音 + 50 孤立肺音 + 145 混合心肺音 + 145 配对源心音 + 145 配对源肺音)
数据大小 ~37.8 MB(Zenodo)/ ~35.9 MB(UCI)
数据格式 WAV(音频,22,050 Hz,15 秒/条)+ CSV(元数据)
许可证 Creative Commons Attribution 4.0 International(CC BY 4.0)
访问级别 开放(多平台直接下载,无需注册或申请)
DUO 标签 NRES, PUB
语言 英文(元数据 CSV)
首发日期 2024-10-14(v1,arXiv 预印本)
最后更新 2025-05-07(v3,Mendeley Data)
发布机构 McMaster University, Mohawk McMaster Institute for Applied Health Sciences(Torabi, Shirani, Reilly 团队)
官方主页 https://data.mendeley.com/datasets/8972jxbpmp
下载地址 https://data.mendeley.com/datasets/8972jxbpmp / https://archive.ics.uci.edu/dataset/1202 / https://zenodo.org/records/15376628 / https://github.com/Torabiy/HLS-CMDS
DOI 10.1109/IEEEDATA.2025.3566012(IEEE Data Descriptions)/ 10.17632/8972jxbpmp(Mendeley)/ 10.21227/fe0m-k110(IEEE Dataport)
引用次数 4+(Bing Academic,截至 2026-08)
AI 就绪度评分 ⭐⭐⭐(3/5)— 配对 Ground Truth 设计独特但规模小、无官方划分、模拟人环境与真实临床差距显著
页面状态 published

§0 E-E-A-T 信任声明与免责声明

字段 内容
医学审核者 [千方病案医学编辑部]交叉审核:§2 医学背景(ICD-11 映射、心音/肺音病理分类、临床听诊任务定义)、§7 偏倚分析。
数据工程审核者 [千方病案医学编辑部]交叉审核:§4 DAIMS 数据字典、§5 数据划分策略、§6 预处理 Pipeline 和坑点。
审核日期 2026-08-04
审核方式 交叉审核
利益冲突声明 本页面与 HLS-CMDS 数据集作者及发布机构无任何利益关系。千方病案医数集为独立第三方数据集百科平台。

医疗免责声明:本页面提供的医学信息仅供研究和教育目的,不构成医疗建议、诊断或治疗方案。数据集的医学描述基于公开发表的文献,未经逐一临床验证。任何基于该数据集训练的 AI 模型在应用于临床决策前,必须经过独立的临床验证和监管审批。

技术免责声明:本页面的代码示例、预处理建议和基准性能数据基于公开资料整理,不保证在特定环境下的准确性和适用性。使用者应自行验证代码安全性和数据预处理流程的正确性。千方病案医数集不对因使用本页面信息而导致的任何直接或间接损失承担责任。

数据使用合规:使用本页面描述的数据集前,请务必阅读并遵守数据集原始许可协议。HLS-CMDS 采用 CC BY 4.0 许可证,使用时须注明原始来源。DUO 标签仅供参考,具体使用限制以数据集官方协议为准。

§1 数据集概览

§1.0 📌 30 秒速览

HLS-CMDS 是 McMaster 大学于 2024 年发布的心肺音数据集,通过 3M Littmann CORE 数字听诊器从临床模拟人采集 535 条 15 秒录音,覆盖 10 种心音类型和 6 种肺音类型,分布于 12 个标准听诊解剖位置。

它的独特价值在于提供了混合音与单源音的完美配对 Ground Truth——每条混合心肺音录音都有对应的独立心音和独立肺音源信号,这在全球公开数据集中是独一无二的。这一设计直击临床听诊中心音和肺音在胸腔内互相掩盖的技术死角,为深度学习模型执行声源分离提供了成对的训练目标。

你可以用它来:训练一个心肺音盲分离模型(从混合音中提取纯净心音和肺音)、开发智能数字听诊器的异常心音分类算法、或者研究小样本场景下的音频域适应方法。

§1.1 摘要

HLS-CMDS 由 McMaster University 的 Yasaman Torabi、Shahram Shirani 和 James P. Reilly 三位研究者创建,数据采集在 Mohawk McMaster Institute for Applied Health Sciences (IAHS) 的临床模拟实验室完成。该数据集使用 3M Littmann CORE 数字听诊器,在临床模拟人(patient simulator)的 12 个标准听诊解剖位置上采集了三类录音:孤立心音(Bell 滤波模式)、孤立肺音(Diaphragm 滤波模式)和混合心肺音(Midrange 滤波模式)。所有录音在受控无噪声环境中进行,每条 15 秒,采样率 22,050 Hz,以 WAV 格式保存。

数据集的核心创新在于配对设计:v2/v3 版本的 145 条混合录音中,每一条都有对应的独立心音源录音和独立肺音源录音,共计形成 145 组完整的三元组(心音 + 肺音 + 混合音)。这种设计使研究者能够在监督学习框架下训练声源分离模型,而非仅依赖盲源分离(BSS)的无监督方法。

§1.2 为什么重要

技术创新维度:在 HLS-CMDS 发布之前,心肺音分离研究长期受限于缺乏配对 Ground Truth。传统方法(如 NMF、ICA)只能在无监督框架下工作,无法定量评估分离质量。HLS-CMDS 通过临床模拟人分别输出独立的心音、肺音和混合音频,首次为深度学习社区提供了成对的完美 Ground Truth,使监督学习分离方法成为可能。这从根本上改变了心肺音分离研究的范式——从"猜测源信号"到"已知源信号的监督学习"。

应用推动维度:智能数字听诊器是远程医疗和基层医疗的关键设备。在真实临床场景中,听诊器拾取的声音始终是心音和肺音的混合体,而现有 AI 分类模型大多只在孤立心音或孤立肺音上训练,导致在混合音场景下性能急剧下降(研究表明从 89% 降至 41%)。HLS-CMDS 为解决这一"混合干扰"痛点提供了直接可用的训练数据,推动了智能听诊器在嘈杂病房环境下的准确度跃升。

§1.3 同类数据集对比

数据集 样本量 模态 配对 Ground Truth 核心差异化
HLS-CMDS 535 条 心音/肺音/混合音 ✅ 完美配对 唯一提供混合→单源配对的公开数据集
PhysioNet/CinC 2016 3,126 条 仅心音 大规模心音分类基准,无肺音/混合音
ICBHI 2017 5,355 条 仅呼吸音 大规模呼吸音分类基准,无心音/混合音
PASCAL Heart Sound 661 条 仅心音 早期心音分类挑战赛数据集
Eko / Littmann 内部数据 未知 混合音 商业数据,不公开

§1.4 版本演进

时间 事件
2024-10 v1 首次发布(arXiv 预印本 arXiv:2410.03280),210 条录音(50 HS + 50 LS + 110 Mix),无配对源信号
2024-10 Mendeley Data / GitHub 同步发布,CC BY 4.0 许可
2025-03 v2 发布(Mendeley Data),扩展至 535 条录音,新增 145 条配对源心音和 145 条配对源肺音
2025-05 IEEE Data Descriptions 期刊正式发表,DOI: 10.1109/IEEEDATA.2025.3566012
2025-05 v3 发布(Mendeley Data),同步上线 UCI ML Repository (id=1202) 和 Zenodo
2025-08 UCI ML Repository 收录,11,700+ 次浏览(截至 2026-08)

§1.5 典型 AI 应用场景

  1. 心肺音声源分离:从混合录音中提取纯净心音和肺音,使用配对 Ground Truth 进行监督训练(核心任务)
  2. 异常心音分类:10 类心音(正常/杂音/S3/S4/心律失常等)的多分类任务
  3. 异常肺音分类:6 类肺音(正常/喘息/爆裂音/干啰音/胸膜摩擦音等)的多分类任务
  4. 域适应与迁移学习:在 PhysioNet/CinC 2016 或 ICBHI 2017 上预训练,迁移到 HLS-CMDS 混合音场景
  5. 小样本音频学习:在仅 535 条录音的约束下研究数据增强、Few-shot 学习和正则化策略

§2 医学背景

§2.1 ICD-11 编码映射

数据集标签 ICD-11 编码 中文疾病名
Murmur (LDM/MSM/LSM/ESM) BC81 心脏杂音
Atrial Fibrillation (AF) BC81.1 心房颤动
Tachycardia (T) BC81.3 心动过速
Atrioventricular Block (AVB) BC83.0 房室传导阻滞
Third Heart Sound (S3) BC81.Z 心音异常(第三心音)
Fourth Heart Sound (S4) BC81.Z 心音异常(第四心音)
Wheezing (W) CA23.0 喘息
Fine Crackles (FC) CA43.1 细湿啰音
Coarse Crackles (CC) CA43.2 粗湿啰音
Rhonchi ® CA23.1 干啰音
Pleural Rub (PR) DB98.Z 胸膜摩擦音

§2.1b SNOMED CT 映射

数据集标签 SNOMED CT SNOMED CT 术语
Murmur 448370001 Murmur (finding)
Atrial Fibrillation 67782005 Atrial fibrillation (disorder)
Tachycardia 86650006 Tachycardia (finding)
Atrioventricular Block 27885002 Complete atrioventricular block (disorder)
Wheeze 248254009 Wheeze (finding)
Crackles 409629000 Crackles (finding)
Rhonchi 94310008 Rhonchi (finding)
Pleural Rub 72414001 Pleural rub (finding)

§2.2 疾病简介与流行病学

心脏瓣膜病与心律失常:心脏杂音是瓣膜性心脏病最典型的体征,全球约 5% 的成人存在病理性心脏杂音。心房颤动是最常见的持续性心律失常,全球患病人数超过 3,300 万。第三心音(S3)和第四心音(S4)分别提示心力衰竭和心室顺应性下降,是床旁听诊的重要诊断线索。

呼吸系统疾病:喘息是哮喘和慢性阻塞性肺疾病(COPD)的标志性体征,全球哮喘患者超 3 亿、COPD 患者超 2 亿。湿啰音提示肺水肿、肺炎或间质性肺病,干啰音提示气道狭窄。胸膜摩擦音则提示胸膜炎。

§2.3 临床任务定义

任务类型 临床目标 对应数据集子集
声源分离 从混合听诊音中分离出纯净心音和肺音 Mix + 配对 HS/LS
心音分类 判定心音是否异常及具体异常类型 HS(孤立)或 Mix 分离后
肺音分类 判定肺音是否异常及具体异常类型 LS(孤立)或 Mix 分离后
筛查 从混合音直接判定心肺是否异常 Mix(直接输入)

§2.4 患者人群特征

维度 特征
数据来源 临床模拟人(patient simulator),非真实患者
采集时间 2024 年,具体起止时间未公开
"年龄"分布 不适用(模拟人无年龄属性)
"性别"分布 CSV 元数据含 Gender 字段(F/M),反映模拟人生理参数设置
采集地点 加拿大安大略省汉密尔顿 McMaster University, Mohawk IAHS
采集环境 受控无噪声实验室环境

§2.5 临床意义

在常规床旁听诊中,心音和肺音始终混合存在——心脏的舒张收缩和肺的呼吸运动在胸腔内产生叠加振动。然而,现有 AI 听诊系统几乎都在孤立心音或孤立肺音上训练和评估,导致在真实混合听诊场景下性能大幅退化。HLS-CMDS 通过模拟人提供了受控的混合→单源配对数据,使研究者能够量化和弥合"孤立→混合"的性能差距,这对推动智能听诊器从实验室走向临床部署具有关键意义。

§2.6 金标准

数据子集 标注方式 标注者 金标准性质
HS(孤立心音) 模拟人预设病种 + 数字听诊器录音 模拟人控制器(instructor tablet) 参考标准(模拟人程序化输出)
LS(孤立肺音) 同上 同上 同上
Mix(混合音) 模拟人同时输出心音 + 肺音 同上 参考标准
配对源 HS/LS 混合音对应的单独心音/肺音录音 同上 配对 Ground Truth(核心金标准)

金标准说明:HLS-CMDS 的金标准来自临床模拟人的程序化输出,而非真实患者的临床诊断。模拟人(如 3M/Laerdal 系列)可精确控制输出的心音和肺音类型,确保每条录音的"标签"是确定性的。这种设计的优势是标签零噪声,劣势是声音为模拟而非自然病理产生,与真实患者听诊音存在域差距。

§3 数据集规格

§3.0 版本抉择矩阵

你的需求 推荐版本 大小 理由
心肺音分离研究(核心任务) v2/v3 ~38 MB 含 145 组配对三元组,是唯一可做监督分离的版本
仅心音或仅肺音分类 v1 或 v2/v3 ~14 MB(v1)/ ~38 MB(v2) v1 的 50 HS + 50 LS 足够做分类基线
轻量快速实验 / Colab UCI ML Repository ~36 MB UCI 提供 ucimlrepo 一行代码加载,最便捷
可复现研究引用 v3 (IEEE Data Descriptions) ~38 MB 期刊发表版本,引用 DOI: 10.1109/IEEEDATA.2025.3566012

§3.1 模态详细说明

HLS-CMDS 是纯音频数据集,所有录音为单声道 WAV 文件,采样率 22,050 Hz,时长 15 秒/条。录音设备为 3M Littmann CORE 数字听诊器,支持三种声学滤波模式:

滤波模式 适用场景 频率范围(典型) 对应数据集子集
Bell 低频心音 20–200 Hz HS
Diaphragm 高频肺音 100–500 Hz LS
Midrange 混合心肺音 20–500 Hz Mix

录音通过蓝牙从听诊器传输至 Eko Software 应用,再上传至 Eko Cloud,最终保存为 WAV 文件。

§3.2 样本拆分

子集 录音数 说明 文件
HS(孤立心音) 50 10 种心音类型 × 6 个心音听诊位置 HS.zip + HS.csv
LS(孤立肺音) 50 6 种肺音类型 × 6 个肺音听诊位置 LS.zip + LS.csv
Mix(混合心肺音) 145 心音 + 肺音同时输出 Mix.zip + Mix.csv
配对源 HS 145 每条 Mix 对应的独立心音 Mix.zip(含源文件)
配对源 LS 145 每条 Mix 对应的独立肺音 Mix.zip(含源文件)
总计 535 ~37.8 MB

§3.3 数据格式

文件类型 格式 大小 说明
音频文件 WAV (22,050 Hz, 16-bit) ~117 KB/条 15 秒单声道录音
心音元数据 CSV 1.6 KB HS.csv: Sound ID, Gender, Heart Sound Type, Location
肺音元数据 CSV 1.3 KB LS.csv: Sound ID, Gender, Lung Sound Type, Location
混合音元数据 CSV 7.3 KB Mix.csv: Mixed Sound ID, Gender, Heart Sound Type, Lung Sound Type, Location, Heart Sound ID, Lung Sound ID
README TXT 3.2 KB HLS_CMDS_README.txt

§3.4 存储大小

版本 压缩后大小 解压后大小 来源
v1 ~14.3 MB ~18 MB Mendeley Data
v2/v3 ~37.8 MB ~47 MB Mendeley / Zenodo / UCI

§3.5 标注方式

HLS-CMDS 的标注来自临床模拟人的程序化输出,而非人工标注:

  1. 操作员通过 instructor tablet 选择模拟人要输出的心音/肺音类型
  2. 模拟人精确执行程序化声音输出
  3. 数字听诊器在指定解剖位置录音
  4. 录音的"标签"即为操作员选择的病种,无标注噪声

这种方式的优势是标签 100% 准确(零标注噪声),劣势是声音为模拟而非自然病理产生。

§3.6 标注者信息

维度 信息
标注者 临床模拟人(patient simulator)程序化输出
标注者资质 不适用(机器程序化生成)
一致性检验 不需要(程序化输出完全确定)
人工审核 无(标签由模拟人控制器直接设定)

§3.7 采集时间

2024 年(具体月份未公开)。

§3.8 地理覆盖

单一机构:加拿大安大略省汉密尔顿 McMaster University, Mohawk McMaster Institute for Applied Health Sciences (IAHS)。

§3.9 设备规格

设备 规格
数字听诊器 3M Littmann CORE Digital Stethoscope
声学滤波 Bell / Diaphragm / Midrange 三模式
传输方式 蓝牙 → Eko Software → Eko Cloud
临床模拟人 未公开具体型号(推测为 Laerdal SimMan 系列)
模拟人控制 Instructor tablet via WiFi
采样率 22,050 Hz
位深 16-bit
声道 单声道
录音时长 15 秒/条
保存格式 WAV

§3.10 深度溯源链

临床模拟人 (patient simulator)
    ↓ 程序化心音/肺音输出
3M Littmann CORE 数字听诊器
    ↓ 蓝牙传输
Eko Software (平板/手机 App)
    ↓ 上传
Eko Cloud
    ↓ 导出
WAV 文件 (22,050 Hz, 15s)
    ↓ 整理 + CSV 元数据
HS.zip / LS.zip / Mix.zip
    ↓ 发布
Mendeley Data / UCI / Zenodo / IEEE Dataport
    ↓ GitHub 代码库
Torabiy/HLS-CMDS (可视化脚本 + Jupyter Notebook)

§4 数据结构详解

§4.0 目录结构

HLS-CMDS/
├── HS.csv                    # 心音元数据(50 条)
├── HS.zip                    # 心音音频文件
│   ├── H0001.wav             # 15s, 22050 Hz
│   ├── H0002.wav
│   └── ...H0050.wav
├── LS.csv                    # 肺音元数据(50 条)
├── LS.zip                    # 肺音音频文件
│   ├── L0001.wav
│   ├── L0002.wav
│   └── ...L0050.wav
├── Mix.csv                   # 混合音元数据(145 条 + 配对引用)
├── Mix.zip                   # 混合音 + 配对源文件
│   ├── Mix/                  # 混合录音(145 条)
│   │   ├── M0001.wav
│   │   └── ...M0145.wav
│   ├── Source_HS/            # 配对源心音(145 条)
│   │   ├── M0001.wav         # 与 Mix/M0001.wav 配对
│   │   └── ...
│   └── Source_LS/            # 配对源肺音(145 条)
│       ├── M0001.wav         # 与 Mix/M0001.wav 配对
│       └── ...
└── HLS_CMDS_README.txt       # 说明文件

注意:GitHub 仓库中 Mix.zip 因文件较大被拆分为 Mix1.zip、Mix2.zip、Mix3.zip,需解压后合并。

§4.1 DAIMS 标准化字段描述表

HS.csv 字段
字段名 数据类型 说明 示例值 AI 用途 观测误差 信息性缺失编码 取值范围
Sound ID string 心音录音文件名 H0001 文件定位 H0001–H0050
Gender string 模拟人性别设置 F 分层分析 F, M
Heart Sound Type string 心音类型缩写 NH 分类标签 NH/LDM/MSM/LSM/AF/S4/ESM/S3/T/AVB
Location string 听诊解剖位置 A 位置编码 A/RUSB/LUSB/LLSB/RC/LC
LS.csv 字段
字段名 数据类型 说明 示例值 AI 用途 观测误差 信息性缺失编码 取值范围
Sound ID string 肺音录音文件名 L0001 文件定位 L0001–L0050
Gender string 模拟人性别设置 M 分层分析 F, M
Lung Sound Type string 肺音类型缩写 NL 分类标签 NL/W/FC/R/PR/CC
Location string 听诊解剖位置 RUA 位置编码 RUA/RMA/RLA/LUA/LMA/LLA
Mix.csv 字段
字段名 数据类型 说明 示例值 AI 用途 观测误差 信息性缺失编码 取值范围
Mixed Sound ID string 混合录音文件名 M0001 文件定位 M0001–M0145
Gender string 模拟人性别设置 F 分层分析 F, M
Heart Sound Type string 混合音中的心音类型 MSM 分类标签 NH/LDM/MSM/LSM/AF/S4/ESM/S3/T/AVB
Lung Sound Type string 混合音中的肺音类型 W 分类标签 NL/W/FC/R/PR/CC
Location string 听诊解剖位置 RUA 位置编码 12 个位置
Heart Sound ID string 配对源心音文件名 H0001 分离目标引用 H0001–H0050
Lung Sound ID string 配对源肺音文件名 L0001 分离目标引用 L0001–L0050

§4.2 标签分布

心音类型分布(HS + Mix 中的心音标签)
心音类型 缩写 HS 条数 Mix 条数 总计 占比
Normal Heart NH 5 14 19 9.7%
Mid Systolic Murmur MSM 5 18 23 11.7%
Late Diastolic Murmur LDM 5 15 20 10.2%
Late Systolic Murmur LSM 5 12 17 8.7%
Early Systolic Murmur ESM 5 13 18 9.2%
Atrial Fibrillation AF 5 16 21 10.7%
Third Heart Sound S3 5 15 20 10.2%
Fourth Heart Sound S4 5 14 19 9.7%
Tachycardia T 5 14 19 9.7%
Atrioventricular Block AVB 5 14 19 9.7%
肺音类型分布(LS + Mix 中的肺音标签)
肺音类型 缩写 LS 条数 Mix 条数 总计 占比
Normal Lung NL ~8 ~28 ~36 18.5%
Wheezing W ~8 ~25 ~33 16.9%
Fine Crackles FC ~8 ~22 ~30 15.4%
Rhonchi R ~9 ~24 ~33 16.9%
Pleural Rub PR ~8 ~23 ~31 15.9%
Coarse Crackles CC ~9 ~23 ~32 16.4%

注意:上述分布为基于数据集结构(50 LS 覆盖 6 种类型 × 6 位置,145 Mix 覆盖多种组合)的估算。精确分布请下载 CSV 文件后统计。

Mix 子集类别不平衡
维度 异常比例 说明
心音异常(Mix 子集) ~91.0% 仅 14/145 条为正常心音
肺音异常(Mix 子集) ~80.7% 仅 ~28/145 条为正常肺音

关键发现(Cai, 2026, PLoS One):Mix 子集严重类别不平衡,91% 心音异常、80.7% 肺音异常。这导致 AUPRC 基线很高(0.8586),模型容易在排序指标上"看起来好"但阈值操作行为差。

§4.3 数据统计

  • 总录音时长:535 × 15s = 8,025s ≈ 2 小时 14 分钟
  • 音频采样点数/条:22,050 × 15 = 330,750 samples
  • 文件数:535 个 WAV + 3 个 CSV + 1 个 README = 539 文件

§4.4 数据层级

数据集 → 子集(HS/LS/Mix)→ 录音条目 → 音频采样序列
                              ↓ Mix 子集
                     三元组(Mix + Source HS + Source LS)

§4.5 缺失值情况

字段 缺失情况 说明
所有 CSV 字段 无缺失 模拟人程序化生成,元数据完整
音频文件 无缺失 所有 535 条录音文件完整

§5 数据划分与使用建议

§5.1 官方划分

HLS-CMDS 未提供官方 train/val/test 划分。研究者需自行划分。

§5.2 推荐划分策略

策略 适用任务 划分方式 注意事项
三元组分组 K-Fold 声源分离 按三元组(Mix + Source HS + Source LS)分组,避免同一三元组的组件跨集 ⚠️ 必须在三元组级别分组,否则数据泄漏
位置分层 K-Fold 心音/肺音分类 按 Location 分层,确保每个位置在各 fold 中比例一致 控制位置混杂
类型分层 K-Fold 心音/肺音分类 按声音类型分层,确保稀有类别(如 AVB)在训练集中有足够样本 10 类心音每类仅 ~19 样本
Leave-One-Type-Out 泛化性评估 每次留出一种声音类型作为测试集 评估对未见类型的泛化能力

§5.3 分离任务划分约束

关键:心肺音分离任务的数据划分必须在三元组级别进行。即一个三元组(Mix_i + Source_HS_i + Source_LS_i)的所有三个文件必须同时进入同一个 fold。如果 Mix_i 在训练集而 Source_HS_i 在测试集,模型可能通过学习源信号的特征间接"作弊"。

§5.4 跨数据集迁移方案

预训练数据集 预训练任务 迁移到 HLS-CMDS
PhysioNet/CinC 2016 心音分类(正常/异常) Heart Teacher → 知识蒸馏到 HLS-CMDS 混合音分类
ICBHI 2017 呼吸音分类(6 类) Lung Teacher → 知识蒸馏到 HLS-CMDS 混合音分类
AudioSet 通用音频分类 通用声学特征提取器 → 微调

§5.5 样本量评估

维度 评估
分离任务 145 组三元组偏少,需重度数据增强
心音分类 50 HS 样本极少,10 类仅 ~5 样本/类,需迁移学习
肺音分类 50 LS 样本极少,6 类仅 ~8 样本/类,需迁移学习
混合音分类 145 Mix 可勉强训练,但类别不平衡严重

§5.6 推荐使用流程

1. 下载 v3 数据集(Mendeley / UCI / Zenodo)
2. 解压,验证文件完整性(535 WAV + 3 CSV)
3. 按 §5.2 推荐策略划分(分离任务用三元组分组 K-Fold)
4. 信号预处理:归一化 → 去噪 → 分帧
5. 特征提取:Log-Mel Spectrogram / MFCC / Waveform
6. 模型训练:分离任务用配对监督,分类任务用迁移学习
7. 评估:SDR/SI-SDR(分离)/ AUROC/F1(分类)
8. 外部验证:在 PhysioNet 2016 / ICBHI 2017 上验证泛化性

§6 AI 就绪指南

§6.1 快速上手

# ========================================
# HLS-CMDS 快速上手 — Python 版
# 环境要求: librosa>=0.10, pandas, numpy, matplotlib
#
# ⚠️ 目录结构预期:
#   请将下载的 HS.zip / LS.zip / Mix.zip 解压至 ./data/ 目录:
#   ./data/
#   ├── HS.csv              # 心音元数据
#   ├── HS/                 # 心音 WAV 文件
#   │   ├── H0001.wav
#   │   └── ...
#   ├── LS.csv              # 肺音元数据
#   ├── LS/                 # 肺音 WAV 文件
#   ├── Mix.csv             # 混合音元数据
#   └── Mix/                # 混合音 + 配对源文件
#       ├── M0001.wav       # 混合录音
#       ├── Source_HS/M0001.wav  # 配对源心音
#       └── Source_LS/M0001.wav  # 配对源肺音
#
#   或使用 ucimlrepo 一键加载(仅元数据):
#   pip install ucimlrepo
# ========================================

import librosa
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

#  方式一:从 UCI ML Repository 加载元数据 
from ucimlrepo import fetch_ucirepo
hls = fetch_ucirepo(id=1202)
X = hls.data.features
y = hls.data.targets
print(f"UCI 加载完成: {len(X)} 条记录")
print(f"列名: {list(X.columns)}")

#  方式二:从本地 WAV 文件加载音频 
# 加载一条混合录音及其配对源信号
mix_audio, sr = librosa.load(''''''''''''''''./data/Mix/M0001.wav'''''''''''''''', sr=22050)
source_hs, _ = librosa.load(''''''''''''''''./data/Mix/Source_HS/M0001.wav'''''''''''''''', sr=22050)
source_ls, _ = librosa.load(''''''''''''''''./data/Mix/Source_LS/M0001.wav'''''''''''''''', sr=22050)

print(f"混合音: {len(mix_audio)} samples, {len(mix_audio)/sr:.1f}s")
print(f"源心音: {len(source_hs)} samples")
print(f"源肺音: {len(source_ls)} samples")

# 验证混合音 ≈ 源心音 + 源肺音(模拟人叠加)
reconevent-blocked= source_hs + source_ls
error = np.mean(np.abs(mix_audio - reconstruction))
print(f"混合音 vs 源叠加误差: {error:.6f}")

#  读取元数据 
mix_meta = pd.read_csv(''''''''''''''''./data/Mix.csv'''''''''''''''')
print(f"\nMix 子集: {len(mix_meta)} 条")
print(f"心音类型分布:\n{mix_meta[''''''''''''''''Heart Sound Type''''''''''''''''].value_counts()}")
print(f"肺音类型分布:\n{mix_meta[''''''''''''''''Lung Sound Type''''''''''''''''].value_counts()}")

#  可视化 
fig, axes = plt.subplots(3, 1, figsize=(14, 8), sharex=True)
t = np.arange(len(mix_audio)) / sr
axes[0].plot(t, source_hs, ''''''''''''''''b-'''''''''''''''', alpha=0.7, linewidth=0.5)
axes[0].set_title(''''''''''''''''Source Heart Sound'''''''''''''''')
axes[0].set_ylabel(''''''''''''''''Amplitude'''''''''''''''')
axes[1].plot(t, source_ls, ''''''''''''''''g-'''''''''''''''', alpha=0.7, linewidth=0.5)
axes[1].set_title(''''''''''''''''Source Lung Sound'''''''''''''''')
axes[1].set_ylabel(''''''''''''''''Amplitude'''''''''''''''')
axes[2].plot(t, mix_audio, ''''''''''''''''r-'''''''''''''''', alpha=0.7, linewidth=0.5)
axes[2].set_title(''''''''''''''''Mixed Sound'''''''''''''''')
axes[2].set_ylabel(''''''''''''''''Amplitude'''''''''''''''')
axes[2].set_xlabel(''''''''''''''''Time (s)'''''''''''''''')
plt.tight_layout()
plt.savefig(''''''''''''''''hls_cmds_waveform.png'''''''''''''''', dpi=150)
plt.show()

§6.2 数据获取

平台 链接 大小 说明
Mendeley Data https://data.mendeley.com/datasets/8972jxbpmp ~38 MB 官方主站,v3 最新版
UCI ML Repository https://archive.ics.uci.edu/dataset/1202 ~36 MB 支持 ucimlrepo 一行加载
Zenodo https://zenodo.org/records/15376628 ~38 MB Zenodo 镜像
IEEE Dataport https://ieee-dataport.org/ (DOI: 10.21227/fe0m-k110) ~38 MB IEEE 平台
GitHub https://github.com/Torabiy/HLS-CMDS 代码库(可视化脚本 + Notebook)
Kaggle https://www.kaggle.com/datasets/yasamantorabi/heart-and-lung-sounds-dataset-hls-cmds ~64 MB Kaggle 镜像

推荐:Mendeley Data 为官方主站,数据最完整。UCI ML Repository 适合快速实验(支持 pip install ucimlrepo 一行加载元数据)。

§6.3 预处理 Pipeline

# ========================================
# HLS-CMDS 预处理 Pipeline
# 功能:WAV → 归一化 → 去噪 → Log-Mel Spectrogram
# ========================================

import librosa
import numpy as np
from scipy import signal

def preprocess_hls_cmds(wav_path, sr=22050, n_mels=128, n_fft=1024, hop_length=256):
    """HLS-CMDS 音频预处理:WAV → 归一化 → 带通滤波 → Log-Mel Spectrogram"""

    # 1. 加载音频
    audio, _ = librosa.load(wav_path, sr=sr)

    # 2. 幅度归一化(每条录音独立归一化)
    audio = audio / (np.max(np.abs(audio)) + 1e-8)

    # 3. 带通滤波(心音 20-200Hz, 肺音 100-500Hz, 混合 20-500Hz)
    #    根据子集类型选择截止频率
    sos = signal.butter(4, [20, 500], ''''''''''''''''bandpass'''''''''''''''', fs=sr, output=''''''''''''''''sos'''''''''''''''')
    audio_filtered = signal.sosfiltfilt(sos, audio)

    # 4. 去除静音段(基于能量阈值)
    frame_length = 2048
    hop = 512
    rms = librosa.feature.rms(y=audio_filtered, frame_length=frame_length, hop_length=hop)[0]
    threshold = 0.01 * np.max(rms)
    nonevent-blocked= rms > threshold
    if np.any(non_silent):
        start = np.argmax(non_silent) * hop
        end = (len(non_silent) - np.argmax(non_silent[::-1])) * hop
        audio_filtered = audio_filtered[start:end]

    # 5. 重新分帧为固定长度(如 5 秒 = 110250 samples)
    target_len = 5 * sr
    if len(audio_filtered) > target_len:
        # 滑窗切割
        segments = []
        for i in range(0, len(audio_filtered) - target_len + 1, target_len):
            segments.append(audio_filtered[i:i + target_len])
        audio_segments = np.array(segments)
    else:
        # 零填充
        audio_segments = np.pad(audio_filtered, (0, target_len - len(audio_filtered)))

    # 6. Log-Mel Spectrogram
    mel_specs = []
    for seg in audio_segments:
        mel = librosa.feature.melspectrogram(
            y=seg, sr=sr, n_mels=n_mels, n_fft=n_fft, hop_length=hop_length
        )
        mel_db = librosa.power_to_db(mel, ref=np.max)
        mel_specs.append(mel_db)

    return np.array(mel_specs), audio_segments


def prepare_separation_triplet(mix_path, source_hs_path, source_ls_path, sr=22050):
    """准备分离任务的三元组数据"""

    mix, _ = librosa.load(mix_path, sr=sr)
    hs, _ = librosa.load(source_hs_path, sr=sr)
    ls, _ = librosa.load(source_ls_path, sr=sr)

    # 确保长度一致
    min_len = min(len(mix), len(hs), len(ls))
    mix, hs, ls = mix[:min_len], hs[:min_len], ls[:min_len]

    # 归一化
    mix = mix / (np.max(np.abs(mix)) + 1e-8)
    hs = hs / (np.max(np.abs(hs)) + 1e-8)
    ls = ls / (np.max(np.abs(ls)) + 1e-8)

    # STFT
    n_fft = 1024
    hop = 256

    mix_stft = librosa.stft(mix, n_fft=n_fft, hop_length=hop)
    hs_stft = librosa.stft(hs, n_fft=n_fft, hop_length=hop)
    ls_stft = librosa.stft(ls, n_fft=n_fft, hop_length=hop)

    # 幅度谱和相位
    mix_mag = np.abs(mix_stft)
    mix_phase = np.angle(mix_stft)
    hs_mag = np.abs(hs_stft)
    ls_mag = np.abs(ls_stft)

    return {
        ''''''''''''''''mix_mag'''''''''''''''': mix_mag,       # 混合音幅度谱
        ''''''''''''''''mix_phase'''''''''''''''': mix_phase,   # 混合音相位
        ''''''''''''''''hs_mag'''''''''''''''': hs_mag,         # 源心音幅度谱(目标 1)
        ''''''''''''''''ls_mag'''''''''''''''': ls_mag,         # 源肺音幅度谱(目标 2)
        ''''''''''''''''mix_audio'''''''''''''''': mix,
        ''''''''''''''''hs_audio'''''''''''''''': hs,
        ''''''''''''''''ls_audio'''''''''''''''': ls
    }


# 批量预处理
import os
from tqdm import tqdm

def batch_preprocess(data_root=''''''''''''''''./data'''''''''''''''', output_dir=''''''''''''''''./processed''''''''''''''''):
    """批量预处理所有录音"""
    os.makedirs(output_dir, exist_ok=True)

    # 处理 Mix 三元组(分离任务核心)
    mix_csv = pd.read_csv(os.path.join(data_root, ''''''''''''''''Mix.csv''''''''''''''''))
    triplets = []

    for _, row in tqdm(mix_csv.iterrows(), total=len(mix_csv), desc="Processing triplets"):
        mix_path = os.path.join(data_root, ''''''''''''''''Mix'''''''''''''''', f"{row[''''''''''''''''Mixed Sound ID'''''''''''''''']}.wav")
        hs_path = os.path.join(data_root, ''''''''''''''''Mix'''''''''''''''', ''''''''''''''''Source_HS'''''''''''''''', f"{row[''''''''''''''''Mixed Sound ID'''''''''''''''']}.wav")
        ls_path = os.path.join(data_root, ''''''''''''''''Mix'''''''''''''''', ''''''''''''''''Source_LS'''''''''''''''', f"{row[''''''''''''''''Mixed Sound ID'''''''''''''''']}.wav")

        if all(os.path.exists(p) for p in [mix_path, hs_path, ls_path]):
            triplet = prepare_separation_triplet(mix_path, hs_path, ls_path)
            triplets.append({
                ''''''''''''''''mix_id'''''''''''''''': row[''''''''''''''''Mixed Sound ID''''''''''''''''],
                ''''''''''''''''hs_type'''''''''''''''': row[''''''''''''''''Heart Sound Type''''''''''''''''],
                ''''''''''''''''ls_type'''''''''''''''': row[''''''''''''''''Lung Sound Type''''''''''''''''],
                ''''''''''''''''data'''''''''''''''': triplet
            })

    print(f"处理完成: {len(triplets)} 组三元组")
    np.save(os.path.join(output_dir, ''''''''''''''''triplets.npy''''''''''''''''), triplets)
    return triplets

§6.4 框架 DataLoader

<details>
<summary>PyTorch DataLoader(分离任务 + 分类任务)</summary>

import torch
from torch.utils.data import Dataset, DataLoader
import librosa
import numpy as np
import pandas as pd
import os

class HLSCMDSSeparationDataset(Dataset):
    """HLS-CMDS 心肺音分离任务 Dataset"""

    def __init__(self, data_root, mix_csv_path, segment_length=22050*5,
                 n_fft=1024, hop_length=256, transform=None):
        self.data_root = data_root
        self.segment_length = segment_length
        self.n_fft = n_fft
        self.hop_length = hop_length
        self.transform = transform

        self.meta = pd.read_csv(mix_csv_path)
        self.triplet_ids = self.meta[''''''''''''''''Mixed Sound ID''''''''''''''''].tolist()

    def __len__(self):
        return len(self.triplet_ids)

    def __getitem__(self, idx):
        mix_id = self.triplet_ids[idx]

        # 加载三元组
        mix, sr = librosa.load(
            os.path.join(self.data_root, ''''''''''''''''Mix'''''''''''''''', f''''''''''''''''{mix_id}.wav''''''''''''''''), sr=22050)
        hs, _ = librosa.load(
            os.path.join(self.data_root, ''''''''''''''''Mix'''''''''''''''', ''''''''''''''''Source_HS'''''''''''''''', f''''''''''''''''{mix_id}.wav''''''''''''''''), sr=22050)
        ls, _ = librosa.load(
            os.path.join(self.data_root, ''''''''''''''''Mix'''''''''''''''', ''''''''''''''''Source_LS'''''''''''''''', f''''''''''''''''{mix_id}.wav''''''''''''''''), sr=22050)

        # 对齐长度
        min_len = min(len(mix), len(hs), len(ls))
        mix, hs, ls = mix[:min_len], hs[:min_len], ls[:min_len]

        # 随机截取固定长度片段
        if min_len > self.segment_length:
            start = np.random.randint(0, min_len - self.segment_length)
            mix = mix[start:start + self.segment_length]
            hs = hs[start:start + self.segment_length]
            ls = ls[start:start + self.segment_length]
        else:
            pad = self.segment_length - min_len
            mix = np.pad(mix, (0, pad))
            hs = np.pad(hs, (0, pad))
            ls = np.pad(ls, (0, pad))

        # 归一化
        mix = mix / (np.max(np.abs(mix)) + 1e-8)
        hs = hs / (np.max(np.abs(hs)) + 1e-8)
        ls = ls / (np.max(np.abs(ls)) + 1e-8)

        if self.transform:
            mix, hs, ls = self.transform(mix, hs, ls)

        return {
            ''''''''''''''''mix'''''''''''''''': torch.FloatTensor(mix).unsqueeze(0),  # [1, T]
            ''''''''''''''''hs'''''''''''''''': torch.FloatTensor(hs).unsqueeze(0),    # [1, T] — 分离目标 1
            ''''''''''''''''ls'''''''''''''''': torch.FloatTensor(ls).unsqueeze(0),    # [1, T] — 分离目标 2
            ''''''''''''''''mix_id'''''''''''''''': mix_id
        }


class HLSCMDSClassificationDataset(Dataset):
    """HLS-CMDS 心音/肺音分类任务 Dataset"""

    HEART_TYPES = [''''''''''''''''NH'''''''''''''''', ''''''''''''''''LDM'''''''''''''''', ''''''''''''''''MSM'''''''''''''''', ''''''''''''''''LSM'''''''''''''''', ''''''''''''''''AF'''''''''''''''', ''''''''''''''''S4'''''''''''''''', ''''''''''''''''ESM'''''''''''''''', ''''''''''''''''S3'''''''''''''''', ''''''''''''''''T'''''''''''''''', ''''''''''''''''AVB'''''''''''''''']
    LUNG_TYPES = [''''''''''''''''NL'''''''''''''''', ''''''''''''''''W'''''''''''''''', ''''''''''''''''FC'''''''''''''''', ''''''''''''''''R'''''''''''''''', ''''''''''''''''PR'''''''''''''''', ''''''''''''''''CC'''''''''''''''']

    def __init__(self, data_root, csv_path, subset=''''''''''''''''HS'''''''''''''''', task=''''''''''''''''heart'''''''''''''''',
                 segment_length=22050*5, n_mels=128, transform=None):
        self.data_root = data_root
        self.subset = subset  # ''''''''''''''''HS'''''''''''''''', ''''''''''''''''LS'''''''''''''''', or ''''''''''''''''Mix''''''''''''''''
        self.task = task      # ''''''''''''''''heart'''''''''''''''', ''''''''''''''''lung'''''''''''''''', or ''''''''''''''''both''''''''''''''''
        self.segment_length = segment_length
        self.n_mels = n_mels
        self.transform = transform

        self.meta = pd.read_csv(csv_path)

        if task == ''''''''''''''''heart'''''''''''''''':
            self.label_map = {t: i for i, t in enumerate(self.HEART_TYPES)}
            self.label_col = ''''''''''''''''Heart Sound Type''''''''''''''''
        elif task == ''''''''''''''''lung'''''''''''''''':
            self.label_map = {t: i for i, t in enumerate(self.LUNG_TYPES)}
            self.label_col = ''''''''''''''''Lung Sound Type''''''''''''''''

    def __len__(self):
        return len(self.meta)

    def __getitem__(self, idx):
        row = self.meta.iloc[idx]

        if self.subset == ''''''''''''''''HS'''''''''''''''':
            audio, sr = librosa.load(
                os.path.join(self.data_root, ''''''''''''''''HS'''''''''''''''', f"{row[''''''''''''''''Sound ID'''''''''''''''']}.wav"), sr=22050)
        elif self.subset == ''''''''''''''''LS'''''''''''''''':
            audio, sr = librosa.load(
                os.path.join(self.data_root, ''''''''''''''''LS'''''''''''''''', f"{row[''''''''''''''''Sound ID'''''''''''''''']}.wav"), sr=22050)
        elif self.subset == ''''''''''''''''Mix'''''''''''''''':
            audio, sr = librosa.load(
                os.path.join(self.data_root, ''''''''''''''''Mix'''''''''''''''', f"{row[''''''''''''''''Mixed Sound ID'''''''''''''''']}.wav"), sr=22050)

        # 随机截取
        if len(audio) > self.segment_length:
            start = np.random.randint(0, len(audio) - self.segment_length)
            audio = audio[start:start + self.segment_length]
        else:
            audio = np.pad(audio, (0, self.segment_length - len(audio)))

        # 归一化
        audio = audio / (np.max(np.abs(audio)) + 1e-8)

        # Log-Mel Spectrogram
        mel = librosa.feature.melspectrogram(
            y=audio, sr=22050, n_mels=self.n_mels, n_fft=1024, hop_length=256)
        mel_db = librosa.power_to_db(mel, ref=np.max)

        label = self.label_map[row[self.label_col]]

        if self.transform:
            mel_db = self.transform(mel_db)

        return {
            ''''''''''''''''mel'''''''''''''''': torch.FloatTensor(mel_db).unsqueeze(0),  # [1, n_mels, T_frames]
            ''''''''''''''''label'''''''''''''''': torch.LongTensor([label])[0],
            ''''''''''''''''sound_id'''''''''''''''': row.get(''''''''''''''''Sound ID'''''''''''''''', row.get(''''''''''''''''Mixed Sound ID'''''''''''''''', ''''''''''''''''''''''''''''''''))
        }


#  使用示例 
# 分离任务
sep_dataset = HLSCMDSSeparationDataset(
    data_root=''''''''''''''''./data'''''''''''''''',
    mix_csv_path=''''''''''''''''./data/Mix.csv'''''''''''''''',
    segment_length=22050*5
)
sep_loader = DataLoader(sep_dataset, batch_size=8, shuffle=True, num_workers=4)

# 分类任务(心音)
cls_dataset = HLSCMDSClassificationDataset(
    data_root=''''''''''''''''./data'''''''''''''''',
    csv_path=''''''''''''''''./data/HS.csv'''''''''''''''',
    subset=''''''''''''''''HS'''''''''''''''',
    task=''''''''''''''''heart''''''''''''''''
)
cls_loader = DataLoader(cls_dataset, batch_size=16, shuffle=True, num_workers=4)

# 测试
for batch in sep_loader:
    print(f"分离任务 batch: mix={batch[''''''''''''''''mix''''''''''''''''].shape}, hs={batch[''''''''''''''''hs''''''''''''''''].shape}, ls={batch[''''''''''''''''ls''''''''''''''''].shape}")
    break

for batch in cls_loader:
    print(f"分类任务 batch: mel={batch[''''''''''''''''mel''''''''''''''''].shape}, label={batch[''''''''''''''''label''''''''''''''''].shape}")
    break

</details>

<details>
<summary>TensorFlow / Keras DataLoader</summary>

import tensorflow as tf
import librosa
import numpy as np
import pandas as pd
import os

def create_tf_dataset(data_root, csv_path, subset=''''''''''''''''Mix'''''''''''''''', batch_size=8,
                      segment_length=22050*5, n_mels=128, task=''''''''''''''''separation''''''''''''''''):
    """创建 TF Dataset for HLS-CMDS"""

    meta = pd.read_csv(csv_path)

    def gen():
        for _, row in meta.iterrows():
            if task == ''''''''''''''''separation'''''''''''''''' and subset == ''''''''''''''''Mix'''''''''''''''':
                mix_id = row[''''''''''''''''Mixed Sound ID'''''''''''''''']
                mix, _ = librosa.load(os.path.join(data_root, ''''''''''''''''Mix'''''''''''''''', f''''''''''''''''{mix_id}.wav''''''''''''''''), sr=22050)
                hs, _ = librosa.load(os.path.join(data_root, ''''''''''''''''Mix'''''''''''''''', ''''''''''''''''Source_HS'''''''''''''''', f''''''''''''''''{mix_id}.wav''''''''''''''''), sr=22050)
                ls, _ = librosa.load(os.path.join(data_root, ''''''''''''''''Mix'''''''''''''''', ''''''''''''''''Source_LS'''''''''''''''', f''''''''''''''''{mix_id}.wav''''''''''''''''), sr=22050)

                min_len = min(len(mix), len(hs), len(ls))
                mix, hs, ls = mix[:min_len], hs[:min_len], ls[:min_len]

                if min_len > segment_length:
                    for i in range(0, min_len - segment_length + 1, segment_length):
                        yield (
                            mix[i:i+segment_length].astype(np.float32),
                            np.stack([hs[i:i+segment_length], ls[i:i+segment_length]], axis=0).astype(np.float32)
                        )

    if task == ''''''''''''''''separation'''''''''''''''':
        output_signature = (
            tf.TensorSpec(shape=(segment_length,), dtype=tf.float32),
            tf.TensorSpec(shape=(2, segment_length), dtype=tf.float32)
        )
    else:
        output_signature = (
            tf.TensorSpec(shape=(n_mels, None), dtype=tf.float32),
            tf.TensorSpec(shape=(), dtype=tf.int32)
        )

    dataset = tf.data.Dataset.from_generator(gen, output_signature=output_signature)
    dataset = dataset.batch(batch_size).prefetch(tf.data.AUTOTUNE)

    return dataset

# 使用
sep_ds = create_tf_dataset(''''''''''''''''./data'''''''''''''''', ''''''''''''''''./data/Mix.csv'''''''''''''''', task=''''''''''''''''separation'''''''''''''''', batch_size=8)
for mix_batch, target_batch in sep_ds.take(1):
    print(f"TF 分离 batch: mix={mix_batch.shape}, target={target_batch.shape}")

</details>

§6.5 常见坑点

⚠️ 坑点 1:分离任务数据泄漏——三元组未分组划分(分类:数据泄漏)

问题:在心肺音分离任务中,如果数据划分没有在三元组级别(Mix + Source HS + Source LS)进行分组,同一三元组的组件可能同时出现在训练集和测试集中。

症状:分离性能异常高(SDR > 15 dB),远超文献报告水平。模型实际上在"记忆"源信号模式而非学习分离。

解决:使用 GroupKFoldGroupShuffleSplit,以三元组 ID 为 group key:

from sklearn.model_selection import GroupKFold
groups = mix_meta[''''''''''''''''Mixed Sound ID''''''''''''''''].values  # 三元组 ID
gkf = GroupKFold(n_splits=5)
for train_idx, test_idx in gkf.split(X, y, groups):
    # 确保 train 和 test 中无相同的三元组 ID

参考:Cai (2026), PLoS One. “Comparative modeling of mixed cardiopulmonary sounds in a low-resource paired dataset.”

⚠️ 坑点 2:Mix 子集严重类别不平衡(分类:偏倚陷阱)

问题:Mix 子集中 91% 心音异常、80.7% 肺音异常。直接训练会导致模型偏向"异常"类别,在排序指标(AUROC)上看似良好但实际操作行为差。

症状:AUROC > 0.90 但 Balanced Accuracy < 0.60。模型将几乎所有样本预测为"异常"。

解决

  1. 使用 Balanced Accuracy 或 Macro F1 而非 Accuracy
  2. 温度缩放(Temperature Scaling)校准概率输出
  3. 在内验证集上选择任务特定阈值(最大化 Balanced Accuracy)
  4. 使用 Focal Loss 或类别加权 Cross-Entropy

参考:Cai (2026), PLoS One — 该论文专门研究了此问题,发现温度缩放 + 阈值选择可将 Balanced Accuracy 从 ~0.55 提升至 0.6894。

⚠️ 坑点 3:模拟人声音与真实患者听诊音的域差距(分类:偏倚陷阱)

问题:HLS-CMDS 的录音来自临床模拟人而非真实患者。模拟人的声音是理想化的病种模板,缺乏自然病理的细微变化、个体差异和临床环境噪声。

症状:在 HLS-CMDS 上训练的模型迁移到真实患者数据(如 PhysioNet 2016 或 ICBHI 2017)时性能大幅下降。Yaqub et al. (2025) 发现从分离混合音中提取的心音分类准确率从 89% 暴跌至 41%。

解决

  1. 始终在真实患者数据集上进行外部验证
  2. 使用域适应(Domain Adaptation)技术缩小模拟→真实的域差距
  3. 混合训练:将 HLS-CMDS 与 PhysioNet 2016 / ICBHI 2017 混合使用
  4. 对模拟人数据施加数据增强(加噪、混响、频带扰动)模拟真实环境

参考:Yaqub et al. (2025), CMES. “Spectrotemporal Deep Learning for Heart Sound Classification under Clinical Noise Conditions.”

⚠️ 坑点 4:三种滤波模式导致频域不一致(分类:预处理陷阱)

问题:心音用 Bell 模式采集(低频增强),肺音用 Diaphragm 模式(高频增强),混合音用 Midrange 模式(全频带)。三种模式下的频率响应不同,直接混合训练会导致频域特征不一致。

症状:模型在 HS 子集上训练后直接应用于 Mix 子集时性能下降。分离模型的源信号估计与真实源信号频谱形状不匹配。

解决

  1. 对所有录音施加统一的带通滤波(如 20–500 Hz)消除滤波模式差异
  2. 在频谱图级别做归一化(per-bin mean/std normalization)
  3. 使用数据增强(随机 EQ)增强滤波模式鲁棒性

参考:Torabi et al. (2024), arXiv:2410.03280.

⚠️ 坑点 5:Mix.zip 大文件拆分(分类:工程陷阱)

问题:GitHub 仓库中的 Mix.zip 因 GitHub 文件大小限制被拆分为 Mix1.zip、Mix2.zip、Mix3.zip,需手动解压合并。Mendeley/UCI/Zenodo 版本无此问题。

症状:从 GitHub 下载后找不到 Mix.zip,只有 Mix1/2/3.zip。直接加载报 FileNotFoundError。

解决:从 Mendeley Data 或 UCI ML Repository 下载完整版,或从 GitHub 下载后手动合并:

# 解压并合并
unzip Mix1.zip -d Mix/
unzip Mix2.zip -d Mix/
unzip Mix3.zip -d Mix/

⚠️ 坑点 6:小样本过拟合——535 条录音的训练困境(分类:评估误用)

问题:HLS-CMDS 仅 535 条 15 秒录音,其中 Mix 三元组仅 145 组。对于深度学习模型,这远远不够。直接训练大型网络(如 ResNet-50、Transformer)会严重过拟合。

症状:训练集 AUROC > 0.99 但验证集 < 0.70。Fold-to-fold 方差极大(±0.16 AUROC)。

解决

  1. 使用轻量模型(< 1M 参数):ResNet-18、1D-CNN、CRNN
  2. 重度数据增强(SpecAugment、时间拉伸、混响)
  3. 迁移学习:在 PhysioNet 2016 / ICBHI 2017 / AudioSet 上预训练
  4. 嵌套交叉验证(Nested CV):外层评估、内层调参
  5. 报告 fold-wise 均值 ± 标准差,不报告单次最佳

参考:Cai (2026), PLoS One — 使用嵌套分组五折评估,报告 fold-wise 方差。

§6.6 数据增强策略

方法 安全性 适用任务 说明
时间拉伸(Time Stretching, ±10%) 分类/分离 改变速度不改变音高
音高平移(Pitch Shifting, ±2 semitones) 分类 改变音高不改变速度
SpecAugment(时间/频率掩码) 分类/分离 在 Mel 频谱图上掩码
加性高斯白噪声(SNR 20-40 dB) 分类/分离 模拟环境噪声
混响(RIR Convolution) ⚠️ 分类 可能改变病理特征,需谨慎
Mixup(同类混合) 分类 同类音频混合增强
随机增益(±6 dB) 分类/分离 幅度变化
频带扰动(Bandwidth Perturbation) ⚠️ 分类 可能移除诊断频带
时间移位(Circular Shift) 分类/分离 循环移位
通道翻转(信号取反) 分类/分离 相位翻转不影响特征

§6.7 模型推荐配置

模型 任务 参数量 预训练 预期性能 说明
1D-CNN (5 层) 分类 ~0.5M ImageNet 不适用 HS Acc 85-89% 轻量基线,适合小样本
ResNet-18 (Mel 输入) 分类 ~11M ImageNet 预训练 HS Acc 86-89% 2D Mel 当图像输入
CRNN (CNN+GRU) 分类 ~2M 从头训练 HS F1 0.80-0.85 兼顾频域和时序特征
U-Net (1D) 分离 ~8M 从头训练 SDR-Heart 5-7 dB 波形域分离
Demucs / Conv-TasNet 分离 ~3-8M 从头训练 SDR-Heart 6-10 dB 通用声源分离架构
Shared-Backbone Multi-Task CNN 联合分类 ~5M Teacher 预训练 AUROC 0.65-0.71 心音+肺音双头输出

§6.8 硬件配置

配置 CPU GPU 内存 磁盘 训练时间
最低 4-core 无(CPU 推理) 8 GB 1 GB ~30 分钟/fold
推荐 8-core RTX 3060 (12 GB) 16 GB 2 GB ~5 分钟/fold
高性能 16-core RTX 4090 (24 GB) 32 GB 5 GB ~1 分钟/fold
Colab 免费 T4 (16 GB) 12 GB ~10 分钟/fold

说明:HLS-CMDS 数据量极小(~38 MB),训练瓶颈在数据加载和增强而非 GPU 计算。CPU 也可完成全流程。

§6.9 评估指标

# ========================================
# HLS-CMDS 评估指标
# 分离任务:SDR / SI-SDR / SIR / SAR
# 分类任务:AUROC / AUPRC / Balanced Accuracy / Macro F1
# ========================================

import numpy as np
from sklearn.metrics import (roc_auc_score, average_precision_score,
                             balanced_accuracy_score, f1_score)

#  分离任务指标 
def sdr(estimated, target):
    """Signal-to-Distortion Ratio"""
    estimated = estimated.flatten()
    target = target.flatten()
    alpha = np.dot(target, estimated) / (np.dot(target, target) + 1e-8)
    noise = estimated - alpha * target
    return 10 * np.log10(np.dot(target, target) / (np.dot(noise, noise) + 1e-8) + 1e-8)

def si_sdr(estimated, target):
    """Scale-Invariant SDR"""
    estimated = estimated - np.mean(estimated)
    target = target - np.mean(target)
    alpha = np.dot(target, estimated) / (np.dot(target, target) + 1e-8)
    projection = alpha * target
    noise = estimated - projection
    return 10 * np.log10(np.dot(projection, projection) / (np.dot(noise, noise) + 1e-8) + 1e-8)

def evaluate_separation(estimated_hs, estimated_ls, true_hs, true_ls):
    """评估心肺音分离性能"""
    return {
        ''''''''''''''''SDR_Heart'''''''''''''''': sdr(estimated_hs, true_hs),
        ''''''''''''''''SDR_Lung'''''''''''''''': sdr(estimated_ls, true_ls),
        ''''''''''''''''SI-SDR_Heart'''''''''''''''': si_sdr(estimated_hs, true_hs),
        ''''''''''''''''SI-SDR_Lung'''''''''''''''': si_sdr(estimated_ls, true_ls),
    }

#  分类任务指标 
def evaluate_classification(y_true, y_pred, y_prob, task_name=''''''''''''''''heart''''''''''''''''):
    """评估心音/肺音分类性能"""
    n_classes = len(np.unique(y_true))

    metrics = {
        ''''''''''''''''Accuracy'''''''''''''''': np.mean(y_true == y_pred),
        ''''''''''''''''Balanced_Accuracy'''''''''''''''': balanced_accuracy_score(y_true, y_pred),
        ''''''''''''''''Macro_F1'''''''''''''''': f1_score(y_true, y_pred, average=''''''''''''''''macro''''''''''''''''),
    }

    if n_classes > 2:
        metrics[''''''''''''''''Macro_AUROC''''''''''''''''] = roc_auc_score(y_true, y_prob, multi_class=''''''''''''''''ovr'''''''''''''''', average=''''''''''''''''macro'''''''''''''''')
        metrics[''''''''''''''''Macro_AUPRC''''''''''''''''] = average_precision_score(
            np.eye(n_classes)[y_true], y_prob, average=''''''''''''''''macro'''''''''''''''')
    else:
        metrics[''''''''''''''''AUROC''''''''''''''''] = roc_auc_score(y_true, y_prob[:, 1])
        metrics[''''''''''''''''AUPRC''''''''''''''''] = average_precision_score(y_true, y_prob[:, 1])

    print(f"\n=== {task_name} 分类评估 ===")
    for k, v in metrics.items():
        print(f"  {k}: {v:.4f}")

    return metrics

#  嵌套交叉验证报告 
def report_nested_cv_results(fold_metrics):
    """报告嵌套 CV 结果(均值 ± 标准差)"""
    print("\n=== 嵌套 5-Fold CV 结果 ===")
    for metric_name in fold_metrics[0].keys():
        values = [fm[metric_name] for fm in fold_metrics]
        mean = np.mean(values)
        std = np.std(values)
        print(f"  {metric_name}: {mean:.4f} ± {std:.4f}")
    print("\n注意: fold-to-fold 方差可能较大(小样本数据集),")
    print("请参考 Cai (2026) 的讨论——将结果视为描述性比较证据而非统计推断。")

§6.10 MLOps 笔记

  • 数据版本管理:推荐使用 Mendeley Data v3 或 Zenodo 固定版本作为引用基准。GitHub 仓库可追踪代码变更。

  • 可复现性:固定随机种子(torch.manual_seed, np.random.seed),报告 fold-wise 结果而非单次最佳。

  • 模型部署:HLS-CMDS 训练的模型不可直接用于临床诊断。必须在真实患者数据(如 PhysioNet 2016、ICBHI 2017)上完成外部验证后方可考虑部署。

  • 数据增强流水线:由于样本量极小(535 条),建议将数据增强嵌入 DataLoader 中实时执行,每个 epoch 看到不同的增强样本。

§7 质量评估与局限性

§7.1 已知偏倚

偏倚类型 描述 严重程度 缓解措施
模拟人偏倚 声音为理想化病种模板,缺乏自然病理细微变化 在真实患者数据上做外部验证;域适应
环境偏倚 录音在无噪声实验室采集,缺乏真实临床环境噪声 数据增强:加噪、混响、随机 SNR
类别不平衡 Mix 子集 91% 心音异常、80.7% 肺音异常 使用 Balanced Accuracy / Focal Loss / 阈值校准
单一机构 仅 McMaster University 一地采集 跨数据集验证(PhysioNet / ICBHI)
小样本 仅 535 条录音,10 类心音每类仅 ~19 样本 重度数据增强 + 迁移学习 + 轻量模型
无人口统计多样性 模拟人无真实年龄/种族/体型差异 不适用(模拟人固有局限)

§7.2 标注质量评估

标注方式 准确率 一致性 局限性
模拟人程序化输出 100%(定义性准确) 完全一致 标签虽无噪声,但声音本身是模拟而非自然病理

§7.3 泛化性讨论

场景 失效风险 证据
真实患者心音听诊 Yaqub et al. (2025): 分离混合音后心音分类从 89% 降至 41%
真实患者肺音听诊 无直接证据,但模拟→真实域差距普遍存在
不同听诊器设备 3M Littmann CORE 特有频率响应,迁移到其他品牌需校准
儿科听诊 模拟人为成人设置,儿科心音频率和节律不同
噪声环境 录音在无噪声环境采集,真实病房 SNR 可能 < 0 dB

§7.4 伦理考量

  1. 无真实患者数据:所有录音来自临床模拟人,无患者隐私问题。IRB 审批不适用。
  2. 模拟人性别设置:CSV 中 Gender 字段(F/M)反映模拟人生理参数配置,不代表真实人口统计。
  3. 可及性:CC BY 4.0 开放许可,任何人均可免费下载使用,无申请门槛。
  4. 潜在误用风险:在该数据集上训练的模型如果直接用于临床诊断,可能因模拟→真实的域差距导致误诊。必须在真实数据上验证。

§7.5 公平性评估

不适用——模拟人无真实人口统计属性(年龄、种族、 socioeconomic status)。

§7.6 数据漂移提示

HLS-CMDS 的录音为一次性采集,不存在纵向数据漂移问题。但需注意模拟人固件版本更新可能导致声音输出参数变化——建议在论文中报告模拟人型号和固件版本(当前未公开)。

§7.7 DAIMS 24 项数据就绪度评估

# 检查项 状态 说明
1 数据集版本号 v1 (2024-10), v2 (2025-03), v3 (2025-05)
2 许可证 CC BY 4.0,明确可商用
3 DOI 10.1109/IEEEDATA.2025.3566012 (IEEE) + 10.17632/8972jxbpmp (Mendeley)
4 数据字典 README + CSV 列名清晰
5 标注协议 模拟人程序化输出,步骤明确
6 标注者资质 不适用(模拟人程序化)
7 数据采集协议 设备型号、滤波模式、采样率明确
8 ICD/SNOMED 映射 无标准编码映射(本 Wiki 补充)
9 数据划分 无官方 train/val/test 划分
10 缺失值文档化 无缺失值
11 已知偏倚文档化 ⚠️ 论文未系统讨论偏倚(本 Wiki 补充)
12 数据质量指标 ⚠️ 未提供信噪比、录音质量评分
13 标签分布统计 CSV 可统计(本 Wiki 提供估算)
14 患者去标识化 不适用(模拟人数据)
15 IRB / 伦理审批 不适用(非人类受试者)
16 数据格式标准 WAV + CSV,标准格式
17 API / 加载工具 UCI ucimlrepo + GitHub 代码
18 基准性能 ⚠️ 无官方基准(社区论文有结果)
19 外部验证 无系统外部验证(Yaqub et al. 部分验证)
20 更新计划 ⚠️ GitHub 标注 “Active” 但无明确更新计划
21 FAIR 原则 多平台镜像(Findable)、标准格式(Accessible)、WAV(Interoperable)、CC BY(Reusable)
22 数据使用标签 (DUO) ⚠️ 无正式 DUO 标签(本 Wiki 补充 NRES/PUB)
23 Croissant 元数据 无 Croissant 1.1 元数据(本 Wiki 补充)
24 机器可读引用 BibTeX / DOI 提供

DAIMS 评分:14 / 24
评分解读中等 — 核心数据完整但缺乏标准化基础设施。

对你意味着什么:HLS-CMDS 的数据本身设计精巧(配对 Ground Truth 独一无二),但作为 AI 训练资源存在明显短板:无官方数据划分、无标准编码映射、无系统偏倚文档、无官方基准。建议在训练前执行以下操作:(1) 自行实现三元组分组 K-Fold 划分;(2) 使用本 Wiki 的 ICD-11/SNOMED CT 映射补充编码;(3) 在 PhysioNet 2016 / ICBHI 2017 上进行外部验证;(4) 施加重度数据增强以应对小样本和域差距。

§7.8 外部验证矩阵

外部数据集 来源机构 样本量 评估任务 性能指标 相对内部变化 关键发现
PhysioNet/CinC 2016 PhysioNet (MIT) 3,126 条 心音二分类(正常/异常) Acc 88% ResNet-18 迁移到 HLS-CMDS 后二分类 88%
HLS-CMDS (Mix 分离后) McMaster 145 条 心音四分类 Acc 41% -48% 从混合音分离后心音分类暴跌,信号处理伪影敏感
ICBHI 2017 ICBHI 5,355 条 呼吸音分类 AUROC 0.9855 (teacher) 作为 Lung Teacher 预训练,迁移到 HLS-CMDS 混合音
HLS-CMDS (Mix 直接分类) McMaster 145 条 心肺双二分类 AUROC 0.7107 Source-aware 模型最强,但 fold 方差大 (±0.166)

约束:本矩阵仅记录有同行评审论文支撑的外部评估结果。

§8 基准性能与生态

§8.1 排行榜

排名 模型 任务 性能指标 年份 关键技术 完整引用 代码
1 ResNet-18 (ImageNet 预训练) 心音四分类 Acc 89% 2025 2D Mel 频谱图 + ImageNet 迁移 Yaqub et al., 2025, CMES. DOI: 10.32604/cmes.2025.071571
2 ResNet-18 (PhysioNet 预训练) 心音二分类 Acc 88% 2025 PhysioNet 2016 预训练 → HLS-CMDS 微调 Yaqub et al., 2025, CMES. DOI: 10.32604/cmes.2025.071571
3 Light Source-Aware Model 心肺双二分类 Macro AUROC 0.7107 ± 0.1659 2026 配对源信号轻量正则化 + 嵌套 5-Fold Cai, 2026, PLoS One. DOI: 10.1371/journal.pone.0352180
4 Calibrated Student-Only 心肺双二分类 Macro Balanced Acc 0.6894 ± 0.0548 2026 温度缩放 + 阈值优化 Cai, 2026, PLoS One. DOI: 10.1371/journal.pone.0352180
5 ResNet-18 (PhysioNet 预训练) 心音四分类 Acc 86% 2025 PhysioNet 迁移,四分类(正常/杂音/额外音/节律) Yaqub et al., 2025, CMES. DOI: 10.32604/cmes.2025.071571

注意:不同论文的任务定义、评估协议和划分策略不同,绝对数值不可直接比较。Cai (2026) 使用嵌套分组五折 CV,Yaqub et al. (2025) 使用固定划分。HLS-CMDS 是小样本数据集(145 组三元组),fold-to-fold 方差极大(±0.166 AUROC),结果应视为描述性比较证据而非统计推断。

§8.2 SOTA 总结与选型建议

你的任务 推荐方法 预期性能 关键要点
心音分类(孤立) ResNet-18 + ImageNet + Mel Acc ~89% 从头训练比 PhysioNet 迁移更好(89% vs 86%)
心音分类(混合分离后) 暂无可靠方法 Acc ~41% 信号分离伪影严重降低分类性能,需专门研究
心肺双二分类(混合直接) Light Source-Aware + 校准 AUROC ~0.71 配对源信号做轻量正则化优于教师蒸馏
心肺音分离 暂无系统基准 SDR 5-10 dB (估) 可参考 NMF/Conv-TasNet/U-Net 等通用方法

§8.3 评估协议

HLS-CMDS 无官方评估协议。推荐社区共识方案:

  1. 分离任务

    • 按三元组分组 5-Fold CV
    • 报告 SDR / SI-SDR(Heart 和 Lung 分别报告)
    • 报告 fold-wise 均值 ± 标准差
  2. 分类任务

    • 按声音类型分层 5-Fold CV
    • 报告 Macro AUROC / Balanced Accuracy / Macro F1
    • 对 Mix 子集报告 prevalence-defined no-skill AUPRC 基线
    • 使用温度缩放 + 内验证集阈值选择
  3. 嵌套 CV

    • 外层 5-Fold 评估
    • 内层在训练 fold 中划分验证集用于超参选择和校准

§8.4 相关数据集

数据集 类型 规模 与 HLS-CMDS 关系
PhysioNet/CinC 2016 心音分类 3,126 条 互补:大规模心音基准,可作为 Heart Teacher 预训练
ICBHI 2017 呼吸音分类 5,355 条 互补:大规模呼吸音基准,可作为 Lung Teacher 预训练
PASCAL Heart Sound 心音分类 661 条 互补:早期心音数据集
CirCor DigiScope 心音分类 5,482 条 互补:2022 年发布的大规模心音数据集
NeoSSNet (论文) 新生儿心肺分离 方法参考:深度学习实时分离框架

§8.5 关键论文

  1. Torabi, Y., Shirani, S., & Reilly, J. P. (2025). “Descriptor: Heart and Lung Sounds Dataset Recorded from a Clinical Manikin using Digital Stethoscope (HLS-CMDS).” IEEE Data Descriptions. DOI: 10.1109/IEEEDATA.2025.3566012
    — 数据集发表论文,描述采集方法、数据结构和应用场景。

  2. Cai, R. (2026). “Comparative modeling of mixed cardiopulmonary sounds in a low-resource paired dataset: Discrimination, calibration, and operating-point behavior.” PLoS One, 21(6), e0352180. DOI: 10.1371/journal.pone.0352180
    — 首个系统评估 HLS-CMDS 的论文,比较了 4 种模型族(shared-backbone CNN / student-only / dual-teacher / source-aware),发现轻量 source-aware 模型在排序指标上最强(AUROC 0.7107),校准后 student-only 在阈值指标上最优(Balanced Acc 0.6894)。

  3. Yaqub, A., et al. (2025). “Spectrotemporal Deep Learning for Heart Sound Classification under Clinical Noise Conditions.” Computer Modeling in Engineering & Sciences, 145(2), 2503–2533. DOI: 10.32604/cmes.2025.071571
    — 在 PhysioNet 2016 上预训练 ResNet-18,迁移到 HLS-CMDS 做心音分类(二分类 88%,四分类 89%),并进行了关键的压力测试:从混合音中分离心音后分类准确率暴跌至 41%。

  4. Torabi, Y., Shirani, S., & Reilly, J. P. (2024). “Manikin-Recorded Cardiopulmonary Sounds Dataset Using Digital Stethoscope.” arXiv preprint, arXiv:2410.03280.
    — v1 版本的 arXiv 预印本。

§8.6 社区活跃度

平台 指标 数值(截至 2026-08)
UCI ML Repository 浏览量 11,700+
Mendeley Data 浏览量/下载量 活跃(v1-v3 持续更新)
GitHub Commits 75
Google Scholar 引用次数 4+
IEEE Dataport 浏览量 活跃

§8.7 生态快照

资源 类型 链接 Star/Fork(截至 2026-08) 为什么值得关注
Torabiy/HLS-CMDS 官方代码 GitHub 活跃 官方可视化脚本(波形/频谱图/饼图)+ Jupyter Notebook
UCI ML Repository 数据加载 UCI 支持 ucimlrepo 一行代码加载元数据
Kaggle 镜像 数据下载 Kaggle Kaggle 环境内直接加载
PhysioNet/CinC 2016 互补数据集 PhysioNet 心音分类大规模基准,Heart Teacher 预训练源
ICBHI 2017 互补数据集 Zenodo 呼吸音分类大规模基准,Lung Teacher 预训练源

§9 相关资源与引用

§9.1 引用格式

BibTeX:

@article{torabi2025hls-cmds,
  title={Descriptor: Heart and Lung Sounds Dataset Recorded from a Clinical Manikin using Digital Stethoscope (HLS-CMDS)},
  author={Torabi, Yasaman and Shirani, Shahram and Reilly, James P.},
  journal={IEEE Data Descriptions},
  year={2025},
  doi={10.1109/IEEEDATA.2025.3566012}
}

APA:

Torabi, Y., Shirani, S., &amp; Reilly, J. P. (2025). Descriptor: Heart and Lung Sounds Dataset Recorded from a Clinical Manikin using Digital Stethoscope (HLS-CMDS). IEEE Data Descriptions. https://doi.org/10.1109/IEEEDATA.2025.3566012

IEEE:

Y. Torabi, S. Shirani, and J. P. Reilly, "Descriptor: Heart and Lung Sounds Dataset Recorded from a Clinical Manikin using Digital Stethoscope (HLS-CMDS)," in IEEE Data Descriptions, 2025, doi: 10.1109/IEEEDATA.2025.3566012.

§9.2 多平台 DOI

平台 DOI
IEEE Data Descriptions (期刊) 10.1109/IEEEDATA.2025.3566012
Mendeley Data 10.17632/8972jxbpmp
IEEE Dataport 10.21227/fe0m-k110
arXiv (v1 预印本) 10.48550/arXiv.2410.03280

§9.3 相关千方 Wiki 条目

§9.4 外部资源

  • GitHub 代码库https://github.com/Torabiy/HLS-CMDS — 官方可视化脚本(audio_plotter.py 波形图、audio_spectrogram.py Mel 频谱图、Donut_chart.py 分布饼图)+ HLS_CMDS.ipynb Jupyter Notebook
  • Eko 平台:录音通过 Eko Software 和 Eko Cloud 采集和存储
  • 3M Littmann CORE:数字听诊器产品页面

§9.5 声学听诊解剖位置说明

心音听诊位置(6 个)
缩写 英文 中文 对应瓣膜
A Apex 心尖部 二尖瓣
RUSB Right Upper Sternal Border 胸骨右缘上部 主动脉瓣
LUSB Left Upper Sternal Border 胸骨左缘上部 肺动脉瓣
LLSB Lower Left Sternal Border 胸骨左缘下部 三尖瓣
RC Right Costal Margin 右肋缘 肝区/右心
LC Left Costal Margin 左肋缘 左心/脾区
肺音听诊位置(6 个)
缩写 英文 中文
RUA Right Upper Anterior 右上前胸
RMA Right Mid Anterior 右中前胸
RLA Right Lower Anterior 右下前胸
LUA Left Upper Anterior 左上前胸
LMA Left Mid Anterior 左中前胸
LLA Left Lower Anterior 左下前胸

§9.6 声音类型缩写对照

心音类型(10 种)
缩写 英文 中文 病理特征
NH Normal Heart 正常心音 S1-S2 正常序列
LDM Late Diastolic Murmur 舒张晚期杂音 收缩前杂音,提示二尖瓣狭窄
MSM Mid Systolic Murmur 收缩中期杂音 喷射性杂音,提示主动脉瓣狭窄
LSM Late Systolic Murmur 收缩晚期杂音 提示二尖瓣脱垂
AF Atrial Fibrillation 心房颤动 不规则心律
S4 Fourth Heart Sound 第四心音 舒张晚期奔马律
ESM Early Systolic Murmur 收缩早期杂音 提示室间隔缺损
S3 Third Heart Sound 第三心音 舒张早期奔马律,提示心衰
T Tachycardia 心动过速 心率 > 100 bpm
AVB Atrioventricular Block 房室传导阻滞 PR 间期延长或脱漏
肺音类型(6 种)
缩写 英文 中文 病理特征
NL Normal Lung 正常肺音 正常呼吸音
W Wheezing 喘息 高频哮鸣音,提示哮喘/COPD
FC Fine Crackles 细湿啰音 吸气末爆裂音,提示间质性肺病
R Rhonchi 干啰音 低频鼾音,提示气道分泌物
PR Pleural Rub 胸膜摩擦音 皮革摩擦声,提示胸膜炎
CC Coarse Crackles 粗湿啰音 吸气早期爆裂音,提示肺水肿/肺炎

§10 AI 使用声明卡

§10.1 AI 模型使用

模型 版本 用途
Claude Sonnet 4 条目全文撰写、代码示例生成、研究信息综合

§10.2 AI 参与范围

全文生成 — AI 负责信息搜集、结构设计和全文撰写,人工负责审核和发布。

§10.3 输入来源

  1. Torabi, Y., Shirani, S., & Reilly, J. P. (2025). IEEE Data Descriptions. DOI: 10.1109/IEEEDATA.2025.3566012
  2. Mendeley Data v3: https://data.mendeley.com/datasets/8972jxbpmp
  3. UCI ML Repository: https://archive.ics.uci.edu/dataset/1202
  4. GitHub README: https://github.com/Torabiy/HLS-CMDS
  5. Cai, R. (2026). PLoS One. DOI: 10.1371/journal.pone.0352180
  6. Yaqub, A. et al. (2025). CMES. DOI: 10.32604/cmes.2025.071571
  7. 《Global Medical AI Datasets》(PDF) — 数据集基础介绍

§10.4 人工校验表

内容模块 审核者 审核方式 审核状态
§2 医学背景 千方病案医学编辑部 交叉审核 ✅ 已通过
§3 数据规格 千方病案医学编辑部 与 Mendeley/UCI/GitHub 官方文档交叉比对 ✅ 已验证
§4 数据字典 千方病案医学编辑部 与 CSV 列名和 README 比对 ✅ 已验证
§6 代码示例 千方病案医学编辑部 逻辑审查 ✅ 已通过
§7 偏倚分析 千方病案医学编辑部 交叉审核 ✅ 已通过
§8 排行榜 千方病案医学编辑部 与论文原文比对 ✅ 已验证

§10.5 AI 生成章节

全部章节由 AI 生成,经人工交叉审核后发布。

§10.6 最后人工审核日期

2026-08-04

页面状态:published(全部内容已完成审核并发布)

返回 AI Ready 数据集