% STD_ERP - Constructs and returns channel or ICA activation ERPs for a dataset.
% Saves the ERPs into a Matlab file, [dataset_name].icaerp, for
% data channels or [dataset_name].icaerp for ICA components,
% in the same directory as the dataset file. If such a file
% already exists, loads its information.
% Usage:
% >> [erp, times] = std_erp(EEG, 'key', 'val', ...);
% Inputs:
% EEG - a loaded epoched EEG dataset structure. May be an array
% of such structure containing several datasets.
%
% Optional inputs:
% 'components' - [numeric vector] components of the EEG structure for which
% activation ERPs will be computed. Note that because
% computation of ERP is so fast, all components ERP are
% computed and saved. Only selected component
% are returned by the function to Matlab
% {default|[] -> all}
% 'channels' - [cell array] channels of the EEG structure for which
% activation ERPs will be computed. Note that because
% computation of ERP is so fast, all channels ERP are
% computed and saved. Only selected channels
% are returned by the function to Matlab
% {default|[] -> none}
% 'recompute' - ['on'|'off'] force recomputing ERP file even if it is
% already on disk.
% 'trialindices' - [cell array] indices of trials for each dataset.
% Default is all trials.
% 'recompute' - ['on'|'off'] force recomputing data file even if it is
% already on disk.
% 'rmcomps' - [integer array] remove artifactual components (this entry
% is ignored when plotting components). This entry contains
% the indices of the components to be removed. Default is none.
% 'interp' - [struct] channel location structure containing electrode
% to interpolate (this entry is ignored when plotting
% components). Default is no interpolation.
% 'fileout' - [string] name of the file to save on disk. The default
% is the same name (with a different extension) as the
% dataset given as input.
% 'savetrials' - ['on'|'off'] save single-trials ERSP. Requires a lot of disk
% space (dataset space on disk times 10) but allow for refined
% single-trial statistics.
%
% ERP specific options:
% 'rmbase' - [min max] remove baseline. This option does not affect
% the original datasets.
%
% Outputs:
% erp - ERP for the requested ICA components in the selected
% latency window. ERPs are scaled by the RMS over of the
% component scalp map projection over all data channels.
% times - vector of times (epoch latencies in ms) for the ERP
%
% File output:
% [dataset_file].icaerp % component erp file
% OR
% [dataset_file].daterp % channel erp file
%
% See also: STD_SPEC, STD_ERSP, STD_TOPO, STD_PRECLUST
%
% Authors: Arnaud Delorme, SCCN, INC, UCSD, January, 2005
% Copyright (C) Arnaud Delorme, SCCN, INC, UCSD, October 11, 2004, arno@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 [X, t] = std_erp(EEG, varargin)
if nargin < 1
help std_erp;
return;
end
% decode inputs
% -------------
if ~isempty(varargin)
if ~ischar(varargin{1})
varargin = { varargin{:} [] [] };
if all(varargin{1} > 0)
options = { 'components' varargin{1} 'timerange' varargin{2} };
else
options = { 'channels' -varargin{1} 'timerange' varargin{2} };
end
else
options = varargin;
end
else
options = varargin;
end
g = finputcheck(options, { 'components' 'integer' [] [];
'channels' 'cell' {} {};
'rmbase' 'real' [] [];
'trialindices' { 'integer','cell' } [] [];
'rmcomps' 'cell' [] cell(1,length(EEG));
'fileout' 'string' [] '';
'trialinfo' 'struct' [] struct([]);
'savetrials' 'string' { 'on','off' } 'off';
'interp' 'struct' { } struct([]);
'timerange', 'real', [], [];
'recompute', 'string', { 'on', 'off' }, 'off' }, 'std_erp');
if ischar(g), error(g); end
if isempty(g.trialindices), g.trialindices = cell(length(EEG)); end
if ~iscell(g.trialindices), g.trialindices = { g.trialindices }; end
if isfield(EEG,'icaweights')
numc = size(EEG(1).icaweights,1);
else
error('EEG.icaweights not found');
end
if isempty(g.components)
g.components = 1:numc;
end
% % THIS SECTION WOULD NEED TO TEST THAT THE PARAMETERS ON DISK ARE CONSISTENT
%
% % filename
% % --------
if isempty(g.fileout), g.fileout = fullfile(EEG(1).filepath, EEG(1).filename(1:end-4)); end
if ~isempty(g.channels)
filenameshort = [ g.fileout '.daterp'];
prefix = 'chan';
else
filenameshort = [ g.fileout '.icaerp'];
prefix = 'comp';
end
%filename = fullfile( EEG(1).filepath, filenameshort);
filename = filenameshort;
% ERP information found in datasets
% ---------------------------------
if exist(filename) && strcmpi(g.recompute, 'off')
fprintf('File "%s" found on disk, no need to recompute\n', filenameshort);
if nargout > 0
setinfo.filebase = filename;
if strcmpi(prefix, 'comp')
[X, ~, t] = std_readfile(setinfo, 'components', g.components, 'timelimits', g.timerange, 'measure', 'erp');
else
[X, ~, t] = std_readfile(setinfo, 'channels', g.channels, 'timelimits', g.timerange, 'measure', 'erp');
end
if ~isempty(X), return; end
else
return;
end
end
% No ERP information found
% ------------------------
% if ischar(EEG.data)
% TMP = eeg_checkset( EEG, 'loaddata' ); % load EEG.data and EEG.icaact
% else
% TMP = EEG;
% end
% && isempty(TMP.icaact)
% TMP.icaact = (TMP.icaweights*TMP.icasphere)* ...
% reshape(TMP.data(TMP.icachansind,:,:), [ length(TMP.icachansind) size(TMP.data,2)*size(TMP.data,3) ]);
% TMP.icaact = reshape(TMP.icaact, [ size(TMP.icaact,1) size(TMP.data,2) size(TMP.data,3) ]);
%end
%if strcmpi(prefix, 'comp'), X = TMP.icaact;
%else X = TMP.data;
%end
if isempty(g.channels)
X = eeg_getdatact(EEG, 'component', 1:size(EEG(1).icaweights,1), 'trialindices', g.trialindices );
else X = eeg_getdatact(EEG, 'trialindices', g.trialindices, 'rmcomps', g.rmcomps, 'interp', g.interp);
end
% Remove baseline mean
% --------------------
pnts = EEG(1).pnts;
trials = size(X,3);
timevals = EEG(1).times;
if ~isempty(g.timerange)
disp('Warning: the ''timerange'' option is deprecated and has no effect');
end
if ~isempty(X)
if ~isempty(g.rmbase)
disp('Removing baseline...');
options = { options{:} 'rmbase' g.rmbase };
[~, timebeg] = min(abs(timevals - g.rmbase(1)));
[~, timeend] = min(abs(timevals - g.rmbase(2)));
if ~isempty(timebeg)
X = rmbase(X,pnts, timebeg:timeend);
else
X = rmbase(X,pnts);
end
end
X = reshape(X, [ size(X,1) pnts trials ]);
if strcmpi(prefix, 'comp')
if strcmpi(g.savetrials, 'on')
X = repmat(sqrt(mean(EEG(1).icawinv.^2))', [1 EEG(1).pnts size(X,3)]) .* X;
else
X = repmat(sqrt(mean(EEG(1).icawinv.^2))', [1 EEG(1).pnts]) .* mean(X,3); % calculate ERP
end
elseif strcmpi(g.savetrials, 'off')
X = mean(X, 3);
end
end
eeglab_options;
if option_single
X = single(X);
end
% Save ERPs in file (all components or channels)
% ----------------------------------------------
if isempty(timevals), timevals = linspace(EEG(1).xmin, EEG(1).xmax, EEG(1).pnts)*1000; end; % continuous data
fileNames = computeFullFileName( { EEG.filepath }, { EEG.filename });
if strcmpi(prefix, 'comp')
savetofile( filename, timevals, X, 'comp', 1:size(X,1), options, {}, fileNames, g.trialindices, g.trialinfo);
%[X,t] = std_readerp( EEG, 1, g.components, g.timerange);
else
if ~isempty(g.interp)
savetofile( filename, timevals, X, 'chan', 1:size(X,1), options, { g.interp.labels }, fileNames, g.trialindices, g.trialinfo);
else
tmpchanlocs = EEG(1).chanlocs;
savetofile( filename, timevals, X, 'chan', 1:size(X,1), options, { tmpchanlocs.labels }, fileNames, g.trialindices, g.trialinfo);
end
%[X,t] = std_readerp( EEG, 1, g.channels, g.timerange);
end
% compute full file names
% -----------------------
function res = computeFullFileName(filePaths, fileNames);
for index = 1:length(fileNames)
res{index} = fullfile(filePaths{index}, fileNames{index});
end
% -------------------------------------
% saving ERP information to Matlab file
% -------------------------------------
function savetofile(filename, t, X, prefix, comps, params, labels, dataFiles, dataTrials, trialInfo);
disp([ 'Saving ERP file ''' filename '''' ]);
allerp = [];
for k = 1:length(comps)
allerp = setfield( allerp, [ prefix int2str(comps(k)) ], squeeze(X(k,:,:)));
end
if nargin > 6 && ~isempty(labels)
allerp.labels = labels;
end
allerp.times = t;
allerp.datatype = 'ERP';
allerp.parameters = params;
allerp.datafiles = dataFiles;
allerp.datatrials = dataTrials;
allerp.trialinfo = trialInfo;
std_savedat(filename, allerp);