This is a collaborative space. In order to contribute, send an email to maximilien.chaumon@icm-institute.org
On any page, type the letter L on your keyboard to add a "Label" to the page, which will make search easier.

Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

In this tutorial you will find a description of all the steps necessary to obtain the sources localisation of continuous (non averaged) data using a beamformer approach in FieldTrip for a group of subjects in using the MNI template

Prerequisites

Input data

EEG signals (EEG)

Fieldtrip can import the data coming from our BrainAmps system. If a 3D digitalisation of the EEG electrodes coordinates was performed you should insert this information in the file using multiconv (see the appropriate tutorial). It is also possible to use an EEG template (you can do that after the EEG importation in FieldTrip).

MEG signals (MEG)

FieldTrip can import the fif files coming from our MEG system and those pre processed with our in-house tools. If you acquired simultaneous MEG+EEG data, FieldTrip will import both of them.

MRI

If you have the individual anatomy of each of your subjects (T1 MRI), you should process it with FieldTrip as described below.

If you don't have the individual anatomy, then you have to choose a template in FieldTrip.

Needed software

FieldTrip

For MEG fif files pre processed outside FieldTrip: You will need two in-house scripts to read the marker files we add to the MEG fif files (put them in your matlab path):

A short script to pre process the MRI in FieldTrip: pre_process_mri_for_ft.m

A simple script to visualize beamformer results: visuBF.m

D.I.C.S. analysis with FieldTrip

Overview of the process:

 

Suggested data organisation

The mat files generated by FieldTrip can be stored together with the pre-processed data. You may want to create a specific sub folder "FT" to store them in each subject.

 

 

Read data

The data should be pre processed (i.e. artefact free) at this point and the FieldTrip folder in your matlab path.

MEG data

Read MEG data
ft_defaults ; %% Load fieldtrip configuration

%% Read two runs, define trials around LEFT_MVT_CLEAN marker (-2s to 2s around the marker), read also BIO005 which is an EMG.
[ trials ] = trial_definition_ft( {'cardiocor_blinkcor_run03_tsss.fif' 'cardiocor_blinkcor_run04_tsss.fif'}, 'LEFT_MVT_CLEAN', 2.0, 2.0, 'BIO005' ) ;

 

EEG

See with Nathalie

 

MRI processing

MRI processing
mri=ft_read_mri(dicom_file_name);
%% Realign the MRI to the MEG coordinate
cfg=[];
cfg.method = 'interactive' ;
cfg.coordsys = 'neuromag' ;
mri_aligned = ft_volumerealign(cfg,mri) ;

save('mri_aligned.mat', 'mri_aligned');

%% Segmentation
cfg           = [];
cfg.output    = 'brain';
segmentedmri  = ft_volumesegment(cfg, mri_aligned);

save('segmentedmri.mat', 'segmentedmri') ;

 
% construct volume conductor model (i.e. head model) for each subject
cfg = [];
cfg.method = 'singleshell';
vol = ft_prepare_headmodel(cfg, seg);
vol = ft_convert_units(vol, 'cm');
save('vol.mat', 'vol') ;

 

 

 

General configuration

Parameters
%% Load the head model created during the MRI pre processing
load vol ; %% load head model located in the subject directory and obtained from the T1 MRI of the subject
 
%% Load the MRI data for visualisation purpose
load('mri_aligned.mat') ; %% MRI data needed for vizualisation
load('segmentedmri.mat') ;

overall_time_window = [-2 2] ; %% if you modify this modify the trials def above ! Is this used below ???

%% Define time window for active state and baseline
active_time_window = [0.2 0.6] ;
reference_time_window = [-1.4 -1.0] ;

%% Basic configuration of the beamformer
beamformer_lambda_normalization = '10%' ;
lead_field_depth_normalization = 'column' ;

%% Frequency of interest and associated width (we will examine here the 16 Hz to 28 Hz band)
freqofinterest = 22 ;
freqhalfwin = 6 ;

%% Select the channel of interest
channelsofinterest = {'MEG*2', 'MEG*3'}; %% Gradiometers on an Elekta system
%% channelsofinterest = {'MEG*1'} ; %% Magnetometer on an Elekta system

Data preparation

Data preparation
% Select time window of interest
cfg = [];
cfg.toilim = active_time_window ;
data_timewindow_active = ft_redefinetrial(cfg,trials);

% Select time window of control
cfg = [];
cfg.toilim = reference_time_window ;
data_timewindow_ref = ft_redefinetrial(cfg,trials);

% Concatenate for common spatial filter computation
data_all = ft_appenddata([], data_timewindow_active, data_timewindow_ref);
 
% Trials will full window
cfg = [];
cfg.toilim = overall_time_window ;
full_data_all = ft_redefinetrial(cfg,trials);

 

