ERP学习笔记-频域分析之小波变换fieldtrip

**频域分析:**在不同的频率下数据的情况

**注意:**本脚本使用的是fieldtrip-20170830,不要轻易更改版本,可能会报错

修改后代码可以根据Cond_all自动运行每个不同条件的数据,并保存为struct格式

第一步:条件设置

Matlab 复制代码
%定义每个条件的marker信息
Cond_all = {'B1(S57)','onlygo-go-cue';'B2(S77)','onlygo-go-go';'B3(S41)','uninf-go-cue';'B4(S61)','uninf-go-go'}';

第二步:将数据转换为fieldtrip可以分析的格式

基础代码
Matlab 复制代码
%% Transform data
%定义数据所在的路径
data_root = 'E:\data';
%筛选路径下所有set格式的文件
filenames = dir([data_root, filesep, '*.set']);
%提取文件的个数信息
subj_num = length(filenames);
%创建空胞元以储存后续信息
all_EEG = cell(subj_num,1);%所有的
all_EEG_B1 = cell(subj_num,1);%条件B1
all_EEG_B2 = cell(subj_num,1);%条件B2
all_EEG_B3 = cell(subj_num,1);
%对于每个被试
for i = 1:subj_num
    %拼接数据的绝对路径
    fn = [data_root, filesep, filenames(i).name];
    %导入subj_num被试的数据
    EEG = pop_loadset(fn);
    %分别提取B1 B2 B3条件的数据
    %对应eeglab中条件的mark形式,以及关注的时间段
    %如果读取的数据没有进行基线校正,这里需要进行基线校正
    EEG_B1 = pop_epoch(EEG, {'B1(S11)'},[-0.5 3]);
    EEG_B2 = pop_epoch(EEG, {'B2(S12)'},[-0.5 3]);
    EEG_B3 = pop_epoch(EEG, {'B3(S13)'},[-0.5 3]);
    %分别储存所有数据 B1 B2 B3条件的数据
    all_EEG{i} = EEG;
    all_EEG_B1{i} = EEG_B1;
    all_EEG_B2{i} = EEG_B2;
    all_EEG_B3{i} = EEG_B3;
end
%保存数据为mat文件
save('all_EEG.mat','all_EEG');
save('all_EEG_B1.mat','all_EEG_B1');
save('all_EEG_B2.mat','all_EEG_B2');
save('all_EEG_B3.mat','all_EEG_B3');
%% eeglab 2 fieldtrip
%创建空胞元以储存后续信息
all_data = cell(subj_num,1);
all_data_B1 = cell(subj_num,1);
all_data_B2 = cell(subj_num,1);
all_data_B3 = cell(subj_num,1);
%对于每个被试
for i=1:subj_num
    %对第i个被试进行数据格式转化
    all_data{i} = eeglab2fieldtrip(all_EEG{i}, 'preprocessing');
    all_data_B1{i} = eeglab2fieldtrip(all_EEG_B1{i}, 'preprocessing');
    all_data_B2{i} = eeglab2fieldtrip(all_EEG_B2{i}, 'preprocessing');
    all_data_B3{i} = eeglab2fieldtrip(all_EEG_B3{i}, 'preprocessing');
end
%保存数据为mat文件
save('data_transformed.mat','all_data','all_data_B1','all_data_B2','all_data_B3');
修改后代码
Matlab 复制代码
%% Transform data
%% 基础设置
%epochs的开始时间
time_start = -0.5;%%%%%%需修改
%epochs的结束时间
time_end = 1;%%%%%%需修改
%epochs的时间段
time_epoch = [time_start time_end];
%基线校正的时间段
time_baseline = [time_start*1000 0];
%定义数据所在的路径
data_root = path_re_ref;%%%%%%需修改
%筛选路径下所有set格式的文件
filenames = dir([data_root, filesep, '*.set']);
%提取文件的个数信息
subj_num = length(filenames);
%% 创建空胞元以储存后续信息,自动根据Cond_all生成
% 提取第一列的所有B编号
b_names = Cond_all(1,:);
% 创建结构体来存储所有EEG数据
all_EEG = struct();
data_transf = struct();
% all_EEG.all = cell(subj_num, 1);
% 循环创建cell数组
for i = 1:length(b_names)
    % 使用正则表达式提取B编号(如B3、B4、B10等)
    b_match{i} = regexp(b_names{i}, 'B\d+', 'match');
    field_name = char(b_match{i});  % 直接使用匹配到的B编号
    all_EEG.(field_name) = cell(subj_num, 1);%保存初始数据
    data_transf.(field_name) = cell(subj_num, 1);%保存eeglab 2 fieldtrip后数据
