% TIMEF - Returns estimates and plots of mean event-related spectral
%           perturbation (ERSP) and inter-trial coherence (ITC) changes
%           across event-related trials (epochs) of a single input time series.
%        * Uses either fixed-window, zero-padded FFTs (fastest), wavelet
%           0-padded DFTs (both Hanning-tapered), OR multitaper spectra ('mtaper').
%        * For the wavelet and FFT methods, output frequency spacing
%           is the lowest frequency ('srate'/'winsize') divided by 'padratio'.
%           NaN input values (such as returned by EVENTLOCK) are ignored.
%        * If 'alpha' is given, then bootstrap statistics are computed
%           (from a distribution of 'naccu' surrogate data trials) and
%           non-significant features of the output plots are zeroed out
%           (i.e., plotted in green).
%        * Given a 'topovec' scalp map weights vector and an 'elocs' electrode
%           location file or structure, the figure also shows a TOPOPLOT
%           image of the specified scalp map.
%
%        * Note: Left-click on subplots to view and zoom in separate windows.
% Usage:
%        >> [ersp,itc,powbase,times,freqs,erspboot,itcboot,itcphase] = ...
%                timef(data,frames,tlimits,srate,cycles,...
%                                 'key1',value1,'key2',value2, ... );
% NOTE:
%        * For more detailed information about TIMEF, >> timef details
%        * Default values may differ when called from POP_TIMEF
%
% Required inputs:
%       data        = Single-channel data vector (1,frames*ntrials) (required)
%       frames      = Frames per trial                     {def|[]: datalength}
%       tlimits     = [mintime maxtime] (ms) Epoch time limits
%                      {def|[]: from frames,srate}
%       srate       = data sampling rate (Hz)                  {def:250}
%       cycles      = If 0 -> Use FFTs (with constant window length) {0 = FFT}
%                     If >0 -> Number of cycles in each analysis wavelet
%                     If [wavecycles factor] -> wavelet cycles increase with
%                     frequency  beginning at wavecyles (0<factor<1; factor=1
%                     -> no increase, standard wavelets; factor=0 -> fixed epoch
%                     length, as in FFT.  Else, 'mtaper' -> multitaper decomp.
%
%    Optional Inter-Irial Coherence (ITC) type:
%       'type'      = ['coher'|'phasecoher'] Compute either linear coherence
%                      ('coher') or phase coherence ('phasecoher') also known
%                      as the phase coupling factor           {'phasecoher'}.
%    Optional detrending:
%       'detret'    = ['on'|'off'], Detrend data in time.               {'off'}
%       'detrep'    = ['on'|'off'], Detrend data across trials          {'off'}
%
%    Optional FFT/DFT parameters:
%       'winsize'   = If cycles==0: data subwindow length (fastest, 2^n<frames);
%                     If cycles >0: *longest* window length to use. This
%                      determines the lowest output frequency       {~frames/8}
%       'timesout'  = Number of output times (int<frames-winframes)       {200}
%       'padratio'  = FFT-length/winframes (2^k)                            {2}
%                      Multiplies the number of output frequencies by
%                      dividing their spacing. When cycles==0, frequency
%                      spacing is (low_freq/padratio).
%       'maxfreq'   = Maximum frequency (Hz) to plot (& to output if cycles>0)
%                      If cycles==0, all FFT frequencies are output.      {50}
%       'baseline'  = Spectral baseline window center end-time (in ms).    {0}
%       'powbase'   = Baseline spectrum (power, not dB) to normalize the data.
%                      {def|NaN->from data}
%
%    Optional multitaper parameters:
%       'mtaper'    = If [N W], performs multitaper decomposition.
%                      (N is the time resolution and W the frequency resolution;
%                      maximum taper number is 2NW-1). Overwrites 'winsize' and
%                      'padratio'.
%                     If [N W K], uses K Slepian tapers (if possible).
%                      Phase is calculated using standard methods.
%                      The use of mutitaper with wavelets (cycles>0) is not
%                      recommended (as multiwavelets are not implemented).
%                      Uses Matlab functions DPSS, PMTM.      {no multitaper}
%
%    Optional bootstrap parameters:
%       'alpha'     = If non-0, compute two-tailed bootstrap significance prob.
%                     level. Show non-signif. output values in green       {0}
%       'naccu'     = Number of bootstrap replications to accumulate       {200}
%       'baseboot'  = Bootstrap baseline to subtract (1 -> use 'baseline'(above)
%                                                     0 -> use whole trial) {1}
%    Optional scalp map:
%       'topovec'   = Scalp topography (map) to plot                     {none}
%       'elocs'     = Electrode location file for scalp map
%                     File should be ascii in format of  >> topoplot example
%                     May also be an EEG.chanlocs struct.
%                     {default: file named in icadefs.m}
%    Optional plotting parameters:
%       'hzdir'     = ['up'|'down'] Direction of the frequency axes; reads default
%                     from icadefs.m                                     {'up'}
%       'plotersp'  = ['on'|'off'] Plot power spectral perturbations     {'on'}
%       'plotitc'   = ['on'|'off'] Plot inter trial coherence            {'on'}
%       'plotphase' = ['on'|'off'] Plot sign of the phase in the ITC panel, i.e.
%                     green->red, pos.-phase ITC, green->blue, neg.-phase ITC {'on'}
%       'erspmax'   = [real dB] set the ERSP max. for the scale (min= -max){auto}
%       'itcmax'    = [real<=1] set the ITC maximum for the scale          {auto}
%       'title'     = Optional figure title                                {none}
%       'marktimes' = Non-0 times to mark with a dotted vertical line (ms) {none}
%       'linewidth' = Line width for 'marktimes' traces (thick=2, thin=1)  {2}
%       'pboot'     = Bootstrap power limits (e.g., from TIMEF)    {from data}
%       'rboot'     = Bootstrap ITC limits (e.g., from TIMEF)      {from data}
%       'axesfont'  = Axes text font size                                  {10}
%       'titlefont' = Title text font size                                 {8}
%       'vert'      = [times_vector] -> plot vertical dashed lines at given ms.
%       'verbose'   = ['on'|'off'] print text                              {'on'}
%
%    Outputs:
%            ersp   = Matrix (nfreqs,timesout) of log spectral diffs. from
%                     baseline (in dB).  NB: Not masked for significance.
%                     Must do this using erspboot
%            itc    = Matrix of inter-trial coherencies (nfreqs,timesout)
%                     (range: [0 1]) NB: Not masked for significance.
%                     Must do this using itcboot
%          powbase  = Baseline power spectrum (NOT in dB, used to norm. the ERSP)
%            times  = Vector of output times (sub-window centers) (in ms)
%            freqs  = Vector of frequency bin centers (in Hz)
%         erspboot  = Matrix (2,nfreqs) of [lower;upper] ERSP significance diffs
%          itcboot  = Matrix (2,nfreqs) of [lower;upper] ITC thresholds (not diffs)
%          itcphase = Matrix (nfreqs,timesout) of ITC phase (in radians)
%
% Plot description:
%   Assuming both 'plotersp' and 'plotitc' options are 'on' (= default).
%   The upper panel presents the data ERSP (Event-Related Spectral Perturbation)
%   in dB, with mean baseline spectral activity (in dB) subtracted. Use
%   "'baseline', NaN" to prevent TIMEF from removing the baseline.
%   The lower panel presents the data ITC (Inter-Trial Coherence).
%   Click on any plot axes to pop up a new window (using 'AXCOPY')
%   -- Upper left marginal panel presents the mean spectrum during the baseline
%      period (blue), and when significance is set, the significance threshold
%      at each frequency (dotted green-black trace).
%   -- The marginal panel under the ERSP image shows the maximum (green) and
%      minimum (blue) ERSP values relative to baseline power at each frequency.
%   -- The lower left marginal panel shows mean ITC across the imaged time range
%      (blue), and when significance is set, the significance threshold (dotted
%      green-black).
%   -- The marginal panel under the ITC image shows the ERP (which is produced by
%      ITC across the data spectral pass band).
%
% Author: Sigurd Enghoff, Arnaud Delorme & Scott Makeig
%          CNL / Salk Institute 1998- | SCCN/INC, UCSD 2002-
%
% Known problems:
%   Significance masking currently fails for linear coherence.
%
% See also: CROSSF

% Copyright (C) 1998 Sigurd Enghoff, Scott Makeig, Arnaud Delorme,
% CNL / Salk Institute 8/1/98-8/28/01
%
% 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.

% 10-19-98 avoided division by zero (using MIN_ABS) -sm
% 10-19-98 improved usage message and commandline info printing -sm
% 10-19-98 made valid [] values for tvec and g.elocs -sm
% 04-01-99 added missing freq in freqs and plots, fixed log scaling bug -se & -tpj
% 06-29-99 fixed frequency indexing for constant-Q -se
% 08-24-99 reworked to handle NaN input values -sm
% 12-07-99 adjusted ERPtimes to plot ERP under ITC -sm
% 12-22-99 debugged ERPtimes, added BASE_BOOT -sm
% 01-10-00 debugged BASE_BOOT=0 -sm
% 02-28-00 added NOTE on formula derivation below -sm
% 03-16-00 added AXCOPY feature -sm & tpj
% 04-16-00 added multiple marktimes loop -sm
% 04-20-00 fixed ITC cbar limits when specified in input -sm
% 07-29-00 changed frequencies displayed msg -sm
% 10-12-00 fixed bug in freqs when cycles>0 -sm
% 02-07-01 fixed inconsistency in BASE_BOOT use -sm
% 08-28-01 matlab 'key' value arguments -ad
% 08-28-01 multitaper decomposition -ad
% 01-25-02 reformated help & license -ad
% 03-08-02 debug & compare to old timef function -ad
% 03-16-02 timeout automatically adjusted if too high -ad
% 04-02-02 added 'coher' option -ad

function [P,R,mbase,times,freqs,Pboot,Rboot,Rphase,PA] = timef(X,frames,tlimits,Fs,varwin,varargin);

% Note: undocumented arg PA is output of 'phsamp','on'

%varwin,winsize,g.timesout,g.padratio,g.maxfreq,g.topovec,g.elocs,g.alpha,g.marktimes,g.powbase,g.pboot,g.rboot)

% ITC:   Normally, R = |Sum(Pxy)| / (Sum(|Pxx|)*Sum(|Pyy|)) is linear coherence.
%        But here, we consider:  Phase(Pyy) = 0 and |Pyy| = 1 -> Pxy = Pxx
%        Giving, R = |Sum(Pxx)|/Sum(|Pxx|), the inter-trial coherence (ITC)
%        Also called 'phase-locking factor' by Tallon-Baudry et al. (1996),
%        the ITC is the phase coherence between the data time series and the
%        time-locking event time series.

% Read system-wide / dir-wide constants:
icadefs

% Constants set here:
ERSP_CAXIS_LIMIT = 0;           % 0 -> use data limits; else positive value
                                % giving symmetric +/- caxis limits.
ITC_CAXIS_LIMIT  = 0;           % 0 -> use data limits; else positive value
                                % giving symmetric +/- caxis limits.

% Commandline arg defaults:
DEFAULT_EPOCH	= NaN;		% Frames per trial
DEFAULT_TIMLIM  = NaN;	                % Time range of g.frames (ms)
DEFAULT_FS	= 250;			% Sampling frequency (Hz)
DEFAULT_NWIN	= 200;			% Number of windows = horizontal resolution
DEFAULT_VARWIN	= 0;			% Fixed window length or fixed number of cycles.
				% =0: fix window length to that determined by nwin
				% >0: set window length equal to varwin cycles
				%     Bounded above by winsize, which determines
				%     the min. freq. to be computed.
DEFAULT_OVERSMP	= 2;			% Number of times to oversample frequencies
DEFAULT_MAXFREQ = 50;			% Maximum frequency to display (Hz)
DEFAULT_TITLE	= '';			% Figure title
DEFAULT_ELOC    = 'chan.locs';	% Channel location file
DEFAULT_ALPHA   = NaN;			% Percentile of bins to keep
DEFAULT_MARKTIME= NaN;

% Font sizes:
AXES_FONT       = 10;           % axes text FontSize
TITLE_FONT      = 8;

if nargout>7
   Rphase = []; % initialize in case Rphase asked for, but ITC not computed
end

if (nargin < 1)
	help timef
	return
end

if ischar(X) && strcmp(X,'details')
   more on
   help timefdetails
   more off
   return
end

if (min(size(X))~=1 || length(X)<2)
	error('Data must be a row or column vector.');
end

if nargin < 2 || isempty(frames) || isnan(frames)
	frames = DEFAULT_EPOCH;
elseif (~isnumeric(frames) || length(frames)~=1 || frames~=round(frames))
	error('Value of frames must be an integer.');
elseif (frames <= 0)
	error('Value of frames must be positive.');
elseif (rem(length(X),frames) ~= 0)
	error('Length of data vector must be divisible by frames.');
end
if isnan(frames) || isempty(frames)
    frames = length(X);
end

if nargin < 3 || isempty(tlimits) || isnan(tlimits(1))
	tlimits = DEFAULT_TIMLIM;
elseif (~isnumeric(tlimits) || sum(size(tlimits))~=3)
	error('Value of tlimits must be a vector containing two numbers.');
elseif (tlimits(1) >= tlimits(2))
	error('tlimits interval must be ascending.');
end

if (nargin < 4)
	Fs = DEFAULT_FS;
elseif (~isnumeric(Fs) || length(Fs)~=1)
	error('Value of srate must be a number.');
elseif (Fs <= 0)
	error('Value of srate must be positive.');
end

if isempty(tlimits) || isnan(tlimits(1))
   hlim = 1000*frames/Fs;  % fit default tlimits to srate and frames
   tlimits = [0 hlim];
end

