% EEG_REGEPOCHS - Convert a continuous dataset into consecutive epochs of
% a specified regular length by adding dummy events of type
% and epoch the data around these events. Alternatively
% only insert events for extracting these epochs.
% May be used to split up continuous data for
% artifact rejection followed by ICA decomposition.
% The computed EEG.icaweights and EEG.icasphere matrices
% may then be exported to the continuous dataset and/or
% to its epoched descendents.
% Usage:
% >> EEGout = eeg_regepochs(EEG); % use defaults
% >> EEGout = eeg_regepochs(EEG, 'key', val, ...);
%
% Required input:
% EEG - EEG continuous data structure (EEG.trials = 1)
%
% Optional inputs:
% 'recurrence' - [in s] the regular recurrence interval of the dummy
% events used as time-locking events for the
% consecutive epochs {default: 1 s}
% 'limits' - [minsec maxsec] latencies relative to the time-locking
% events to use as epoch boundaries. Stated epoch length
% will be reduced by one data point to avoid overlaps
% {default: [0 recurrence_interval]}
% 'rmbase' - [NaN|latency] remove baseline (s). NaN does not remove
% baseline. 0 remove the pre-0 baseline. To
% remove the full epoch baseline, enter a value
% larger than the upper epoch limit. Default is 0.
% 'eventtype' - [string] name for the time locking event type. Default is 'X'
% 'eventdata' - [struct|cell] additional data to store with each event
% For example { 'condition' 'a' 'run' 1 }
% 'extractepochs' - ['on'|'off'] extract data epochs ('on') or simply
% insert events ('off'). Default is 'on'.
%
% Outputs:
% EEGout - the input EEG structure separated into consecutive
% epochs.
%
% See also: POP_EDITEVENTVALS, POP_EPOCH, RMBASE
%
% Authors: Hilit Serby, Arnaud Delorme & Scott Makeig, SCCN/INC/UCSD, Sep 02, 2005
% Copyright (C) Hilit Serby, SCCN, INC, UCSD, Sep 02, 2005, hilit@sccn.ucsd.edu
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.
function EEG = eeg_regepochs(EEG, varargin)
if nargin < 1
help eeg_regepochs;
return;
end
if length(EEG) > 1
EEG = pop_mergeset(EEG, [1:length(EEG)]);
end
% test input variables
% --------------------
if ~isstruct(EEG) || ~isfield(EEG,'event')
error('first argument must be an EEG structure')
elseif EEG.trials > 1
error('input dataset must be continuous data (1 epoch)');
end
if nargin > 1 && ~ischar(varargin{1})
options = {};
if nargin >= 2, options = { options{:} 'recurrence' varargin{1} }; end
if nargin >= 3, options = { options{:} 'limits' varargin{2} }; end
if nargin >= 4, options = { options{:} 'rmbase' varargin{3} }; end
else
options = varargin;
end
g = finputcheck(options, { 'recurrence' 'real' [] 1;
'limits' 'real' [] NaN;
'rmbase' 'real' [] 0;
'eventtype' 'string' {} 'X';
'eventdata' {'cell' 'struct'} [] {};
'extractepochs' 'string' { 'on','off' } 'on' }, 'eeg_regepochs');
if ischar(g), error(g); end
if g.recurrence < 0 || g.recurrence > EEG.xmax
error('recurrence_interval out of bounds');
end
if iscell(g.eventdata)
g.eventdata = struct(g.eventdata{:});
end
if nargin < 3 || all(isnan(g.limits))
g.limits = [0 g.recurrence];
end
if isnan(g.limits)
g.limits = [0 1];
end
if length(g.limits) ~= 2 || g.limits(2) <= g.limits(1)
error('epoch limits must be a 2-vector [minsec maxsec]')
end
% calculate number of events to add
% ---------------------------------
bg = 0; % beginning of data
en = EEG.xmax; % end of data in sec
nu = floor((EEG.xmax+1/EEG.srate)/g.recurrence); % number of type 'X' events to add and epoch on
% bg = EEG.event(1).latency/EEG.srate; % time in sec of first event
% en = EEG.event(end).latency/EEG.srate; % time in sec of last event
% nu = length((bg+g.recurrence):g.recurrence:(en-g.recurrence)); % number of 'X' events, one every 'g.recurrence' sec
if nu < 1
error('specified recurrence_interval too long')
end
% print info on commandline
% -------------------------
eplength = g.limits(2)-g.limits(1);
fprintf('The input dataset will be split into %d epochs of %g s\n',nu,eplength);
if (eplength-g.recurrence)/eplength*100 > 0
fprintf('Epochs will overlap by %2.0f%%.\n',(eplength-g.recurrence)/eplength*100);
end
% insert events and urevents at the end of the current (ur)event tables
% ---------------------------------------------------------------------
fprintf('Inserting %d type ''%s'' events: ', nu, g.eventtype);
nevents = length(EEG.event);
% convert all event types to strings
for k = 1:nevents
EEG.event(k).type = num2str(EEG.event(k).type);
end
nurevents = length(EEG.urevent);
for k = 1:nu
if rem(k,40)
fprintf('.')
else
fprintf('%d',k)
end
if k==40 || ( k>40 && ~rem(k-40,70))
fprintf('\n');
end
EEG.event(nevents+k).type = g.eventtype;
EEG.event(nevents+k).latency = g.recurrence*(k-1)*EEG.srate+1;
EEG.urevent(nurevents+k).type = g.eventtype;
EEG.urevent(nurevents+k).latency = g.recurrence*(k-1)*EEG.srate+1;
EEG.event(nevents+k).urevent = nurevents+k;
% add additional information
if ~isempty(g.eventdata)
fNames = fieldnames(g.eventdata);
for iField = 1:length(fNames)
EEG.event( nevents+k).(fNames{iField}) = g.eventdata.(fNames{iField});
EEG.urevent(nurevents+k).(fNames{iField}) = g.eventdata.(fNames{iField});
end
end
end
fprintf('\n');
% sort the events based on their latency
% --------------------------------------
fprintf('Sorting the event table.\n');
EEG = pop_editeventvals( EEG, 'sort', {'latency' 0});
% split the dataset into epochs
% ------------------------------
if strcmpi(g.extractepochs, 'on')
fprintf('Splitting the data into %d %2.2f-s epochs\n',nu,eplength);
setname = sprintf('%s - %g-s epochs', EEG.setname, g.recurrence);
EEG = pop_epoch( EEG, { g.eventtype }, g.limits, 'newname', ...
setname, 'epochinfo', 'yes');
% baseline zero the epochs
% ------------------------
if ~isnan(g.rmbase) && g.limits(1) < g.rmbase
fprintf('Removing the pre %3.2f second baseline mean of each epoch.\n', g.rmbase);
EEG = pop_rmbase( EEG, [g.limits(1) g.rmbase]*1000);
end
end;