end
%% 读取eeglab中的数据,分条件保存到all_EEG中,并转换数据保存到data_transf中
%对于每个被试
for nsub = 1:subj_num
    %拼接数据的绝对路径
    fn = [data_root, filesep, filenames(nsub).name];
    %导入subj_num被试的数据
    EEG = pop_loadset(fn);
    % all_EEG.all{nsub} = EEG;
    %遍历每个条件,分别提取B1 B2 B3条件的数据
    %对应eeglab中条件的mark形式,以及关注的时间段
    %如果读取的数据没有进行基线校正,这里需要进行基线校正
    for i = 1:length(b_match)
        b_name = char(b_match{i});  % 如 'B3', 'B4'
        b_epoch_name = b_names{i};  % 如 'B3(S41)', 'B4(S61)'
        % 处理EEG数据
        EEG_temp = pop_epoch(EEG, {b_epoch_name}, time_epoch);
        EEG_temp = pop_rmbase(EEG_temp, time_baseline, []);
        % eeglab 2 fieldtrip
        data_temp = eeglab2fieldtrip(EEG_temp, 'preprocessing');
        % 存储到结构体
        all_EEG.(b_name){nsub} = EEG_temp;
        data_transf.(b_name){nsub} = data_temp;
    end
end
%保存数据为mat文件
save('all_EEG.mat','all_EEG');
save('data_transf.mat','data_transf');

第三步:进行小波变换和基线校正

基础代码
Matlab 复制代码
%%
load('data_transformed.mat')
%提取被试的数量
subj_num = length(all_data);
%创建空胞元以保存后续信息
all_data_tf = cell(subj_num,1);
all_data_tf_B1 = cell(subj_num,1);
all_data_tf_B2 = cell(subj_num,1);
all_data_tf_B3 = cell(subj_num,1);
cfg = [];
cfg.method     = 'wavelet';
cfg.keeptrials =  'no';
cfg.output     = 'pow';
cfg.foi        = 3:1:40;%关注频段
% cfg.width      = 7;
cfg.width      = linspace(3,7,length(cfg.foi));
cfg.toi        = -0.5:0.001:1;	%关注时间段
cfg.pad = 'nextpow2';% more efficient FFT computation than the default 'maxperlen'
%对于每一个被试
for  i = 1:subj_num
    %根据cfg中的指定参数,对data进行时频变换
    %dimord与powspctrm中的内容是对应的
    all_data_tf{i} = ft_freqanalysis(cfg,all_data{i});
    all_data_tf_B1{i} = ft_freqanalysis(cfg,all_data_B1{i});
    all_data_tf_B2{i} = ft_freqanalysis(cfg,all_data_B2{i});
    all_data_tf_B3{i} = ft_freqanalysis(cfg,all_data_B3{i});
end
save('data_tf.mat','all_data_tf','all_data_tf_B1','all_data_tf_B2','all_data_tf_B3');

基线校正,以all_data_tf为例

Matlab 复制代码
%% 以all_data_tf为例
load('data_tf.mat')
%% 基线校正
load data_tf.mat
cfg = [];
cfg.baseline = [-0.5 0];%需要根据自己的数据修改
cfg.baselinetype =  'relchange';
cfg.parameter = 'powspctrm';
for i = 1:length(all_data_tf)
    all_data_baseline_tf{1,i} = ft_freqbaseline(cfg, all_data_tf{1,i});
end
save('data_tf_baseline.mat','all_data_baseline_tf');
修改后代码
Matlab 复制代码
%% 小波变换
load('data_transf.mat')
%% 提取被试的数量
% 获取结构体的所有字段名
fields = fieldnames(data_transf);
first_field_data = data_transf.(fields{1});
subj_num = size(first_field_data, 1);
%% 创建空胞元以保存后续信息
data_TFR = struct();
data_TFR_baseline = struct();
% 提取第一列的所有B编号
b_names = Cond_all(1,:);
% 循环创建cell数组
for i = 1:length(b_names)
    % 使用正则表达式提取B编号(如B3、B4、B10等)
    b_match{i} = regexp(b_names{i}, 'B\d+', 'match');
    field_name = char(b_match{i});  % 直接使用匹配到的B编号
    data_TFR.(field_name) = cell(subj_num, 1);%保存小波变换后数据
    data_TFR_baseline.(field_name) = cell(subj_num, 1);%保存基线校正后的数据