framesdiff = frames - Fs*(tlimits(2)-tlimits(1))/1000;
if abs(framesdiff) > 1
        error('Given time limits, frames and sampling rate are incompatible');
elseif framesdiff ~= 0
   	tlimits(1) = tlimits(1) - 0.5*framesdiff*1000/Fs;
   	tlimits(2) = tlimits(2) + 0.5*framesdiff*1000/Fs;
    	fprintf('Adjusted time limits slightly, to [%.1f,%.1f] ms, to match frames and srate.\n',tlimits(1),tlimits(2));
end

if (nargin < 5)
	varwin = DEFAULT_VARWIN;
elseif (~isnumeric(varwin) || length(varwin)>2)
	error('Value of cycles must be a number.');
elseif (varwin < 0)
	error('Value of cycles must be zero or positive.');
end

% consider structure for these arguments
% --------------------------------------
if ~isempty(varargin)
    try, g = struct(varargin{:});
    catch, error('Argument error in the {''param'', value} sequence'); end;
end
g.tlimits = tlimits;
g.frames   = frames;
g.srate   = Fs;
g.cycles  = varwin(1);
if length(varwin)>1
	g.cyclesfact = varwin(2);
else
	g.cyclesfact = 1;
end

try, g.title;      catch, g.title = DEFAULT_TITLE; end
try, g.winsize;    catch, g.winsize = max(pow2(nextpow2(g.frames)-3),4); end
try, g.pad;        catch, g.pad = max(pow2(nextpow2(g.winsize)),4); end
try, g.timesout;   catch, g.timesout = DEFAULT_NWIN; end
try, g.padratio;   catch, g.padratio = DEFAULT_OVERSMP; end
try, g.maxfreq;    catch, g.maxfreq = DEFAULT_MAXFREQ; end
try, g.topovec;    catch, g.topovec = []; end
try, g.elocs;      catch, g.elocs = DEFAULT_ELOC; end
try, g.alpha;      catch, g.alpha = DEFAULT_ALPHA; end;
try, g.marktimes;  catch, g.marktimes = DEFAULT_MARKTIME; end
try, g.powbase;    catch, g.powbase = NaN; end
try, g.pboot;      catch, g.pboot = NaN; end
try, g.rboot;      catch, g.rboot = NaN; end
try, g.plotersp;   catch, g.plotersp = 'on'; end
try, g.plotitc;    catch, g.plotitc  = 'on'; end
try, g.detrep;     catch, g.detrep = 'off'; end
try, g.detret;     catch, g.detret = 'off'; end
try, g.baseline;   catch, g.baseline = 0; end
try, g.baseboot;   catch, g.baseboot = 1; end
try, g.linewidth;  catch, g.linewidth = 2; end
try, g.naccu;      catch, g.naccu = 200; end
try, g.mtaper;     catch, g.mtaper = []; end
try, g.vert;       catch, g.vert = []; end
try, g.type;       catch, g.type = 'phasecoher'; end
try, g.phsamp;     catch, g.phsamp = 'off'; end
try, g.plotphase;  catch, g.plotphase = 'on'; end
try, g.itcmax;     catch, g.itcmax = []; end
try, g.erspmax;    catch, g.erspmax = []; end
try, g.verbose;    catch, g.verbose = 'on'; end
try, g.chaninfo;   catch, g.chaninfo = []; end
try, g.hzdir;      catch, g.hzdir = HZDIR; end; % default from icadefs
lasterr('');

% testing arguments consistency
% -----------------------------
if strcmp(g.hzdir,'up')
    g.hzdir = 'normal';
elseif strcmp(g.hzdir,'down')
    g.hzdir = 'reverse';
else
    error('unknown ''hzdir'' value - not ''up'' or ''down''');
end

switch lower(g.verbose)
    case { 'on', 'off' }, ;
    otherwise error('verbose must be either on or off');
end
if (~ischar(g.title))
	error('Title must be a string.');
end

if (~isnumeric(g.winsize) || length(g.winsize)~=1 || g.winsize~=round(g.winsize))
	error('Value of winsize must be an integer number.');
elseif (g.winsize <= 0)
	error('Value of winsize must be positive.');
elseif (g.cycles == 0 && pow2(nextpow2(g.winsize)) ~= g.winsize)
	error('Value of winsize must be an integer power of two [1,2,4,8,16,...]');
elseif (g.winsize > g.frames)
	error('Value of winsize must be less than frames per epoch.');
end

if (~isnumeric(g.timesout) || length(g.timesout)~=1 || g.timesout~=round(g.timesout))
	error('Value of timesout must be an integer number.');
elseif (g.timesout <= 0)
	error('Value of timesout must be positive.');
end
if (g.timesout > g.frames-g.winsize)
	g.timesout = g.frames-g.winsize;
	disp(['Value of timesout must be <= frames-winsize, timeout adjusted to ' int2str(g.timesout) ]);
end

if (~isnumeric(g.padratio) || length(g.padratio)~=1 || g.padratio~=round(g.padratio))
	error('Value of padratio must be an integer.');
elseif (g.padratio <= 0)
	error('Value of padratio must be positive.');
elseif (pow2(nextpow2(g.padratio)) ~= g.padratio)
	error('Value of padratio must be an integer power of two [1,2,4,8,16,...]');
end

if (~isnumeric(g.maxfreq) || length(g.maxfreq)~=1)
	error('Value of maxfreq must be a number.');
elseif (g.maxfreq <= 0)
	error('Value of maxfreq must be positive.');
elseif (g.maxfreq > Fs/2)
	myprintf(g.verbose,['Warning: value of maxfreq reduced to Nyquist rate' ...
		 ' (%3.2f)\n\n'], Fs/2);
	g.maxfreq = Fs/2;
end

if isempty(g.topovec)
	g.topovec = [];
	if isempty(g.elocs)
		error('Channel location file must be specified.');
	end
end
if isempty(g.elocs)
	g.elocs = DEFAULT_ELOC;
elseif (~ischar(g.elocs)) && ~isstruct(g.elocs)
	error('Channel location file must be a valid text file.');
end

if (~isnumeric(g.alpha) || length(g.alpha)~=1)
	error('timef(): Value of g.alpha must be a number.\n');
elseif (round(g.naccu*g.alpha) < 2)
	myprintf(g.verbose,'Value of g.alpha is out of the normal range [%g,0.5]\n',2/g.naccu);
    g.naccu = round(2/g.alpha);
	myprintf(g.verbose,'  Increasing the number of bootstrap iterations to %d\n',g.naccu);
end
if g.alpha>0.5 || g.alpha<=0
    error('Value of g.alpha is out of the allowed range (0.00,0.5).');
end
if ~isnan(g.alpha)
   if g.baseboot > 0
     myprintf(g.verbose,'Bootstrap analysis will use data in baseline (pre-0 centered) subwindows only.\n')
   else
     myprintf(g.verbose,'Bootstrap analysis will use data in all subwindows.\n')
   end
end
if ~isnumeric(g.vert)
    error('vertical line(s) option must be a vector');
else
	if ~isempty(g.vert)
        if min(g.vert(:)) < g.tlimits(1) || max(g.vert(:)) > g.tlimits(2)
            error('vertical line(s) time out-of-bound');
        end
	end
end

if ~isnan (g.rboot)
  if size(g.rboot) == [1,1]
    if g.cycles == 0
        g.rboot = g.rboot*ones(g.winsize*g.padratio/2);
    end
  end
end

if ~isempty(g.mtaper) % mutitaper, inspired from Bijan Pesaran matlab function
  if length(g.mtaper) < 3
        %error('mtaper argument must be [N W] or [N W K]');

    if g.mtaper(1) * g.mtaper(2) < 1
        error('mtaper 2 first arguments'' product must be higher than 1');
    end
    if length(g.mtaper) == 2
        g.mtaper(3) = floor( 2*g.mtaper(2)*g.mtaper(1) - 1);
    end
    if length(g.mtaper) == 3
        if g.mtaper(3) > 2 * g.mtaper(1) * g.mtaper(2) -1
            error('mtaper number too high (maximum (2*N*W-1))');
        end
    end
    disp(['Using ' num2str(g.mtaper(3)) ' tapers.']);
    NW = g.mtaper(1)*g.mtaper(2);   % product NW
    N  = g.mtaper(1)*g.srate;
    [e,v] = dpss(N, NW, 'calc');
    e=e(:,1:g.mtaper(3));
    g.alltapers = e;
  else
    g.alltapers = g.mtaper;
    disp('mtaper argument not [N W] or [N W K]; considering raw taper matrix');
  end

  g.winsize = size(g.alltapers, 1);
  g.pad = max(pow2(nextpow2(g.winsize)),256); % pad*nextpow

  %nfk = floor([0 g.maxfreq]./g.srate.*g.pad); % not used any more
  %g.padratio = 2*nfk(2)/g.winsize;

  g.padratio = g.pad/g.winsize;

  %compute number of frequencies
  %nf = max(256, g.pad*2^nextpow2(g.winsize+1));
  %nfk = floor([0 g.maxfreq]./g.srate.*nf);
  %freqs = linspace( 0, g.maxfreq, diff(nfk)); % this also work in the case of a FFT

end;

switch lower(g.plotphase)
    case { 'on', 'off' }, ;
    otherwise error('plotphase must be either on or off');
end
switch lower(g.plotersp)
    case { 'on', 'off' }, ;
    otherwise error('plotersp must be either on or off');
end
switch lower(g.plotitc)
    case { 'on', 'off' }, ;
    otherwise error('plotitc must be either on or off');
end
switch lower(g.detrep)
    case { 'on', 'off' }, ;
    otherwise error('detrep must be either on or off');
end
switch lower(g.detret)
    case { 'on', 'off' }, ;
    otherwise error('detret must be either on or off');
end
switch lower(g.phsamp)
    case { 'on', 'off' }, ;
    otherwise error('phsamp must be either on or off');
end
if ~isnumeric(g.linewidth)
    error('linewidth must be numeric');
end
if ~isnumeric(g.naccu)
    error('naccu must be numeric');
end
if ~isnumeric(g.baseline)
    error('baseline must be numeric');
end
switch g.baseboot
    case {0,1}, ;
    otherwise, error('baseboot must be 0 or 1');
end
switch g.type
    case { 'coher', 'phasecoher', 'phasecoher2' },;
    otherwise error('Type must be either ''coher'' or ''phasecoher''');
end;
if isnan(g.baseline)
    g.unitpower = 'uV/Hz';
else
    g.unitpower = 'dB';
end

if (g.cycles == 0) %%%%%%%%%%%%%% constant window-length FFTs %%%%%%%%%%%%%%%%
    freqs = linspace(0, g.srate/2, g.padratio*g.winsize/2+1);
    freqs = freqs(2:end);
    win = hanning(g.winsize);

    P  = zeros(g.padratio*g.winsize/2,g.timesout); % summed power
    PP = zeros(g.padratio*g.winsize/2,g.timesout); % power
    R  = zeros(g.padratio*g.winsize/2,g.timesout); % mean coherence
    RR = zeros(g.padratio*g.winsize/2,g.timesout); % (coherence)
    Pboot = zeros(g.padratio*g.winsize/2,g.naccu); % summed bootstrap power
    Rboot = zeros(g.padratio*g.winsize/2,g.naccu); % summed bootstrap coher
    Rn = zeros(1,g.timesout);
    Rbn = 0;

	switch g.type
	    case { 'coher' 'phasecoher2' },
           cumulX = zeros(g.padratio*g.winsize/2,g.timesout);
           cumulXboot = zeros(g.padratio*g.winsize/2,g.naccu);
        case 'phasecoher'
           switch g.phsamp
             case 'on'
               cumulX = zeros(g.padratio*g.winsize/2,g.timesout);
           end
    end;

else % %%%%%%%%%%%%%%%%%% cycles>0, Constant-Q (wavelet) DFTs %%%%%%%%%%%%%%%%%%%%

    freqs = g.srate*g.cycles/g.winsize*[2:2/g.padratio:g.winsize]/2;
    dispf = find(freqs <= g.maxfreq);
    freqs = freqs(dispf);

    win = dftfilt(g.winsize,g.maxfreq/g.srate,g.cycles,g.padratio,g.cyclesfact);
    P = zeros(size(win,2),g.timesout);       % summed power
    R = zeros(size(win,2),g.timesout);       % mean coherence
    PP = repmat(NaN,size(win,2),g.timesout); % initialize with NaN
    RR = repmat(NaN,size(win,2),g.timesout); % initialize with NaN
    Pboot = zeros(size(win,2),g.naccu);  % summed bootstrap power
    Rboot = zeros(size(win,2),g.naccu);  % summed bootstrap coher
    Rn = zeros(1,g.timesout);
    Rbn = 0;

	switch g.type
	  case { 'coher' 'phasecoher2' },
           cumulX = zeros(size(win,2),g.timesout);
           cumulXboot = zeros(size(win,2),g.naccu);
      case 'phasecoher'
           switch g.phsamp
             case 'on'
               cumulX = zeros(size(win,2),g.timesout);
           end
   end;
end

switch g.phsamp
  case 'on'
    PA = zeros(size(P,1),size(P,1),g.timesout); % NB: (freqs,freqs,times)
end                                             %       phs   amp

wintime = 1000/g.srate*(g.winsize/2); % (1000/g.srate)*(g.winsize/2);
times = [g.tlimits(1)+wintime:(g.tlimits(2)-g.tlimits(1)-2*wintime)/(g.timesout-1):g.tlimits(2)-wintime];
ERPtimes = [g.tlimits(1):(g.tlimits(2)-g.tlimits(1))/(g.frames-1):g.tlimits(2)+0.000001];
ERPindices = [];
for ti=times
 [tmp indx] = min(abs(ERPtimes-ti));
 ERPindices  = [ERPindices indx];
