Alice-Sabrina-Ivy/kardia-qtc
GitHub: Alice-Sabrina-Ivy/kardia-qtc
这是一个从 KardiaMobile 6L PDF 导出中计算 QTc 的 Python 工具,用于家庭健康监测和量化自我研究。
Stars: 0 | Forks: 0
# KardiaMobile 6L QTc 测量工具
一个 Python 脚本,用于从 [KardiaMobile 6L](https://www.kardia.com/) 导出的 PDF 中测量 QT 间期并计算 QTc。该脚本直接解析 PDF 的内部矢量路径数据,以恢复原始的 300 Hz ECG 采样,然后在所有可用 T 波的导联上测量 QT。
## ⚠️ 免责声明
**这不是一个医疗设备。** 这是一个实验性、未经验证的脚本,仅供个人参考使用。其输出不应在没有临床医生审查的情况下用于做出医疗决策。如果您担心 QTc 延长,请进行临床 12 导联心电图检查。
检测参数和 PDF 布局常数是根据 2026 年中旬 Kardia 软件的记录调优的。对于其他受试者、体型或 PDF 格式,结果可能不同。使用风险自负。
## 功能说明
KardiaMobile 生成带有节律条带的 6 导联 PDF 导出。从该 PDF 获取 QT 通常需要要么在打印输出上进行目视测量,要么使用 AliveCor 的付费临床医生审查服务。此脚本:
1. 打开 PDF 并解压其内容流
2. 直接从 PDF 的矢量路径操作符中提取 ECG 采样 — 恢复原始的 300 Hz 波形,无需任何图像处理或光栅化
3. 按 Y 坐标将采样点划分为全部 6 个导联
4. 在导联 II、III 和 aVF 中检测 R 峰
5. 对于每个心跳,测量 **Q 波起始**、**T 波峰值** 和 **T 波结束**(通过切线法 — 国际临床标准)
6. 过滤掉 T 波检测不可靠的心跳
7. 报告平均 QT、按导联细分以及通过 **Bazett** 和 **Fridericia** 公式计算的 QTc — 附带标准误差估计
8. 保存诊断图,显示所有 4 个节律条带页面以及按导联的 QT 分布,以便您可以目视验证测量结果
## 适用人群
- 拥有 KardiaMobile 6L 且希望无需临床医生审查订阅即可获取编程化 QTc 读数的人
- 正在服用已知有 QT 延长风险药物、希望在就诊期间进行更频繁监测的人 — 常见例子包括某些抗生素(阿奇霉素、左氧氟沙星、莫西沙星)、抗抑郁药(西酞普兰、高剂量艾司西酞普兰)、抗真菌药(氟康唑、伏立康唑)、抗精神病药(氟哌啶醇、齐拉西酮、喹硫平)、止吐药和促动力药(昂丹司琼、多潘立酮、氟哌利多)、抗心律失常药(索他洛尔、多非利特、胺碘酮)和美沙酮
- 已确诊长 QT 综合征、进行补充性家庭追踪的人
- 任何进行量化自我研究、希望获取自身数据的人
- 希望以 Kardia 导出数据作为起点进行 ECG 信号处理的开发者
这是补充数据。它不能替代临床护理,也不适用于任何急性或紧急情况。
## 快速开始
```
# 所有依赖项均可通过 pip 安装——无需系统包
pip install pypdf numpy scipy matplotlib
# 运行
python measure_qtc.py path/to/kardia-export.pdf
```
输出打印到标准输出:心率、平均 QT、按导联细分、QTc Bazett(带标准误差)、QTc Fridericia 以及解释性标志。诊断图保存到 `/tmp/qtc_work/qtc_diagnostic.png`(可通过 `--workdir` 覆盖)。
**务必查看诊断图。** 如果按导联的直方图差异巨大,或者导联 II 条带显示错误的 R 峰检测(红色三角形明显位于错误位置),请不要相信该数值。
## 获取一致读数
对于趋势追踪,一致性比绝对精度更重要:
- **每天同一时间**(通常早晨最干净 — 咖啡因、进餐、活动等混杂因素较少)
- **记录前静坐并保持平静 5 分钟以上**
- **记录前 1 小时内无咖啡因、兴奋剂或剧烈活动**
- **标准 Kardia 6L 手部位置** — 双手拇指放在顶部电极上,第三个电极放在左脚踝或膝盖上
- **30 秒记录**(Kardia 默认)
将每个 PDF 以日期命名保存。对每个 PDF 运行脚本,并保留简单日志:日期、心率、QTc Bazett ± 标准误差。
## 解释输出
| QTc Bazett | 标志 | 一般解释 |
|----------------|----------|------------------------------|
| <450 ms | 正常 | 在正常范围内 |
| 450–460 ms | 高正常 | 临界值;注意趋势 |
| 460–470 ms | 临界 | 与处方医生讨论 |
| >470 ms | 延长 | 需要进行临床评估 |
这些阈值通常适用于成年女性;成年男性的上限通常短约 10 毫秒。您的处方医生可能会根据具体情况(例如,特定药物、先天性长 QT)使用不同的阈值。
**从基线的变化通常比绝对值更重要。** 当开始服用一种 QT 延长药物时常用的标准:如果 QTc 比个人基线增加 >60 毫秒,即使绝对值仍在“正常”范围内,也应进一步调查。
使用矢量方法,单次读数的精度约为 QTc Bazett ±2 毫秒标准误差,这意味着从基线开始约 15–20 毫秒的真实变化是可以检测到的 — 比临床 60 毫秒阈值严格得多。在开始任何新药物之前,进行 3–5 次读数,间隔 1–2 周,以获得可靠的个人基线,然后将未来的读数与该平均值进行比较。
## 为什么选择矢量解析而非图像处理
更显而易见的方法是光栅化 PDF 并从像素中检测 ECG 轨迹。这行得通(此脚本的早期版本就是这样做的),但矢量方法明显更好,因为 Kardia PDF 将 ECG 存储为实际的逐样本矢量路径操作符,而不是渲染的图像。直接解析它们可以恢复原始 ADC 样本。
| 指标 | 光栅方法 | 矢量方法 |
|-------------------|----------------------|----------------------|
| 使用的页数 | 4 页中的 1 页 | 4 页中的 4 页 |
| 使用的导联 | 仅导联 II | II, III, aVF |
| 每次读数的心跳数 | 4–6 | 30–40 |
| QT 精度 | ±10–15 毫秒/心跳 | ±2–5 毫秒/心跳 |
| QTc Bazett 标准误差 | ~±10 毫秒 | ~±2 毫秒 |
| 是否需要平滑 | 是(Savgol) | 否 |
| 网格线噪声 | 后期过滤 | 无(通过颜色区分) |
矢量方法报告的 QTc 系统性地比光栅化低约 10 毫秒,因为基于像素的轨迹检测会因轨迹厚度和网格线边缘效应略微增加 T 结束估计值。
## 工作原理(技术细节)
Kardia PDF 由 Skia 生成,并将 ECG 存储为其内容流中的 PDF 矢量路径操作符,而不是光栅化图像:
```
x y m # moveto - start a path at (x, y)
x y l # lineto - draw line to (x, y)
S # stroke - render the path
```
每个 `l`(直线到)端点是一个 ECG 样本。脚本的流程:
1. **使用 pypdf 打开 PDF。** 对于 4 个节律条带页面(PDF 页面 2–5)中的每一个,解压内容流。
2. **通过描边颜色识别 ECG 路径。** 内容流包含网格线(浅紫色,`0.8196 0.8196 0.9608 RG`)、文本(各种灰色)和 ECG 样本(纯黑色,`0 0 0 RG`)。ECG 颜色在 ECG 路径之前仅设置一次,因此其后的所有内容都是 ECG。
3. **提取采样点。** 每个 `l` 操作符端点是一个 ECG 样本。坐标单位为 PDF 点(1/72 英寸)。每个页面约 14,000 个样本,跨 6 个导联 = 每个导联每页约 2,400 个样本。
4. **通过 Y 坐标按导联分区。** 6 个导联占据条带,Y 中心分别为 172、260、352、441、529、621 PDF 点(从上到下:I, II, III, aVR, aVL, aVF)。每个条带的样本落在其中心 ±40 点范围内,因此分区是明确的。
5. **转换为物理单位。** 在 25 mm/s 走纸速度和 10 mm/mV 振幅下:
- 水平方向 1 PDF 点 = 14.11 毫秒(因此样本间距 0.2362 点 = 3.33 毫秒 = 300 Hz,AliveCor 的原生速率)
- 垂直方向 1 PDF 点 = 0.0353 mV
6. **检测 R 峰** 在导联 II、III、aVF 中使用 `scipy.signal.find_peaks`,最小高度为 0.5 mV(导联 III 为 0.3 mV,其 R 波较小)。
7. **对于每个心跳,测量 Q 波起始、T 波峰值、T 波结束:**
- **Q 波起始:** 从 R 波向后走,直到斜率降至 0.02 mV/样本(6 mV/s)以下 — 快速上升阈值
- **T 波峰值:** R 波后 150–450 毫秒窗口内的最大幅度
- **T 波结束(切线法):** 在 T 波峰值后 0–150 毫秒内找到最陡的下降斜率;将该切线线外推到 T 波后基线;交点即为 T 波结束
8. **过滤受污染的心跳** 使用基于密度的聚类。保留距离最密集聚类中心 ±20 毫秒以内的心跳;丢弃异常值。这对任何单个心跳或导联中的 T 波检测失败具有鲁棒性。
9. **计算 QTc** 使用 Bazett(QT/√RR)和 Fridericia(QT/RR^⅓)公式。RR 根据所有导联 II R 峰间隔计算(不仅仅是过滤后的心跳),因此心率不受哪些心跳可测量 QT 的影响。
## 验证导联识别是否正确(请首先执行此操作!)
如果您是第一次在自己的 Kardia 导出数据上运行此脚本,最重要的健全性检查是运行后**查看诊断图**(默认为 `/tmp/qtc_work/qtc_diagnostic.png`)。顶部的 4 个面板显示了每个节律页面中的导联 II。您应该看到:
- 干净的 P-QRS-T 形态,QRS 尖峰**向上**,小的正向 T 波
- 标记 R 峰的红色向下三角形(▽)— 这些应落在每个 R 峰上,并且仅落在 R 峰上
- 每页条带大约有 8–10 个心跳
如果 R 峰错误、导联看起来有噪声,或者脚本报告错误“未找到 ECG 颜色块”,AliveCor 可能已更改其 PDF 格式,脚本中的常数(导联 Y 中心、颜色正则表达式)将需要调整。
## 注意事项(以及代码为何如此设计)
这些在开发过程中出现;代码已处理它们,但如果您修改代码,请注意:
### 1. 颜色识别至关重要
ECG 是“黑色”(`0 0 0 RG`),但 PDF 流在到达 ECG 之前为文本渲染多次设置描边颜色。诀窍是,在路径批量绘制开始之前设置的最后一个颜色就是 ECG 颜色,并且该颜色块包含数千个 m/l 操作符(而网格线或文本下划线只有少数几个)。如果 AliveCor 为 ECG 使用不同的颜色,正则表达式 `\b0\s+0\s+0\s+RG\b` 将需要更新。
### 2. 第 2 页有校准脉冲
第一个节律页面(PDF 的第 2 页)以一个短暂的 1 mV 方波校准脉冲开始。这会出现在提取的数据中,如果当作一个心跳,会欺骗 R 峰检测。脚本会自动丢弃每页的第一个和最后一个心跳以处理此问题和其他边缘效应。
### 3. Y 中心位置是页面布局特定的
Y 中心(172、260、352、441、529、621)基于截至 2026 年中观察到的 KardiaMobile 6L PDF 布局。如果 AliveCor 更改布局,这些常数将需要更新。
### 4. 导联 III 的 T 波可能非常小
导联 III 的 T 波幅度通常接近 0.05 mV 的检测下限,因此导联 III 中的许多心跳会被跳过(通常每次读数可测量 3 个,而导联 II 约 20 个)。这是正确的行为 — 跳过一个心跳比报告不可靠的测量要好。多导联策略意味着导联 II 和 aVF 承担了大部分测量任务。
### 5. 电压基线是每条带的中位数
每个导联条带的垂直基线(“0 mV”)计算为该导联所有样本 Y 值的中位数。这可行是因为 ECG 上的大部分样本都处于基线(心跳之间);QRS 和 T 波只占总样本的一小部分,不会显著改变中位数。如果记录期间基线漂移,则需要更复杂的方法(滚动中位数)。
### 6. Bazett 标准误差是近似的
`qtc_bazett_se` 值是 `(QT_std / sqrt(N)) / sqrt(RR_s)`,这是在**假设 RR 准确已知**的情况下,QT 均值通过 Bazett 校正传播的标准误差。这略微低估了真实的标准误差(RR 有其自身的不确定性),但在典型心率下,这种低估很小,因为 RR 不确定性的贡献远小于 QT 不确定性。将报告的标准误差视为不确定性的下限。
## 局限性
- **不能替代临床心电图。** 如果报告 QTc 升高,或比基线上升趋势超过 30 毫秒,请在做出药物决定前进行临床 12 导联心电图并由心脏病专家审查。
- **仅限导联 II、III、aVF。** 某些 QT 延长模式(切迹 T 波、显著的 U 波)在胸前导联上更容易识别,而 Kardia 6L 记录不包括这些。
- **切线法系统性低估**相比基于阈值的“基线交叉处的 T 结束”。这是设计如此 — 切线法是国际临床标准。它报告的长度比阈值方法短约 10–20 毫秒,只要一致使用同一种方法,对于趋势追踪来说是可以接受的。
- **仅在一名受试者的记录上进行了验证。** 检测参数是根据经验调整的。其他人的 T 波幅度、QRS 形态或节律不规则可能需要参数调整。请务必检查诊断图。
- **依赖于当前的 Kardia PDF 布局。** 矢量解析方法依赖于稳定的 PDF 结构(颜色代码、导联 Y 中心、内容流组织)。任何 AliveCor 格式更改都可能需要代码更新。
## 文件
- `measure_qtc.py` — 主脚本
- `README.md` — 本文件
## 贡献
欢迎提交 PR,特别是针对:
- 其他 Kardia 型号(单导联 KardiaMobile,未来的 12 导联设备)
- AliveCor PDF 格式更新(不同布局版本、颜色代码)
- 更好的 T 结束检测(替代切线变体、机器学习方法)
- 基于 T 波信噪比的按导联加权平均
- 自动导联位置检测(而非硬编码 Y 中心)
## 许可证
[MIT](LICENSE) — 您可以对此做任何事情,只需保留版权声明。不提供任何明示或暗示的保证。
标签:Bazett公式, ECG信号处理, Fridericia公式, PDF数据提取, QTc计算, 个人健康工具, 切线法检测, 医疗数据解析, 多导联心电图, 家庭健康监测, 心电图分析, 心脏健康跟踪, 逆向工具, 量化自我, 非医疗设备应用