Time-Frequency analysis

Time-Frequency analysis
cfg              = [];
cfg.output       = 'pow';
cfg.channel      = 'MEG';
cfg.method       = 'mtmconvol';
cfg.taper        = 'hanning';
cfg.foi          = 7:2:40;                         % analysis 2 to 30 Hz in steps of 2 Hz 
cfg.t_ftimwin    = ones(length(cfg.foi),1).*0.5;   % length of time window = 0.5 sec
cfg.toi          = -2.0:0.05:2.0;                  % time window "slides" from -2.0 to 2.0 sec in steps of 0.05 sec (50 ms)
cfg.trials       = 'all';

TFRhann = ft_freqanalysis(cfg, full_data_all);
 
%% Visualization
cfg = [];
cfg.xlim = [0.1 0.2];                
cfg.ylim = [20 20];                  
cfg.zlim = [-1e-28 1e-28];           
cfg.baseline     = [-0.2 -0.0]; 
cfg.baselinetype = 'absolute';
cfg.layout       = 'neuromag306mag.lay';

figure; ft_topoplotTFR(cfg,TFRhann);

% for the multiple plots also:
cfg = [];
cfg.ylim = [20 20];                  
cfg.baseline     = [-0.2 -0.0]; 
cfg.baselinetype = 'absolute';
cfg.layout       = 'neuromag306mag.lay';
cfg.xlim = [-0.4:0.1:0.4];
cfg.comment = 'xlim';
cfg.commentpos = 'title';
figure; ft_topoplotTFR(cfg,TFRhann);

cfg = [];
cfg.baseline     = [-1.0 -0.8]; 
cfg.baselinetype = 'absolute'; 
%% cfg.zlim         = [-1e-27 1e-27];           
cfg.showlabels   = 'yes';   
cfg.layout       = 'neuromag306mag.lay';
figure; ft_multiplotTFR(cfg, TFRhann);

CSD Computation

CSD computation
%% Compute cross-sepctral density matrices
powcsd_all = compute_crosprect(channelsofinterest, freqofinterest, freqhalfwin, data_all) ;
powcsd_active = compute_crosprect(channelsofinterest, freqofinterest, freqhalfwin, data_timewindow_active) ;

powcsd_ref = compute_crosprect(channelsofinterest, freqofinterest, freqhalfwin, data_timewindow_ref) ;

Forward operator

Forward operator
% Create leadfield grid
cfg                 = [];
cfg.channel         = channelsofinterest ;
cfg.grad            = powcsd_active.grad;
cfg.vol             = vol ;
cfg.dics.reducerank = 2; % default for MEG is 2, for EEG is 3
cfg.grid.resolution = 1.0;   % use a 3-D grid with a 0.5 cm resolution
cfg.grid.unit       = 'cm';
cfg.grid.tight      = 'yes';
cfg.normalize       =  lead_field_depth_normalization ; %% Depth normalization
[grid] = ft_prepare_leadfield(cfg);

 

 

 

 

D.I.C.S. Analysis

%% Compute DICS filters for the concatenated data
cfg              = [];
cfg.channel      = channelsofinterest ;
cfg.method       = 'dics';
cfg.frequency    = freqofinterest ;
cfg.grid         = grid;
cfg.headmodel    = vol;
cfg.senstype     = 'MEG';
cfg.dics.keepfilter   = 'yes'; % We wish to use the calculated filter later on
cfg.dics.projectnoise = 'yes';
cfg.dics.lambda  = beamformer_lambda_normalization;
source_all = ft_sourceanalysis(cfg, powcsd_all);

%% Apply computed filters to each active and reference windows
cfg              = [];
cfg.channel      = channelsofinterest ;
cfg.method       = 'dics';
cfg.frequency    = freqofinterest ;
cfg.grid         = grid;
cfg.grid.filter  = source_all.avg.filter;
cfg.dics.projectnoise = 'yes';
cfg.headmodel          = vol;
cfg.dics.lambda  = beamformer_lambda_normalization ;
cfg.senstype     ='MEG' ;

%% Source analysis active
source_active = ft_sourceanalysis(cfg, powcsd_active);

%% Source analysis reference
source_reference = ft_sourceanalysis(cfg, powcsd_ref);

%% Compute differences (power) between active and reference
source_diff = source_active ;
source_diff.avg.pow  = (source_active.avg.pow - source_reference.avg.pow) ./ (source_active.avg.pow + source_reference.avg.pow);

%% Display the results
visuBF( source_diff, 'title' )
%% MRI reslicing

mri_resliced = ft_volumereslice([], mri_aligned);

%% Display results superimposed on MRI

