基于念通智能 iRecorder W32,配置设计、刺激预览、实时波形、脑电采集全在一个窗口。
cd eeg_acquisition
py -3.12 -m venv .venv # 推荐 Python 3.12 (netifaces 有预编译包)
.venv\Scripts\activate
pip install pyqt5 pyqtgraph scipy numpy pygame pyserial edflib-python pywifi comtypes netifaces matplotlib
pip install ..\eConEXG-SDK-0.1.35Python 3.13 用户:
netifaces无预编译包,项目已内置补丁绕过,详见 常见问题。
copy ..\eConEXG-SDK-0.1.35\examples\test_iRecorder.py .
python test_iRecorder.py确认能搜到设备(如 iRe-E5C101)后再启动主程序。
每次打开新终端先激活虚拟环境,再运行:
cd eeg_acquisition
.venv\Scripts\activate # 激活虚拟环境 (每次必做)
python main.py # 新建实验
# 或
python main.py configs/experience.json # 加载已有配置一个窗口,三页切换:
- 配置页 — 6 个标签页设计实验
- 采集页 — 实时波形 + 设备控制 + 实验执行
- 数据显示 — 浏览 BDF 文件,选择滤波/原始模式,双击弹窗查看
底部三按钮切换:[实验配置] [采集] [数据显示]。
- 设计实验(或加载 JSON)→ 点「确认配置 → 进入采集」
- 电脑连接 iRecorder WiFi 热点
- 点「连接设备」→ 实时波形即刻显示
- 点「阻抗检测」→ 检查各通道接触情况(
<5000良好 /5000-20000可接受 />20000需调整 /∞接触不良) - 点「刺激预览」→ 独立窗口预览完整实验流程
- 点「▶ 开始实验」→ 全自动执行,实验结束自动停止
| 标签 | 内容 |
|---|---|
| 基础 | 受试者 ID、输出目录、采集提前量(基线)、刺激前等待(rest) |
| 通道 | 头形椭圆 10-20 电极图,勾选有绿色背景,快捷预设按钮 |
| 基元 | 表格增删;图片/声音列有浏览按钮 (默认 stimuli/);留空=黑屏/无声 |
| Epoch | 表格增删;选中后「编辑序列」打开拖拽式编排器 |
| 滤波 | 带通 0.16–70Hz、陷波 50Hz、伪影 ±50μV |
| 预览 | 自动汇总基元、Epoch、总试次、预计时长 |
顶部工具栏:打开 JSON → 保存 (覆盖) → 另存为 (新位置)。
实时波形 — 统一坐标系,所有通道共享 Y 轴。水平虚线标注刻度 (间距可调),灰色实线为每通道基线,绿色波形滚动显示 (当前电位在 x=0)。实时显示经过带通+陷波滤波(lfilter 因果滤波,有轻微延迟),右上角下拉框改刻度间距 + 重置视图按钮。记录到 BDF 的数据使用零相位 filtfilt 离线处理,时间信号精确无延迟。
按钮 — 三列等宽:
[连接设备][阻抗检测][刺激预览] │ [暂停][▶ 开始实验][终止] │ [← 返回配置]
连接设备后可点「阻抗检测」检查各通道接触情况。不合格通道在波形显示中画直线。
独立可拖动窗口,屏幕 75% 居中。受试者看到:有图片 → 等比缩放;无图片 → 基元名称灰字;实验结束 → 自动关闭。
切换到「数据显示」页 → 自动扫描 data/ 目录列出所有 BDF 文件。
- 顶部四选一:
- EDFlib 滤波 — EDFlib 读数据 + MNE 取 annotations,1-40Hz 带通 + 50Hz 陷波
- EDFlib 原始 — 同上,无滤波
- MNE 滤波 — MNE 全流程,滤波同上
- MNE 原始 — MNE 全流程,无滤波
- 两套方案互为主备:EDFlib 自写自读最稳,MNE 是标准库适合后续分析
- 双击文件名 → 弹出独立 matplotlib 子进程窗口,多个可同时打开
python src/read.py # 滤波显示 (改 FILE 路径)
python src/readrear.py # 原始显示 (改 FILE 路径)每个 Trial 的采集流程(一条连续数据流,rest + baseline + 基元不分开):
Rest 休息 (pre_stim_ms) → _BEGIN → Baseline 基线 → 基元序列 → _END
↑ 记录静息 EEG,不打标注 ↑ 标注 @ 配置推算帧位
n 种 Epoch × m 次 → 随机打乱 → 刺激前等待(记录 resting EEG) → 采集 → 在线预处理 → 通过/拒绝(自动补做)。
基元标注:TTEEPP(6 位)
| 位置 | 含义 | 示例 |
|---|---|---|
| TT | Trial 编号 (01-99) | 01, 02, 03... |
| EE | Epoch 类型代码 (AA-ZZ) | AA, AB, BA... |
| PP | 基元序号 (01-99) | 01, 02, 03 |
Trial 标记:T01A_BEGIN / T01A_END,实验标记:EXP_START / EXP_END。每个基元只打一条 start 标注,不打 end。
两个时间设置(采集提前量 baseline / 刺激前等待 pre_stim)可独立调节。
data/
├── S001_raw_20260715_143022.bdf 原始 EEG(含 rest + 全部 trial, 全部通道)
└── S001_preproc_20260715_143022.bdf 预处理后(仅通过 artifact 检查的 trial)
标准 BDF+ 格式,含完整 trigger annotation,可直接导入 EEGLAB / MNE / BrainVision Analyzer。
eeg_acquisition/
├── main.py ← 入口
├── README.md
├── CHANGES_20260718.md ← 修改记录
├── .gitignore
├── configs/ ← 实验配置 JSON
├── stimuli/ ← 刺激素材 (图片/音频)
├── data/ ← BDF 输出 (gitignore)
└── src/
├── read.py ← 命令行 BDF 查看 (滤波)
├── readrear.py ← 命令行 BDF 查看 (原始)
├── main_window.py ← 主窗口 + 实验线程
├── stimulus_window.py ← 刺激窗口
├── data_viewer.py ← 数据显示页 (GUI 内浏览)
├── _plot_window.py ← 独立绘图子进程
├── bdf_writer.py ← BDF 写入 (EDFlib-Python)
├── config.py ← 数据模型
├── trigger.py ← Trigger 编码
├── epoch_manager.py ← 序列管理
├── signal_processor.py ← 滤波 + 伪影
└── eConEXG/ ← SDK (设备驱动层)
| 现象 | 原因 | 解决 |
|---|---|---|
No module named 'netifaces' |
Python 3.13 无预编译包 | 项目已内置补丁, 或用 Python 3.12 |
| 点「连接设备」找不到设备 | SDK find_devs(duration) 清空队列的 bug |
已修复:改用非阻塞轮询 |
| 刺激窗口关掉后预览不停止 | close() 默认只隐藏 |
已设 WA_DeleteOnClose,关闭即销毁 |
| Qt platform plugin 报错 | venv 下找不到 Qt 插件 | 已修复:main.py 自动设置路径 |
| 实验结束后不能重启 | 按钮状态未恢复 | 已修复 |
| 阻抗全绿/全显示 0.00kΩ | SDK 返回值非毫欧, 旧版单位错误 | 已修复, 现在显示分级 (良好/可接受/需调整) |
| 标注全堆在 0s | BDF onset 计算未加 _total_written |
已修复 |
| 标注数量被截断 | Annotation channel 只有 1 个, 容量不够 | 已修复:扩到 16 通道 |
| 实验线程无声崩溃 | 设备断连时无 try/except | 已修复:崩了弹窗提示 + BDF 正常关闭 |
| preproc BDF 打不开 | 所有 trial 被 artifact 拒绝导致空文件 | 已修复空文件保护; 调高伪影阈值或改善电极接触 |
| 波形全是 -5000μV / 数据全是 0 | 电极接触不良/设备未传输 | 用阻抗检测确认, 检查 WiFi 距离 |
| BDF 读不出来 | 文件路径含中文或文件损坏 | 用 read.py 测试 |
| 实时显示波形"起飞" | 连接后未开启数据流 | 已修复 |