end
ERPtimes = ERPtimes(ERPindices); % subset of ERP frames on t/f window centers

if ~isempty(find(times < g.baseline))
   baseln = find(times < g.baseline); % subtract means of pre-0 (centered) windows
else
   baseln = 1:length(times); % use all times as baseline
end
if ~isnan(g.alpha) && length(baseln)==0
  myprintf(g.verbose,'timef(): no window centers in baseline (times<%g) - shorten (max) window length.\n', g.baseline)
  return
elseif ~isnan(g.alpha) && g.baseboot
  myprintf(g.verbose,'   %d bootstrap windows in baseline (center times < %g).\n',...
          length(baseln), g.baseline)
end
dispf = find(freqs <= g.maxfreq);
stp = (g.frames-g.winsize)/(g.timesout-1);

myprintf(g.verbose,'Computing Event-Related Spectral Perturbation (ERSP) and\n');
switch g.type
    case 'phasecoher',  myprintf(g.verbose,'  Inter-Trial Phase Coherence (ITC) images based on %d trials\n',length(X)/g.frames);
    case 'phasecoher2', myprintf(g.verbose,'  Inter-Trial Phase Coherence 2 (ITC) images based on %d trials\n',length(X)/g.frames);
    case 'coher',       myprintf(g.verbose,'  Linear Inter-Trial Coherence (ITC) images based on %d trials\n',length(X)/g.frames);
end
myprintf(g.verbose,'  of %d frames sampled at %g Hz.\n',g.frames,g.srate);
myprintf(g.verbose,'Each trial contains samples from %d ms before to\n',g.tlimits(1));
myprintf(g.verbose,'  %.0f ms after the timelocking event.\n',g.tlimits(2));
myprintf(g.verbose,'The window size used is %d samples (%g ms) wide.\n',g.winsize,2*wintime);
myprintf(g.verbose,'The window is applied %d times at an average step\n',g.timesout);
myprintf(g.verbose,'  size of %g samples (%g ms).\n',stp,1000*stp/g.srate);
myprintf(g.verbose,'Results are oversampled %d times; the %d frequencies\n',g.padratio,length(dispf));
myprintf(g.verbose,'  displayed are from %2.1f Hz to %3.1f Hz.\n',freqs(dispf(1)),freqs(dispf(end)));
if ~isnan(g.alpha)
  myprintf(g.verbose,'Only significant values (bootstrap p<%g) will be colored;\n',g.alpha)
  myprintf(g.verbose,'  non-significant values will be plotted in green\n');
end

trials = length(X)/g.frames;
baselength = length(baseln);
myprintf(g.verbose,'\nOf %d trials total, processing trial:',trials);

% detrend over epochs (trials) if requested
% -----------------------------------------
switch g.detrep
    case 'on'
        X = reshape(X, g.frames, length(X)/g.frames);
        X = X - mean(X,2)*ones(1, length(X(:))/g.frames);
        X = X(:)';
end;

