第 2 层 · 基础配置层 · 第 5 步 / 共 25 步

步骤 05:单位校正

校正通道物理单位(如 V vs μV)

🕐 20 分钟🎯 难度:入门🔗 核心 API:raw.apply_function⬅️ 前置:步骤 4

1. 目标

确保所有通道使用统一的物理单位。MNE-Python 的所有 IO 读取函数在加载时默认把数据换算成 SI 基本单位 V(伏特),EEG 因此以 V 而不是 µV 存储。mne.preprocessing.fix_channel_units 并不存在——本步骤给出真正可行的单位校正做法。

2. 何时使用 / 何时跳过

  • 必须使用:当文件头记录的通道单位与实际不符,且 IO 函数未能正确换算时
  • 可跳过:使用 MNE 内置 IO 函数(read_raw_edf / read_raw_fif / read_raw_brainvision)后单位已正确换算到 V

3. 前置条件

  • 已执行步骤 04:通道列表已确定

4. 核心代码

Python
import mne
import numpy as np

# ====== 1) 查看当前单位(诊断单位异常) ======
# MNE 中所有单位都是 mne.io.constants.FIFF_UNIT_* 之一
from collections import Counter
units = Counter([ch['unit'] for ch in raw.info['chs']])
print(f"通道单位分布: {dict(units)}")
# 期望:{'107': N} (107 即 FIFF_UNIT_V,V 伏特)

for ch in raw.info['chs'][:5]:
    print(ch['ch_name'], ch['unit'], ch['range'], ch['cal'])

# ====== 2) 数据值是 V,但文件头标记为 µV,需要 × 1e6 反向校准 ======
# 这种情况表现为:raw.plot() 看不到任何信号(数据被压扁到几乎 0)
# 诊断:data.max() ~ 1e-5 而不是 1e-11(数量级异常)
data, _ = raw[0, :1000]
amp = data.max() - data.min()
print(f"振幅: {amp:.2e} V")
# 期望:1e-7 ~ 1e-3(EEG 量级)
# 如果是 ~1e-12 ~ 1e-10,说明单位换算时多乘了 1e6

if amp < 1e-8:  # 异常小
    raw.apply_function(lambda x: x * 1e6, picks='eeg')
    print("已施加 × 1e6 校正")

# ====== 3) 反向:数据是 V,但文件头期望 µV,需要 ÷ 1e6 ======
elif amp > 1e-2:  # 异常大
    raw.apply_function(lambda x: x * 1e-6, picks='eeg')
    print("已施加 × 1e-6 校正")

# ====== 4) 验证:单位现在应一致 ======
print("校准后单位分布:")
units_after = Counter([ch['unit'] for ch in raw.info['chs']])
print(dict(units_after))

⚠️ 关键事实:MNE 的 IO 函数(read_raw_*)在加载时已把数据换算到 SI 基本单位 V。所以正常情况下不需要任何单位校正——直接 raw.plot() 即可观察。

5. 单位换算规则速查

场景 现象 处理
IO 加载后数据正常 data.max() ~ 1e-4 ✅ 无需处理
数据被压扁到接近 0 data.max() ~ 1e-12 apply_function(lambda x: x*1e6)
数据异常大 data.max() ~ 1e2 apply_function(lambda x: x*1e-6)

📌 口诀:1 µV = 1e-6 V;从 µV 改 V 乘 1e-6;从 V 改 µV 乘 1e6。

6. 验证方法

Python
import numpy as np

# 验证 1:振幅数量级
data, _ = raw[:5, :int(raw.info['sfreq'])]  # 前 5 通道、前 1 秒(必须 int 切片)
amp_max = np.abs(data).max()
print(f"EEG 振幅峰值: {amp_max:.2e} V")
# 期望:1e-7 ~ 1e-4

# 验证 2:可视化
raw.plot(duration=5, scalings=dict(eeg=20e-6))
# 期望:能用 µV 单位直观看到正常 ERP

# 验证 3:与设备规格对照
# 检查 raw.info['chs'][i]['range'] 单位
for ch in raw.info['chs'][:3]:
    print(f"{ch['ch_name']}: range={ch['range']:.2e} V, cal={ch['cal']:.2e}")

7. 常见错误

错误 原因 解决方案
找不到 mne.preprocessing.fix_channel_units 该函数不存在(从未在 mne.preprocessing 中出现过) 用 apply_function 手动校正
调用 apply_function 后单位字段不变 apply_function 不修改 ch['unit'],仅缩放数据 数据正确即可;单位字段仅是元数据
raw.plot() 看不到 ERP 数据被压扁 用诊断代码判断后 × 1e6
raw.plot() ERP 振幅极大 数据被放大 用诊断代码判断后 × 1e-6
拒绝阈值设置错 用了错误单位 reject=dict(eeg=150e-6) 始终基于 V

8. 官方来源

资源类型 链接
Raw.apply_function https://mne.tools/stable/generated/mne.io.Raw.html#mne.io.Raw.apply_function
单位常量 https://mne.tools/stable/python_reference.html
单位换算说明 https://mne.tools/stable/overview/implementation.html

9. 学术引用

无需单独引用。单位规范属于实验数据元数据规范。