end
%% 时频变换和基线校正
cfg = [];
cfg.method     = 'wavelet';
cfg.keeptrials =  'no';
cfg.output     = 'pow';
cfg.foi        = 3:1:40;%关注频段
% cfg.width      = 7;
cfg.width      = linspace(3,7,length(cfg.foi));
cfg.toi        = -0.5:0.001:1;	%关注时间段
cfg.pad = 'nextpow2';% more efficient FFT computation than the default 'maxperlen'
%基线校正
cfg.baseline = [-0.5 0];%%%%%%需修改
cfg.baselinetype =  'relchange';
cfg.parameter = 'powspctrm';
%对于每一个被试
for  nsub = 1:subj_num
    %根据cfg中的指定参数,对data进行时频变换
    %dimord与powspctrm中的内容是对应的
    for i = 1:length(b_match)
        b_name = char(b_match{i});  % 如 'B3', 'B4'
        data_TFR.(b_name){nsub} = ft_freqanalysis(cfg,data_transf.(b_name){nsub});%时频变换
        data_TFR_baseline.(b_name){nsub} = ft_freqbaseline(cfg,data_TFR.(b_name){nsub});%基线校正
    end
end
save('data_TFR.mat','data_TFR');
save('data_TFR_baseline.mat','data_TFR_baseline');

第四步:画图

基础代码

以all_data_tf为例

Matlab 复制代码
%% 画图
load data_tf_baseline.mat
cfg = [];
cfg.channel = 'all';
%进行时频维度的组水平叠加平均
group_data_tf = ft_freqgrandaverage(cfg,all_data_tf{:});
%% 绘制所有通道的时频图,按照通道位置摆放
cfg = [];
%定义通道排布系统
cfg.layout = 'EEG1005.lay';
%是否可以界面交互
cfg.interactive = 'yes';
%是否绘制头轮廓
cfg.showoutline = 'yes';
%绘图
ft_multiplotTFR(cfg,group_data_tf);
%% 绘制单幅时频图,按照通道
cfg = [];
%定义通道排布系统
cfg.layout = 'EEG1005.lay';
%选择的通道
%如果cfg.channel中定义了多个通道,则是绘制这多个通道的均值
%cfg.channel = {'Cz','Fz'};
%如果像绘制单个通道的时频图,则
cfg.channel = 'Cz';
%绘图
ft_multiplotTFR(cfg,group_data_tf);
%% 绘制特定时频域下的地形图
cfg = [];
%定义通道排布系统
cfg.layout = 'EEG1005.lay';
%感兴趣的时间段
cfg.xlim = [0.08 0.42];
%感兴趣频率段
cfg.ylim = [8 13];
%定义colorbar
cfg.zlim = [-5.21e+06 5.21e+06];
%绘图
ft_multiplotTFR(cfg,group_data_tf);
相关推荐
MarkHD16 小时前
智能体在车联网中的应用:第51天 模仿学习与离线强化学习:破解数据效率与安全困局的双刃剑
学习·安全
Drawing stars19 小时前
JAVA后端 前端 大模型应用 学习路线
java·前端·学习
崇山峻岭之间19 小时前
Matlab学习记录33
开发语言·学习·matlab
玄〤20 小时前
黑马点评中 VoucherOrderServiceImpl 实现类中的一人一单实现解析(单机部署)
java·数据库·redis·笔记·后端·mybatis·springboot
科技林总20 小时前
【系统分析师】3.5 多处理机系统
学习
芯思路21 小时前
STM32开发学习笔记之三【按键】
笔记·stm32·学习
Lips61121 小时前
2026.1.11力扣刷题笔记
笔记·算法·leetcode
charlie1145141911 天前
从 0 开始的机器学习——NumPy 线性代数部分
开发语言·人工智能·学习·线性代数·算法·机器学习·numpy
咚咚王者1 天前
人工智能之核心基础 机器学习 第十二章 半监督学习
人工智能·学习·机器学习
袁气满满~_~1 天前
Python数据分析学习
开发语言·笔记·python·学习