cfg            = [];
cfg.parameter = 'avg.pow';
source_active_int  = ft_sourceinterpolate(cfg, source_active, mri_resliced);
source_reference_int  = ft_sourceinterpolate(cfg, source_reference, mri_resliced);
source_diff_int  = source_active_int;
source_diff_int.pow  = (source_active_int.pow - source_reference_int.pow) ./ (source_active_int.pow + source_reference_int.pow);

%% Display the results
visuBF( source_diff_int, 'title' )

 

 

LCMV + DICS(EMG)

LCMV
%% LCMV ANALYSIS TO GET TEMPORAL INFORMATION with virtual sensors

 

%% Retrieve correct labelling of the trials

data_all.trialinfo = [zeros(length(data_timewindow_active.trial), 1); ones(length(data_timewindow_ref.trial), 1)];

 

%% Compute covariance of the data (as a whole - both conditions)

cfg                   = [];

cfg.covariance        = 'yes';

cfg.channel           = channelsofinterest ;

cfg.vartrllength      = 0;

cfg.covariancewindow  = 'all';

cfg.trials            = 'all';

tlock                 = ft_timelockanalysis(cfg, trials);

 

%% Localisation of max beta suppression

[minval, minpowindx] = min(source_diff.avg.pow(:));

pos_cm = source_diff.pos(minpowindx,:) ;

 

%% You may choose yourself a location of interest

pos_cm = [0.0 5.0 9.0 ] ; %% CS

%% pos_cm = [0.0 -4.0 5.0 ] ; %% Others loc --- checked where !

 

 

%% Used to store the EP computed at each virtual sensor location

evoked_virtual_zscore = {} ;

evoked_virtual = {} ;

index = 1 ;

 

for i_scan = -60:5:60

 

 

    %% Compute filter for corresponding virtual sensor

    cfg                    = [];

    cfg.method             = 'lcmv';

    cfg.headmodel          = vol ;

    cfg.grid.pos           = [pos_cm(1)+i_scan/10 pos_cm(2) pos_cm(3)] ;

    %% cfg.grid.pos           = [pos_cm(1) pos_cm(2)+i_scan/10 pos_cm(3)] ;

    cfg.grid.inside        = 1:size(cfg.grid.pos, 1);

    cfg.grid.outside       = [];

    cfg.grid.unit          = 'cm'; %% DO NOT FORGET THAT !

    cfg.keepfilter         = 'yes';

    cfg.lcmv.fixedori      = 'yes'; % project on axis of most variance using SVD

    cfg.lcmv.projectnoise  = 'yes' ;

    cfg.lcmv.lambda        = beamformer_lambda_normalization ;

    cfg.lcmv.weightnorm    = 'nai' ;

    cfg.lcmv.normalize     = lead_field_depth_normalization ; %% Depth normalization

    source_idx       = ft_sourceanalysis(cfg, tlock);

    beamformer = source_idx.avg.filter{1};

    

    %% Apply filter to the raw data

    chansel = ft_channelselection(channelsofinterest, data_all.label); % find MEG sensor names

    chansel = match_str(data_all.label, chansel);

    pow_data = [];

    pow_data.label = {'pow_x', 'pow_y', 'pow_z'};

    pow_data.time = trials.time;

    for i=1:length(trials.trial)

        pow_data.trial{i} = beamformer * trials.trial{i}(chansel,:);

    end

    

    %     %% construct a single virtual channel in the maximum power orientation (not usefull if fixed orig above)

    %     timeseries = cat(2, pow_data.trial{:});

    %     [u, s, v] = svd(timeseries, 'econ');

    %

    %     % this is equal to the first column of matrix V, apart from the scaling with s(1,1)

    %     timeseriesmaxproj = u(:,1)' * timeseries;

    %     virtualchanneldata = [];

    %     virtualchanneldata.label = {'cortex'};

    %     virtualchanneldata.time = trials.time;

    %     for i=1:length(trials.trial)

    %         virtualchanneldata.trial{i} = u(:,1)' * beamformer * trials.trial{i}(chansel,:);

    %     end

    

    %% Together with option fixedori (fixed oreintation) this is suffisent (we have only one vector not three)

    virtualchanneldata = [];

    virtualchanneldata.label = {'cortex'};

    virtualchanneldata.time = trials.time;

    for i=1:length(trials.trial)

        virtualchanneldata.trial{i} = pow_data.trial{i} ;

    end

    

    

%     %% Time-frequency analysis

%     cfg              = [];

%     cfg.output       = 'pow';

%     cfg.channel      = 'cortex';

%     cfg.method       = 'mtmconvol';

%     cfg.taper        = 'hanning';

%     cfg.foi          = 7:2:100;                         % analysis 2 to 30 Hz in steps of 2 Hz

%     cfg.t_ftimwin    = ones(length(cfg.foi),1).*0.5;   % length of time window = 0.5 sec

