% EEG_GETEPOCHEVENT - Return dataset event field values for all events
% of one or more specified types
% Usage:
% >> epochval = eeg_getepochevent( EEG );
% >> epochval = eeg_getepochevent( EEG, 'key', 'val');
%
% Inputs:
% EEG - Input dataset
%
% Optional inputs:
% 'type' - String containing an event type. Cell array of string
% may be used to select several event types;
% {} is all types of events. Note: Requires that
% a field named 'type' is defined in 'EEG.event'.
% 'timewin' - [start end] Event time window in milliseconds
% (default []=whole epoch).
% 'fieldname' - Name of the field to return the values for.
% Default field is 'EEG.event.latency' in milliseconds
% (though internally this information is stored in
% real frames).
% 'trials' - [integer array] return values only for selected trials.
%
% Outputs:
% epochval - A value of the selected field for each epoch. This is
% NaN if no selected event occurred during the epoch. If
% several values are available for each epoch, only the
% first one is taken into consideration.
% Latencies are measured in msec relative to epoch onset.
% Forced to be numerical, where a string is converted by
% double to its ascii number which is normalized to be
% between 0 and 1, and the string is summed together. See
% the subfunction ascii2num for more details.
% allepochval - cell array with same length as the number of epoch
% containing all values for all epochs. This output is
% useful when several value are found within each epoch.
% Not forced to be numerical.
%
% Notes: 1) Each epoch structure refers to the events that occurred
% during its time window. This function allows the user to return
% specified field values for a subset of the defined events.
%
% 2) If several of the selected events occur during a single epoch,
% a warning is issued, and value of ONLY THE FIRST event in the epoch
% is returned.
%
% If NO EVENT is selected in a given epoch, the value returned
% is NaN.
%
% 3) If the user elects to return the latency field, EEG_GETEPOCHEVENT
% recomputes the latency of each event relative to the epoch time
% limits.
%
% Example:
% >> latencies = eeg_getepochevent(EEG, 'rt');
% % Return the latencies (by default) in milliseconds of events having
% % type 'rt' (reaction time)
%
% >> latencies = eeg_getepochevent(EEG, {'target','rare'}, [0 300], 'position');
% % Return the position (field 'position') of 'target' or 'rare' type
% % events occurring between 0 and 300 milliseconds of each epoch.
% % Returns NaN for epochs with no such events. (See Notes above).
%
% Author: Arnaud Delorme & Scott Makeig, CNL / Salk Institute, 15 Feb 2002
%
% See also: EEGLAB, EPOCH
% Copyright (C) 15 Feb 2002 Arnaud Delorme, Salk Institute, arno@salk.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.
% 02/15/02 modified function according to new event structure -ad
function [epochval, allepochval] = eeg_getepochevent(EEG, varargin);
if nargin < 2
help eeg_getepochevent;
return;
end
% process more than one EEG dataset (for STUDY purposes)
% ------------------------------------------------------
if length(EEG) > 1
% the trial input may be a cell array; it has to be
% extracted before calling the function on each dataset
trials = cell(1,length(EEG));
for iArg = length(varargin)-1:-2:1
if strcmpi(varargin{iArg}, 'trials')
trials = varargin{iArg+1};
varargin(iArg:iArg+1) = [];
end
end
epochval = [];
for dat = 1:length(EEG)
tmpepochval = eeg_getepochevent(EEG(dat), 'trials', trials{dat}, varargin{:});
epochval = [ epochval tmpepochval ];
end
return;
end
% deal with old input format
% -------------------------
options = {};
oldformat = 0;
if nargin < 3
oldformat = 1;
elseif isnumeric(varargin{2}) && length(varargin{2}) == 2
oldformat = 1;
elseif length(varargin) == 3 && isfield(EEG.event,varargin(3))
oldformat = 1;
end
if oldformat
if nargin > 1, options = { options{:} 'type' varargin{1} }; end
if nargin > 2, options = { options{:} 'timewin' varargin{2} }; end
if nargin > 3, options = { options{:} 'fieldname' varargin{3} }; end
else
options = varargin;
end
opt = finputcheck(options, { 'type' { 'string';'cell' } { [] [] } '';
'timewin' 'real' [] [-Inf Inf];
'fieldname' 'string' [] 'latency';
'trials' { 'real';'cell' } [] [] }, 'eeg_getepochevent');
if ischar(opt), error(opt); end
if iscell(opt.trials) && ~isempty(opt.trials), opt.trials = opt.trials{1}; end
if isempty(opt.timewin)
opt.timewin = [-Inf Inf];
end
if isempty(EEG.event)
disp('Getepochevent: no event structure, aborting.'); return;
end
% check if EEG.epoch contain references to events
% -----------------------------------------------
if ~isfield( EEG.event, 'epoch' )
disp('Getepochevent: no epoch indices in events, considering continuous values.');
end
% check if EEG.epoch and EEG.event contains 'latency' field
% ------------------------------------------
if ~isfield( EEG.event, opt.fieldname)
disp(['Getepochevent: no ''' opt.fieldname ''' field in events, aborting.']); return;
end
% deal with empty types
% ---------------------
if ~isempty(opt.type) && ~iscell(opt.type)
opt.type = { opt.type };
end
% convert types
% -------------
for indextype=1:length(opt.type)
if ischar(opt.type{indextype}) && isnumeric(EEG.event(1).type)
if ~isempty(str2num(opt.type{indextype}))
opt.type{indextype} = str2num(opt.type{indextype});
else
error('eeg_getepochevent: string type cannot be found in numeric event type array');
end;
elseif isnumeric(opt.type{indextype}) && ischar(EEG.event(1).type)
opt.type{indextype} = num2str(opt.type{indextype});
end
end
% select epochs
% -------------
if ~isempty(opt.type)
Ieventtmp = [];
tmpevent = EEG.event;
for indextype=1:length(opt.type)
typeval = opt.type{indextype};
if ischar(typeval)
Ieventtmp = [Ieventtmp strmatch(typeval, { tmpevent.type }, 'exact')' ];
else
Ieventtmp = [Ieventtmp find(typeval == [ tmpevent.type ] ) ];
end
end
else
Ieventtmp = [1:length(EEG.event)];
end
% select latencies
% ----------------
if isfield(EEG.event, 'latency') && (opt.timewin(1) ~= -Inf || opt.timewin(2) ~= Inf)
selected = ones(size(Ieventtmp));
for index=1:length(Ieventtmp)
if ~isfield(EEG.event, 'epoch'), epoch = 1;
else epoch = EEG.event(Ieventtmp(index)).epoch;
end
reallat = eeg_point2lat(EEG.event(Ieventtmp(index)).latency, epoch, ...
EEG.srate, [EEG.xmin EEG.xmax]*1000, 1E-3);
if reallat < opt.timewin(1) || reallat > opt.timewin(2)
selected(index) = 0;
end
end
Ieventtmp = Ieventtmp( find(selected == 1) );
end
% select events
% -------------
epochval = cell(1,EEG.trials); epochval(:) = { nan };
allepochval = cell(1, EEG.trials); allepochval(:) = { {} };
if strcmp(opt.fieldname, 'latency')
for index = 1:length(Ieventtmp)
if ~isfield(EEG.event, 'epoch'), epoch = 1;
else epoch = EEG.event(Ieventtmp(index)).epoch;
end
allepochval{epoch}{end+1} = eeg_point2lat(EEG.event(Ieventtmp(index)).latency, epoch, ...
EEG.srate, [EEG.xmin EEG.xmax]*1000, 1E-3);
if length(allepochval{epoch}) == 1
epochval{epoch} = allepochval{epoch}{end};
else
if length(allepochval{epoch}) == 2 && nargout < 2
disp(['Warning: multiple event latencies found in epoch ' int2str(epoch) ]);
%, ignoring event ' int2str(Ieventtmp(index)) ' (''' num2str(EEG.event(Ieventtmp(index)).type) ''' type)' ]);
end
end
end
elseif strcmp(opt.fieldname, 'duration')
for index = 1:length(Ieventtmp)
eval( [ 'val = EEG.event(Ieventtmp(index)).' opt.fieldname ';']);
if ~isempty(val)
if ~isfield(EEG.event, 'epoch'), epoch = 1;
else epoch = EEG.event(Ieventtmp(index)).epoch;
end
epochval{epoch} = val/EEG.srate*1000;
allepochval{epoch}{end+1} = val/EEG.srate*1000;
end
end
else
for index = 1:length(Ieventtmp)
eval( [ 'val = EEG.event(Ieventtmp(index)).' opt.fieldname ';']);
if ~isempty(val)
if ischar(val)
val = ascii2num(val);
%val_tmp = double(val); % force epochval output to be numerical
% **Turn string into number that will sort in alphebetical order**
%val = 0;
%for val_count = 1:length(val_tmp)
% -48 so that '1' is scaled to ascii number 1, not 49
% /74 to scale double('z')=122 to 1
% 10^((2-... scale to 0 to 100milliseconds
% val = val + (val_tmp(val_count)-48)/74*10^(2-(val_count-1));
%end
% **End turn string ...**
end
if ~isfield(EEG.event, 'epoch'),
epoch = 1;
else epoch = EEG.event(Ieventtmp(index)).epoch;
end
epochval{epoch} = val(1);
allepochval{epoch}{end+1} = val(1);
end
end
end;
if isnumeric(epochval{1})
try
epochval = [ epochval{:} ];
for index = 1:length(allepochval)
allepochval{index} = [ allepochval{index}{:} ];
end
catch
end
end
% select specific trials
if ~isempty(opt.trials)
epochval = epochval(opt.trials);
allepochval = allepochval(opt.trials);
end
%% SUBFUNCTION ASCII2NUM
% Maps ascii characters ['0','9'] to [1, 10], ['a','z'] to [11, 36]
% This is intended for alphebetically sorting string arrays numerically
% ascii_in [string array]
% output [double]
function out = ascii2num(ascii_in)
ascii_vector = double(ascii_in);
out = 0;
% go through each character in the string and scale and add it to output
for val_count = 1:length(ascii_vector)
ascii_char = ascii_vector(val_count);
if ascii_char>=48 && ascii_char<=57 % ['0','9'] to [1, 10]
ascii_adj = ascii_char - 47;
elseif ascii_char>=65 && ascii_char<=90 % ['A','Z'] to [11, 36]
ascii_adj = ascii_char - 64;
elseif ascii_char>=97 && ascii_char<=122 % ['a','z'] to [11, 36]
ascii_adj = ascii_char - 96;
else ascii_adj = ascii_char;
end
out = out + ascii_adj/36^val_count;
end