% EVENTLOCK - DEPRECATED: Please use EEGALIGN instead.
% EVENTLOCK - Time lock data epochs to specified event frames or event x-values.
% Use to timelock existing data epochs to reaction times or other events
%
% Usage:
% >> [dataout,medval,shiftframes] = eventlock(data,frames,eventframes,medval);
% >> [dataout,medval,shiftframes] = eventlock(data,xvals,eventvals,medval);
%
% Inputs for multi-channel data:
% data = input data, size(chans,frames*epochs)
% frames = scalar, frames per epoch {0 -> data length}
% eventframes = time locking event frames, size(1,epochs)
% medval = median eventframe to align to {default: median(eventvals)}
%
% Inputs for single-channel data:
% data = input data, size(frames, epochs)
% xvals = vector of epoch time-values, size(1,frames)
% OR xvals = [startval nframes srate] (ms N Hz)
% eventvals = x-values of time locking events, size(1,epochs)
% medval = median event time to align to {default: median(eventvals)}
%
% Outputs:
% dataout = shifted/sorted data out; size(dataout) = size(data)
% medval = median eventval (time or frame). Data is aligned to this.
% shifts = number of frames shifted for each epoch
% (Note: shift > 0 means shift forward|right)
%
% Note: Missing values are filled with NaN. Some toolbox functions
% ( TIMEF, CROSSF, CROSSCOHER ) handle NaNs correctly.
% To truncate to non-NaN values, use
% >> dataout = matsel(dataout,frames,...
% 1+max(shifts(find(shifts>=0))):frames+min(shifts(find(shifts<=0))));
%
% Author: Scott Makeig, SCCN/INC/UCSD, La Jolla, 8/20/99
% Copyright (C) 8/20/99 Scott Makeig, SCCN/INC/UCSD, scott@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.
% 8/23/99 debugged right shifts -sm
% 8/25/99 allowed single- or multiple-channel data -sm
% 3/9/00 fixed order of dims in help msg -sm & ev
% 01-25-02 reformated help & license -ad
function [data,medval,shifts] = eventlock(data,arg2,eventvals,medval)
VERBOSE=0;
%
%%%%%%%%%%%%%% Reshape data to (frames,ntrials) %%%%%%%%%%%%%
%
if nargin < 3
help eventlock
return
end
MULTICHANNEL = 0;
if length(arg2) == 1 % then assume multi-channel: size(chans,epochs*frames)
MULTICHANNEL = 1;
if arg2==0
frames = length(eventvals); % default 1 epoch
else
frames = arg2;
end
xvals = 1:frames;
else % assume single-channel: size(frames,epochs)
MULTICHANNEL = 0;
xvals = arg2;
if length(xvals) ~= 3
frames = length(xvals);
else
frames = xvals(2);
end
end
rows = size(data,1);
if MULTICHANNEL
ntrials = size(data,2)/frames;
else
ntrials = size(data,2);
end
if length(xvals) == 3 % assume [startval nvals srate] format
srate = xvals(3);
endval = xvals(1)+(xvals(2)-1)*xvals(3)+1e-16;
xvals = xvals(1):1000/xvals(3):endval;
xvals = xvals(1:frames); % make sure of length!
else
srate = 1000/(xvals(2)-xvals(1));
end
if MULTICHANNEL
if frames*ntrials ~= size(data,2)
fprintf(...
'Input data length (%d) is not a multiple of the eventframes length (%d).\n',...
size(data,2), frames);
return
end
elseif frames~= size(data,1)
fprintf(...
'Input data frames (%d) is not equal to xvals length (%d).\n',...
size(data,1), length(xvals));
return
end
if length(eventvals) ~= ntrials
fprintf(...
'eventlock(): Number of eventvals (%d) must equal number of trials (%d).\n',...
length(eventvals), ntrials);
return
end
if MULTICHANNEL
fprintf('Input data is %d channels by %d frames * %d trials.\n',...
rows,frames,ntrials);
else
fprintf('Input data is %d frames by %d trials.\n',...
frames,ntrials);
end
%
%%%%%%%%%%%%%%%%%%% Align data to eventvals %%%%%%%%%%%%%%%%%%%
%
if MULTICHANNEL
frames = rows*frames;
data = reshape(data,frames,ntrials);
end % NB: data is now size((chans*)frames,ntrials)
aligndata=repmat(nan,frames,ntrials); % begin with matrix of NaN's
shifts = zeros(1,ntrials);
if ~exist('medval') || isempty(medval)
medval= median(eventvals);
end
[medval medx] = min(abs(medval-xvals));
medval = xvals(medx);
if MULTICHANNEL
fprintf('Aligning data to median event frame %g.\n',medval);
else % SINGLE CHANNEL
fprintf('Aligning data to median event time %g.\n',medval);
end
for i=1:ntrials, %%%%%%%%% foreach trial %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% idx = eventvals(i);
% shft = round(medx-idx);
[tmpx idx] = min(abs(xvals-eventvals(i)));
shft = medx-idx;
if VERBOSE;fprintf('Trial %d -shift = %d\n',i,shft);end
shifts(i) = shft;
if MULTICHANNEL
shft = shft*rows; % shift in multiples of chans
end
if shft>0, % shift right %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if frames > shft
aligndata((1+shft):end,i) = data(1:(end-shft),i);
else
fprintf('No eventlocked data for epoch %d - required shift too large!\n',i);
end
elseif shft < 0 % shift left %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if frames > -shft
aligndata(1:(end+shft),i) = data((1-shft):end,i);
else
fprintf('No eventlocked data for epoch %d - required shift too large.\n',i);
end
else % shft == 0 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
aligndata(:,i) = data(:,i);
end
end % end trial %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fprintf('Shifted trials by %d to %d frames.\n',min(shifts),max(shifts));
if ~MULTICHANNEL
fprintf(' %g to %g msec.\n',...
1000/srate*min(shifts),1000/srate*max(shifts));
end
data = aligndata; % now data is aligned to sortvar
if MULTICHANNEL
data = reshape(data,rows,frames/rows*ntrials); % demultiplex channels
end