%     cfg.toi          = -2.0:0.05:2.0;                  % time window "slides" from -0.5 to 1.5 sec in steps of 0.05 sec (50 ms)

%     TFRvirtualchanneldata = ft_freqanalysis(cfg, virtualchanneldata);

%     title(['X = ' num2str(pos_cm(1)+i_scan/10)]) ;

%     print(['TF-virtualChannel_alpha_' num2str(pos_cm(1)+i_scan/10)],'-dpng')

% 

%     %% Display the results as a TF map

%     cfg = [];

%     cfg.baseline     = reference_time_window ;

%     cfg.baselinetype = 'db';

%     cfg.channelname   = 'cortex'; % top figure

%     cfg.zlim = [-5 5] ;

%     figure;ft_singleplotTFR(cfg, TFRvirtualchanneldata);

    

    

    %% Evoked potential on the virtual sensor

    cfg.demean             = 'yes';

    cfg.baselinewindow     = reference_time_window;

    evoked_virtual{index}  = ft_timelockanalysis(cfg, virtualchanneldata);

    

    evoked_virtual_zscore{index} = evoked_virtual{index} ;

    mean_bl = mean(evoked_virtual{index}.avg(1,nearest(evoked_virtual{1}.time, -2.0):nearest(evoked_virtual{1}.time, -1.8)) ,2) ;

    std_bl = std(evoked_virtual{index}.avg(1,nearest(evoked_virtual{1}.time, -2.0):nearest(evoked_virtual{1}.time, -1.8)) , 0, 2) ;

    evoked_virtual_zscore{index}.avg = (evoked_virtual{index}.avg - mean_bl)/std_bl ;

    

    %% Display the evoked potential

    cfg.ylim = [-0.2 0.2] ;

    figure ; ft_singleplotER(cfg, evoked_virtual{index}) ; 

    title(['X = ' num2str(pos_cm(1)+i_scan/10)]) ;

    print(['EV-mag-virtualChannel_beta_' num2str(pos_cm(2)+i_scan/10)],'-dpng')

    

    cfg.ylim = [-10 10] ;

    figure ; ft_singleplotER(cfg, evoked_virtual_zscore{index}) ; 

    title(['X = ' num2str(pos_cm(1)+i_scan/10)]) ;

    print(['EV-mag-zscore-virtualChannel_beta_' num2str(pos_cm(2)+i_scan/10)],'-dpng')

    

    index = index + 1 ;

end

 

figure

for i = 1:index-1

   plot(evoked_virtual_zscore{1}.time, evoked_virtual_zscore{i}.avg);

   hold on

end

hold off

 

 

%% Coherence with EMG

 

%% %% First using EMG

channelsofinterest = {'MEG*2', 'MEG*3'}; %% Gradiometers on an Elekta system

 

 

%% Compute cross spectrum matrix

cfg            = [];

cfg.method     = 'mtmfft';

cfg.output     = 'powandcsd';

cfg.taper           = 'dpss';

cfg.tapsmofrq       = 5;

cfg.foi             = 10;

cfg.keeptrials = 'yes';

cfg.channel    = {'MEG*2' 'MEG*3' 'BIO005'};

cfg.channelcmb = {'MEG*2' 'MEG*2'; 'MEG*3' 'MEG*3';, 'MEG*2' 'MEG*3' ; 'MEG*2' 'BIO005' ; 'MEG*3' 'BIO005'};

 

powcsd           = ft_freqanalysis(cfg, data_timewindow_active);

 

 

% Create leadfield grid

cfg                 = [];

cfg.channel         = channelsofinterest ;

cfg.grad            = powcsd.grad;

cfg.vol             = vol ;

cfg.dics.reducerank = 2; % default for MEG is 2, for EEG is 3

cfg.grid.resolution = 1.0;   % use a 3-D grid with a 0.5 cm resolution

cfg.grid.unit       = 'cm';

cfg.grid.tight      = 'yes';

cfg.normalize       =  lead_field_depth_normalization ; %% Depth normalization

[grid] = ft_prepare_leadfield(cfg);

 

cfg                 = [];

cfg.method          = 'dics';

cfg.refchan         = 'BIO005';

cfg.frequency       = freqofinterest ;

cfg.grid            = grid;

cfg.vol             = vol;

cfg.grid.unit       = 'cm';

cfg.dics.lambda  = beamformer_lambda_normalization;

%% cfg.dics.reducerank = 2; % default for MEG is 2, for EEG is 3

 

source              = ft_sourceanalysis(cfg, powcsd);

 

cfg              = [];

cfg.method       = 'ortho';

cfg.funparameter = 'coh';

ft_sourceplot(cfg, source);
  • No labels