[FieldTrip] Source fitting with template MRI/Headmodel

Tommy Wilson tommy.wilson at med.einstein.yu.edu
Wed Jan 25 17:13:23 CET 2017


Hi Matt,

Thanks so much for your reply here!

I believe I've correctly implemented your comments: I computed a common
filter by source analyzing the combined (read: averaged) data/covariance
matrix. In a second step, I used this filter to source localize each
condition separately. I subsequently contrasted the two conditions, but I'm
seeing that sourceU.avg.pow > sourceA.avg.pow at about 99% of the voxels. I
attached an image of the ft_sourceplot to this email. (I don't know why the
NaNs aren't masking appropriately, but I can figure that out on my own
time).

I also attempted your quick and dirty solution to see if I could reproduce
that, and I'm seeing the same thing as above (sourceU.avg.pow > sourceA.avg.pow
in 99% of voxels), which is exactly the opposite of what you said you came
up with. (The ft_sourceplot for this scenario looks identical to the first,
which is unsurprising--in both cases, we used the average covariance matrix
to construct the filters, so they ought to be identical). I must be doing
something wrong here, but alas, I can't seem to put the pieces together.

Any help/guidance you could provide would be deeply appreciated. I've
attached the updated script to this email (and printed it below for
posterity), and as before, the data can be found here
<https://www.dropbox.com/s/8w99ejwrzmwc5pt/Source_fitting_dump.mat?dl=0>.

Again, thank you for taking the time to respond.

Best,

Tommy

--- CODE ---

%% Source fitting protocol
% Fieldtrip path (to find template MRI)
ftdir = 'your\path\here\fieldtrip-20160309';

% Average both conditions to generate common filter
M = ft_timelockgrandaverage(struct(),A,U);
M.cov = mean(cat(3,A.cov,U.cov),3);

% Equate covariance matrices for now to rule out any differences in the
% source fit due to differences in covariances
% A.cov = U.cov;

%%% Do the LCMV sourcefitting
cfg                     = [];
cfg.method              = 'lcmv';
cfg.grid                = leadfield;
cfg.vol                 = vol;
cfg.elec                = elec;
cfg.lcmv.lambda         = '15%';
cfg.lcmv.keepfilter     = 'yes';
cfg.lcmv.fixedori       = 'yes';
cfg.lcmv.projectnoise   = 'yes';

% Generate common filter
sourceM = ft_sourceanalysis(cfg,M);

% Add the common filter to the cfg
cfg.grid.filter = sourceM.avg.filter;

% Source fit the originals
sourceA = ft_sourceanalysis(cfg,A);
sourceU = ft_sourceanalysis(cfg,U);

%%% Matt's quick and dirty version
% Replace A's cov matrix with an average of A.cov and U.cov
tmp = A.cov;
A.cov = mean(cat(3,tmp,U.cov),3);

cfg                     = [];
cfg.method              = 'lcmv';
cfg.grid                = leadfield;
cfg.vol                 = vol;
cfg.elec                = elec;
cfg.lcmv.lambda         = '15%';
cfg.lcmv.keepfilter     = 'yes';
cfg.lcmv.fixedori       = 'yes';
cfg.lcmv.projectnoise   = 'yes';

% Generate common test filter
sourceA_common_test = ft_sourceanalysis(cfg,A);

% Add common filter to configuration
cfg.grid.filter = sourceA_common_test.avg.filter;

% Replace original covariance matrix
A.cov = tmp;

% Now fit both A and U with the common test filter
sourceA_test = ft_sourceanalysis(cfg,A);
sourceU_test = ft_sourceanalysis(cfg,U);


%%% Attempt a contrast
% Create the contrasts
sourceContrast = sourceA;
sourceContrast.avg.pow = sourceA.avg.pow - sourceU.avg.pow;
sourceContrast_test = sourceA_test;
sourceContrast_test.avg.pow = sourceA_test.avg.pow - sourceU_test.avg.pow;

