资讯动态

EEGLAB脑电分析全流程:预处理、ERP/功率谱与机器学习衔接

发布时间:2026/10/27 10:36:35 来源:尧图企业网站定制
简介EEGLab V10.0.0.0b 是面向脑电EEG分析初学者与科研人员的开源工具包适用于神经科学、心理学、生物医学工程等场景可完成信号质量检查、预处理、事件相关电位ERP分析、频率分析与源定位等任务并为脑机接口、疾病诊断等机器学习应用提供数据基础。压缩包约182.31MB文件总数与类型明细暂无数据从内容说明看应包含安装指南、主程序、示例数据集、用户手册及脚本示例便于快速搭建分析环境并对照练习。已有196人学习说明其在脑电预处理与跨学科研究中具有一定参考价值。内容重点在于把滤波、去噪、眼动校正、平均参考等预处理流程与ERP、频谱、源定位分析串联起来读者可据此理解从原始EEG到可解释结果的完整链路并尝试将SVM、随机森林等分类方法接入用于认知任务分析或BCI原型验证。1. 拿到一个 EEGLab 压缩包先别急着双击脑电分析这条路上最容易把人劝退的从来不是算法而是环境。你手上有一份采集下来的原始数据几十个通道、几十分钟时长、事件标记乱七八糟想把它变成能喂给机器学习模型的矩阵中间隔着一整套预处理流水线。EEGLAB 就是这个流水线上最常被选中的那一段MATLAB 环境下运行图形界面能点命令行能脚本化数据结构是公开的EEG结构体往下接人工智能那套分类器或者深度学习框架都不需要写转换层。脑电分析本身是典型的交叉性学科做信号的人、做实验的人、做模型的人经常不在同一个语境里而 EEGLAB 的价值就在于它给了三方一个共同的中间格式。这份 EEGLab V10.0.0.0b 压缩包解决的就是「把一套能跑通、能复现、能批量的分析环境立起来」这件事适合刚接手脑电数据、手里只有 MATLAB 和一堆.set文件的人也适合已经会用 GUI 点、但想把流程固化成脚本的老手。2. 解压到能跑EEGLAB 的目录结构与路径依赖压缩包解开之后第一眼看上去会有点乱根目录下同时躺着eeglab.m、eeglab.fig、functions、plugins、sample_data这些条目。很多人图省事直接把整个文件夹丢进 MATLAB 的toolbox目录结果下一次换机器就找不到路径了。我一般建议把 EEGLAB 当成一个独立的便携工具目录来管理比如统一放在D:\tools\eeglab或~/tools/eeglab路径里不要有中文、不要有空格、不要有括号这三条不是洁癖是后面一连串报错的源头。2.1 目录里每个东西是干什么的理解目录分工比记住菜单在哪重要得多。functions是核心函数库pop_*系列函数几乎全在这里plugins是插件目录ICA 相关的runica、时频分析的timef、数据清洗的clean_rawdata都靠插件补sample_data里带了一套示例数据用来验证安装是否成功根目录的eeglab.m是启动入口它不只是打开一个窗口还会初始化EEG、ALLEEG、CURRENTSET这几个全局变量并读取eeg_options.m里的内存配置。提示eeg_options.m里的option_storedisk决定数据是常驻内存还是落盘读取。数据量大、机器内存紧张时把它打开代价是每次切数据集都要多一次磁盘 IO。2.2 启动脚本与路径注册不要用「双击eeglab.m」的方式启动那样 MATLAB 的当前工作目录会被改掉后面读数据全是相对路径的坑。正确做法是先固定工作目录再注册路径最后调启动函数。% 固定工具根目录避免中文、空格、括号 eeglab_root D:\tools\eeglab; % 把主目录和两个子目录递归加入搜索路径 addpath(eeglab_root); addpath(genpath(fullfile(eeglab_root, functions))); addpath(genpath(fullfile(eeglab_root, plugins))); % 启动 EEGLAB初始化 EEG / ALLEEG / CURRENTSET 全局变量 eeglab; % 确认版本与插件加载情况 disp(eeglab(version)); plugin_askinstall(clean_rawdata, clean_rawdata, false); % 检查插件是否存在addpath(genpath(...))和addpath(...)的区别在于是否递归子目录functions下面层级很深必须用genpath。eeglab无参数调用会打开 GUI 并挂上全局变量如果你是在无图形界面的服务器上做批处理可以改用eeglab nogui但这样依赖 GUI 的pop_*函数仍然能跑只是不弹窗。plugin_askinstall的第三个参数设成false表示只检查不询问适合写进自动化脚本。路径注册完之后用压缩包自带的示例数据做一次冒烟测试这一步能提前暴露 80% 的安装问题。% 切到示例数据目录再读取避免相对路径混乱 sample_dir fullfile(eeglab_root, sample_data); cd(sample_dir); % 读取示例数据集同时加载 .fdt 数据文件 EEG pop_loadset(eeglab_data.set); % 打印关键字段确认数据结构完整 fprintf(通道数: %d, 采样率: %d Hz, 时长: %.1f s\n, ... EEG.nbchan, EEG.srate, EEG.pnts / EEG.srate); fprintf(事件数: %d, 电极位置数: %d\n, ... length(EEG.event), length(EEG.chanlocs));这段代码的第一行很关键.set文件通常和同名的.fdt二进制文件配对存在pop_loadset会按.set里记录的相对路径去找.fdt。如果你把.set单独拷到别处而漏了.fdt报错会是很不直观的「文件读取失败」。第二段用EEG.nbchan、EEG.srate、EEG.pnts三个字段做交叉校验正常情况下EEG.data的维度应当是「通道数 × 采样点数 × 试次数」没分段时第三维是 1。2.3 版本与依赖的现实边界压缩包名字里的10.0.0.0b更像是打包者自己的构建编号不一定是官方发布序列里的正式版本号。这意味着两件事一是网上搜到的教程里出现的函数签名不一定对得上二是里面预置的插件版本是冻结的不会自动更新。常见做法是先用eeglab(version)把实际版本打印出来记在项目 README 里再核对几个关键函数的参数名比如老版滤波是pop_eegfilt(EEG, lowcut, highcut)新版是pop_eegfiltnew(EEG, locutoff, low, hicutoff, high)两者参数位置完全不同混用必然报错。MATLAB 侧的最低要求是能支持inputParser和matlab.graphics那套对象体系太老的版本会在绘图函数上直接崩。Signal Processing Toolbox 基本是硬依赖滤波、重采样、功率谱都靠它Statistics and Machine Learning Toolbox 在统计检验和部分聚类函数里会用到。没有这些工具箱的机器可以先跑通导入和分段但别指望能把整条流水线走完。3. 从原始信号到可用数据集预处理流水线的参数边界EEGLAB 的图形界面把预处理拆成了一串菜单项但真正决定结果质量的不是点哪个按钮而是每一步的参数怎么定。我见过太多人照着教程把流程点完最后 ERP 波形一团糊回头查半天发现是滤波截止频率和基线窗口打架。这一章把导入、滤波、重参考、分段、基线、伪迹剔除串成一条可脚本化的线每一步都给出参数理由。3.1 导入非标准格式与通道定位真实项目里拿到的数据很少是 EEGLAB 原生格式。常见的入口有三类厂商私有格式通过pop_biosig或对应插件读、通用文本/EDF、以及已经转好的.set。以文本矩阵为例导入时需要显式声明采样率和通道数否则 EEGLAB 会按默认值猜。% 从纯文本矩阵导入每行一个通道每列一个采样点 fid fopen(raw_data.txt, r); raw fscanf(fid, %f, [nchan, Inf]); fclose(fid); % 用 pop_importdata 构造 EEG 结构体必须显式给采样率 EEG pop_importdata(dataformat, array, data, raw, ... srate, 1000, nbchan, nchan, xmin, 0); % 补充电极位置优先用标准模板其次用实测坐标文件 EEG pop_chanedit(EEG, lookup, standard_1005.elc); % 保存成 EEGLAB 原生格式后续所有步骤都基于它 EEG pop_saveset(EEG, filename, sub01_raw.set, filepath, out_dir);pop_importdata的dataformat设成array表示直接传内存矩阵如果数据量大到内存吃不消可以改成ascii让它自己读文件。xmin是第一个采样点对应的时间设成 0 还是设成真实起始时刻会影响后面事件对齐做事件相关电位时必须和刺激记录对齐。pop_chanedit的lookup参数会去plugins目录下找电极位置模板文件standard_1005.elc是 10-5 系统的标准位置如果你的帽子是 10-20 系统用standard-10-5-cap385.elp更贴。没有正确电极位置后面做 ICA 成分头皮地形图、做源定位全是错的。注意通道位置缺失时 EEGLAB 不会报错只会让EEG.chanlocs里的X、Y、Z字段为空等到画地形图那一步才炸排查成本很高。3.2 滤波与重参考频率参数怎么定滤波是整条流水线里最容易「玄学」的一步。参数不是拍脑袋定的取决于你下游要做什么。做 ERP 波形分析高通截止放 0.1 Hz 能保住慢波成分但会让基线漂移更明显做 ICA 分解高通必须提到 1 Hz 左右否则慢漂移会被 ICA 当成独立成分分出来白白浪费维度做时频分析或功率谱高通甚至可以放到 0.5 Hz 以下因为你要看的就是低频功率。% 陷波去掉 50 Hz 工频及其谐波国内电网环境默认 50 Hz EEG pop_eegfiltnew(EEG, locutoff, 48, hicutoff, 52, revfilt, 1); % 高通 0.1 Hz保留慢波适合 ERP 分析 EEG pop_eegfiltnew(EEG, locutoff, 0.1, hicutoff, []); % 低通 40 Hz压掉高频肌电同时保住 gamma 以下的分析空间 EEG pop_eegfiltnew(EEG, hicutoff, 40, locutoff, []);三条命令的顺序有讲究先陷波再去趋势先高通再低通。revfilt设成 1 表示反向滤波也就是把 48 到 52 Hz 这一段「挖掉」这是pop_eegfiltnew实现带阻的标准写法。高通和低通分两次调用比一次性写两个截止频率更好排查问题——如果波形出现异常振荡你能立刻定位是哪一级滤波器造成的。pop_eegfiltnew默认用 FIR 滤波器阶数由截止频率和过渡带宽自动推算EEG.srate越高阶数越长计算也越慢。如果数据采样率是 1000 Hz 而你要切 0.1 Hz 高通滤波器阶数可能上千处理几十分钟的数据会明显卡顿。这时候的常见做法是先把数据降采样到 250 或 500 Hz 再滤波降采样之前记得先做一次抗混叠低通。重参考是另一处容易翻车的地方。平均参考average reference要求通道数足够多、覆盖足够全通道数少于 32 的时候用平均参考会把参考电极附近的噪声扩散到所有通道。乳突参考、鼻尖参考则要看实验设计不能随手改。% 平均参考传空数组表示用全部通道的均值做参考 EEG pop_reref(EEG, []); % 指定参考通道例如第 32 号电极时改成 % EEG pop_reref(EEG, 32); % 重参考后检查数据范围异常大值通常意味着参考通道本身坏了 fprintf(数据范围: %.2f ~ %.2f uV\n, min(EEG.data(:)), max(EEG.data(:)));pop_reref(EEG, [])里的空数组不是省略是「用全部通道均值」的语义写成pop_reref(EEG)在某些版本里行为不同显式传参更稳。重参考之后一定要看一眼数值范围正常头皮脑电在几十微伏量级如果出现上万微伏八成是某个坏通道被平均进去了。3.3 分段、基线与伪迹剔除的先后顺序分段epoching把连续数据按事件切成一试一个的片段是整个流程里唯一「不可逆」的操作——切完之后再想改时间窗口就得从头重来。所以事件标记必须先清洗干净。% 先看事件类型分布确认标记字符串拼写 types {EEG.event.type}; [uniq, ~, idx] unique(types); counts accumarray(idx(:), 1); disp(table(uniq, counts, VariableNames, {type, count})); % 按刺激标记分段窗口 -200 ms 到 800 ms EEG pop_epoch(EEG, {S 1, S 2}, [-0.2 0.8], newname, sub01_epoched); % 基线校正用刺激前 200 ms 的均值归零 EEG pop_rmbase(EEG, [-200 0]); % 自动剔除幅度异常的试次阈值按数据质量调 EEG pop_eegthresh(EEG, 1, 1:EEG.nbchan, -100, 100, -0.2, 0.8, 0, 0);事件类型统计那一段别省。真实数据里S 1和S 1中间差一个空格会被当成两个不同事件分段时只匹配到一半试次而你从波形上根本看不出来。pop_epoch的时间窗口单位是秒而pop_rmbase和pop_eegthresh的时间参数单位是毫秒这个不一致是 EEGLAB 的历史遗留写脚本时要格外小心。pop_eegthresh的参数依次是通道组、通道索引、下限、上限、起始时间、结束时间、是否只标记不删除、是否显示进度。最后两个参数设成 0 表示直接剔除。阈值定多少没有标准答案常见起点是 ±75 到 ±100 微伏但如果你的数据里本身就有大幅度的慢波这个阈值会误杀需要先看波形分布再定。分段后的试次数会直接决定后续机器学习模型的样本量。假设你有 40 个试次、剔除掉 15%剩 34 个再分成两类做分类每类十几个样本这种量级下交叉验证的方差会大到结论不可信。这也是为什么脑电分析接机器学习时必须先算清楚样本量而不是先把流水线跑完再说。4. 把 ERP 和功率谱变成机器学习能吃的特征矩阵EEGLAB 本身不是机器学习工具它的定位是「把脏数据洗成干净张量」。往下走的那一步才是脑电分析和人工智能真正接上的地方。这一章给两条特征路线事件相关电位ERP的时域幅值特征以及功率谱密度PSD的频带特征两条路线最终都导出成「样本 × 特征」的二维矩阵可以直接丢进 scikit-learn。4.1 ERP 幅值特征从三维张量到二维矩阵分段之后的EEG.data是「通道 × 时间点 × 试次」的三维数组。机器学习模型要的是二维矩阵所以需要沿时间维度做降维。最直接的做法是取若干个时间窗内的平均幅值而不是把每个采样点都当特征——500 Hz 采样、1000 ms 窗口一个通道就有 500 个点32 个通道直接一万六千维样本才几十个这是典型的维度灾难。% EEG.data 维度: 通道 x 时间点 x 试次 [nchan, ntime, ntrials] size(EEG.data); % 定义感兴趣时间窗毫秒对应经典 ERP 成分 windows [80 120; 170 230; 250 350; 350 500]; % N1 / P2 / N2 / P3 附近 wlabels {N1, P2, N2, P3}; % 预分配特征矩阵每个试次 x (通道数 * 时间窗数) X zeros(ntrials, nchan * size(windows, 1)); for w 1:size(windows, 1) % 把毫秒转成采样点索引并限制在合法范围内 idx round(windows(w, :) / 1000 * EEG.srate) 1; idx max(min(idx, ntime), 1); % 对时间窗求均值压掉单个采样点的噪声 seg mean(EEG.data(:, idx(1):idx(2), :), 2); % 把「通道 x 试次」转置后填进对应列块 X(:, (w-1)*nchan (1:nchan)) squeeze(seg); end % 同时导出标签标签来源是每个试次的事件类型 labels {EEG.epoch.eventtype};这段代码的关键在mean(..., 2)沿第二维时间求均值得到「通道 × 试次」再转置成「试次 × 通道」填进特征矩阵的列块。时间窗的选取要有生理依据N1 在 100 ms 附近、P3 在 300 ms 附近这些是文献里公认的成分随便切窗会让特征失去可解释性。round(...)1那个加一是因为 MATLAB 索引从 1 开始而时间是 0 起点。EEG.epoch.eventtype拿出来的是每个试次对应的事件类型注意它可能是 cell 套 cell 的结构取决于分段时匹配了几个事件。取标签前先用class()看一眼类型是cell就再套一层cellfun((x) x{1}, ...)。4.2 频带功率特征spectopo 与自算 PSDERP 特征只反映锁时活动如果研究关注的是节律性活动比如 alpha 功率变化、theta 与工作记忆的关系就得走功率谱这条路。EEGLAB 自带spectopo做可视化但批量导出特征建议自己算可控性更好。% 参数设定频带边界按经典划分 bands [1 4; 4 8; 8 13; 13 30]; % delta / theta / alpha / beta blabels {delta, theta, alpha, beta}; % 用 pwelch 逐通道逐试次算功率谱 win 2 * EEG.srate; % 2 秒窗频率分辨率 0.5 Hz nover round(win * 0.5); % 50% 重叠 nfft 2^nextpow2(win); Xf zeros(ntrials, nchan * size(bands, 1)); for t 1:ntrials for c 1:nchan [pxx, f] pwelch(squeeze(EEG.data(c, :, t)), win, nover, nfft, EEG.srate); for b 1:size(bands, 1) % 频带内功率积分而不是取峰值 mask f bands(b, 1) f bands(b, 2); val trapz(f(mask), pxx(mask)); Xf(t, (b-1)*nchan c) log10(val); % 对数变换压掉量级差异 end end endpwelch的窗口长度直接决定频率分辨率2 秒窗对应 0.5 Hz 分辨率能分开 theta 和 alpha但时间定位能力差如果研究关注短时事件相关的功率变化得改用 Morlet 小波或pop_newtimef做时频分解代价是特征维度暴涨。trapz做频带内积分比直接取max(pxx)稳因为单个频点的功率受噪声影响极大。最后取log10是必须的脑电功率跨越好几个数量级不取对数的话分类器的权重会被高功率频带完全主导低功率但判别性强的频带被淹没。4.3 导出到 Python 与交叉验证的防泄漏特征矩阵算完下一步是交给 scikit-learn。跨语言传递最稳的格式是 CSV 或者 MAT注意列名要能追溯回「哪个通道的哪个频带」否则模型跑出高准确率你也不知道是哪个特征在起作用。import numpy as np import pandas as pd from sklearn.model_selection import StratifiedKFold, cross_val_score from sklearn.pipeline import make_pipeline from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression # 读 MATLAB 导出的特征与标签假设已在 MATLAB 端写成 CSV X pd.read_csv(features.csv).values y pd.read_csv(labels.csv).values.ravel() # 标准化必须放进 pipeline否则会在交叉验证中泄漏测试集信息 clf make_pipeline( StandardScaler(), LogisticRegression(C0.1, max_iter1000, class_weightbalanced) ) # 分层 K 折保证每折里类别比例一致 cv StratifiedKFold(n_splits5, shuffleTrue, random_state42) scores cross_val_score(clf, X, y, cvcv, scoringbalanced_accuracy) print(fbalanced accuracy: {scores.mean():.3f} /- {scores.std():.3f})这段代码里最容易被忽略的是StandardScaler的位置。很多人先在全体数据上做一次标准化再送进交叉验证测试集的均值和方差就这么泄漏进了训练过程准确率虚高好几个点。把它塞进make_pipeline之后每一折的标准化参数只从该折的训练部分估计这才是干净的做法。class_weightbalanced是脑电分类的常用配置因为试次级别上两类样本几乎不可能完全均衡。评分指标用balanced_accuracy而不是accuracy同样的道理样本不均衡时全猜多数类也能拿到很高的准确率但这个数字没有任何意义。C0.1是给小样本场景加的强正则样本量上到几百以后可以放开调。5. 避坑与排查五个反复出现的翻车现场EEGLAB 的报错信息质量参差不齐有些问题会以完全不相干的形态出现。下面五条是我在不同机器、不同数据上反复遇到的每条按「看到什么 → 为什么 → 怎么办」写清楚。5.1 现象启动后菜单全灰点什么都不响应原因通常是路径注册不完整。eeglab.m启动时会检查functions和plugins是否在搜索路径里缺一个就把对应菜单项禁用但不会弹窗告诉你缺了哪个。还有一种情况是机器上装了多个 EEGLAB 副本path里残留了旧版本的functions函数调用命中了老版本。解决方式是清空再重建路径不要靠addpath往上叠。% 先移除所有含 eeglab 字样的路径再重新注册 p strsplit(path, pathsep); old p(contains(lower(p), eeglab)); if ~isempty(old) rmpath(old{:}); end addpath(D:\tools\eeglab); addpath(genpath(D:\tools\eeglab\functions)); addpath(genpath(D:\tools\eeglab\plugins)); rehash toolboxcache; % 清掉 MATLAB 的函数缓存rehash toolboxcache这一步很多人省掉结果改了路径还是报旧错误因为 MATLAB 缓存了函数句柄。5.2 现象读大文件时 MATLAB 直接卡死或报「Out of memory」原因在于EEG.data默认是double类型每个采样点占 8 字节。64 通道、1000 Hz、30 分钟的数据就是 64 × 1000 × 1800 × 8 ≈ 920 MB再做一次滤波会产生临时副本内存直接翻倍。ICA 分解更狠会把数据矩阵复制好几份。解决办法是三条并用把数据转成single精度、打开option_storedisk让数据落盘、以及在做 ICA 之前先降采样。% 转单精度精度损失对脑电分析可以忽略 EEG.data single(EEG.data); % 打开磁盘存储选项减少常驻内存 pop_editset(EEG, commands, ); % 或在 GUI 里 File Preferences 勾选 Store data in disk file % 降采样到 250 Hz 再做 ICA计算量降一个数量级 EEG pop_resample(EEG, 250);pop_resample内部带抗混叠滤波不需要手动先低通。降采样之后EEG.srate会同步更新后续所有时间参数自动按新采样率换算。5.3 现象画头皮地形图时报「No channel locations」原因是EEG.chanlocs里的坐标字段为空。这个状态从导入那一刻就注定了但一直不影响滤波分段所以很容易被忽略直到最后出图才暴露。补救要在 ICA 之前做因为 ICA 权重矩阵本身不依赖电极位置但成分的头皮投影依赖。用pop_chanedit重新lookup一次标准模板如果实际帽子不是标准排布就得用实测的.elp或.sfp文件。提示确认真实电极位置是否已加载看EEG.chanlocs(1)展开后X、Y、Z是否有非空数值光看labels有名字不算数。5.4 现象脚本在别人机器上能跑自己这里报「参数名无效」pop_eegfiltnew是老函数新版本 EEGLAB 里部分pop_*函数改成了inputParser风格参数名从位置参数变成名称-值对大小写、连字符都有讲究。压缩包里的版本固定但你在网上抄的代码可能来自另一个版本。排查方法是直接看函数源码的头几行注释那里的参数说明就是当前版本的权威定义。% 只看参数说明不执行 help pop_eegfiltnew % 或者直接打开源码 edit pop_eegfiltnew比help更快的办法是用nargin和inputParser的addParameter那几行CtrlF搜addParameter就能列出所有合法参数名。这比对着报错试参数快得多。5.5 现象分段后试次数比预期少一半原因九成是事件标记的字符串不匹配。厂商设备导出的标记可能带前导空格、可能是数字而不是字符串、可能被转成了S 1这种双空格形式。pop_epoch做的是精确字符串匹配差一个字符就整类漏掉。处理办法是先做一次全量统计把事件类型和出现次数打出来对照实验记录。% 统计所有事件类型及其出现次数 types {EEG.event.type}; if ~iscellstr(types) types cellfun(num2str, types, UniformOutput, false); end [uniq, ~, idx] unique(types); counts accumarray(idx(:), 1); disp(sortrows(table(uniq, counts, VariableNames, {type, count})));如果发现数字类型和字符串类型混在一起先统一成字符串再匹配。这一段代码建议固化进你的预处理脚本开头每次跑之前自动打印一遍比事后追查划算得多。6. 批处理脚本与质量校验表把流程钉死单个被试跑通不代表流程可用真正的检验是「换一个被试的文件脚本不改一行也能跑完」。我的做法是把预处理写成接受文件路径的函数外部用dir遍历每个被试输出一行质量指标到汇总表里跑完一次性检查。function summary preprocess_one(setfile, out_dir) % 单个被试的完整预处理返回一行质量指标 [~, name, ~] fileparts(setfile); try EEG pop_loadset(setfile); EEG pop_eegfiltnew(EEG, locutoff, 48, hicutoff, 52, revfilt, 1); EEG pop_eegfiltnew(EEG, locutoff, 0.1, hicutoff, []); EEG pop_eegfiltnew(EEG, hicutoff, 40, locutoff, []); EEG pop_reref(EEG, []); EEG pop_epoch(EEG, {S 1, S 2}, [-0.2 0.8]); n_before EEG.trials; EEG pop_rmbase(EEG, [-200 0]); EEG pop_eegthresh(EEG, 1, 1:EEG.nbchan, -100, 100, -0.2, 0.8, 0, 0); EEG pop_saveset(EEG, filename, [name _clean.set], filepath, out_dir); % 汇总一行质量指标 summary table({name}, n_before, EEG.trials, ... EEG.trials / n_before, {EEG.srate}, ... VariableNames, {subject, n_epoch_before, n_epoch_after, ... keep_ratio, srate}); catch ME % 单个被试失败不能中断整批 summary table({name}, NaN, NaN, NaN, NaN, ... VariableNames, {subject, n_epoch_before, n_epoch_after, ... keep_ratio, srate}); fprintf([FAIL] %s: %s\n, name, ME.message); end endtry-catch不是偷懒是批处理必备。一个被试的数据坏了就让整晚的计算白跑这种亏吃过一次就记住了。表里保留keep_ratio这个字段跑完直接按它排序比值低于 0.7 的被试单独拎出来看波形比值高于 0.98 的也要看——可能是阈值设太松伪迹全放过去了。质量校验这块我给一张常用的阈值参考表具体数值要按自己的数据分布调不要照抄。指标合理区间超出后的常见原因试次保留率 keep_ratio0.7 – 0.95偏低是坏通道或阈值过严偏高是阈值过松单通道标准差5 – 50 微伏超过 100 通常是电极脱落或阻抗异常分段后总试次每类 ≥ 30低于此数值分类结论不可信事件类型唯一值数与实验设计一致多出来是标记字符串格式不统一降采样后采样率250 或 500 Hz太低会切掉 40 Hz 以上成分这张表的用法不是逐项打勾而是先按keep_ratio排序看两端再用通道标准差定位坏通道。发现某个通道标准差超过 100 微伏先在原始连续数据上画那段波形确认是物理接触问题还是数据处理引入的前者只能重新采集或整通道剔除后者回头查滤波和重参考的顺序。还有一个细节批处理脚本里所有输出文件名都带上被试编号和预处理日期sub01_clean_20240115.set这种命名方式比cleaned.set强太多。半年后回头看你唯一能依靠的就是文件名里的信息。从那以后我每次搭新环境都强制先跑一遍示例数据的冒烟测试再拿一个已知结果正常的被试跑完整流程对照两项都对上才开始批量。这个习惯帮我拦下过好几次「路径指向旧版本」「电极位置文件缺失」这类只在批处理里才暴露的问题。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