for i=1:trials
    if (rem(i,100)==0)
        myprintf(g.verbose,'\n');
    end
	if (rem(i,10) == 0)
		myprintf(g.verbose,'%d',i);
	elseif (rem(i,2) == 0)
		myprintf(g.verbose,'.');
	end

    ERP = blockave(X,g.frames); % compute the ERP trial average

    Wn = zeros(1,g.timesout);
	for j=1:g.timesout,
		tmpX = X([1:g.winsize]+floor((j-1)*stp)+(i-1)*g.frames);
                                                      % pull out data g.frames
		tmpX = tmpX - mean(tmpX); % remove the mean for that window
        switch g.detret, case 'on', tmpX = detrend(tmpX); end
		if ~any(isnan(tmpX))
		  if (g.cycles == 0) % FFT
            if ~isempty(g.mtaper)   % apply multitaper (no hanning window)
                tmpXMT = fft(g.alltapers .* ...
                             (tmpX(:) * ones(1,size(g.alltapers,2))), g.pad);
			    %tmpXMT = tmpXMT(nfk(1)+1:nfk(2),:);
			    tmpXMT = tmpXMT(2:g.padratio*g.winsize/2+1,:);
                PP(:,j) = mean(abs(tmpXMT).^2, 2);
                  % power; can also ponderate multitaper by their eigenvalues v
		        tmpX = win .* tmpX(:);
               	tmpX = fft(tmpX, g.pad);
    		    tmpX = tmpX(2:g.padratio*g.winsize/2+1);
            else
               % TF and MC (12/2006): Calculation changes made so that
                % power can be correctly calculated from ERSP.
		        tmpX = win .* tmpX(:);
               	tmpX = fft(tmpX,g.padratio*g.winsize);
                tmpX = tmpX / g.winsize;    % TF and MC (12/11/2006): normalization, divide by g.winsize
    		    tmpX = tmpX(2:g.padratio*g.winsize/2+1);
                PP(:,j) = 2/0.375*abs(tmpX).^2; % power
                % TF and MC (12/14/2006): multiply by 2 account for negative frequencies,
                % Counteract the reduction by a factor 0.375
                % that occurs as a result of cosine (Hann) tapering. Refer to Bug 446
            end;
          else % wavelet
            if ~isempty(g.mtaper)  % apply multitaper
			    tmpXMT = g.alltapers .* (tmpX(:) * ones(1,size(g.alltapers,2)));
			    tmpXMT = transpose(win) * tmpXMT;
                PP(:,j) = mean(abs(tmpXMT).^2, 2); % power
		        tmpX = transpose(win) * tmpX(:);
            else
		        tmpX = transpose(win) * tmpX(:);
                PP(:,j) = abs(tmpX).^2; % power
            end
          end

          if abs(tmpX) < eps    % If less than smallest possible machine value
                                % (i.e. if it's zero) then call it 0.
		        RR(:,j) = zeros(size(RR(:,j)));
          else
		      switch g.type
		        case { 'coher' },
		          RR(:,j) = tmpX;
                  cumulX(:,j) = cumulX(:,j)+abs(tmpX).^2;
		        case { 'phasecoher2' },
		          RR(:,j) = tmpX;
                  cumulX(:,j) = cumulX(:,j)+abs(tmpX);
		        case 'phasecoher',
		          RR(:,j) = tmpX ./ abs(tmpX); % normalized cross-spectral vector
         		  switch g.phsamp
             		  case 'on'
                	    cumulX(:,j) = cumulX(:,j)+abs(tmpX); % accumulate for PA
          		  end
              end
         end
          Wn(j) = 1;
        end

        switch g.phsamp
         case 'on' % PA (freq x freq x time)
          PA(:,:,j) = PA(:,:,j)  + (tmpX ./ abs(tmpX)) * ((PP(:,j)))';
                                           % cross-product: unit phase (column)
                                           %                times amplitude (row)
        end
	end % window

	if ~isnan(g.alpha) % save surrogate data for bootstrap analysis
        j = 1;
        goodbasewins = find(Wn==1);
        if g.baseboot % use baseline windows only
          goodbasewins = find(goodbasewins<=baselength);
        end
        ngdbasewins = length(goodbasewins);
        if ngdbasewins>1
		  while j <= g.naccu
            i=ceil(rand*ngdbasewins);
            i=goodbasewins(i);
			Pboot(:,j) = Pboot(:,j) + PP(:,i);
		    Rboot(:,j) = Rboot(:,j) + RR(:,i);
		    switch g.type
		        case 'coher',       cumulXboot(:,j) = cumulXboot(:,j)+abs(tmpX).^2;
		        case 'phasecoher2', cumulXboot(:,j) = cumulXboot(:,j)+abs(tmpX);
            end
            j = j+1;
          end
          Rbn = Rbn + 1;
	    end
	end % bootstrap

    Wn = find(Wn>0);
    if length(Wn)>0
	  P(:,Wn) = P(:,Wn) + PP(:,Wn); % add non-NaN windows
	  R(:,Wn) = R(:,Wn) + RR(:,Wn);
	  Rn(Wn) = Rn(Wn) + ones(1,length(Wn)); % count number of addends
    end
end % trial

% if coherence, perform the division
% ----------------------------------
switch g.type
 case 'coher',
  R = R ./ ( sqrt( trials*cumulX ) );
  if ~isnan(g.alpha)
	  Rboot = Rboot ./ ( sqrt( trials*cumulXboot ) );
  end
 case 'phasecoher2',
  R = R ./ ( cumulX );
  if ~isnan(g.alpha)
	  Rboot = Rboot ./ cumulXboot;
  end;
 case 'phasecoher',
  R = R ./ (ones(size(R,1),1)*Rn);
end;

switch g.phsamp
 case 'on'
  tmpcx(1,:,:) = cumulX; % allow ./ below
  for j=1:g.timesout
    PA(:,:,j) = PA(:,:,j) ./ repmat(PP(:,j)', [size(PP,1) 1]);
  end
end

if min(Rn) < 1
  myprintf(g.verbose,'timef(): No valid timef estimates for windows %s of %d.\n',...
                         int2str(find(Rn==0)),length(Rn));
  Rn(find(Rn<1))==1;
  return
end
P = P ./ (ones(size(P,1),1) * Rn);

if isnan(g.powbase)
  myprintf(g.verbose,'\nComputing the mean baseline spectrum\n');
  mbase = mean(P(:,baseln),2)';
else
  myprintf(g.verbose,'Using the input baseline spectrum\n');
  mbase = g.powbase;
end
if ~isnan( g.baseline(1) ) && ~isnan( mbase(1) )
    P = 10 * (log10(P) - repmat(log10(mbase(1:size(P,1)))',[1 g.timesout])); % convert to (10log10) dB
else
    P = 10 * log10(P);
end

Rsign = sign(imag(R));
if nargout > 7
   for lp = 1:size(R,1)
       Rphase(lp,:) = rem(angle(R(lp,:)),2*pi); % replaced obsolete phase() -sm 2/1/6
   end
   Rphase(find(Rphase>pi))  = 2*pi-Rphase(find(Rphase>pi));
   Rphase(find(Rphase<-pi)) = -2*pi-Rphase(find(Rphase<-pi));
end

R = abs(R); % convert coherence vector to magnitude

if ~isnan(g.alpha) % if bootstrap analysis included . . .
    if Rbn>0
	   i = round(g.naccu*g.alpha);
       if isnan(g.pboot)
            Pboot = Pboot / Rbn; % normalize
            if ~isnan( g.baseline )
	            Pboot = 10 * (log10(Pboot) - repmat(log10(mbase)',[1 g.naccu]));
            else
                Pboot = 10 * log10(Pboot);
            end;
            Pboot = sort(Pboot');
	        Pboot = [mean(Pboot(1:i,:)) ; mean(Pboot(g.naccu-i+1:g.naccu,:))];
       else
            Pboot = g.pboot;
       end

      if isnan(g.rboot)
	       Rboot = abs(Rboot) / Rbn;
	       Rboot = sort(Rboot');
	       Rboot = mean(Rboot(g.naccu-i+1:g.naccu,:));
      else
           Rboot = g.rboot;
      end
    else
      myprintf(g.verbose,'No valid bootstrap trials...!\n');
    end
end

switch lower(g.plotitc)
   case 'on',
       switch lower(g.plotersp),
          case 'on', ordinate1 = 0.67; ordinate2 = 0.1; height = 0.33; g.plot = 1;
          case 'off', ordinate2 = 0.1; height = 0.9; g.plot = 1;
       end;
   case 'off', ordinate1 = 0.1; height = 0.9;
       switch lower(g.plotersp),
          case 'on', ordinate1 = 0.1; height = 0.9;  g.plot = 1;
          case 'off', g.plot = 0;
       end;
end;

if g.plot
    myprintf(g.verbose,'\nNow plotting...\n');
    set(gcf,'DefaultAxesFontSize',AXES_FONT)
    colormap(jet(256));
    pos = get(gca,'position');
    q = [pos(1) pos(2) 0 0];
    s = [pos(3) pos(4) pos(3) pos(4)];
end

switch lower(g.plotersp)
 case 'on'
    %
    %%%%%%% image the ERSP %%%%%%%%%%%%%%%%%%%%%%%%%%
    %
	h(1) = subplot('Position',[.1 ordinate1 .9 height].*s+q);

	PP = P;            % PP will be ERSP power after
	if ~isnan(g.alpha) % zero out nonsignif. power differences
		PP(find((PP > repmat(Pboot(1,:)',[1 g.timesout])) ...
                    & (PP < repmat(Pboot(2,:)',[1 g.timesout])))) = 0;
	end

    if ERSP_CAXIS_LIMIT == 0
	   ersp_caxis = [-1 1]*1.1*max(max(abs(P(dispf,:))));
    else
       ersp_caxis = ERSP_CAXIS_LIMIT*[-1 1];
    end

    if ~isnan( g.baseline )
        imagesc(times,freqs(dispf),PP(dispf,:),ersp_caxis);
    else
        imagesc(times,freqs(dispf),PP(dispf,:));
    end
    set(gca,'ydir',g.hzdir);  % make frequency ascend or descend
	if ~isempty(g.erspmax)
		caxis([-g.erspmax g.erspmax]);
	end

	hold on
	plot([0 0],[0 freqs(max(dispf))],'--m','LineWidth',g.linewidth); % plot time 0
    if ~isnan(g.marktimes) % plot marked time
     for mt = g.marktimes(:)'
	   plot([mt mt],[0 freqs(max(dispf))],'--k','LineWidth',g.linewidth);
     end
    end
	hold off
	set(h(1),'YTickLabel',[],'YTick',[])
	set(h(1),'XTickLabel',[],'XTick',[])
	if ~isempty(g.vert)
		for index = 1:length(g.vert)
			line([g.vert(index), g.vert(index)], [min(freqs(dispf)) max(freqs(dispf))], 'linewidth', 1, 'color', 'm');
		end
	end

	h(2) = gca;
	h(3) = cbar('vert'); % ERSP colorbar axes
	set(h(2),'Position',[.1 ordinate1 .8 height].*s+q)
	set(h(3),'Position',[.95 ordinate1 .05 height].*s+q)
	title([ 'ERSP(' g.unitpower ')' ])

	E = [min(P(dispf,:));max(P(dispf,:))];
	h(4) = subplot('Position',[.1 ordinate1-0.1 .8 .1].*s+q); % plot marginal ERSP means
                                                    % below the ERSP image
	plot(times,E,[0 0],...
	     [min(E(1,:))-max(max(abs(E)))/3 max(E(2,:))+max(max(abs(E)))/3], ...
             '--m','LineWidth',g.linewidth)
	axis([min(times) max(times) ...
             min(E(1,:))-max(max(abs(E)))/3 max(E(2,:))+max(max(abs(E)))/3])

	tick = get(h(4),'YTick');
	set(h(4),'YTick',[tick(1) ; tick(end)])
	set(h(4),'YAxisLocation','right')
    set(h(4),'TickLength',[0.020 0.025]);
	xlabel('Time (ms)')
	ylabel( g.unitpower )

	E = 10 * log10(mbase(dispf));
	h(5) = subplot('Position',[0 ordinate1 .1 height].*s+q); % plot mean spectrum
                                                    % to left of ERSP image
    plot(freqs(dispf),E,'LineWidth',g.linewidth)
	if ~isnan(g.alpha)
        hold on;
		plot(freqs(dispf),Pboot(:,dispf)+[E;E],'g', 'LineWidth',g.linewidth);
		plot(freqs(dispf),Pboot(:,dispf)+[E;E],'k:','LineWidth',g.linewidth)
	end

	axis([freqs(1) freqs(max(dispf)) min(E)-max(abs(E))/3 max(E)+max(abs(E))/3])
	tick = get(h(5),'YTick');
    if (length(tick)>1)
	   set(h(5),'YTick',[tick(1) ; tick(end-1)])
    end
    set(h(5),'TickLength',[0.020 0.025]);
	set(h(5),'View',[90 90])
	xlabel('Frequency (Hz)')
	ylabel( g.unitpower )
    if strcmp(g.hzdir,'normal')
        freqdir = 'reverse';
    else
        freqdir = 'normal';
    end
    set(h(5),'xdir',freqdir);  % make frequency ascend or descend
end

switch lower(g.plotitc)
  case 'on'
    %
    %%%%%%%%%%%% Image the ITC %%%%%%%%%%%%%%%%%%
    %
	h(6) = subplot('Position',[.1 ordinate2 .9 height].*s+q); % ITC image

	RR = R; % RR is the masked ITC (R)
	if ~isnan(g.alpha)
		RR(find(RR < repmat(Rboot(1,:)',[1 g.timesout]))) = 0;
	end

    if ITC_CAXIS_LIMIT == 0
	   coh_caxis = min(max(max(R(dispf,:))),1)*[-1 1]; % 1 WAS 0.4 !
    else
       coh_caxis = ITC_CAXIS_LIMIT*[-1 1];
    end

	if exist('Rsign') && strcmp(g.plotphase, 'on')
		imagesc(times,freqs(dispf),Rsign(dispf,:).*RR(dispf,:),coh_caxis); % <---
	else
		imagesc(times,freqs(dispf),RR(dispf,:),coh_caxis); % <---
	end
	if ~isempty(g.itcmax)
		caxis([-g.itcmax g.itcmax]);
	end
	tmpcaxis = caxis;
    set(gca,'ydir',g.hzdir);  % make frequency ascend or descend

	hold on
	plot([0 0],[0 freqs(max(dispf))],'--m','LineWidth',g.linewidth);
    if ~isnan(g.marktimes)
     for mt = g.marktimes(:)'
	   plot([mt mt],[0 freqs(max(dispf))],'--k','LineWidth',g.linewidth);
     end
    end
	hold off
	set(h(6),'YTickLabel',[],'YTick',[])
	set(h(6),'XTickLabel',[],'XTick',[])
	if ~isempty(g.vert)
		for index = 1:length(g.vert)
			line([g.vert(index), g.vert(index)], ...
                  [min(freqs(dispf)) max(freqs(dispf))], ...
                  'linewidth', 1, 'color', 'm');
		end
	end

	h(7) = gca;
	h(8) = cbar('vert');
	%h(9) = get(h(8),'Children');
	set(h(7),'Position',[.1 ordinate2 .8 height].*s+q)
	set(h(8),'Position',[.95 ordinate2 .05 height].*s+q)
	set(h(8),'YLim',[0 tmpcaxis(2)]);
	title('ITC')

    %
    %%%%% plot the ERP below the ITC image %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
	% E = mean(R(dispf,:));

    ERPmax = max(ERP);
    ERPmin = min(ERP);
    ERPmax = ERPmax + 0.1*(ERPmax-ERPmin);
    ERPmin = ERPmin - 0.1*(ERPmax-ERPmin);
	h(10) = subplot('Position',[.1 ordinate2-0.1 .8 .1].*s+q); % ERP

    plot(ERPtimes,ERP(ERPindices),...
         [0 0],[ERPmin ERPmax],'--m','LineWidth',g.linewidth);
    hold on; plot([times(1) times(length(times))],[0 0], 'k');
    axis([min(ERPtimes) max(ERPtimes) ERPmin ERPmax]);

	tick = get(h(10),'YTick');
	set(h(10),'YTick',[tick(1) ; tick(end)])
    set(h(10),'TickLength',[0.02 0.025]);
	set(h(10),'YAxisLocation','right')
	xlabel('Time (ms)')
    ylabel('\muV')
    if (~isempty(g.topovec))
      if length(g.topovec) ~= 1, ylabel(''); end; % ICA component
    end

	E = mean(R(dispf,:)');
	h(11) = subplot('Position',[0 ordinate2 .1 height].*s+q); % plot the marginal mean
                                                    % ITC left of the ITC image
	if ~isnan(g.alpha)
		plot(freqs(dispf),E,'LineWidth',g.linewidth); hold on;
        plot(freqs(dispf),Rboot(dispf),'g', 'LineWidth',g.linewidth);
        plot(freqs(dispf),Rboot(dispf),'k:','LineWidth',g.linewidth);
        axis([freqs(1) freqs(max(dispf)) 0 max([E Rboot(dispf)])+max(E)/3])
	else
		plot(freqs(dispf),E,'LineWidth',g.linewidth)
		axis([freqs(1) freqs(max(dispf)) min(E)-max(E)/3 max(E)+max(E)/3])
	end

	tick = get(h(11),'YTick');
	set(h(11),'YTick',[tick(1) ; tick(length(tick))])
	set(h(11),'View',[90 90])
        set(h(11),'TickLength',[0.020 0.025]);
	xlabel('Frequency (Hz)')
	ylabel('ERP')
    if strcmp(g.hzdir,'normal')
        freqdir = 'reverse';
    else
        freqdir = 'normal';
    end
    set(gca,'xdir',freqdir);  % make frequency ascend or descend

    %
    %%%%%%%%%%%%%%% plot a topoplot() %%%%%%%%%%%%%%%%%%%%%%%
    %
	if (~isempty(g.topovec))
		h(12) = subplot('Position',[-.1 .43 .2 .14].*s+q);
		if length(g.topovec) == 1
		  topoplot(g.topovec,g.elocs,'electrodes','off', ...
			   'style', 'blank', 'emarkersize1chan', 10, 'chaninfo', g.chaninfo);
		else
		  topoplot(g.topovec,g.elocs,'electrodes','off', 'chaninfo', g.chaninfo);
		end
		    axis('square')
	end
end; % switch

if g.plot
	try, icadefs; set(gcf, 'color', BACKCOLOR); catch, end
    if (length(g.title) > 0)
	    axes('Position',pos,'Visible','Off');
	    h(13) = text(-.05,1.01,g.title);
	    set(h(13),'VerticalAlignment','bottom')
	    set(h(13),'HorizontalAlignment','left')
        set(h(13),'FontSize',TITLE_FONT);
    end

    axcopy(gcf);
end

% symmetric Hanning tapering function
% -----------------------------------
function w = hanning(n)
if ~rem(n,2)
   w = .5*(1 - cos(2*pi*(1:n/2)'/(n+1)));
   w = [w; w(end:-1:1)];
else
   w = .5*(1 - cos(2*pi*(1:(n+1)/2)'/(n+1)));
   w = [w; w(end-1:-1:1)];
end

function myprintf(verbose, varargin)
    if strcmpi(verbose, 'on')
        fprintf(varargin{:});
    end


function [elem,idx,volume,bdFlag] = fixorder3(node,elem,bdFlag)
%% FIXORDER3 fix orientation of tetrahedron
%
%   elem = FIXORDER3(node,elem) computes signed volume of all tetrahedron
%   in the triangulation and switch the vertices such that all signed
%   volume is positive.
%
%   [elem,idx,volume] = FIXORDER3(node,elem) also outputs the index set of
%   elements whose volume is negative.
%
%   [elem,idx,volume,bdFlag] = FIXORDER3(node,elem,bdFlag) changes the bdFlag
%   for boundary conditions.
%
% See also fixorder
%
% Copyright (C) Long Chen. See COPYRIGHT.txt for details.

if (nargin==2)
    bdFlag = [];
end
% compute volume and elemSign of each tetrahedron
[volume,elemSign] = simplexvolume(node,elem);
% find tetrahedron with negative volume and switch the vertices
idx = find(elemSign==-1);
elem(idx,[2 3]) = elem(idx,[3 2]);
if exist('bdFlag','var') && ~isempty(bdFlag)
    bdFlag(idx,[2 3]) = bdFlag(idx,[3 2]);
end


% IALM + LMSVDS (Liu et al. 2012)
% process_video('RPCA', 'IALM_LMSVDS', 'dataset/demo.avi', 'output/demo_IALM_LMSVDS.avi');
[L,S] = inexact_alm_rpca_with_lmsvds(M);


% Data File DTX2
% Free damped vibrations
% of a particle
  m    = 'm';    % mass of the particle
  Fx   = '-k*v - c*x'; % projections of forces on x
  x0   = '0.1';  % initial coordinate
  v0   = '10';   % initial velocity
  Tend = 20;     % upper bound of integration
  eps  = 1e-10;  % desirable accuracy
  np   = 3;      % number of parameters
  P{1} = 'm';    % mass of the particle
  P{2} = 'k';    % coefficient of resistance
  P{3} = 'c';    % spring stiffness


% Snell's Law And Critical Angle Reflection Example
%
% This example illustrates Snell's law by steering a tone burst from a
% linear array transducer within a layered heterogeneous medium. It builds
% on the Simulating Transducer Field Patterns Example.
%
% author: Bradley Treeby
% date: 10th December 2009
% last update: 24th August 2014
%
% This function is part of the k-Wave Toolbox (http://www.k-wave.org)
% Copyright (C) 2009-2014 Bradley Treeby and Ben Cox

% This file is part of k-Wave. k-Wave is free software: you can
% redistribute it and/or modify it under the terms of the GNU Lesser
% General Public License as published by the Free Software Foundation,
% either version 3 of the License, or (at your option) any later version.
%
% k-Wave is distributed in the hope that it will be useful, but WITHOUT ANY
% WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
% FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
% more details.
%
% You should have received a copy of the GNU Lesser General Public License
% along with k-Wave. If not, see <http://www.gnu.org/licenses/>.

clear all;

% =========================================================================
% SIMULATION
% =========================================================================

% create the computational grid
Nx = 128;           % number of grid points in the x (row) direction
Ny = Nx;            % number of grid points in the y (column) direction
dx = 50e-3/Nx;    	% grid point spacing in the x direction [m]
dy = dx;            % grid point spacing in the y direction [m]
kgrid = makeGrid(Nx, dx, Ny, dy);

% define the properties of a layered propagation medium
medium.alpha_power = 1.5;   % [dB/(MHz^y cm)]
medium.alpha_coeff = 0.75;  % [dB/(MHz^y cm)]
medium.density = 1000;      % [kg/m^3]
c0 = 1500;                  % [m/s]
medium_mulp = 2;
medium.sound_speed = c0*ones(Nx, Ny);
medium.sound_speed(Nx/2:end, :) = medium_mulp*c0;

% create the time array
[kgrid.t_array, dt] = makeTime(kgrid, medium.sound_speed);
kgrid.t_array = 0:dt:1000*dt;

% define a source mask for a linear element transducer with an odd number
% of elements
num_elements = 61;
source.p_mask = zeros(Nx, Ny);
x_offset = 25;
y_offset = 20;
start_index = Ny/2 - round(num_elements/2) + 1 - y_offset;
source.p_mask(x_offset, start_index:start_index + num_elements - 1) = 1;

% define the properties of the tone burst
sampling_freq = 1/dt;   % [Hz]
steering_angle = 20;    % [deg]
element_spacing = dx;   % [m]
tone_burst_freq = 1e6;  % [Hz]
tone_burst_cycles = 8;

% create an element index relative to the centre element of the transducer
element_index = -(num_elements - 1)/2:(num_elements - 1)/2;

% use geometric beam forming to calculate the tone burst offsets for each
% transducer element based on the element index
tone_burst_offset = 200 + element_spacing*element_index*sin(steering_angle*pi/180)/(c0*dt);

% create the tone burst signals
source.p = toneBurst(sampling_freq, tone_burst_freq, tone_burst_cycles, 'SignalOffset', tone_burst_offset);

% assign the input options
input_args = {'DisplayMask', source.p_mask};

% run the simulation
kspaceFirstOrder2D(kgrid, medium, source, [], input_args{:});


function [ x, qraux, ipvt ] = cqrdc ( x, ldx, n, p, ipvt, job )

%*****************************************************************************80
%
%% CQRDC computes the QR factorization of an N by P complex matrix.
%
%  Discussion:
%
%    CQRDC uses Householder transformations to compute the QR factorization
%    of an N by P matrix X.  Column pivoting based on the 2-norms of the
%    reduced columns may be performed at the user's option.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 May 2007
%
%  Author:
%
%    MATLAB version by John Burkardt
%
%  Reference:
%
%    Jack Dongarra, Jim Bunch, Cleve Moler, Pete Stewart,
%    LINPACK User's Guide,
%    SIAM, 1979,
%    ISBN13: 978-0-898711-72-1,
%    LC: QA214.L56.
%
%  Parameters:
%
%    Input, complex X(LDX,P), the matrix whose decomposition
%    is to be computed.
%
%    Input, integer LDX, the leading dimension of X.  N <= LDX.
%
%    Input, integer N, the number of rows of the matrix.
%
%    Input, integer P, the number of columns in the matrix X.
%
%    Input, integer IPVT(P), integers that control the
%    selection of the pivot columns.  The K-th column X(K) of X is placed
%    in one of three classes according to the value of IPVT(K):
%      IPVT(K) > 0, then X(K) is an initial column.
%      IPVT(K) == 0, then X(K) is a free column.
%      IPVT(K) < 0, then X(K) is a final column.
%    Before the decomposition is computed, initial columns are moved to the
%    beginning of the array X and final columns to the end.  Both initial
%    and final columns are frozen in place during the computation and only
%    free columns are moved.  At the K-th stage of the reduction, if X(K)
%    is occupied by a free column it is interchanged with the free column
%    of largest reduced norm.
%
%    Input, integer JOB, initiates column pivoting.
%    0, no pivoting is done.
%    nonzero, pivoting is done.
%
%    Output, complex X(LDX,P); the upper triangle contains the upper
%    triangular matrix R of the QR factorization.  Below its diagonal, X
%    contains information from which the unitary part of the decomposition
%    can be recovered.  If pivoting has been requested, the decomposition is
%    not that of the original matrix X, but that of X with its columns
%    permuted as described by IPVT.
%
%    Output, complex QRAUX(P), further information required to recover
%    the unitary part of the decomposition.
%
%    Output, integer IPVT(P); the index of the column of the
%    original matrix that has been interchanged into
%    the K-th column, if pivoting was requested.
%    IPVT is not referenced if JOB == 0.
%
  pl = 1;
  pu = 0;

  if ( job ~= 0 )
%
%  Pivoting has been requested.  Rearrange the columns according to IPVT.
%
    for j = 1 : p

      swapj = ( 0 < ipvt(j) );
      negj = ( ipvt(j) < 0 );

      if ( negj )
        ipvt(j) = -j;
      else
        ipvt(j) = j;
      end

      if ( swapj )

        if ( j ~= pl )
          temp      = x(1:n,pl);
          x(1:n,pl) = x(1:n,j);
          x(1:n,j)  = temp;
        end

        ipvt(j) = ipvt(pl);
        ipvt(pl) = j;
        pl = pl + 1;

      end

    end

    pu = p;

    for jj = 1 : p

      j = p - jj + 1;

      if ( ipvt(j) < 0 )

        ipvt(j) = -ipvt(j);

        if ( j ~= pu )

          temp      = x(1:n,pu);
          x(1:n,pu) = x(1:n,j);
          x(1:n,j)  = temp;

          i        = ipvt(pu);
          ipvt(pu) = ipvt(j);
          ipvt(j)  = i;

        end

        pu = pu - 1;

      end

    end

  end
%
%  Compute the norms of the free columns.
%
  for j = pl : pu
    qraux(j) = scnrm2 ( n, x(1:n,j), 1 );
    work(j) = qraux(j);
  end
%
%  Perform the Householder reduction of X.
%
  lup = min ( n, p );

  for l = 1 : lup
%
%  Locate the column of largest norm and bring it
%  into the pivot position.
%
    if ( pl <= l & l < pu )

      maxnrm = 0.0;
      maxj = l;

      for j = l : pu
        if ( maxnrm < real ( qraux(j) ) )
          maxnrm = real ( qraux(j) );
          maxj = j;
        end
      end

      if ( maxj ~= l )

        temp        = x(1:n,l);
        x(1:n,l)    = x(1:n,maxj);
        x(1:n,maxj) = temp;

        qraux(maxj) = qraux(l);
        work(maxj)  = work(l);

        i          = ipvt(maxj);
        ipvt(maxj) = ipvt(l);
        ipvt(l)    = i;

      end

    end

    qraux(l) = 0.0;

    if ( l ~= n )
%
%  Compute the Householder transformation for column L.
%
      nrmxl = scnrm2 ( n-l+1, x(l:n,l), 1 );

      if ( cabs1 ( nrmxl ) ~= 0.0 )

        if ( cabs1 ( x(l,l) ) ~= 0.0 )
          nrmxl = csign2 ( nrmxl, x(l,l) );
        end

        x(l:n,l) = x(l:n,l) / nrmxl;
        x(l,l) = 1.0 + x(l,l);
%
%  Apply the transformation to the remaining columns,
%  updating the norms.
%
        for j = l+1 : p

          t = - ( conj ( transpose ( x(l:n,l) ) ) * x(l:n,j) ) / x(l,l);
          x(l:n,j) = x(l:n,j) + t * x(l:n,l);

          if ( j < pl | pu < j )
            continue
          end

          if ( cabs1 ( qraux(j) ) == 0.0 )
            continue
          end

          tt = 1.0 - ( abs ( x(l,j) ) / real ( qraux(j) ) )^2;
          tt = max ( tt, 0.0 );
          t = tt;
          tt = 1.0 + 0.05 * tt * ( real ( qraux(j) ) / real ( work(j) ) )^2;

          if ( tt ~= 1.0 )
            qraux(j) = qraux(j) * sqrt ( t );
          else
            qraux(j) = scnrm2 ( n-l, x(l+1:n,j), 1 );
            work(j) = qraux(j);
          end

        end
%
%  Save the transformation.
%
        qraux(l) = x(l,l);
        x(l,l) = -nrmxl;

      end

    end

  end

  return
end


% op_freqrange.m
% Jamie Near, McGill University 2014.
%
% USAGE:
% out=op_freqrange(in,ppmmin,ppmmax);
%
% DESCRIPTION:
% Output only a specified frequency range of the input spectrum.
%
% INPUTS:
% in         = input data in matlab structure format.
% ppmmin     = minimum extent of frequency range in ppm.
% ppmmax     = maximum extent of frequency range in ppm.
%
% OUTPUTS:
% out        = Output following frequency range selection.

function out=op_freqrange(in,ppmmin,ppmmax);

%Calculate Specs using fft
fullspecs=fftshift(ifft(in.fids,[],in.dims.t),in.dims.t);

%now take only the specified range of the spectrum
specs=fullspecs(in.ppm>ppmmin & in.ppm<ppmmax,:,:);

%convert back to time domain
%if the length of Fids is odd, then you have to do a circshift of one to
%make sure that you don't introduce a small frequency shift into the fids
%vector.
if mod(size(specs,in.dims.t),2)==0
    %disp('Length of vector is even.  Doing normal conversion');
    fids=fft(fftshift(specs,in.dims.t),[],in.dims.t);
else
    %disp('Length of vector is odd.  Doing circshift by 1');
    fids=fft(circshift(fftshift(specs,in.dims.t),1),[],in.dims.t);
end

%calculate the size;
sz=size(fids);

%calculate the ppm scale
ppm=in.ppm(in.ppm>ppmmin & in.ppm<ppmmax);

%calculate the new spectral width and dwelltime:
dppm=abs(ppm(2)-ppm(1));
ppmrange=abs((ppm(end)-ppm(1)))+dppm;
spectralwidth=ppmrange*in.Bo*42.577;
dwelltime=1/spectralwidth;

%calculate the time scale
t=[0:dwelltime:(sz(1)-1)*dwelltime];

%FILLING IN DATA STRUCTURE
out=in;
out.fids=fids;
out.specs=specs;
out.sz=sz;
out.ppm=ppm;
out.t=t;
out.spectralwidth=spectralwidth;
out.dwelltime=dwelltime;

%FILLING IN THE FLAGS
out.flags=in.flags;
out.flags.writtentostruct=1;
out.flags.freqranged=1;


function [qua, DCMbn, euler] = att_update(wb, DCMbn, qua, omega_ie_n, omega_en_n, dt, att_mode)
% att_update: updates attitude using quaternion or DCM.
%
% INPUT
%   wb,         3x1 incremental turn-rates in body-frame (rad/s).
%   DCMbn,      3x3 body-to-nav DCM.
%   qua,        4x1 quaternion.
%   omega_ie_n, 3x3 skew-symmetric Earth rate matrix (rad/s).
%   omega_en_n, 3x3 skew-symmetric transport rate (rad/s).
%   dt,         1x1 IMU sampling interval (s).
%	att_mode,   attitude mode (string).
%      'quaternion': attitude updated as quaternion. Default value.
%             'dcm': attitude updated as Direct Cosine Matrix.
%
% OUTPUT
%   qua,      4x1 updated quaternion.
%   DCMbn,    3x3 updated body-to-nav DCM.
%   euler,    3x1 updated Euler angles (rad).
%
%   Copyright (C) 2014, Rodrigo Gonzalez, all rights reserved.
%
%   This file is part of NaveGo, an open-source MATLAB toolbox for
%   simulation of integrated navigation systems.
%
%   NaveGo is free software: you can redistribute it and/or modify
%   it under the terms of the GNU Lesser General Public License (LGPL)
%   version 3 as published by the Free Software Foundation.
%
%   This program is distributed in the hope that it will be useful,
%   but WITHOUT ANY WARRANTY; without even the implied warranty of
%   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%   GNU Lesser General Public License for more details.
%
%   You should have received a copy of the GNU Lesser General Public
%   License along with this program. If not, see
%   <http://www.gnu.org/licenses/>.
%
% Reference:
%
%	Titterton, D.H. and Weston, J.L. (2004). Strapdown
% Inertial Navigation Technology (2nd Ed.). Institution
% of Engineering and Technology, USA.
%
%	Crassidis, J.L. and Junkins, J.L. (2011). Optimal Esti-
% mation of Dynamic Systems, 2nd Ed. Chapman and Hall/CRC, USA.
% Eq. 7.39, p. 458.
%
% Version: 004
% Date:    2022/03/06
% Author:  Rodrigo Gonzalez <rodralez@frm.utn.edu.ar>
% URL:     https://github.com/rodralez/navego

if nargin < 7, att_mode  = 'quaternion'; end

%% Gyros output correction for Earth and transport rates

om_ie_n = skewm_inv(omega_ie_n);
om_en_n = skewm_inv(omega_en_n);
wb = (wb - DCMbn' * (om_ie_n + om_en_n));  % Titterton, Eq. 3.29, p. 32

if strcmp(att_mode, 'quaternion')
%% Quaternion update

    qua   = qua_update(qua, wb, dt);    % Quaternion update
    qua   = qua / norm(qua);            % Brute-force normalization
    DCMbn = qua2dcm(qua);               % DCM update
    euler = qua2euler(qua);             % Euler angles update

elseif strcmp(att_mode, 'dcm')
%% DCM update

    delta_theta = wb * dt;                  % Incremental Euler angles
    DCMbn = dcm_update(DCMbn, delta_theta); % DCM update
    euler = dcm2euler(DCMbn);               % Euler angles update
    qua   = euler2qua(euler);               % Quaternion update
    qua   = qua / norm(qua);                % Brute-force normalization

else
    error('att_update: no attitude update mode defined. Check the attitude update mode selected.')
end

end


function [varargout]=triSurfRemoveThreeConnect(varargin)

% function [Ft,Vt,Ct,L]=triSurfRemoveThreeConnect(Fd,Vd,Cd)
% ------------------------------------------------------------------------
% In a surface triangulation "3-connected" locations often contain poor
% quality triangles of a locally smaller area then the rest of the surface.
% Smoothening does not resolve this issue since the quality is not great
% improved even after vertex is at the centre of its neighbouring nodes.
% Hence the function triSurfRemoveThreeConnect instead removes the central
% nodes and groups the affected triangles into a single triangle.
% The input sets Fd, Vd and Cd represent the input faces, vertices and face
% colours respectively. The output sets Ft, Vt and Ct represent the fixed
% faces, vertices and face colours respectively. In addition a logic L can
% be output which defines the affected vertices in Vd. The output may
% consist of [Ft,Vt] or [Ft,Vt,Ct] or [Ft,Vt,Ct,L].
% The last nnz(L)/3 faces in Ft represent the fixed faces.
%
%
% Kevin Mattheus Moerman
% gibbon.toolbox@gmail.com
%
% 2014/06/03 Created
% 2015/05/01 Updated with varagin type input
%------------------------------------------------------------------------

%% Parse input
Fd=varargin{1};
Vd=varargin{2};

if nargin==3
    Cd=varargin{3};
else
    Cd=[];
end

if isempty(Cd)
    Cd=(1:1:size(Fd,1))';
end

%%

%Get patch face/vertex connectivity matrices
[IND_F,IND_V]=patchIND(Fd,Vd,1);

%Count point connectivity
numFriends=sum(IND_V>0,2); %Number of vertex neighbours
logicThree=numFriends==3; %Logic for vertices with only three connected neighbours

%Remove boundary points from list
TR=triangulation(Fd,Vd);
indFree=freeBoundary(TR);
indFree=unique(indFree(:));
if ~isempty(indFree)
    logicThree(indFree)=0;
end

if nnz(logicThree)>0

    %IND_V subset
    IND_V_three=IND_V(logicThree,:);

    %Snap vertices to mean of neighbours such that vertex normal should
    %coincide with new surface normal
    logicValid=IND_V_three>0;
    Xp=NaN(size(IND_V_three));
    Yp=NaN(size(IND_V_three));
    Zp=NaN(size(IND_V_three));
    Xp(logicValid)=Vd(IND_V_three(logicValid),1);
    Yp(logicValid)=Vd(IND_V_three(logicValid),2);
    Zp(logicValid)=Vd(IND_V_three(logicValid),3);
    Vp=[gnanmean(Xp,2) gnanmean(Yp,2) gnanmean(Zp,2)];
    Vd(logicThree,:)=Vp; %Replace points

    %Get new faces
    IND_F_three=IND_F(logicThree,:);
    indFacesThree=IND_F_three(IND_F_three>0);
    logicFacesThree=false(size(Fd,1),1);
    logicFacesThree(indFacesThree)=1;
    IND_V_three=sort(IND_V_three,2);
    if size(IND_V_three,2)>3
        IND_V_three=IND_V_three(:,end-2:end);
    end
    F_new=IND_V_three;

    %Fix face orientation based on normals
    indUsed=unique(F_new(:));
    V_new=Vd(indUsed,:);
    indFix=zeros(size(Vd,1),1);
    indFix(indUsed)=1:numel(indUsed);
    F_new_fix=indFix(F_new);
    if size(F_new,1)==1
        F_new_fix=F_new_fix';
    end
    [~,~,Nd]=patchNormal(Fd,Vd);
    [N_new]=patchNormal(F_new_fix,V_new);
    N_sum_mag=sqrt(sum((Nd(logicThree,:)+N_new).^2,2));
    logicFlip=N_sum_mag<1;
    F_new(logicFlip,:)=fliplr(F_new(logicFlip,:));

    %Get color information for new faces
    logicValid=IND_F_three>0;

    C_F_three=nan(size(IND_F_three));
    C_F_three(logicValid)=Cd(IND_F_three(logicValid));
    C_new=gnanmean(C_F_three,2);

    %Faces to keep
    F_keep=Fd(~logicFacesThree,:);
    C_keep=Cd(~logicFacesThree,:);

    %Join and create vertex/face/color sets
    Ft=[F_keep;F_new];
    Ct=[C_keep;C_new];

    indUsed=unique(Ft(:));
    Vt=Vd(indUsed,:);
    indFix=zeros(size(Vd,1),1);
    indFix(indUsed)=1:numel(indUsed);
    Ft=indFix(Ft);

else
    Ft=Fd;
    Vt=Vd;
    Ct=Cd;
    logicFacesThree=false(size(Ft,1),1);
end

switch nargout
    case 2
        varargout{1}=Ft;
        varargout{2}=Vt;
    case 3
        varargout{1}=Ft;
        varargout{2}=Vt;
        varargout{3}=Ct;
    case 4
        varargout{1}=Ft;
        varargout{2}=Vt;
        varargout{3}=Ct;
        varargout{4}=logicFacesThree;
    otherwise
        error('Wrong number of output arguments');
end

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


function randint_test ( )

%*****************************************************************************80
%
%% RANDINT_TEST shows how random integers are generated in MATLAB.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    13 February 2013
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'RANDINT_TEST:\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Test the MATLAB RANDINT function.\n' );

  randint_test01 ( );

  randint_test02 ( );

  seed = 123456789;
  randint_test03 ( seed );

  seed = 987654321;
  randint_test03 ( seed );

  seed = 123456789;
  randint_test03 ( seed );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'RANDINT_TEST:\n' );
  fprintf ( 1, '  Normal end of execution.\n' );

  fprintf ( 1, '\n' );
  timestamp ( );

  return
end
function randint_test01 ( )

%*****************************************************************************80
%
%% RANDINT_TEST01 simply calls the random integer generator a few times.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    13 February 2013
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'RANDINT_TEST01:\n' );
  fprintf ( 1, '  In MATLAB, random integers are generated by calling RANDINT:\n' );
  fprintf ( 1, '  If a range is not specified, the values are 0 or 1.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  A = randint ( )      a random scalar value.\n' );
  fprintf ( 1, '  B = randint ( 5, 1 ) a random column vector of 5 entries.\n' );
  fprintf ( 1, '  C = randint ( 1, 5 ) a random row vector of 5 entries.\n' );
  fprintf ( 1, '  D = randint ( 3, 4 ) a 3 by 4 random matrix.\n' );
  fprintf ( 1, '  E = randint ( 5 )    a 5 by 5 random matrix.\n' );

  a = randint ( )
  b = randint ( 5, 1 )
  c = randint ( 1, 5 )
  d = randint ( 3, 4 )
  e = randint ( 5 )

  return
end
function randint_test02 ( )

%*****************************************************************************80
%
%% RANDINT_TEST02 specifies the range.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    13 February 2013
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'RANDINT_TEST02:\n' );
  fprintf ( 1, '  RANDINT allows the user to specify the numeric range.\n' );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  A = randint (  1, 1, [ 5,    10 ] ) a random scalar value.\n' );
  fprintf ( 1, '  B = randint ( 10, 1, [ 7,     8 ] ) a random column vector of 5 entries.\n' );
  fprintf ( 1, '  C = randint (  1, 5, [ -1,   +1 ] ) a random row vector of 5 entries.\n' );
  fprintf ( 1, '  D = randint (  3, 4, [ -5,   +5 ] ) a 3 by 4 random matrix.\n' );
  fprintf ( 1, '  E = randint (  5, 5, [ 100, 200 ] ) a 5 by 5 random matrix.\n' );

  a = randint ( 1,  1, [   5,  10 ] )
  b = randint ( 10, 1, [   7,   8 ] )
  c = randint ( 1,  5, [  -1,  +1 ] )
  d = randint ( 3,  4, [  -5,  +5 ] )
  e = randint ( 5,  5, [ 100, 200 ] )

  return
end
function randint_test03 ( seed )

%*****************************************************************************80
%
%% RANDINT_TEST03 sets the seed before calling RANDINT.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    13 February 2013
%
%  Author:
%
%    John Burkardt
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'RANDINT_TEST03:\n' );
  fprintf ( 1, '  By setting the random number seed, you can control\n' );
  fprintf ( 1, '  how the random number sequence begins.\n' );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  The command "rng ( 123456789 )" sets the seed to 123456789.\n' );

  rng ( seed );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Seed has been set to %d\n', seed );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Now generate 5 random values.\n' );

  for i = 1 : 5
    a = randint ( 1, 1, [ 1, 100 ] );
    fprintf ( 1, '  RANDINT(1,1,[1,100]) = %g\n', a );
  end

  rng ( seed );

  fprintf ( 1, '\n' );
  fprintf ( 1, '  Seed has been reset to %d\n', seed );
  fprintf ( 1, '\n' );
  fprintf ( 1, '  Now generate 5 more random values.\n' );

  for i = 1 : 5
    a = randint ( 1, 1, [ 1, 100 ] );
    fprintf ( 1, '  RANDINT(1,1,[1,100]) = %g\n', a );
  end

  return
end
function timestamp ( )

%*****************************************************************************80
%
%% TIMESTAMP prints the current YMDHMS date as a timestamp.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    14 February 2003
%
%  Author:
%
%    John Burkardt
%
  t = now;
  c = datevec ( t );
  s = datestr ( c, 0 );
  fprintf ( 1, '%s\n', s );

  return
end


function [c,Ls,g,shift,M] = erblett(f,bins,fs,varargin)
%ERBLETT  ERBlet non-stationary Gabor filterbank
%   Usage: [c,Ls,g,shift,M] = erblett(f,bins,fs,varargin)
%          [c,Ls,g,shift] = erblett(...)
%          [c,Ls] = erblett(...)
%          c = erblett(...)
%
%   Input parameters:
%         f         : The signal to be analyzed (For multichannel
%                     signals, input should be a matrix which each
%                     column storing a channel of the signal)
%         bins      : Desired bins per ERB
%         fs        : Sampling rate of f (in Hz)
%         varargin  : Optional input pairs (see table below)
%   Output parameters:
%         c         : Transform coefficients (matrix or cell array)
%         Ls        : Original signal length (in samples)
%         g         : Cell array of Fourier transforms of the analysis
%                     windows
%         shift     : Vector of frequency shifts
%         M         : Number of time channels
%
%   This function computes an ERBlet constant-Q transform via non-stationary
%   Gabor filterbanks. Given the signal *f*, the ERBlet parameter *bins*,
%   as well as the sampling rate *fs* of *f*, the corresponding ERBlet
%   coefficients *c* are given as output. For reconstruction, the length of
%   *f* and the filterbank parameters can be returned also.
%
%   The transform produces phase-locked coefficients in the
%   sense that each filter is considered to be centered at
%   0 and the signal itself is modulated accordingly.
%
%   Optional input arguments arguments can be supplied like this::
%
%       erblett(f,bins,fs,'Qvar',Qvar)
%
%   The arguments must be character strings followed by an
%   argument:
%
%     'Qvar',Qvar              Bandwidth variation factor
%
%     'M_fac',M_fac            Number of time channels are rounded to
%                              multiples of this
%
%     'winfun',winfun          Filter prototype (see |firwin| for available
%                              filters)
%
%   Examples:
%   ---------
%
%   The following example shows analysis and synthesis with |erblett| and
%   |ierblett|:::
%
%       [f,fs] = gspi;
%       binsPerERB = 4;
%       [c,Ls,g,shift,M] = erblett(f,binsPerERB,fs);
%       fr = ierblett(c,g,shift,Ls);
%       rel_err = norm(f-fr)/norm(f)
%       plotfilterbank(c,Ls./M,[],fs,'dynrange',60);
%
%   See also:  ierblett, firwin
%
%   References:  ltfatnote027

% Authors: Thibaud Necciari, Nicki Holighaus
% Date: 10.04.13

warning(['LTFAT: ERBLETT has been deprecated and will be removed',...
         ' in the future releases, please use AUDFILTERS with ''erb'' and FILTERBANK instead.']);

%% Check input arguments
if nargin < 3
    error('Not enough input arguments');
end

[f,Ls,W]=comp_sigreshape_pre(f,upper(mfilename),0);

% Set defaults

definput.keyvals.usrM = [];
definput.keyvals.Qvar = 1;
definput.keyvals.M_fac = 1;
definput.keyvals.winfun = 'nuttall';

% Check input arguments

[flags,keyvals,usrM]=ltfatarghelper({'usrM'},definput,varargin);

%% Create the ERBlet dictionary

df = fs/Ls; % frequency resolution in the FFT

fmin = 0;
fmax = fs/2;

% Convert fmin and fmax into ERB
erblims = freqtoerb([fmin,fmax]);

% Determine number of freq. channels
Nf = bins*ceil(erblims(2)-erblims(1));

% Determine center frequencies
fc = erbspace(fmin,fmax,Nf)';

% Concatenate "virtual" frequency positions of negative-frequency windows
fc = [fc ; flipud(fc(1:end-1))];

gamma = audfiltbw(fc); % ERB scale

% Convert center frequencies in Hz into samples

posit = round(fc/df);% Positions of center frequencies in samples
posit(Nf+1:end) = Ls-posit(Nf+1:end);% Extension to negative freq.

% Compute desired essential (Gaussian) support for each filter
Lwin = 4*round(gamma/df);

% Nuttall windows are slightly broader than Gaussians, this is offset by
% the factor 1.1

M = round(keyvals.Qvar*Lwin/1.1);

% Compute cell array of analysis filters
g = arrayfun(@(x) firwin(keyvals.winfun,x)/sqrt(x),M,'UniformOutput',0);

g{1}=1/sqrt(2)*g{1};
g{end}=1/sqrt(2)*g{end};

M = keyvals.M_fac*ceil(M/keyvals.M_fac);
N = length(posit);  % The number of frequency channels

if ~isempty(usrM)
    if numel(usrM) == 1
        M = usrM*ones(N,1);
    else
        M = usrM;
    end
end

%% The ERBlet transform

% some preparation

f = fft(f);

c=cell(N,1); % Initialisation of the result

% The actual transform

for ii = 1:N
    Lg = length(g{ii});

    idx = [ceil(Lg/2)+1:Lg,1:ceil(Lg/2)];
    win_range = mod(posit(ii)+(-floor(Lg/2):ceil(Lg/2)-1),Ls)+1;

    if M(ii) < Lg % if the number of frequency channels is too small,
        % aliasing is introduced
        col = ceil(Lg/M(ii));
        temp = zeros(col*M(ii),W,assert_classname(f));

        temp([end-floor(Lg/2)+1:end,1:ceil(Lg/2)],:) = ...
            bsxfun(@times,f(win_range,:),g{ii}(idx));
        temp = reshape(temp,M(ii),col,W);

        c{ii} = squeeze(ifft(sum(temp,2)));

        % Using c = cellfun(@(x) squeeze(ifft(x)),c,'UniformOutput',0);
        % outside the loop instead does not provide speedup; instead it is
        % slower in most cases.
    else
        temp = zeros(M(ii),W,assert_classname(f));
        temp([end-floor(Lg/2)+1:end,1:ceil(Lg/2)],:) = ...
            bsxfun(@times,f(win_range,:),g{ii}(idx));

        c{ii} = ifft(temp);
    end
end

if max(M) == min(M)
    c = cell2mat(c);
    c = reshape(c,M(1),N,W);
end

if nargout > 3
    shift = [Ls-posit(end); diff(posit)];% Frequency hop sizes in samples
end


function XYZtransform = transformPointCloud(XYZ,Rt)
    XYZtransform = Rt(1:3,1:3) * XYZ + repmat(Rt(1:3,4),1,size(XYZ,2));
end


function c=comp_wfbt(f,wtNodes,rangeLoc,rangeOut,ext)
%COMP_WFBT Compute Wavelet Filterbank Tree
%   Usage:  c=comp_wfbt(f,wtNodes,rangeLoc,rangeOut,ext);
%
%   Input parameters:
%         f        : Input L*W array.
%         wtNodes  : Filterbank tree nodes (elementary filterbanks) in
%                    BF order. Length *nodeNo* cell array of structures.
%         rangeLoc : Idxs of each node terminal outputs. Length *nodeNo*
%                    cell array of vectors.
%         rangeOut : Output subband idxs of each node terminal outputs.
%         ext      : Type of the forward transform boundary handling.
%
%   Output parameters:
%         c        : Cell array of coefficients. Each element is one
%                    subband (matrix with W columns).
%

% Do non-expansve transform if ext=='per'
doPer = strcmp(ext,'per');
% Pre-allocated output
c = cell(sum(cellfun(@(rEl) numel(rEl),rangeOut)),1);

 ca = {f};
 % Go over all nodes in breadth-first order
 for jj=1:numel(wtNodes)
    % Load current filterbank
    wtNode = wtNodes{jj}.h(:);
    % Node filters to a cell array
    % hCell = cellfun(@(hEl) conj(flipud(hEl.h(:))),wtNode,'UniformOutput',0);
    hCell = cellfun(@(hEl) hEl.h(:),wtNode,'UniformOutput',0);
    % Node filters subs. factors
    a = wtNodes{jj}.a;
    % Node filters initial skips
    if(doPer)
       %offset = cellfun(@(hEl) 1-numel(hEl.h)-hEl.offset,wtNode);
       offset = cellfun(@(hEl) hEl.offset,wtNode);
    else
       offset = -(a-1);
    end

    % Run filterbank
    catmp=comp_filterbank_td(ca{1},hCell,a,offset,ext);
    % Pick what goes directy to the output...
    c(rangeOut{jj}) = catmp(rangeLoc{jj});
    % and save the rest.
    diffRange = 1:numel(hCell);
    diffRange(rangeLoc{jj}) = [];
    ca = [ca(2:end);catmp(diffRange)];
 end


clc;
close all
%% which one to show?
idx = 24;
coordIndices = [1,2,3];

imgFig1 = figure(1);
set(imgFig1, 'Position', [100 100 1400 900]) % [1 1 width height]

subplot(2,2,1);
imagesc(imgMat(:,:,:,idx)); axis off image;
subplot(2,2,2);
imagesc(instanceMaskMat(:,:,:,idx)); axis off image;
subplot(2,2,3);
A = (predInstanceMaskMat0(:,:,coordIndices,idx) + 1) / 2;
imagesc(A);  axis off image;
%% 3D surface
subplot(2,2,4);

r = 1;
[x,y,z] = sphere(50);
x0 = 0; y0 = 0; z0 = 0;
x = x*r + x0;
y = y*r + y0;
z = z*r + z0;

% figure
lightGrey = 0.7*[1 1 1]; % It looks better if the lines are lighter
surface(x,y,z, 'FaceColor', 'none', 'EdgeColor',lightGrey)
hold on
%% points
hold on;
points = reshape(predInstanceMaskMat0(:,:,coordIndices,idx), [], 3);
points = points';
pointsColor = points - (-1);%min(points(:)); % -1
pointsColor = pointsColor ./ 2;%max(pointsColor(:));
for i = 1:size(points,2)
    plot3( points(1,i), points(2,i), points(3,i), 's', 'MarkerSize',3, 'MarkerFaceColor', pointsColor(:,i)', 'MarkerEdgeColor', pointsColor(:,i)');
end
hold off;

axis off square
view([1 1 0.75]) % adjust the viewing angle
zoom(1.4)

%% save result
if flagSaveFig
    export_fig( sprintf('%s/%04d_visualization_single.jpg', saveFolder, i) );
end


% V = est_calcInvCovMatFourierPDC(Rinv,E,foi,fs,N,p, verb)
%
% Obtain the frequency domain transform of the inverse covariance matrix of
% an M-variate VAR[p] process
% This is needed for calculating the analytic statistics for the PDC [1]
%
% Inputs:
%
%     Rinv: inverse process covariance matrix obtained from est_calcInvCovMat
%     E:    noise covariance matrix
%     foi:  frequencies of interest (Hz)
%     fs:   sampling rate
%     N:    # chans
%     p:    model order
%     verb: verbosity level. 0 = no output, 1=text.
%
% Outputs:
%
%     V:    Frequency-domain transform of the inverse covariance matrix
%
% References:
%
% [1] Schelter et al, (2009). Testing for directed influences among neural
% signals using partial directed coherence. J. Neuroscience Methods. 152:210-9.
%
% see also: est_calcInvCovMat(), est_calcInvCovMatFourier()
%
% Author: Tim Mullen 2010, SCCN/INC, UCSD
% Email:  tim@sccn.ucsd.edu

% This function is part of the Source Information Flow Toolbox (SIFT)
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

function V = est_calcInvCovMatFourierPDC(Rinv,E,foi,fs,N,p,verb,DEBUG)

if nargin<8
    DEBUG = false;
end

%% extract the diagonal elements of H=Rinv
% structure of Hd is (e.g., for p=2):
% [diag(H(1,1)), diag(H(2,1)), diag(H(1,2)), diag(H(2,2))]
% where diag(H(u,v)) is the column vector formed by the diagonal of
% submatrix H(u,v) of H
Hd = zeros(N,p^2);
cnt=1;
for v=1:p
    for u=1:p
        Hd(:,cnt)=diag(Rinv((u-1)*N+1:u*N,(v-1)*N+1:v*N));
        cnt=cnt+1;
    end
end

if DEBUG
    for j=1:N
        try chol(reshape(Hd(j,:),[p p])); catch; fprintf('Hj<0: j=%d - ',j); keyboard; end;
    end
end

%% create u,v index vectors
% us = [1 2 ... p 1 2 ... p ... ]'   (p^2 length)
% vs = [1 1 ... 1 2 2 ... 2 ... ]'   (p^2 length)
us = repmat(1:p,1,p)';
vs = zeros(p^2,1);
for ii=1:p
    vs((ii-1)*p+1:(ii-1)*p+p)=ones(p,1)*ii;
end

%% construct the V matrix for all freqs
fi=0;
COS=zeros(p^2,1);
freqs=(2*pi*foi)/fs;
V = zeros(length(freqs),N,N); % NOTE: V will end up (N,N,freqs)
if verb, h=waitbar(0,'calculating V^-1...'); end
for f=freqs
    fi=fi+1;

    %% construct cosine matrix
    COS(:,1) = cos(us*f).*cos(vs*f)+sin(us*f).*sin(vs*f);
%     COS(:,2) = sin(us*f).*sin(vs*f);
%     COS(:,3) = cos(us*f).*sin(vs*f);
%     COS(:,4) = sin(us*f).*sin(vs*f);

    %% multiply Hd and COS matrices to get matrix where row j is
    % [sum_{u,v=1 : p} Hjj(u,v)COS_11(u,v), ...
    %  sum_{u,v=1 : p} Hjj(u,v)COS_21(u,v), ...
    %  sum_{u,v=1 : p} Hjj(u,v)COS_12(u,v), ...
    %  sum_{u,v=1 : p} Hjj(u,v)COS_22(u,v)]
    %
    % where COSab(u,v) is the a,bth element of the sine-cos transform
    % matrix evaluated at u,v.
    %
    % NOTE: reshaping row j to 2x2 yeilds a matrix proportional to V_ij(f)
    % for some specific i
    Vm = Hd*COS;

    % now we multiply in the variances of the i's (E(i,i)) to generate the
    % full V matrix
    Vm = kron(diag(E)',Vm);

    % next, reshape to desired structure (NxNx2x2)
    V(fi,:,:) = Vm';

    if verb, waitbar(fi/length(freqs),h); end
end % for freqs

% permute V: (chs,chs,freqs,2,2)
V = permute(V,[2 3 1]);
if verb, close(h); end


function [LL, LLS, ht] = igarch_likelihood(parameters, epsilon, fepsilon, p, q, errorType, igarchType, constant, backCast, T, estimFlag)
% Log likelihood for IGARCH(P,Q) estimation
%
% USAGE:
%   [LL, LLS, HT] = igarch_likelihood(PARAMETERS,EPSILON,FEPSILON,P,Q,ERRORTYPE,IGARCHTYPE,CONSTANT,BACKCAST,T,ESTIMFLAG)
%
% INPUTS:
%   PARAMETERS   - A vector of IGARCH process parameters
%                    [omega alpha beta [nu lambda]]
%   DATA         - Vector of mean zero residuals
%   EPSILON      - A column of mean zero data
%   FEPSILON     - Either abs(EPSILON) or EPSILON.^2, depending on IGARCHTYPE
%   P            - Positive, scalar integer representing the number of
%                    symmetric innovations
%   Q            - Non-negative, scalar integer representing the number
%                    of lags of conditional variance (0 for ARCH)
%   ERRORTYPE    - [OPTIONAL] The error distribution used, valid types are:
%                    'NORMAL'    - Gaussian Innovations [DEFAULT]
%                    'STUDENTST' - T distributed errors
%                    'GED'       - Generalized Error Distribution
%                    'SKEWT'     - Skewed T distribution
%   IGARCHTYPE   - [OPTIONAL] The type of variance process, either
%                    1 - Model evolves in absolute values
%                    2 - Model evolves in squares [DEFAULT]
%   CONSTANT     - [OPTIONAL] Logical value indicating whether model
%                    should include a constant.  Default is true (include).
%   BACKCAST     - The value used for variance recursion
%   T            - Length of data
%   ESTIMFLAG    - [OPTIONAL] Flag (0 or 1) to indicate if the function
%                    is being used in estimation.  If it is 1, then the parameters are
%                    transformed from unconstrained values to constrained by standard
%                    garch model constraints
%
% OUTPUTS:
%   LL             - Minus 1 times the log likelihood
%   LLS            - Time series of log likelihoods (Also multiplied by -1)
%   HT             - Time series of conditional variances
%
% COMMENTS:
%   See also IGARCH

% Copyright: Kevin Sheppard
% kevin.sheppard@economics.ox.ac.uk
% Revision: 1    Date: 7/12/2009

if nargin==11 && estimFlag
    %If for estimation, transform the parameters
    [parameters,nu,lambda]=igarch_itransform(parameters,p,q,errorType,constant);
else
    %Otherwise the parameters simply must be parsed
    if errorType==2 || errorType==3
        %Seperate nu from the remaning parameters
        nu=parameters(p+q+constant);
        parameters=parameters(1:constant+p+q-1);
    elseif errorType==4
        lambda=parameters(p+q+constant+1);
        nu=parameters(p+q+constant);
        parameters=parameters(1:constant+p+q-1);
    end
end

%Backcast length
m  =  max([p q]);
%Compute the conditional variances
ht=igarch_core(fepsilon,parameters,backCast,p,q,m,T,igarchType,constant);
%Indices for the relevant opservations
t  = (m + 1):T;
ht = ht(t);
%Compute the log likelihoods
switch errorType
    case 1
        [LL, LLS] = normloglik(epsilon,0,ht);
        LLS = -LLS;
        LL = -LL;
    case 2
        [LL, LLS] = stdtloglik(epsilon,0,ht,nu);
        LLS = -LLS;
        LL = -LL;
    case 3
        [LL, LLS] = gedloglik(epsilon,0,ht,nu);
        LLS = -LLS;
        LL = -LL;
    case 4
        [LL, LLS] = skewtloglik(epsilon,0,ht,nu,lambda);
        LLS = -LLS;
        LL = -LL;
end


function combo_test30 ( )

%*****************************************************************************80
%
%% COMBO_TEST30 tests PRUEFER_*.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    25 January 2011
%
%  Author:
%
%    John Burkardt
%
  n = 4;

  fprintf ( 1, ' \n' );
  fprintf ( 1, 'COMBO_TEST30\n' );
  fprintf ( 1, '  Pruefer codes:\n' );
  fprintf ( 1, ' \n' );
  fprintf ( 1, '  PRUEFER_ENUM enumerates,\n' );
  fprintf ( 1, '  PRUEFER_RANK ranks,\n' );
  fprintf ( 1, '  PRUEFER_SUCCESSOR lists,\n' );
  fprintf ( 1, '  PRUEFER_UNRANK unranks.\n' );
%
%  Enumerate.
%
  ncode = pruefer_enum ( n );

  fprintf ( 1, ' \n' );
  fprintf ( 1, '  For N = %d\n', n );
  fprintf ( 1, '  the number of Pruefer codes is %d\n', ncode );
  fprintf ( 1, ' \n' );
%
%  List
%
  p = [];
  rank = -1;

  while ( 1 );

    rank_old = rank;

    [ p, rank ] = pruefer_successor ( n, p, rank );

    if ( rank <= rank_old )
      break
    end

    fprintf ( 1, '  %3d  ', rank );
    for i = 1 : n - 2
      fprintf ( 1, '%5d', p(i) );
    end
    fprintf ( 1, '\n' );

  end
%
%  Unrank.
%
  rank = floor ( ncode / 2 );

  p = pruefer_unrank ( rank, n );

  fprintf ( 1, ' \n' );
  fprintf ( 1, '  The element of rank %d:\n', rank );
  fprintf ( 1, ' \n' );
  for i = 1 : n - 2
    fprintf ( 1, '%5d', p(i) );
  end
  fprintf ( 1, '\n' );
%
%  Rank.
%
  rank = pruefer_rank ( n, p );

  fprintf ( 1, ' \n' );
  fprintf ( 1, '  The rank of the element is computed as %d:\n', rank );

  return
end


%demo_SOFAcalculateITD - Load HRTF and plots ITD.

% #Author: Piotr Majdak
% #Author: Michael Mihocic: bugs fixed (10.2021)
% #Author: Michael Mihocic: header documentation updated (28.10.2021)
%
% SOFA Toolbox - demo script
% Copyright (C) Acoustics Research Institute - Austrian Academy of Sciences
% Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent versions of the EUPL (the "License")
% You may not use this work except in compliance with the License.
% You may obtain a copy of the License at: https://joinup.ec.europa.eu/software/page/eupl
% Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
% See the License for the specific language governing  permissions and limitations under the License.
%

%% Define parameters
% Subject index of the file to convert
subject=3;

%% load SOFA file
SOFAfn=fullfile(SOFAdbPath, 'database', 'cipic', ['subject_' sprintf('%03d',subject) '.sofa']);
Obj=SOFAload(SOFAfn, 'nochecks');

%% Calculate Interaural time delay
[itd_time, ~, ~, Obj_time] = SOFAcalculateITD(Obj, 'time', 'thr', 20);
[itd_samples, ~, ~, Obj_samples] = SOFAcalculateITD(Obj, 'samples', 'thr', 20);

%% Plot results
h = figure('Name',mfilename);
subplot(211)
plot((Obj_time.Data.Delay(:,1) - Obj_time.Data.Delay(:,2))*1e6)
xlabel('Position')
ylabel('Time (\mus)')
title('ITD (time)')
axis tight

subplot(212)
plot((Obj_samples.Data.Delay(:,1) - Obj_samples.Data.Delay(:,2)))
xlabel('Position')
ylabel(['Samples (Fs:' num2str(Obj.Data.SamplingRate), 'Hz)'])
title('ITD (samples)')
axis tight

%% Polar plot (not working in Octave)
if ~exist('OCTAVE_VERSION','builtin')
    figure('Name',mfilename);
    SOFAplotHRTF(Obj, 'itdhorizontal');
    title('ITD (time, horizontal plane)')
end


function y = cropbyval(x, val)
%CROPBYVAL Crop an array by
%
%   Y = CROPBYVAL(X, VAL) returns a subarray identical to X but where any
%   values VAL on the borders of X have been removed.
%
%   Y = CROPBYVAL(X) will determine VAL automatically by looking at the
%   borders of X and picking the most common value.  En error is given if
%   there is no value which is more common that the other values on the
%   border.  Note that automatically chosing VAL slowes down CROPBYVAL.
%
%   For example, if
%
%     X = [ 0  0  0  0
%           1  2  3  0
%           4  5  6  0 ]
%
%   then both Y = CROPBYVAL(X, 0) and Y = CROPBYVAL(X) will return
%
%     Y = [ 1  2  3
%           4  5  6 ]

%   Author:      Peter J. Acklam
%   Time-stamp:  2002-03-03 13:51:33 +0100
%   E-mail:      pjacklam@online.no
%   URL:         http://home.online.no/~pjacklam

   % check number of input arguments
   error(nargchk(1, 2, nargin));

   % if VAL is give, check it, otherwise compute default value
   if nargin == 2
      if any(size(val) ~= 1)
         error('VAL must be a scalar.');
      end
   else
      vals = [];
      sx = size(x);
      dx = ndims(x);
      c = cell(dx, 1);
      for i = 1:dx
         c{i} = 2:sx(i)-1;
      end
      t(prod(sx)) = logical(uint8(1));          % use uint8 to save memory
      t = reshape(t, sx);
      t(:) = t(end);
      t(c{:}) = 0;
      [lens, vals] = rlencode(sort(x(t(:))));
      len = max(lens);
      k = find(len == lens);
      if length(k) > 1
         error('No unique most common value on boundary.');
      end
      val = vals(k);
   end

   % get linear index values of elements different from VAL
   if isnan(val)
      i = find(~isnan(x));
   elseif val == 0
      i = find(x);
   else
      i = find(x ~= val);
   end

   % quick exit if output will be empty
   if isempty(i)
      y = [];
      return
   end

   % The following is based on code by
   % Doug Schwarz <douglas.schwarz@kodak.com>

   sx     = size(x);            % size vector of x
   dx     = length(sx);         % number of dimensions of x
   c      = cell(dx, 1);        % initialize list of subscript
   [c{:}] = ind2sub(sx, i);     % compute the subscripts
   for j = 1:dx
      c{j} = min(c{j}) : max(c{j});
   end
   y = x(c{:});


function [qd] = stateToQd(x)
%Converts qd struct used in hardware to x vector used in simulation
% x is 1 x 13 vector of state variables [pos vel quat omega]
% qd is a struct including the fields pos, vel, euler, and omega

%current state
qd.pos = x(1:3);
qd.vel = x(4:6);

Rot = QuatToRot(x(7:10)');
[phi, theta, yaw] = RotToRPY_ZXY(Rot);

qd.euler = [phi; theta; yaw];
qd.omega = x(11:13);

end


classdef LIRCMOP13 < PROBLEM
% <multi> <real> <large/none> <constrained>
% Constrained benchmark MOP with large infeasible regions

%------------------------------- Reference --------------------------------
% Z. Fan, W. Li, X. Cai, H. Huang, Y. Fang, Y. You, J. Mo, C. Wei, and E.
% Goodman, An improved epsilon constraint-handling method in MOEA/D for
% CMOPs with large infeasible regions, Soft Computing, 2019, 23:
% 12491-12510.
%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

% This function is written by Wenji Li

    methods
        %% Default settings of the problem
        function Setting(obj)
            obj.M = 3;
            if isempty(obj.D); obj.D = 30; end
            obj.lower    = zeros(1,obj.D);
            obj.upper    = ones(1,obj.D);
            obj.encoding = ones(1,obj.D);
        end
        %% Calculate objective values and constraint violations
        function Population = Evaluation(obj,varargin)
            X = varargin{1};
            X = max(min(X,repmat(obj.upper,size(X,1),1)),repmat(obj.lower,size(X,1),1));
            [popsize,variable_length] = size(X);
            sum1 = zeros(popsize,1);
            for j = 3 : variable_length
                sum1 = sum1+10*(X(:,j)-0.5).^2;
            end
            PopObj(:,1) = (1.7057+sum1).*cos(0.5*pi*X(:,1)).*cos(0.5*pi*X(:,2));
            PopObj(:,2) = (1.7057+sum1).*cos(0.5*pi*X(:,1)).*sin(0.5*pi*X(:,2));
            PopObj(:,3) = (1.7057+sum1).*sin(0.5*pi*X(:,1));
            gx          =  PopObj(:,1).^2+PopObj(:,2).^2+PopObj(:,3).^2;
            PopCon(:,1) = (gx-9).*(4-gx);
            PopCon(:,2) = (gx-3.61).*(3.24-gx);
            Population  = SOLUTION(X,PopObj,PopCon,varargin{2:end});
            obj.FE      = obj.FE + length(Population);
        end
        %% Generate points on the Pareto front
        function R = GetOptimum(obj,N)
            R = UniformPoint(N,3);
            R = 1.7057*R./repmat(sqrt(sum(R.^2,2)),1,3);
        end
        %% Generate the image of Pareto front
        function R = GetPF(obj)
            a = linspace(0,pi/2,10)';
            R = {sin(a)*cos(a')*1.7057,sin(a)*sin(a')*1.7057,cos(a)*ones(size(a'))*1.7057};
        end
    end
end


function [ gradientParams, SigmaInvs, CholDecomps, Sigmas, bs, allXresp] = gradientCCNF( params, num_alpha, numBeta, sizeTheta, lambda_a, lambda_b, lambda_th, Precalc_Bs, x, y, Precalc_yBys, Precalc_Bs_flat, constant, num_seqs)
%gradientCCNF Summary of this function goes here
%   Detailed explanation goes here

    % pick out the relevant terms (unpack)
    alphas_init = params(1:num_alpha);
    betasInit = params(num_alpha+1:num_alpha+numBeta);
    thetasInit = reshape(params(num_alpha+numBeta+1:end), sizeTheta);

    % Compute the response from the neural layers
    allXresp = 1./(1 + exp(-thetasInit * x));
    Xt = x;

    bs = 2*alphas_init' * allXresp;

    % This is precalculated for the next step and is basically the
    % feedforward step of the neural net
    Z_precalc = 2 * (allXresp .* (1-allXresp));

    % These are the outputs weighted by the alphas (see eq TODO
    db2_precalc =  bsxfun(@times, Z_precalc, alphas_init);

    num_feats = sizeTheta(2);

    if(constant)

        seq_length = size(x,2)/num_seqs;

        % As the similarities are the same across all series we can reuse our
        % Sigma and SigmaInv calculations

        I = eye(seq_length);
        [SigmaInv] = CalcSigmaCCNFflat(alphas_init, betasInit, seq_length, Precalc_Bs_flat{1}, I, zeros(seq_length));
        CholDecomp=chol(SigmaInv);

        % This is a faster way of inverting a symmetric matrix
        Sigma=CholDecomp\(CholDecomp'\I);
        Sigma_trace = trace(Sigma);

        % mu values associated with each time step
        mus = Sigma * reshape(bs, seq_length, num_seqs);

        % difference between actual and prediction (error)
        diff = (y - mus);

        db_precalc_mult = bsxfun(@times, db2_precalc, diff(:)');

        % Equation 46 from the appendix
        gradientThetasT = Xt * db_precalc_mult';

        % Reshape into the correct format
        gradientThetasT = gradientThetasT(:)';

        gradientThetasT = reshape(gradientThetasT, sizeTheta(2), sizeTheta(1))';
        gradientThetasT = gradientThetasT(:);

        % Some useful precalculations

        % for every sequence get a dot product with itself
        yy = dot(y,y);

        % same goes for the mu
        mumu = dot(mus,mus);

        % calculating the derivative of L with respect to alpha_k (Equation 27)
        % gradientAlphas =  (-yq'*yq +(2*yq'*D')' -2 * D * mu + sum(mu.^2) + trace(Sigma));
        % allXresp is D
        gradient_alphas_add = -sum(yy) + sum(mumu) + num_seqs * Sigma_trace;
        gradient_alphas = 2 * allXresp * (y(:) - mus(:)) + gradient_alphas_add;

        gradient_betas = zeros(numBeta, 1);

        % calculating the derivative of log(L) with respect to the betas
        for k=1:numBeta

            % From Equation 38 (and 39 for gamma)
            % gradient = -yq'*B^(k)*yq + mu'*B^(k)*mu + Vec(Sigma)'*vec(B^(k)

            % We precalculate B^(k) (equation 30), as it does not change
            % over the course of optimisation
            B_k = Precalc_Bs{1}{k};

            % precalculated -yq'*B_k*yq can be used as well as it does not
            % change (stored in Precalc_yBys)
            yq_B_k_yq = sum(Precalc_yBys(:,k));

            % A vectorised version of mu'*B^(k)*mu
            B_k_mu = B_k*mus;
            mu_B_k_mu = mus(:)' * B_k_mu(:);

            % Vec(Sigma)*Vec(B^(k)) can be computed as follows:
            partition_term = num_seqs * Sigma(:)'*B_k(:);

            % Equation 38 and 39 basically
            dLdb = yq_B_k_yq + mu_B_k_mu + partition_term;

            gradient_betas(k) = dLdb;
        end

        gradientParams = [gradient_alphas;gradient_betas;gradientThetasT];

        SigmaInvs = SigmaInv;
        CholDecomps = CholDecomp;
        Sigmas = Sigma;

    else

        SigmaInvs = cell(num_seqs, 1);
        CholDecomps = cell(num_seqs, 1);
        Sigmas = cell(num_seqs, 1);
        gradients = zeros(num_seqs, numel(params));

        a_precalc = zeros(sizeTheta(2)*sizeTheta(1), size(allXresp,2));

        for i=1:size(db2_precalc,1)
            a_precalc((i-1)*num_feats+1:i*num_feats,:) = bsxfun(@times, Xt, db2_precalc(i,:));
        end

        % y can either be in cell format (diff length seqs.) or in matrix
        %, same length seqs
        beg_ind = 1;

        if(iscell(y))
            end_ind = numel(y{1});
            y_cell = true;
        else
            end_ind = size(y,1);
            y_cell = false;
        end

        % Go through every sequence summing the gradients
        for q = 1 : num_seqs

            currResp = allXresp(:,beg_ind:end_ind);
            currB = bs(beg_ind:end_ind)';

            PrecalcB = Precalc_Bs{q};
            PrecalcBFlat = Precalc_Bs_flat{q};

            if(y_cell)
                yq = y{q};
            else
                yq = y(:,q);
            end

            xq = x(2:end, beg_ind:end_ind);

            % Used for equation 46 computation
            a_precalc_curr = a_precalc(:,beg_ind:end_ind);

            precalc_eye = eye(numel(yq));
            precalc_zeros = zeros(numel(yq));

            [ gradientsAlphas, gradientsBetas, gradientsThetas, SigmaInv, CholDecomp, Sigma ] = gradientCCNF_per_seq(alphas_init, betasInit, thetasInit, PrecalcB, xq, yq, currResp, currB, Precalc_yBys(q, :), PrecalcBFlat, a_precalc_curr, precalc_eye, precalc_zeros);

            gradients(q,:) = [gradientsAlphas; gradientsBetas; gradientsThetas(:)];
            SigmaInvs{q} = SigmaInv;
            CholDecomps{q} = CholDecomp;
            Sigmas{q} = Sigma;

            % Update the references to sequence start/end
            if(q ~= num_seqs)
                beg_ind = end_ind + 1;
                if(iscell(y))
                    end_ind = end_ind + numel(y{q+1});
                else
                    end_ind = end_ind + size(y,1);
                end
            end

        end

        gradientParams = sum(gradients,1)';

    end

    % Add the regularisation term
    regAlpha = alphas_init * lambda_a;
    regBeta = betasInit * lambda_b;
    regTheta = thetasInit * lambda_th;

    gradientParams = gradientParams - [regAlpha; regBeta; regTheta(:)];
end