% Gauge what percent of the contrast is negative (i.e. sourceU power >
% sourceA power)
perc_neg =
sum(sourceContrast.avg.pow(sourceContrast.inside(:))<0)./numel(sourceContrast.avg.pow(sourceContrast.inside(:)));
perc_neg_test =
sum(sourceContrast_test.avg.pow(sourceContrast_test.inside(:))<0)./numel(sourceContrast_test.avg.pow(sourceContrast_test.inside(:)));

%%% Visualize the output
% Load template MRI
mri = ft_read_mri([ftdir '\template\anatomy\single_subj_T1.nii']);

% Interpolate source onto MRI
cfg            = [];
cfg.parameter  = 'avg.pow';
sourceContrast_interp  = ft_sourceinterpolate(cfg, sourceContrast, mri);
sourceContrast_test_interp = ft_sourceinterpolate(cfg, sourceContrast_test,
mri);

% Visualize with ft_sourceplot
cfg = [];
cfg.method        = 'ortho';
cfg.funparameter  = 'avg.pow';
cfg.funcolorlim   = [-100 5];
cfg.maskparameter = cfg.funparameter;
ft_sourceplot(cfg, sourceContrast_interp);

cfg = [];
cfg.method        = 'ortho';
cfg.funparameter  = 'avg.pow';
cfg.funcolorlim   = [-100 5];
cfg.maskparameter = cfg.funparameter;
ft_sourceplot(cfg, sourceContrast_test_interp);

On Tue, Jan 24, 2017 at 4:12 PM Matt Craddock <m.p.craddock at leeds.ac.uk>
wrote:

