做脑电数据分析的,几乎没有人绕得开EEGLAB。尤其在预处理阶段,EEGLAB的图形界面和丰富的插件生态,让很多人从采完数据到出结果,整套流程都在这一个工具箱里完成。但说实话,我见过太多新手在第一步就卡住——不是不会点菜单,而是搞不清楚自己手里的数据到底该怎么进到EEGLAB里,进了之后又怎么确认没进错。这篇合辑的第一节,就把“往EEGLAB导入数据”这件事从头到尾捋一遍,包括环境准备、格式梳理、实际操作、导入后的检查,以及各种排查经验。
这节内容适合谁?刚接触EEGLAB的初学者、从其他软件(比如NeuroScan、BrainVision、Biosemi)转过来的用户,以及那些已经能用EEGLAB跑流程但一直靠“试”来导入数据、没搞懂底层逻辑的人。看完之后,你会对EEGLAB的数据导入机制有一个完整认识,而不是只记住几个菜单路径。
1. 为什么第一课要先死磕“数据导入”,而不是急着学滤波和ICA
很多初学者拿到EEGLAB之后,第一反应是打开界面,然后到处找滤波按钮、ICA按钮。这个心情我太理解了,毕竟预处理流程图谁看了都想快点跑完。但实际做过几个项目就会发现:预处理流程里出问题最多的,往往不是后面的算法参数,而是最前面的数据导入环节。数据导入一旦出错,后面所有步骤都是在错误的数据上徒劳,甚至可能得出完全相反的结论。
EEGLAB的核心数据结构是EEG这个MATLAB结构体,里面装着数据矩阵、通道位置、事件标记、采样率、参考电极等一切后续分析需要的信息。所谓“导入数据”,本质上就是把你采集设备输出的原始文件,转换成这个EEG结构体的过程。这个转换要是做得不干净,后面轻则图标错乱,重则事件时间轴全偏、通道顺序错位,做出来的ERP波形和时频图根本不能用。
还有一个容易被忽略的点:EEGLAB的很多下游操作,比如ICA去伪迹、谱分析、时频分解,都依赖一个结构完整的EEG结构体。像EEG.chanlocs(通道位置信息)如果没导入完整,后面做头皮拓扑图就会直接报错或者画出一张乱图;EEG.event(事件标记)格式不对,做epoch时就会卡住或者提取出空白 trial。与其等后面出了妖蛾子再回头查,不如在最开始就养成一个习惯:每次导入数据后,先花两分钟确认几个关键字段是否到位。
另外从学习路径角度说,EEGLAB的命令行操作比图形界面更可控、更好重复。而命令行操作的基本功,恰恰从导入就开始。你可以在MATLAB里输入一行EEG = pop_loadset('filename.set')来加载预处理好的数据,也可以输入EEG = pop_fileio('raw.edf')直接读原始格式。理解了数据结构是怎么一步步tian充完整的过程,后续用脚本批处理几十个被试数据,才不会两眼一抹黑。
所以这一节讲数据导入,不只是教你怎么“把文件打开”,而是帮你在脑内建立一张图:原始数据在磁盘上是什么样,进入EEGLAB之后变成了什么样,哪些信息会被保留,哪些信息容易被遗漏,以及如何验证转换过程没有丢失关键内容。
2. 环境准备:MATLAB版本、EEGLAB版本和启动路径的坑
2.1 MATLAB和EEGLAB的版本搭配
EEGLAB作为一个开源工具箱,对MATLAB版本的支持跨度很大,但不是说随便哪个版本都行。我个人的建议是:别用太老的MATLAB,也别追最新版。太老的版本(比如R2014a之前的)往往跑不动新版本EEGLAB里的一些依赖函数,而且对内存管理和大数据集的支持也不好;追最新版则容易碰到EEGLAB插件还没适配的情况,尤其是那些第三方插件,经常落后于EEGLAB主版本更新。
以我自己常用的组合来说,MATLAB R2020a到R2023b之间跑EEGLAB 2021.1到2024.x,整体都很稳。这个区间里,EEGLAB的pop_系列函数和依赖的Signal Processing Toolbox,基本都能正常运作。这里要特别提醒:EEGLAB需要MATLAB的Signal Processing Toolbox,缺了这个工具箱,很多频谱分析和滤波相关功能会直接报错。你可以用MATLAB命令行输入ver查看已安装的工具箱列表。
新版EEGLAB下载解压之后,目录里能看到eeglab.m主启动文件,以及functions、plugins等子目录。不要做多余操作,启动方式就是在MATLAB里把当前文件夹切到EEGLAB所在目录,或者用addpath添加路径,然后输入eeglab。
2.2 启动时常见的路径坑
关于路径,有两个非常典型的问题,我在带新手的时候几乎每次都遇到。
第一个坑是中文路径。EEGLAB本身虽然逐步改善了多语言支持,但很多底层函数在处理中文路径时依然可能出问题,尤其是涉及文件读取和插件更新时。我遇到过不止一次:数据放在D:\数据\被试1.set,pop_loadset加载时直接报错,或者图形界面里文件名显示一堆乱码。把文件夹改成英文路径,比如D:\EEG_Data\sub01,问题立刻消失。如果科研项目里有硬性要求必须用中文命名文件,至少保证供EEGLAB读写的工作路径是纯英文。
第二个坑是启动路径不对。有些新手把EEGLAB放在某个很深的嵌套文件夹里,启动时忘了先cd到EEGLAB目录,导致eeglab命令提示“未定义”。解决方法是先cd D:\eeglab2024.0,再输入eeglab,或者直接用addpath(genpath('D:\eeglab2024.0'))把整个EEGLAB目录加进路径。不过genpath会连插件一起加载,启动速度会慢一些,日常使用的话addpath到主目录就够了,EEGLAB启动时自己会处理插件路径。
2.3 EEGLAB界面第一次启动会看到什么
输入eeglab回车之后,弹出的主界面一般长这样:菜单栏有File、Edit、Plot、Tools、Datasets、Help等,下方是一个空列表,左下角提示当前没有数据集(No datasets)。懂MATLAB的人应该能看出来,这个界面本质上就是一个图形化的数据管理器,你导入的数据集会像列表一样呈现在主界面上,可以同时装载多个数据集,互相切换和比较。
从这一节开始往后的所有操作,你都可以在图形界面点,也可以用命令行跑。对新手来说先用图形界面建立操作直觉,对老手来说直接用脚本更高效。两种方式这篇文章都会讲。
3. 摸清EEGLAB支持的格式:不同采集设备的数据怎么进得来
3.1 常见的数据格式及来源
EEGLAB本身不生产数据,它只是一个数据处理平台。不同厂商的脑电采集设备会输出不同格式的原始文件,EEGLAB通过各种插件和函数来“读懂”这些文件。搞清楚你手上数据的“出身”,是选择导入方式的前提。下面列一下最常见的几种:
| 格式后缀 | 来源设备/软件 | 导入方式 |
|---|---|---|
| .set + .fdt | EEGLAB自身格式 | pop_loadset |
| .edf / .edf+ | 欧洲通用格式,多数设备可导出 | pop_fileio或pop_biosig |
| .bdf | Biosemi采集设备 | pop_fileio或pop_biosig |
| .cnt | NeuroScan(Scan 4.x) | pop_loadcnt |
| .eeg / .dat / .vhdr | BrainVision Recorder | pop_loadbv |
| .mff | EGI(Magstim EGI)系统 | pop_readegi或pop_fileio |
| .neurodata | Nexstim等导航刺激系统 | pop_fileio |
| .xdf | Lab Streaming Layer(LSL) | pop_loadxdf |
| .csv / .txt | 通用文本数据 | pop_importepoch等自定义方式 |
这张表只是入门级的格式地图,实际上EEGLAB能读的格式远不止这些。通过File > Import data菜单展开,你能看到一长串支持的格式列表,里面还包括了NeuroMag、ANT等系统。很多时候你在菜单里找不到对应的导入入口,不是EEGLAB不支持,而是需要先安装对应的数据读取插件。
3.2 什么格式的数据最适合EEGLAB
我的回答可能有点反直觉:最适合EEGLAB的格式并不是某个厂商的原始格式,而是.set格式。.set文件是EEGLAB的原生数据格式,它由一个文本头的.set文件和一个二进制数据文件组成(数据量大时后缀是.fdt,数据量小时有可能把数据直接塞进.set文件里)。只要数据转换成了.set,后续加载速度最快,且不会出现格式兼容性问题。
所以一个推荐的流程是:拿到原始采集文件后,第一步用对应的导入函数转成EEGLAB数据集,然后顺手pop_saveset保存一份.set。不要直接在原始文件上反复做预处理,每次都重新导入、重新检查,既慢又容易出错。把“原始格式”转成“EEGLAB格式”当成一个独立的步骤来做,等于给后续所有分析建立了一个干净的起点。这也是专业EEG数据分析流程里很常见的做法。
3.3 通道信息文件(chanlocs)是很多人的盲区
导入脑电数据时有一个经常被忽略的“隐性文件”——通道位置文件(通常是.ced、.txt、.elp、.locs等格式)。EEGLAB里的EEG.chanlocs结构体记录了每个通道的名称和三维坐标,没有它,你虽然也能做滤波、ICA,但画头皮图、做topography分析就会寸步难行。
很多设备的采集软件在导出EEG原始数据时,并不会把通道坐标信息一起打包进数据文件里。也就是说,你导入原始文件后,EEG.chanlocs可能是空的或者只有一个通道名列表,没有坐标。这种情况下,你需要单独加载一个与设备通道布局匹配的坐标文件。EEGLAB菜单里在Edit > Channel locations里加载,也可以用命令行方式:
EEG = pop_chanedit(EEG, 'lookup', 'standard-10-5-cap385.elp');这里用了EEGLAB自带的standard-10-5-cap385.elp标准坐标模板。对于大多数32导、64导的常规排布,这个模板都能对上号。如果用的是特殊电极帽,比如128导或者自制电极分布,则需要找厂商要坐标文件或者手动编辑。
注意:通道位置文件里的通道顺序必须和数据通道顺序一致,如果顺序错位,后面画出来的拓扑图会把电极名字贴到错误的位置上,表面看不出来,但结果完全不可信。
4. 实操导入:图形界面和命令行两条路,都给你走一遍
4.1 图形界面方式:以BDF文件为例
假设你手上是Biosemi ActiveTwo采集的.bdf数据,要导入EEGLAB,步骤是这样的:
- 打开EEGLAB,菜单栏选
File > Import data > Using EEGLAB functions and plugins > Biosemi .bdf (.bdf)。 - 弹出文件选择框,选中你的
.bdf文件。 - 接下来会弹出一个参数设置框,主要是让你确认数据范围偏移量(Data range offset)和是否要对16位/24位数据进行缩放。Biosemi数据的单位是微伏,EEGLAB读入后会自动换算。基本上保持默认值就行,直接点OK。
- 导入完成后,主界面的数据集列表里会多出一行。你可以双击这一行进入数据集查看器,会看到波形图。
这里有个细节:新版EEGLAB的BDF导入用的是BIOSIG插件(pop_biosig),而不是早期的pop_bdfimport。如果你的EEGLAB没有装BIOSIG插件,菜单里可能找不到BDF入口或者导入时报错。解决办法是在File > Manage EEGLAB plugins里在线安装BIOSIG插件,或者去EEGLAB官网插件列表下载后解压到plugins目录,重启EEGLAB。
4.2 命令行方式:更高效,也更容易排错
图形界面适合第一次熟悉流程,但一旦你要处理多个被试、多个文件,或者希望流程可复现,命令行是更好的选择。用命令行导入BDF只需要一行:
EEG = pop_biosig('D:\EEG_Data\sub01.bdf');这一行执行后,MATLAB工作区里会多出一个名为EEG的结构体,同时EEGLAB主界面也会出现这个数据集。任何图形界面里能做的高级设置,命令行都可以通过pop_biosig后面的参数“键值对”来指定。比如设置范围偏移:
EEG = pop_biosig('D:\EEG_Data\sub01.bdf', 'blockrange', [1 100000]);这种写法熟悉MATLAB的人应该不陌生。EEGLAB的pop_系列函数都是这种模式:函数名以pop_开头,第一个参数是数据集,后面的参数是成对的键值。pop_biosig还有个特殊的地方:如果你不提供任何数据文件路径,它直接弹图形选择框,这算是一种交互式命令行的折中方案。
再说一个通用函数pop_fileio。它是EEGLAB里一个比较新的“万能导入器”,底层自动调用了data2bids、bids2eeglab等组件以及各个第三方读取工具。对于很多标准格式(EDF、BDF、GDF等),直接用
EEG = pop_fileio('D:\EEG_Data\sub01.edf');就能导入。pop_fileio会检测文件头、自动判断格式,对新手来说是很友好的入口。不过也要注意,pop_fileio不是万能的,遇到了小众格式或者文件头损坏的数据,还是要回到专门的导入函数。
4.3 三种不同格式的导入实战
为了让你真正理解“格式决定方式”,我把三种最常见的数据导入场景完整演示一遍。
场景一:NeuroScan .cnt文件
NeuroScan采集系统常见于很多老牌实验室,输出的是.cnt(连续数据)或者.eeg(分段数据)。导入.cnt用的是pop_loadcnt:
EEG = pop_loadcnt('D:\EEG_Data\sub01.cnt');如果数据里有事件标记需要一并导入,可以加参数:
EEG = pop_loadcnt('D:\EEG_Data\sub01.cnt', 'dataformat', 'int16');.cnt文件本身会把事件标记存储在文件头或者独立的事件文件里,pop_loadcnt会自动处理大部分情况。
场景二:BrainVision .vhdr文件
BrainVision Recorder导出的是三个文件:.vhdr(文本头文件)、.eeg(二进制数据文件)、.vmrk(标记文件),三者在同一目录下,文件名相同。导入时选.vhdr文件:
EEG = pop_loadbv('D:\EEG_Data\', 'sub01.vhdr');注意pop_loadbv有两个参数,第一个是文件夹路径,第二个是文件名。这个函数非常成熟,事件标记会从.vmrk文件里自动读入EEG.event,包括Marker类型和位置。
场景三:EDF/EDF+通用格式
EDF(European Data Format)是很多第三方设备都能导出的通用格式,在睡眠研究领域尤其常见。EDF+在EDF基础上增加了更灵活的时间戳和注释轨道。导入方法:
EEG = pop_fileio('D:\EEG_Data\sub01.edf');对于EDF+,需要注意它可能包含多个“连续数据段”,BIDS格式里常说的DataRecord就是这种结构。pop_fileio能够读取,但是当EDF+里有注释事件(Annotations)时,这些事件会被转成EEG.event里的特殊类型。新手经常遇到导入EDF+后事件数量异常多,一看全是Annotation型事件,需要在后续分析前做筛选。
4.4 导入过程中涉及的几个参数:采样率、数据范围与极性
pop_函数导入时弹出的参数框里,有几个重要的参数值得单独解释:
采样率(srate):大多数格式的文件头里自带采样率,EEGLAB会自动识别,一般不需要手动填写。但如果你从文本文件导入裸数据,就必须自己指定采样率,这个值一旦填错,后面所有时间相关的分析(ERP、时频)都会出问题。
数据范围(Data Range / Calibration):脑电采集设备的模数转换器(ADC)决定了原始信号的整数范围(比如Biosemi 24位系统是-8388608到8388607),EEGLAB需要把这个整数范围转换成实际微伏值。Biosemi系统导出时通常已经做了转换,但NeuroScan的.cnt有时需要通过calib文件来校准。如果你导入后发现波形幅度不是微伏量级(正常EEG幅度在几十到一两百微伏),很可能就是数据范围没有正确转换。
极性(Polarity):不同系统对“向上偏转代表正电压还是负电压”的约定不同。NeuroScan系统默认是正电压向上,而Biosemi有的记录是负电压向上。EEGLAB不会自动判断极性,需要在导入后通过Tools > Change pole polarity或者直接在数据视图里目测判断。经典的判断方法是看眨眼伪迹:Fp1通道眨眼时通常是明显的负向偏转还是正向偏转,这个不同系统不一样,需要结合自己设备的采集手册确认。
5. 导入只是开始:通道信息、事件标记与采样率的校验调整
数据导入成功,不代表万事大吉。我经常跟人说一句话:“导入完成的瞬间,才是真正开始干活的时候。”因为许多初始错误能够在导入后的简单检查中快速被发现。养成下面这几个检查习惯,能帮你避开后面一堆麻烦。
5.1 检查EEG结构体里的关键字段
导入完成后,在MATLAB命令行直接输入EEG回车,会看到一大串结构体字段。我每次都会快速扫一眼这几个关键量:
EEG.nbchan:通道数。对照你的设备配置,比如64导系统这里应该是64(可能包含参考电极或外部电极)。EEG.pnts:每个通道的数据点数。用EEG.pnts / EEG.srate可以算出总时长(秒),对照采集时长就能验证数据是否完整导入。EEG.srate:采样率,正确值应该是采集时的设置,常见的是250Hz、500Hz、1000Hz等。EEG.xmin:数据起始时间,通常为0或负数(如果导入了epoch前的基线)。EEG.event:事件标记数组。如果是任务态数据,这里的类型数和数量应该和实验设计吻合。
有一个特别常见的错误:导入.cnt文件后EEG.event是空的,但实验明明有事件标记。这种情况往往是.cnt文件里事件信息存储格式特殊,pop_loadcnt没识别全。解决方式是看设备软件能否导出独立的事件文件(如.dat),再用pop_importevent手动导入。
5.2 通道位置的核对与补全
在Edit > Channel locations界面里,可以直观看到每个通道的坐标分布。检查时重点看两点:一是通道名称是否与电极帽标签一一对应,二是通道的三维坐标是否合理。如果电极坐标全部落在了“一个平面上”,说明坐标数据没有被正确插值,后面画拓扑图会变样。
补全通道位置还有一个常见做法:
EEG = pop_chanedit(EEG, 'lookup', 'standard-10-5-cap385.elp');运行之后,如果通道名称和模板匹配成功,EEG.chanlocs里会填上坐标值。如果某些通道显示NaN坐标,说明模板里没有这个通道名,需要手动检查。
5.3 波形目视检查
这一步很土,但很有效。在EEGLAB主界面双击数据集名称,打开数据浏览器,选择一个包含Fp1/Fp2等前额电极的通道,然后滚动波形看有没有明显的眨眼伪迹(大幅值、低频率、形状规则的偏转)。这能一次性验证三件事:数据方向是否正常、极性是否符合预期、通道连接是否正常(不会出现某通道全是直线的高阻抗死信号)。
顺便说一个非常容易被忽略的点:数据浏览器默认显示的电压单位是µV,但如果你导入时没有做校准,显示的数字可能变成了原始整数范围(几万到几十万),满屏波形看起来像一条毛茸茸的直线。这时候别慌,回到第4.4节提到的数据范围问题,重新检查导入参数。
5.4 数据保存:确立标准的.saveset流程
检查无误后,果断保存为.set格式:
EEG = pop_saveset(EEG, 'filename', 'D:\EEG_Data\sub01.set');之后每次进行预处理,都用pop_loadset加载这个文件。这样保证每次分析都从一个固定的、已检查的数据版本出发。如果有多个预处理操作,建议养成“一步一存”的习惯:原始数据存一份、滤波后存一份、ICA去伪迹后存一份。版本管理在科研里非常重要,这能让你追溯每一步变换,不至于在出问题时只能推倒重来。
6. 几种典型故障和排查过程:从现象到根因
这一节整理几个导入环节中我遇到过的真实故障,每个都附排查思路,而不是只给结论。以后你碰到类似问题,可以照着这个排查路径走。
6.1 报错“Cannot read file”或者“Unknown format”
现象:pop_fileio或对应导入函数报错,提示无法读取文件或未知格式。
排查过程:
先看文件后缀和实际编码是否一致。很多设备导出的“文本文件”实际是Unicode编码,用普通文本读取自然会报错。可以用十六进制编辑器或者MATLAB的fopen+fread读前几个字节,看看文件头是否包含了预期格式的标识符。
再看是不是文件被占用。某些采集软件会持续锁定正在写入的数据文件,如果采集刚结束就立刻复制或读取,可能遇到系统级文件锁定报错。解决办法是等软件释放文件,或者先将文件复制到其他目录再导入。
最后检查一下文件是否完整。.bdf和.edf文件末尾都有特定的结束标识,如果导出过程中断,文件可能缺少结尾,导入时就会报错或只导入部分数据。用文件大小和采集时长做乘法估算,能快速判断文件是否有残缺。
6.2 导入BDF后通道数翻倍,或出现大量异常值
现象:导入BDF后EEG.nbchan不是预期的64,而是128或更多,并且波形图上出现一些幅度特别大、明显不是脑电的信号。
排查过程:Biosemi的24位ADC本身有两个独立的数据流,一个记录EEG,一个记录“状态信号”(Status,用于记录事件标记)。在一些旧版BIOSIG插件里,这两个数据流会被当作普通通道全部读入。遇到这种情况,检查一下EEG.chanlocs里是不是包含标签为“Status”或“EXG”一类的通道。如果是,可以保留这些通道用于事件提取,也可以在导入后用pop_select剔除:
EEG = pop_select(EEG, 'nochannel', {'Status'});不过剔除之前要确认事件信息已经通过Status通道提取并转换到EEG.event里了,否则事件就丢了。
6.3 导入EDF+后事件全部变成“Annotation”
现象:EDF+文件里的实验事件(比如Stimulus)导入后,EEG.event里的type全是Annotation,看不到预期的实验事件类型。
排查过程:EDF+规范里把事件注释统一放在专有的“Annotation”轨道里,pop_fileio读入时会把这些注释作为一个事件源导入,所以事件类型名称确实是Annotation,这不一定是错误。解决办法是检查每个“Annotation”事件的description或者code字段,真正的事件信息通常藏在里面:
[EEG.event.type] = deal('dummy'); % 先重置 for i = 1:length(EEG.event) % 假设EEG.event(i).code里保存了实际事件标签 EEG.event(i).type = EEG.event(i).code; end如果code字段包含了类似“Stimulus”和具体刺激参数,就用它替换type字段。如果设备软件能直接把EDF+导出成不同的独立事件轨道,也可以先在设备端设置。
6.4 导入大文件时内存不足
现象:一个1GB以上的BDF或CNT文件导入时,MATLAB提示内存不足(Out of Memory)。
排查过程:这个问题的根本原因不是EEGLAB代码有问题,而是MATLAB加载数据时会把整个文件一次性读入内存。64导、采样率1000Hz、连续记录2小时的数据,数据量大约在64 * 1000 * 7200 * 8字节 ≈ 3.7GB,再加上MATLAB结构体的开销和后续副本,内存消耗可以轻松超过10GB。解决办法有几个层次:
第一,如果内存确实不够,用pop_biosig提供的片断导入功能,只读入数据的一部分先做检查。比如:
EEG = pop_biosig('D:\EEG_Data\sub01.bdf', 'blockrange', [1 100000]);读取前10万个采样点。
第二,升级到64位MATLAB,并且配置足够大的系统内存(建议至少16GB以上)。EEGLAB所有现代功能都依赖于64位MATLAB。
第三,考虑在导入前用设备自带软件对数据进行降采样。比如原始1000Hz的数据降采样到500Hz,数据量直接减半。但降采样一定要在滤波之后进行,否则会出现混叠(aliasing)伪迹,这里有个顺序问题,我在后面的内容里会详细讲。
第四,分段导入再拼接。如果数据非要整段分析,就分多段导入,然后pop_mergeset拼接。这种方法麻烦一点,但在内存受限的电脑上是可行的保底方案。
6.5 中文路径导致的导入失败
现象:文件放在D:\数据\sub01.bdf,导入时报错,但同样的文件放到D:\data\sub01.bdf后导入正常。
排查过程:这是一个典型的编码环境兼容性问题。MATLAB在不同操作系统上的默认字符编码不同,而EEGLAB底层的很多文件读取函数依赖C语言的文件操作接口,对Unicode路径支持不完整。解决方式很简单:工作路径和文件名一律用英文。如果已经积累了中文路径下的数据,建议在导入前先批处理改名或复制到英文目录。
7. 批处理思路:几十个被试的数据如何高效导入和保存
单文件导入搞定了,接下来面临的实际问题是:真实研究项目不会有只有一个被试。当我需要一次导入20个被试、每个被试还有多个block数据时,如果还在图形界面里一个个点,效率太低且容易出错。这时候就需要脚本化。
7.1 最简单的批处理循环
比如你要导入D:\EEG_Data目录下所有.bdf文件,并自动保存为.set:
data_dir = 'D:\EEG_Data'; file_list = dir(fullfile(data_dir, '*.bdf')); for i = 1:length(file_list) filename = fullfile(data_dir, file_list(i).name); EEG = pop_biosig(filename); [~, basename, ~] = fileparts(filename); EEG = pop_saveset(EEG, 'filename', fullfile(data_dir, [basename '.set'])); close; % 关闭绘图窗口,避免占用内存 end这里有个小细节:dir(fullfile(data_dir, '*.bdf'))返回的文件列表包含了文件夹里所有.bdf文件,顺序可能不是按照编号来排列,所以文件名命名时最好用自然编号(如sub01.bdf、sub02.bdf),而不是sub1.bdf、sub10.bdf,这样可以避免文件顺序错乱。
7.2 批处理时的事件和通道位置补全
如果实验过程中记录了不同的block(比如“安静观看”和“任务状态”),你可能需要在导入循环里为每个文件设置不同的事件类型前缀,或者统一加载同一个通道位置文件:
for i = 1:length(file_list) EEG = pop_biosig(fullfile(data_dir, file_list(i).name)); EEG = pop_chanedit(EEG, 'lookup', 'standard-10-5-cap385.elp'); % 设置被试信息 EEG.subject = sprintf('sub%02d', i); EEG.session = 1; EEG = pop_saveset(EEG, 'filename', fullfile(data_dir, sprintf('sub%02d.set', i))); endEEG.subject、EEG.session这些字段虽然在导入时不需要,但加上之后,后续用bids插件导出或者做群体分析时会非常方便。
7.3 批处理脚本的常见翻车点
翻车点一:重复使用EEG变量导致旧数据残留。如果导入循环中某次报错,EEG变量可能保留了上一个文件的内容,继续循环时可能误以为导入成功。可以在每轮循环开头加一行clear EEG,同时用try-catch捕获错误并记录到日志文件,方便排查是哪个文件出现问题。
翻车点二:绘图函数自动弹出窗口导致内存堆积。pop_biosig在导入时如果设置了绘图输出,会弹出图形界面。批处理中几十个文件同时弹出绘图窗口,轻则卡顿,重则崩溃。脚本化处理时,确保参数里没有触发绘图,或者在循环末尾加close all。
翻车点三:张冠李戴。如果批量导入时不小心填错了被试编号或者导错了目录,导入后的.set文件里存的是错误的信息。预防方法是保存后立刻打印一行确认信息:
fprintf('Imported %s, %d channels, %d samples, %d events\n', ... EEG.filename, EEG.nbchan, EEG.pnts, length(EEG.event));这样每个文件的导入情况都会在命令行留下记录,检查起来一目了然。
8. 关于数据导入的几个进阶话题:导入后再导入、数据拼接与自定义格式
8.1 往已有数据集里追加数据:pop_mergeset
有时你手里有同一个被试的多个run记录,需要把它们拼成一个连续数据集再做后续分析。EEGLAB提供了合并数据集的功能,命令行方式是:
EEG1 = pop_loadset('D:\EEG_Data\sub01_run1.set'); EEG2 = pop_loadset('D:\EEG_Data\sub01_run2.set'); EEG = pop_mergeset(EEG1, EEG2, 0);这里的第0个参数表示两个数据集按时间顺序拼接。拼接时要求两者的通道数、采样率完全一致,否则会报错。如果事件标记里记录了每个run的起始时间,拼接后的事件时间轴会自动调整,不需要手动处理。
有一种常见的拼接受限情况:不同run的参考电极或者通道排序不一致。这需要先统一通道顺序,再做拼接:
EEG2 = pop_select(EEG2, 'channel', {EEG1.chanlocs.labels});先按EEG1的通道顺序重排EEG2的通道,再合并,这样能避免通道错位。
8.2 从纯文本数据导入:一个通用方案
有些实验室还在用老式的放大器,数据导出是简单的.txt或.csv,每行一个时间点,每列一个通道。导入这种数据不能直接靠EEGLAB的菜单,需要一些MATLAB基本功。
假设你的文本文件长这样(逗号分隔,第一列是时间或序号,后几列是通道):
1,-12.5,10.2,5.8 2,-10.1,11.0,6.2 ...可以这样导入:
data = importdata('D:\EEG_Data\raw.txt'); srate = 500; % 根据实际采样率填写 data = data.data; % 或者其他你定义的字段 data = data(:, 2:end); % 去掉第一列时间 EEG = pop_importdata('dataformat', 'array', 'nbchan', size(data,2), ... 'data', data, 'srate', srate);pop_importdata是EEGLAB里一个非常好用的“通用导入”入口,可以从工作区数组直接创建数据集。很多非标准格式都可以先用MATLAB读进来,再通过这个函数进入EEGLAB。这个流程一定要掌握,因为现实世界里格式永远比你想象的多样,总有菜单上没有入口的情况。
8.3 事件标记的再导入
有一种常见的场景:数据本身没问题,但采集时事件标记记错了、丢了,事后从行为日志里拿到了准确的事件时间。这时候可以不用重新采集和重新导入整个数据,只需要用pop_importevent来更新事件:
EEG = pop_importevent(EEG, 'filename', 'D:\EEG_Data\sub01_log.txt', ... 'timeunit', 1/EEG.srate, 'fields', {'type', 'latency'}, ... 'skipline', 1);这个函数能把文本日志里的事件类型和发生时间(换算成采样点)导入到EEG.event。事件标记是EEGLAB里最容易出错的地方,像时间单位不一致、latency偏移1个采样点、事件类型是字符串还是数字等细节,都可能影响后面epoch提取。我建议每次导入或替换事件后,都做个可视化检查:画出原始波形,在上面叠加事件标记位置,确认事件时间与刺激出现的时间吻合。
9. 数据导入和重参考的关联:为什么有些导入要先做参考处理
很多人在导入Biosemi数据后,发现所有通道的波形幅度看起来都是一样的,尤其是所有通道都叠加了一个很大的直流漂移。这不是导入错误,而是Biosemi系统本身的特性:它不主动做硬件参考,采集时每个电极都是相对于公共参考点(CMS/DRL)记录的。所以导入Biosemi数据后,第一件事往往就是重参考,通常用全脑平均参考(Average Reference)。
EEGLAB里做全脑平均参考的命令是:
EEG = pop_reref(EEG, []);在图形界面里,路径是Tools > Re-reference the data,什么都不选直接确定就是全脑平均参考。这一步虽然不是“导入”操作,但和导入关系非常紧密,因为如果你不重参考,后续的ICA去伪迹、功率谱计算都会受到参考电极位置的影响。
对于NeuroScan的.cnt数据,采集时通常已经做了在线参考(比如以CZ为参考),导入后是否需要重参考取决于你的实验设计。注意:不管做不做重参考,在做重参考之前都需要确保EEG.chanlocs(通道位置信息)已经补全,因为全脑平均参考在计算时要排除无用电极(如心电、眼电),而这些电极类型需要通过通道位置信息来识别。
10. 这一课做完了,你的数据应该长这样
按照上面所有步骤走完,你的工作目录里应该有一份.set文件(外加可能存在的.fdt文件),其EEG结构体是干净、完整的。命令行输入EEG后,应该能看到类似这样的摘要:
EEG = struct with fields: setname: 'sub01' filename: 'sub01.set' filepath: 'D:\EEG_Data\' nbchan: 64 trials: 1 pnts: 1800000 srate: 500 xmin: 0 xmax: 3600 times: [] data: [64x1800000 double] icaact: [] icawinv: [] icasphere: [] icaweights: [] icachansind: [] chanlocs: [1x64 struct] ref: 'common' event: [1x200 struct] urevent: [1x200 struct] ...重点看nbchan、pnts、srate、event这些字段有没有合理取值。确认无误后,你的后续预处理之路就有了一个扎实的起点。
回到这一课最开始的问题:为什么反复强调数据导入?因为EEGLAB的所有高级分析都建立在“数据被正确读入”这个前提上。我见过太多人花大量时间调ICA参数、换滤波器类型,结果最终发现是导入时通道位置没对导致整个拓扑图失真。磨刀不误砍柴工,数据导入这一步值得你认真对待。下一节合辑我们会讲数据清理和滤波,那时候你会发现,只要导入环节打好了底子,后面全都是水到渠成的事。