Analyzing MEG data in FieldTrip

A much more thorough and complete guide can be found at http://fieldtrip.fcdonders.nl/tutorial. This is intended to give people who haven't used FieldTrip at all an overall feel for how data is structured and analyses are conducted.

How FieldTrip compares to SPM

Like SPM, FieldTrip is written in Matlab. Unlike SPM, there is no graphical interface for conducting analyses; everything is done through scripts. This provides a great deal of flexibility, and the ability to always be able to see exactly what analyses were run. However, it does take a bit of knowledge of Matlab (but not too much).

(SPM now includes a distribution of FieldTrip, so many of the "behind the scenes" analyses are identical.)

Because FieldTrip functions are written in Matlab, to get help on any function you can type "help <function>" in Matlab, or "edit <function>" to view the source (and help). It's a good habit to get into to look at the help for every function you use.

Matlab structures

Most FieldTrip functions take as one of their arguments a configuration (cfg) structure. A structure is a Matlab variable that contains one or more fields, and each field can then in turn contain a type of information. An empty structure can be created using struct([]):

>> c = struct([])

c = 

0x0 struct array with no fields.

>> isstruct(c)

ans =

     1

>> 

By convention, FieldTrip example scripts usually start by creating an empty matrix using [], and then assign some values to turn it into a structure:

>> c = []

c =

     []

>> isstruct(c)

ans =

     0

>> c.myfield = [1 2 3]

c = 

    myfield: [1 2 3]

>> isstruct(c)

ans =

     1

>> 

Now that we have a structure called c, we can add some fields to it using a dot notation (i.e., <structure>.<field>):

>> c.field1 = 1;
>> c.field2 = 3.4;
>> c.you_can_name_them_whatever_you_want = 'structures are fun';
>> c

c = 

                                myfield: [1 2 3]
                                 field1: 1
                                 field2: 3.4000
    you_can_name_them_whatever_you_want: 'structures are fun'

>> 

Note that fields can take any kind of information: vectors, matrices, integers, strings...even other structures. From the perspective of FieldTrip, this makes it easy to pass a lot of information to a function using only a single variable.

Starting FieldTrip

To get started in FieldTrip, you just need to make sure that all of FieldTrip's functions are in your Matlab path. To do so, make sure the main FieldTrip distribution is in your path:

>> addpath /imaging/local/software/fieldtrip/fieldtrip-current

and then run the defaults function:

>> ft_defaults

Now you're ready to go!

Reading in data

For most things you do in FieldTrip, it's probably worth saving the scripts so that you can easily change options and see what you've done.

cfg = [];                          % initialize a cfg variable
cfg.dataset = 'td4sblock1.fif';    % specify the (post-maxfilter, probably) datafile
cfg.trialdef.eventtype = 'trial';  % tell FT what kind of events to get
cfg = ft_definetrial(cfg);         % find the events
data = ft_preprocessing(cfg);      % get the data with default options

In this case, note that the cfg structure is updated by ft_definetrial, and then for ft_preprocessing we are using this new cfg structure.

You may end up with multiple data files (e.g., one per condition), which you can then go on to compare.

== An example script ==

Here is a slightly longer example toy script that includes basic artifact rejection, time-locked averaging, and topographic plotting. FieldTrip also includes extensive options for doing statistics using permutation testing, which are worth looking into.

% (FieldTrip uses the MNE matlab toolbox for reading in data files; it
% should be on your path by default, but when I ran this it wasn't...)
% addpath /opt/mne/matlab/toolbox

clear all

%% define the dataset
cfg = [];
cfg.continuous = 'yes';
cfg.dataset = '08_0424_td4sblock1.fif';


%% set up the trial definition, and define trials
cfg.trialdef.eventtype = 'STI101';
cfg.trialdef.eventvalue = 9;
cfg.trialdef.prestim = .1; % 100 ms pre-stimulus included as baseline
cfg.trialdef.poststim = 1; % keep 1000 ms of data
cfg = ft_definetrial(cfg);

%% reject artifacts based on EOG and sensor jumps using defaults
cfg.artfctdef.eog.channel = {'EEG061';'EEG062'};
cfg = ft_artifact_eog(cfg);

cfg.artfctdef.jump.channel = {'MEG'};
cfg = ft_artifact_jump(cfg);

% now remove any bad sections from definition
cfg = ft_rejectartifact(cfg)


%% read in the data (not including rejected trials)
cfg.channel = {'MEG'};
cfg.lpfilter = 'yes';
cfg.lpfreq = 50;
cfg.hpfilter = 'yes';
cfg.hpfreq = 0.2;
data = ft_preprocessing(cfg);


%% compute a grand average
cfg = []; % we can use a new cfg
timelock = ft_timelockanalysis(cfg, data);



%% plot the grand average for one channel
cfg.channel = {'MEG0222'};
ft_singleplotER(cfg, timelock)


%% topographic plot at 100 ms
cfg = [];
cfg.xlim = [.1 .1]; % around 100 ms
ft_topoplotER(cfg, timelock)