> Hi Tommy,
>
>  > % Equate covariance matrices for now to rule out any differences in the
>  > % source fit due to differences in covariances
>  > U.cov = A.cov;
>  >
>
> This is the problem. ft_sourceanalysis is using the covariance matrix
> and leadfield to construct a spatial filter for each grid point; if the
> covariance matrices are equivalent, the source solutions will be too.
>
> What you need to do is something like run the source analysis on data
> averaged over both conditions first, then take the filter from the
> combined analysis and run source analysis on each condition seperately.
>
> so say sourceAll is the result of
> ft_sourceanalysis(cfg,bothConditions)
>
> You'd do
>
> cfg.grid.filter = sourceAll.avg.filter
>
> then
>
> ft_sourceanalysis(cfg,A)
> ft_sourceanalysis(cfg,U)
>
> As a quick and dirty version I just replaced the covariance matrix in A
> with the average of the two A.cov and U.cov, ran sourceanalysis on that,
> then put A.cov back to its original value and ran sourceanalysis on each
> condition seperately. Spoiler: the unattended condition has lower
> activity everywhere :)
>
> There's some weirdness around the boundaries of the headmodel, not sure
> what's causing that exactly. Maybe try using a different source grid
> instead of the standard one...
>
> Cheers,
> Matt
>
> On 24/01/2017 16:36, Tommy Wilson wrote:
> > Hi Julian,
> >
> > Thank you so much for your reply.
> >
> > I've pasted the commented code below (I apologize for the code dump).
> > I've also attached an m-file to this email if you'd prefer to download
> > it that way. If relevant, you can download the leadfield, headmodel and
> > electrode locations here
> > <https://www.dropbox.com/s/8w99ejwrzmwc5pt/Source_fitting_dump.mat?dl=0>
> > (that file also includes the raw data stored in variables A and U that I
> > am attempting to source-fit).
> >
> > As per your questions: I do indeed have a contrast between attended (A)
> > and unattended (U) conditions. I've written the code below to source-fit
> > both conditions and create the contrast. However, despite that the raw
> > topographies (see attached images) are different, the source-fits are
> > the same (...?). As a consequence, the contrast has no non-zero values.
> > If instead, I normalize to noise (i.e. generate the Neural Activity
> > Index
> > <http://www.fieldtriptoolbox.org/tutorial/beamformer#
> neural_activity_index>)
> > and look at a contrast there, we again see no non-zero values.
> >
> > Outside of the contrast, I've implemented your other suggestions. I've
> > rescaled the original ft_sourceplot such that you can see the extent of
> > it (see attached image). To my mind, it shouldn't look like this, but
> > having never done this before, I'm not quite sure what to expect. I've
> > also included an image of the ft_sourceplot for the Neural Activity
> > Index of sourceA which also appears to me to be artefactual. More to the
> > point, I'd expect that since the topographies for A and U are different,
> > the NAIs should be different, which is not the case.
> >
> > I'm sort of at a loss about how to proceed here. So, thank you very much
> > for taking the time to look into this. If I can supply anything else to
> > help, please don't hesitate to let me know.
> >
> > Best,
> >
> > Tommy Wilson
> >
> > --- CODE ---
> >
> > %% Source fitting protocol
> > % Fieldtrip path (to find template MRI)
> > ftdir = 'your\path\here\';
> >
> > % Equate covariance matrices for now to rule out any differences in the
> > % source fit due to differences in covariances
> > U.cov = A.cov;
> >
> > %%% Do the LCMV sourcefitting
> > cfg                     = [];
> > cfg.method              = 'lcmv';
> > cfg.grid                = leadfield;
> > cfg.vol                 = vol;
> > cfg.elec                = elec;
> > cfg.lcmv.lambda         = '15%';
> > cfg.lcmv.keepfilter     = 'yes';
> > cfg.lcmv.fixedori       = 'yes';
> > cfg.lcmv.projectnoise   = 'yes';
> >
> > sourceA = ft_sourceanalysis(cfg,A);
> > sourceU = ft_sourceanalysis(cfg,U);
> >
> >
> > %%% Attempt a contrast
> > % Create the contrast
> > sourceContrast = sourceA;
> > sourceContrast.avg.pow = sourceA.avg.pow - sourceU.avg.pow;
> >
> > % Check to see if any non-zero values exist in the contrast
> > if all(sourceContrast.avg.pow(sourceContrast.inside(:)) == 0)
> >     warning('No non-zero contast values exist. ft_sourceplot will give
> > an error. Do not plot.');
> > end
> >
> >
> > %%% Instead of a contrast, look at the Neural Activity Index (NAI)
> > % See:
> > http://www.fieldtriptoolbox.org/tutorial/beamformer#
> neural_activity_index
> > sourceA_NAI = sourceA;
> > sourceA_NAI.avg.pow = sourceA.avg.pow./sourceA.avg.noise;
> > sourceU_NAI = sourceU;
> > sourceU_NAI.avg.pow = sourceU.avg.pow./sourceU.avg.noise;
> >
> > if all(sourceA_NAI.avg.pow(sourceA_NAI.inside(:)) -
> > sourceU_NAI.avg.pow(sourceU_NAI.inside(:))==0)
> >     warning('No non-zero contast values exist. ft_sourceplot will give
> > an error. Do not plot.')
> > end
> >
> >
> > %%% Visualize the output
> > % Load template MRI
> > mri = ft_read_mri([ftdir
> > '\fieldtrip-20160309\template\anatomy\single_subj_T1.nii']);
> >
> > % Interpolate source onto MRI
> > cfg            = [];
> > cfg.parameter  = 'avg.pow';
> > sourceA_interp  = ft_sourceinterpolate(cfg, sourceA, mri);
> > sourceA_NAI_interp  = ft_sourceinterpolate(cfg, sourceA_NAI, mri);
> >
> > % Visualize with ft_sourceplot
> > cfg = [];
> > cfg.method        = 'ortho';
> > cfg.funparameter  = 'avg.pow';
> > cfg.funcolorlim   = [0 3e3];
> > cfg.maskparameter = cfg.funparameter;
> > ft_sourceplot(cfg, sourceA_interp);
> >
> > cfg = [];
> > cfg.method        = 'ortho';
> > cfg.funparameter  = 'avg.pow';
> > cfg.maskparameter = cfg.funparameter;
> > ft_sourceplot(cfg, sourceA_NAI_interp);
> >
> > On Tue, Jan 24, 2017 at 3:42 AM Julian Keil <julian.keil at gmail.com
> > <mailto:julian.keil at gmail.com>> wrote:
> >
> >     Hi Tommy,
> >
> >     did you do some sort of contrast (e.g. with the noise estimate or a
> >     baseline) after your source analysis?
> >     Right now, it's not clear what you are looking at. Could you paste
> >     your code not only of the sourceanalysis, but the rest after which
> >     got you to the plot?
> >     It might also be the case that the automatic scaling in the source
> >     plot throws you off - maybe try setting it by hand.
> >
> >     Good luck,
> >
> >     Julian
> >
> >     Am 23.01.2017 um 22:00 schrieb Tommy Wilson:
> >
> >     > Hi all,
> >     >
> >     > I'm working with EEG data and I'm trying to get some basic source
> >     fitting up and running. Unfortunately, I don't have individual
> >     subject MRIs, so I'm using the templates provided by fieldtrip. I've
> >     co-registered my 160 Biosemi electrodes to the standard_bem template
> >     (see attached picture). For the sourcemodel, I'm using the
> >     standard_sourcemodel3d5mm grid (picture attached, overlaid on
> >     standard_bem). I can prepare the leadfield from there with
> >     ft_prepare_leadfield (cfg.normalize = 'yes'), as per the LCMV
> tutorial.
> >     >
> >     > To test this configuration, I've selected a time window in my data
> >     and averaged across it (the covariance matrix was also calculated);
> >     the topography of this averaged data is attached. I then attempted a
> >     source fit with the LCMV beamformer:
> >     >
> >     > cfg                     = [];
> >     > cfg.method              = 'lcmv';
> >     > cfg.grid                = leadfield;
> >     > cfg.vol                 = vol;
> >     > cfg.elec                = elec;
> >     > cfg.lcmv.lambda         = '15%';
> >     > cfg.lcmv.keepfilter     = 'yes';
> >     > cfg.lcmv.fixedori       = 'yes';
> >     > cfg.lcmv.projectnoise   = 'yes';
> >     >
> >     > sourceA = ft_sourceanalysis(cfg,A);
> >     >
> >     > After interpolating to the single_subj_T1.nii provided with
> >     ft_sourceinterpolate and plotting with ft_sourceplot, I am given a
> >     sourceplot that is highly focal in nature (see attached picture).
> >     >
> >     > I'd find it very surprising if this topography were generated
> >     primarily by a source that isn't even inside the brain (as the
> >     sourceplot indicates). So, I'm not sure exactly where/how I'm going
> >     wrong with this one, nor am I sure how to trouble shoot it. Any
> >     guidance you might provide would be greatly appreciated.
> >     >
> >     > Thanks so much,
> >     >
> >     > Tommy
> >     >
> >     > <Grid.PNG><Electrode
> >     localization.PNG><Topo.PNG><Source.PNG>___________________
> ____________________________
> >     > fieldtrip mailing list
> >     > fieldtrip at donders.ru.nl <mailto:fieldtrip at donders.ru.nl>
> >     > https://mailman.science.ru.nl/mailman/listinfo/fieldtrip
> >
> >     _______________________________________________
> >     fieldtrip mailing list
> >     fieldtrip at donders.ru.nl <mailto:fieldtrip at donders.ru.nl>
> >     https://mailman.science.ru.nl/mailman/listinfo/fieldtrip
> >
> >
> >
> > _______________________________________________
> > fieldtrip mailing list
> > fieldtrip at donders.ru.nl
> > https://mailman.science.ru.nl/mailman/listinfo/fieldtrip
> >
> _______________________________________________
> fieldtrip mailing list
> fieldtrip at donders.ru.nl
> https://mailman.science.ru.nl/mailman/listinfo/fieldtrip
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.science.ru.nl/pipermail/fieldtrip/attachments/20170125/12adb0d8/attachment-0002.html>
-------------- next part --------------
%% Source fitting protocol
% Fieldtrip path (to find template MRI)
ftdir = 'your\path\here\fieldtrip-20160309';

% Average both conditions to generate common filter
M = ft_timelockgrandaverage(struct(),A,U);
M.cov = mean(cat(3,A.cov,U.cov),3);

% Equate covariance matrices for now to rule out any differences in the
% source fit due to differences in covariances
% A.cov = U.cov;

%%% Do the LCMV sourcefitting
cfg                     = [];
cfg.method              = 'lcmv';
cfg.grid                = leadfield;
cfg.vol                 = vol;
cfg.elec                = elec;
cfg.lcmv.lambda         = '15%';
cfg.lcmv.keepfilter     = 'yes';
cfg.lcmv.fixedori       = 'yes';
cfg.lcmv.projectnoise   = 'yes';

% Generate common filter
sourceM = ft_sourceanalysis(cfg,M);

% Add the common filter to the cfg
cfg.grid.filter = sourceM.avg.filter;

% Source fit the originals
sourceA = ft_sourceanalysis(cfg,A);
sourceU = ft_sourceanalysis(cfg,U);

%%% Matt's quick and dirty version
% Replace A's cov matrix with an average of A.cov and U.cov
tmp = A.cov;
A.cov = mean(cat(3,tmp,U.cov),3);

cfg                     = [];
cfg.method              = 'lcmv';
cfg.grid                = leadfield;
cfg.vol                 = vol;
cfg.elec                = elec;
cfg.lcmv.lambda         = '15%';
cfg.lcmv.keepfilter     = 'yes';
cfg.lcmv.fixedori       = 'yes';
cfg.lcmv.projectnoise   = 'yes';

% Generate common test filter
sourceA_common_test = ft_sourceanalysis(cfg,A);

% Add common filter to configuration
cfg.grid.filter = sourceA_common_test.avg.filter;

% Replace original covariance matrix
A.cov = tmp;

% Now fit both A and U with the common test filter
sourceA_test = ft_sourceanalysis(cfg,A);
sourceU_test = ft_sourceanalysis(cfg,U);


%%% Attempt a contrast
% Create the contrasts
sourceContrast = sourceA;
sourceContrast.avg.pow = sourceA.avg.pow - sourceU.avg.pow;
sourceContrast_test = sourceA_test;
sourceContrast_test.avg.pow = sourceA_test.avg.pow - sourceU_test.avg.pow;

% Gauge what percent of the contrast is negative (i.e. sourceU power >
% sourceA power)
perc_neg = sum(sourceContrast.avg.pow(sourceContrast.inside(:))<0)./numel(sourceContrast.avg.pow(sourceContrast.inside(:)));
perc_neg_test = sum(sourceContrast_test.avg.pow(sourceContrast_test.inside(:))<0)./numel(sourceContrast_test.avg.pow(sourceContrast_test.inside(:)));

%%% Visualize the output
% Load template MRI
mri = ft_read_mri([ftdir '\template\anatomy\single_subj_T1.nii']);

% Interpolate source onto MRI
cfg            = [];
cfg.parameter  = 'avg.pow';
sourceContrast_interp  = ft_sourceinterpolate(cfg, sourceContrast, mri);
sourceContrast_test_interp = ft_sourceinterpolate(cfg, sourceContrast_test, mri);

% Visualize with ft_sourceplot
cfg = [];
cfg.method        = 'ortho';
cfg.funparameter  = 'avg.pow';
cfg.funcolorlim   = [-100 5];
cfg.maskparameter = cfg.funparameter; 
ft_sourceplot(cfg, sourceContrast_interp);

cfg = [];
cfg.method        = 'ortho';
cfg.funparameter  = 'avg.pow';
cfg.funcolorlim   = [-100 5];
cfg.maskparameter = cfg.funparameter; 
ft_sourceplot(cfg, sourceContrast_test_interp);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: sourceContrast_sourceplot.PNG
Type: image/png
Size: 128252 bytes
Desc: not available
URL: <http://mailman.science.ru.nl/pipermail/fieldtrip/attachments/20170125/12adb0d8/attachment-0002.png>


More information about the fieldtrip mailing list