Skip to content

Read split files into FieldTrip

Sometimes data recordings are split into several files, either because the recording was started and stopped during data acquisition, or because the 2 GB maximum file size of FIF means that long recording sessions are split over several files. When you read data into FieldTrip, you then need to merge the split files into one data file for further processing and correct the samples so that the files align. There are several ways you can achieve this.

Option A: Read files from cell-array (the best solution)

This might not work! Tested 2021-05-25 and it worked for filenames listed in a cell array

Specify the filenames of split-files in a cell array (or use find_files):

fnames = {'file1.fif', 'file2,fif', 'file3.fif'}
Then specify cfg.dataset as the array of filenames. Example:

% Define trials
cfg = [];
cfg.dataset             = fnames ;  % This is the cell-array
cfg.trialdef.prestim    = 1;        % seconds before trigger
cfg.trialdef.poststim   = 1;        % seconds after trigger
cfg.trialdef.eventtype  = 'STI101';
cfg.trialdef.eventvalue = [257, 258, 260];
cfg.trialfun            = 'ft_trialfun_neuromagSTI016fix';

cfg = ft_definetrial(cfg);

% preprocessing
cfg.demean     = 'yes';
cfg.lpfilter   = 'yes';
cfg.lpfreq     = 100;
cfg.hpfilter   = 'no';
cfg.dftfilter  = 'no';
cfg.allowoverlap = 'yes';
cfg.channel    = {'MEG', 'ECG', 'EOG'};

epochs = ft_preprocessing(cfg);

Option B: Read all files, concatenate, and then create trials

Manually correct sample info by reading the header and events with ft_read_header and ft_read_event.

First, specify the filenames:

infiles = {
    fullfile(raw_path,'data_tsss_mc.fif'),
    fullfile(raw_path,'data-1_tsss_mc.fif')
    };

Then read events and headers. This code assumes that the trigger channel is STI101.

%% Read events
for ii = 1:length(infiles)
    hdrs{ii} = ft_read_header(infiles{ii});
    idx = find(not(cellfun('isempty',strfind(hdrs{ii}.label,'STI101'))));
    eve{ii} = ft_read_event(infiles{ii},'chanindx',idx);
end

Now, correct the sample value by adding the number of samples in the previous file to the sample index of the next file.

sam1 = [eve{1}.sample]; 
sam2 = [eve{2}.sample]+hdrs{1}.nSamples;
allsam = [sam1, sam2];
eve2 = appendstruct(eve{1}, eve{2});

Plot to see that it align, as it should.

figure; hold on
plot(allsam, [eve2.value], 'k');
scatter(allsam, [eve2.value], 'r')

In the next step, I did the selection based on the trigger values in the different conditions, like this: rsp_taskA = [eve2.value] == 2. I did this for all the different conditions; in this case, three different conditions.

Then create the trl structure manually. Specify how much time you would like before (prestim) and after (poststim). In contrast, to ft_define_trial, this should be specified in number of samples rather than seconds.

sam_taskA = allsam(rsp_taskA);
sam_taskB = allsam(rsp_taskB);
sam_taskC = allsam(rsp_taskC);
sam_cmb = [sam_taskA, sam_taskB, sam_taskC]';       % Merge trigger samples
con_cmb = ones(size(rsp_taskA)),ones(size(rsp_taskB))*2,ones(size(rsp_taskC))*3]';  % Create label for conditions for bookkeeping.

% Create the trial structure.
prestim = -1000;        % -1000 samples
poststim = 1000;        % +1000 samples
trl = [sam_cmb+prestim, sam_cmb+poststim, repmat(prestim,size(sam_cmb)), con_cmb];

Then you can read in the MEG data split-files as usual and do whatever initial pre-processing you want to do with ft_preprocessing. Then use ft_redefinetrial to chop into epochs based on your previously defined trl structure.

%% Read all datafiles
for ii = 1:length(infiles)
    cfg = [];
    cfg.channel         = 'MEG';
    cfg.dataset         = infiles{ii};
    split_meg{ii} = ft_preprocessing(cfg);
end

%% Merge split files
cfg = [];
cfg.keepsampleinfo='no';
raw_meg = ft_appenddata(cfg,split_meg{:});

%% Make epochs
cfg = [];
cfg.trl = trl;
epo_meg = ft_redefinetrial(cfg, raw_meg);

Option C: Make epochs immediately, then merge split files

See here