% CALIPER - Measure a set of spatial components of a given data epoch relative to
% a reference epoch and decomposition.
% Usage:
% >> [amp,window]=caliper(newepoch,refepoch,weights,compnums,filtnums,times,'noplot');
%
% Inputs:
% newepoch = (nchannels,ntimes) new data epoch
% refepoch = a (nchannels,ntimes) reference data epoch
% weights = (nchannels,ncomponents) unmixing matrix (e.g., ICA weights*sphere)
% compnums = vector of component numbers to return amplitudes for {def|0: all}
% filtnums = [srate highpass lowpass] filter limits for refepoch {def|0: allpass}
% times = [start_ms end_ms] epoch latency limits, else latencies vector {def|0: 0:EEG.pnts-1}
% 'noplot' = produce no plots {default: plots windows for the first <=3 components}
%
% Outputs:
% amps = (1,length(compnums)) vector of mean signed component rms amplitudes
% windows = (length(compnums)),length(times)) matrix of tapering windows used
%
% Notes:
% Function CALIPER works as follows: First the reference epoch is decomposed using
% the given weight matrix (may be ICA, PCA, or etc). Next, the time course of the
% main lobe of the activation in the reference epoch (from max to 1st min, forward
% and backward in time from abs max, optionally after bandpass filtering) is used
% to window the new epoch. Then, the windowed new epoch is decomposed by the same
% weight matrix, and signed rms amplitude (across the channels) is returned of the
% projection of each of the specified component numbers integrated across the windowed
% epoch. If not otherwise specified, plots the windows for the first <= 3 components listed.
%
% Example: Given a grand mean response epoch and weight matrix, it can be used
% to measure amps of grand mean components in single-subject averages.
%
% Authors: Scott Makeig & Marissa Westerfield, SCCN/INC/UCSD, La Jolla, 11/2000
% Copyright (C) 11/2000 Scott Makeig & Marissa Westerfield,, SCCN/INC/UCSD
%
% 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.
% Edit History:
% 12/05/00 -- added fig showing data, ref activation, and window vector -mw
% 12/19/00 -- adjusted new ICAPROJ args -sm
% 01-25-02 reformated help & license -ad
function [amps,windows] = caliper(newepoch,refepoch,weights,compnums,filtnums,times,noplot)
if nargin < 3
help caliper
return
end
if nargin<4
compnums = 0;
end
nchans = size(newepoch,1);
ntimes = size(newepoch,2);
if compnums(1) == 0 || isempty(compnums(1))
compnums = 1:nchans;
end
if min(compnums) < 1 || max(compnums) > size(weights,2)
help caliper
return
end
if nargin<5
filtnums = [];
else
if isempty(filtnums)
filtnums = [];
elseif length(filtnums)==1 && filtnums(1)==0
filtnums = [];
elseif length(filtnums) ~= 3
fprintf('\ncaliper(): filter parameters (filtnums) must have length 3.\n')
return
end
end
if nargin< 6 || isempty(times) || (length(times)==1 && times(1)==0)
times = 0:ntimes-1;
else
if length(times) ~= ntimes
if length(times) ~= 2
fprintf('caliper(): times argument should be [startms endms] or vector.\n')
return
else
times = times(1):(times(2)-times(1))/(ntimes-1):times(2);
times = times(1:ntimes);
end
end
end
if nargin < 7
noplot = 0;
else
noplot = 1;
end
refact = weights(compnums,:)*refepoch; % size (length(compnums),ntimes)
newact = weights(compnums,:)*newepoch;
if length(filtnums) == 3
if ~exist('eegfilt')
fprintf('caliper(): function eegfilt() not found - not filtering refepoch.\n');
else
try
refact = eegfilt(refact,filtnums(1),filtnums(2),filtnums(3));
catch
fprintf('\n%s',lasterr)
return
end
end
end
if size(weights,1) == size(weights,2)
winv = inv(weights);
else
winv = pinv(weights);
end
winvrms = sqrt(mean(winv.*winv)); % map rms amplitudes
amps = [];
windows = [];
n = 1; % component index
for c=compnums
if floor(c) ~= c
help caliper
fprintf('\ncaliper(): component numbers must be integers.\n')
return
end
[lobemax i] = max(abs(refact(n,:)));
f = i+1;
oldact = lobemax;
while f>0 & f<=ntimes & abs(refact(n,f)) < oldact
oldact = abs(refact(n,f));
f = f+1;
end % f is now one past end of "main lobe"
lobeend = f-1;
f = i-1;
oldact = lobemax;
while f>0 & f<=ntimes & abs(refact(n,f)) < oldact
oldact = abs(refact(n,f));
f = f-1;
end % f is now one past start of "main lobe"
lobestart = f+1;
refact(n,1:lobestart) = zeros(1,length(1:lobestart));
refact(n,lobeend:end) = zeros(1,length(lobeend:ntimes));
windows = [windows; refact(n,:)];
refnorm = sum(refact(n,:));
if abs(refnorm)<1e-25
fprintf('caliper(): near-zero activation for component %d - returning NaN amp.\n',c)
amps = [amps NaN];
else
refact(n,:) = refact(n,:)/refnorm; % make reference epoch window sum to 1
amps = [amps winvrms(c)*sum(refact(n,:).*newact(n,:))];
end
n = n+1;
if ~noplot && n <= 4 %%% only plot out at most the first 3 components
refproj = icaproj(refepoch,weights,c);
refproj = env(refproj);
windproj = winv(:,c)*(refact(n-1,:)*refnorm);
windproj = env(windproj);
figure; plot(times,newepoch(2:nchans,:),'g');
hold on;h=plot(times,newepoch(1,:),'g');
hold on;h=plot(times,newepoch(1,:),'g',...
times,refproj(1,:),'b',...
times,windproj(1,:),'r','LineWidth',2);
hold on;plot(times,refproj(2,:),'b',times,windproj(2,:),'r','LineWidth',2);
set(h(1),'linewidth',1);
legend(h,'new data','comp. act.','window');
title(['Component ',int2str(c),'; rms amplitude = ',num2str(amps(n-1))],...
'FontSize',14);
ylabel('Potential (uV)');
end; %% endif
end % c