[FieldTrip] Computing virtual channel ERFs within a source-level contrast's mask
Barnett, Benjy
benjy.barnett.20 at ucl.ac.uk
Tue Dec 12 17:47:54 CET 2023
Hey Guys,
I’m trying to make sense of some source-space analyses I’ve done and I wondered if I could get some expert input. I have computed a source-level contrast between condition A and B across subjects. Each subject performed both conditions. Specifically, I ran a one tailed test to reveal clusters where condition A showed significantly greater activation than condition B. My code to run this contrast is here:
%Group Stats
cfg=[];
cfg.dim = grandavgA{1}.dim;
cfg.method = 'montecarlo';
cfg.statistic = 'ft_statfun_depsamplesT';
cfg.parameter = 'pow';
cfg.correctm = 'cluster';
cfg.numrandomization = 1000;
cfg.clusteralpha = 0.05;
cfg.alpha = 0.05;
cfg.tail = 1; %One tailed, see where A>B (I hope??)
nsubj=numel(grandavgZero);
cfg.design(1,:) = [1:nsubj 1:nsubj];
cfg.design(2,:) = [ones(1,nsubj)*1 ones(1,nsubj)*2];
cfg.uvar = 1; % row of design matrix that contains unit variable (in this case: subjects)
cfg.ivar = 2; % row of design matrix that contains independent variable (the conditions)
stat = ft_sourcestatistics(cfg,grandavgA{:}, grandavgB{:}); %where grandavgA etc. are cell arrays containing subject-level source reconstructions of condition A and B separately
This contrast reveals a large, significant occipito/parietal/temporal cluster where condition A has greater activity than B. I am then using this positive cluster mask as an ROI to create virtual channels and visualise the source-level ERFs for both condition A and B. I do this for each subject, warping the MNI coordinates of the cluster to individual subject-specific space, calculating virtual channels for each of the N pos within the cluster mask, giving me N*3 (multiplied by 3 for each XYZ direction of the dipole) virtual channels for each trial for each condition. The relevant code to do this per subject is here:
gridpos= ft_warp_apply(M,stat.pos(stat.mask,:));%Calculate spatial filter for each voxel over all data
%Calculate spatial filter for each voxel over all data
cfg = [];
cfg.method = 'lcmv';
cfg.sourcemodel = sourcemodel; %subject specific source model
cfg.sourcemodel.pos = gridpos;
cfg.sourcemodel.inside = true(length(cfg.sourcemodel.pos),1);
cfg.unit = sourcemodel.unit;
cfg.headmodel = headmodel;
cfg.lcmv.keepfilter = 'yes';
cfg.lcmv.lambda = '5%';
cfg.channel = {'MEG'};
cfg.senstype = 'MEG';
sourceavg = ft_sourceanalysis(cfg, avg);
dot_filter = cell2mat(sourceavg.avg.filter);
chansel = ft_channelselection('MEG', meg_data.label); % find MEG sensor names
chanindx = match_str(meg_data.label, chansel);
for c = 1:length(conditions)
cond = conditions(c);
if strcmp(cond,’A’)
cfg = [];
cfg.trials = meg_data.trialinfo(:,5) == c;
data = ft_selectdata(cfg,dot_trials);
elseif strcmp(cond,’B’)
cfg = [];
cfg.trials = meg_data.trialinfo(:,5) == c;
data = ft_selectdata(cfg,dot_trials);
end
condvc = [];
condvc.label = {'x' 'y' 'z'};
condvc.time = data.time;
for i = 1:length(data.trial)
condvc.trial{i} = dot_filter * data.trial{i}(chanindx,:); %compute virtual channel
end
cfg = [];
avgcond = ft_timelockanalysis(cfg,condvc);%compute subject level ERF for each condition
VCs{subj,cond} = avgcond;
end
The issue is that once I’ve taken the grand average of the virtual channel ERFs per each condition across subjects, the ERF for condition B (blue) is statistically significantly greater than condition A (red) across the timepoints the original source contrast was computed over. This seems completely backwards. Surely my process is essentially double-dipping, and I should see a greater ERF for condition A over condition B, given that I'm using virtual channels computed within a cluster where A was significantly greater than B at the whole brain level. I’ve tried it this way but also just using the peak voxel within the cluster based on the t-stat, but I get the same counterintuitive pattern of ERF results.
%% Compute Grand Avg over Subjects
cfg = [];
cfg.channel = 'all';
cfg.latency = 'all';
cfg.parameter = 'avg';
grandavg_A = ft_timelockgrandaverage(cfg,VCs{:,1});
grandavg_B = ft_timelockgrandaverage(cfg,VCs{:,2});
%% Plot Average Source-Level ERF For Zero vs non-zero
cfg = [];
cfg.channel = 'all';
%cfg.showlegend = 'yes';
cfg.linewidth = 1.75;
cfg.linecolor = [1,0,0; 0,0,1];
ft_singleplotER(cfg, grandavg_A, grandavg_B);
Am I thinking about this in the correct way, or have I made some error in my code? I’ve not copied my entire scripts so as not to clutter this question, but I hope I have supplied enough for you to follow my method.
All the best,
Benjy
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.science.ru.nl/pipermail/fieldtrip/attachments/20231212/193de425/attachment.htm>
More information about the fieldtrip
mailing list