第 4 层 · 伪迹剔除层 · 第 18 步 / 共 25 步

步骤 18:剔心电成分

识别心电相关 ICA 成分

🕐 25 分钟🎯 难度:进阶🔗 核心 API:ica.find_bads_ecg⬅️ 前置:步骤 17

1. 目标

利用 ECG 通道与 ICA 成分的相关性,识别心跳伪迹成分。识别流程与步骤 17 的眼电成分识别完全一致,仅目标通道不同。

2. 何时使用 / 何时跳过

  • 应当使用:研究中存在 ecg 通道且 ECG 伪迹明显
  • 可跳过:ECG 信号本身很干净;研究只关心短时间窗(< 1 秒)

3. 前置条件

  • 已执行步骤 17:眼电成分识别已完成
  • 数据中存在 ecg 类型通道

4. 核心代码

Python
import mne

# ====== 方式 A:自动识别(推荐新手,默认 ctps) ======
# 注意:method 仅接受 'ctps'(默认)/'correlation',
#       'variance' 不是合法值(从未存在过)
ecg_idx, ecg_scores = ica.find_bads_ecg(
    raw,
    ch_name=None,             # None = 自动选 ecg 通道
    method='ctps',            # cross-trial phase statistics(默认)
    threshold='auto',         # 'auto'(默认)或 float
    # 注意:threshold 对两种 method 都生效:
    # - 'ctps': 表示 Kuiper 检验的显著性水平;'auto' 会基于采样频率自动算
    # - 'correlation': 表示 z-score 阈值
    l_freq=8,                 # 真实默认值(注意是 8 不是 8.0,Hz)
    h_freq=16,                # 真实默认值(不是 30)
)

print(f"自动识别的心电成分: {ecg_idx}")
print(f"各成分分数: {ecg_scores}")

# ====== 方式 B:基于简单相关(最快) ======
ecg_idx, ecg_scores = ica.find_bads_ecg(
    raw,
    ch_name='ECG001',         # 显式指定 ECG 通道
    method='correlation',
    threshold=2.0,
    l_freq=8,
    h_freq=16,
)

# ====== 人工核对(必做) ======
ica.plot_scores(ecg_scores, exclude=ecg_idx)
ica.plot_components(picks=ecg_idx, inst=raw)
ica.plot_sources(inst=raw, picks=ecg_idx, start=0, stop=30)
# 期望:成分时间序列呈现明显的 QRS 周期节律

# ====== 合并到 exclude 列表 ======
ica.exclude.extend(ecg_idx)
print(f"当前排除列表(含 EOG + ECG): {ica.exclude}")

5. 参数详解(真实签名)

ica.find_bads_ecg(inst, ch_name=None, threshold='auto', start=None, stop=None, l_freq=8, h_freq=16, method='ctps', reject_by_annotation=True, measure='zscore', verbose=None)

参数 含义 推荐值
ch_name ECG 通道 None(自动选)/ 'ECG001'
method 检测方法 'ctps'(默认)/'correlation'('variance' 从未是合法值)
threshold 阈值 两种 method 都生效:'ctps' 表示 Kuiper 显著性水平('auto' 按 sfreq 推算);'correlation' 表示 z-score。默认 'auto'
l_freq / h_freq 检测 QRS 频段 8 / 16(真实默认,不是 8–30)
measure 相关性度量 'zscore'(默认)
qrs_threshold ⚠️ 不是本方法参数 (属于 compute_proj_ecg)

两种合法方法对比

方法 原理 速度 稳定性
ctps 跨试验相位统计(默认) 慢 高
correlation 简单相关 快 中

⚠️ method='variance' 从未是 find_bads_ecg 的合法值——传入会触发 _check_option('method', ...),抛 ValueError: Invalid value for the 'method' parameter...(不是 TypeError)。本教材不推荐使用任何"variance"方法。

6. 验证方法

Python
# 验证 1:候选成分数量
print(f"自动检出 ECG 成分数: {len(ecg_idx)}")
assert 0 <= len(ecg_idx) <= 3, "ECG 成分数异常"

# 验证 2:topomap 是否合理
# ECG 成分常见模式:单极强(V-lead 类似)或扩散型
for idx in ecg_idx:
    ica.plot_components(picks=[idx], inst=raw)

# 验证 3:时间序列显示 QRS 节律
ica.plot_sources(inst=raw, picks=ecg_idx, start=0, stop=60)
# 期望:清晰可见周期性心跳尖峰

# 验证 4:与 ECG 通道相关性
import numpy as np
ecg_data = raw.get_data(picks='ecg')[0]
ic_data = ica.get_sources(raw).get_data()[ecg_idx[0]]
corr = np.corrcoef(ecg_data, ic_data)[0, 1]
print(f"IC{ecg_idx[0]} vs ECG 相关系数: {corr:.2f}")
# 期望:|r| > 0.2(ECG 信号较弱时)

7. 常见错误

错误 原因 解决方案
ValueError: Invalid value for the 'method' parameter... 用了 'variance' 等非法值(_check_option 抛 ValueError,不是 TypeError) 改用 'ctps'(默认)/'correlation'
RuntimeError: No ECG channels found 步骤 03 未标 ECG 回到步骤 03 修正
find_bads_ecg 检出 0 成分 ECG 通道伪迹本身不明显 接受现状,跳过本步;或用 SSP(步骤 15)替代
method='ctps' 太慢 需要 epochs(计算跨试验相位) 改用 'correlation'
自动检出 vs 人工判断不一致 边界情况 永远要配合可视化人工核对

8. 官方来源

资源类型 链接
find_bads_ecg https://mne.tools/stable/generated/mne.preprocessing.ICA.html#mne.preprocessing.ICA.find_bads_ecg
ICA 教程 https://mne.tools/stable/auto_tutorials/preprocessing/plot_40_artifact_correction_ica.html
compute_proj_ecg(含 qrs_threshold) https://mne.tools/stable/generated/mne.preprocessing.compute_proj_ecg.html

9. 学术引用

Shackman, A. J., et al. (2009). Identifying robust and sensitive measures for EEG cardiac artifact detection. Psychophysiology, 46(3), 593-606.