Switch to side-by-side view

--- a
+++ b/code/preprocessing/EEG/fastica/fastica.m
@@ -0,0 +1,533 @@
+function [Out1, Out2, Out3] = fastica(mixedsig, varargin)
+%FASTICA - Fast Independent Component Analysis
+%
+%   NOTICE!
+% THIS IS NOT THE ORIGINAL VERSION BUT A MODIFIED VERSION: 
+% this one does not compute the icasig if this is not necessary (otherwise
+% there is no change, thus there is (should be) no change in behaviour
+%   kaigoe  (kai.goergen@bccn-berlin.de)
+%
+% FastICA for Matlab 7.x and 6.x
+% Version 2.5, October 19 2005
+% Copyright (c) Hugo Gävert, Jarmo Hurri, Jaakko Särelä, and Aapo Hyvärinen.
+%
+% FASTICA(mixedsig) estimates the independent components from given
+% multidimensional signals. Each row of matrix mixedsig is one
+% observed signal.  FASTICA uses Hyvarinen's fixed-point algorithm,
+% see http://www.cis.hut.fi/projects/ica/fastica/. Output from the
+% function depends on the number output arguments:
+%
+% [icasig] = FASTICA (mixedsig); the rows of icasig contain the
+% estimated independent components.
+%
+% [icasig, A, W] = FASTICA (mixedsig); outputs the estimated separating
+% matrix W and the corresponding mixing matrix A.
+%
+% [A, W] = FASTICA (mixedsig); gives only the estimated mixing matrix
+% A and the separating matrix W.
+%
+% Some optional arguments induce other output formats, see below.
+%
+% A graphical user interface for FASTICA can be launched by the
+% command FASTICAG
+%
+% FASTICA can be called with numerous optional arguments. Optional
+% arguments are given in parameter pairs, so that first argument is
+% the name of the parameter and the next argument is the value for
+% that parameter. Optional parameter pairs can be given in any order.
+%
+% OPTIONAL PARAMETERS:
+%
+% Parameter name        Values and description
+%
+%======================================================================
+% --Basic parameters in fixed-point algorithm:
+%
+% 'approach'            (string) The decorrelation approach used. Can be
+%                       symmetric ('symm'), i.e. estimate all the
+%                       independent component in parallel, or
+%                       deflation ('defl'), i.e. estimate independent
+%                       component one-by-one like in projection pursuit.
+%                       Default is 'defl'.
+%
+% 'numOfIC'             (integer) Number of independent components to
+%                       be estimated. Default equals the dimension of data.
+%
+%======================================================================
+% --Choosing the nonlinearity:
+%
+% 'g'                   (string) Chooses the nonlinearity g used in 
+%                       the fixed-point algorithm. Possible values:
+%
+%                       Value of 'g':      Nonlinearity used:
+%                       'pow3' (default)   g(u)=u^3
+%                       'tanh'             g(u)=tanh(a1*u)
+%                       'gauss             g(u)=u*exp(-a2*u^2/2)
+%                       'skew'             g(u)=u^2
+% 
+% 'finetune'		(string) Chooses the nonlinearity g used when 
+%                       fine-tuning. In addition to same values
+%                       as for 'g', the possible value 'finetune' is:
+%                       'off'              fine-tuning is disabled.
+%
+% 'a1'                  (number) Parameter a1 used when g='tanh'.
+%                       Default is 1.
+% 'a2'                  (number) Parameter a2 used when g='gaus'.
+%                       Default is 1.
+%
+% 'mu'			(number) Step size. Default is 1.
+%                       If the value of mu is other than 1, then the
+%                       program will use the stabilized version of the
+%                       algorithm (see also parameter 'stabilization').
+%
+%
+% 'stabilization'       (string) Values 'on' or 'off'. Default 'off'. 
+%                       This parameter controls wether the program uses
+%                       the stabilized version of the algorithm or
+%                       not. If the stabilization is on, then the value
+%                       of mu can momentarily be halved if the program
+%                       senses that the algorithm is stuck between two
+%                       points (this is called a stroke). Also if there
+%                       is no convergence before half of the maximum
+%                       number of iterations has been reached then mu
+%                       will be halved for the rest of the rounds.
+% 
+%======================================================================
+% --Controlling convergence:
+%
+% 'epsilon'             (number) Stopping criterion. Default is 0.0001.
+%
+% 'maxNumIterations'    (integer) Maximum number of iterations.
+%                       Default is 1000.
+%
+% 'maxFinetune'         (integer) Maximum number of iterations in 
+%                       fine-tuning. Default 100.
+%
+% 'sampleSize'          (number) [0 - 1] Percentage of samples used in
+%                       one iteration. Samples are chosen in random.
+%                       Default is 1 (all samples).
+%
+% 'initGuess'           (matrix) Initial guess for A. Default is random.
+%                       You can now do a "one more" like this: 
+%                       [ica, A, W] = fastica(mix, 'numOfIC',3);
+%                       [ica2, A2, W2] = fastica(mix, 'initGuess', A, 'numOfIC', 4);
+%
+%======================================================================
+% --Graphics and text output:
+%
+% 'verbose'             (string) Either 'on' or 'off'. Default is
+%                       'on': report progress of algorithm in text format.
+%
+% 'displayMode'         (string) Plot running estimates of independent
+%                       components: 'signals', 'basis', 'filters' or
+%                       'off'. Default is 'off'.
+%
+% 'displayInterval'     Number of iterations between plots.
+%                       Default is 1 (plot after every iteration).
+%
+%======================================================================
+% --Controlling reduction of dimension and whitening:
+%
+% Reduction of dimension is controlled by 'firstEig' and 'lastEig', or
+% alternatively by 'interactivePCA'. 
+%
+% 'firstEig'            (integer) This and 'lastEig' specify the range for
+%                       eigenvalues that are retained, 'firstEig' is
+%                       the index of largest eigenvalue to be
+%                       retained. Default is 1.
+%
+% 'lastEig'             (integer) This is the index of the last (smallest)
+%                       eigenvalue to be retained. Default equals the
+%                       dimension of data.
+%
+% 'interactivePCA'      (string) Either 'on' or 'off'. When set 'on', the
+%                       eigenvalues are shown to the user and the
+%                       range can be specified interactively. Default
+%                       is 'off'. Can also be set to 'gui'. Then the user
+%                       can use the same GUI that's in FASTICAG.
+%
+% If you already know the eigenvalue decomposition of the covariance
+% matrix, you can avoid computing it again by giving it with the
+% following options:
+%
+% 'pcaE'                (matrix) Eigenvectors
+% 'pcaD'                (matrix) Eigenvalues
+%
+% If you already know the whitened data, you can give it directly to
+% the algorithm using the following options:
+%
+% 'whiteSig'            (matrix) Whitened signal
+% 'whiteMat'            (matrix) Whitening matrix
+% 'dewhiteMat'          (matrix) dewhitening matrix
+%
+% If values for all the 'whiteSig', 'whiteSig' and 'dewhiteMat' are
+% supplied, they will be used in computing the ICA. PCA and whitening
+% are not performed. Though 'mixedsig' is not used in the main
+% algorithm it still must be entered - some values are still
+% calculated from it.
+%
+% Performing preprocessing only is possible by the option:
+%
+% 'only'                (string) Compute only PCA i.e. reduction of
+%                       dimension ('pca') or only PCA plus whitening
+%                       ('white'). Default is 'all': do ICA estimation
+%                       as well.  This option changes the output
+%                       format accordingly. For example: 
+%
+%                       [whitesig, WM, DWM] = FASTICA(mixedsig, 
+%                       'only', 'white') 
+%                       returns the whitened signals, the whitening matrix
+%                       (WM) and the dewhitening matrix (DWM). (See also
+%                       WHITENV.) In FastICA the whitening matrix performs
+%                       whitening and the reduction of dimension. Dewhitening
+%                       matrix is the pseudoinverse of whitening matrix.
+%                        
+%                       [E, D] = FASTICA(mixedsig, 'only', 'pca') 
+%                       returns the eigenvector (E) and diagonal 
+%                       eigenvalue (D) matrices  containing the 
+%                       selected subspaces. 
+%
+%======================================================================
+% EXAMPLES
+%
+%       [icasig] = FASTICA (mixedsig, 'approach', 'symm', 'g', 'tanh');
+%               Do ICA with tanh nonlinearity and in parallel (like
+%               maximum likelihood estimation for supergaussian data).
+%
+%       [icasig] = FASTICA (mixedsig, 'lastEig', 10, 'numOfIC', 3);
+%               Reduce dimension to 10, and estimate only 3
+%               independent components.
+%
+%       [icasig] = FASTICA (mixedsig, 'verbose', 'off', 'displayMode', 'off');
+%               Don't output convergence reports and don't plot
+%               independent components.
+%
+%
+% A graphical user interface for FASTICA can be launched by the
+% command FASTICAG
+%
+%   See also FASTICAG
+
+% @(#)$Id$
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Check some basic requirements of the data
+if nargin == 0,
+  error ('You must supply the mixed data as input argument.');
+end
+
+if length (size (mixedsig)) > 2,
+  error ('Input data can not have more than two dimensions.');
+end
+
+if any (any (isnan (mixedsig))),
+  error ('Input data contains NaN''s.');
+end
+
+if ~isa (mixedsig, 'double')
+  fprintf ('Warning: converting input data into regular (double) precision.\n');
+  mixedsig = double (mixedsig);
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Remove the mean and check the data
+
+[mixedsig, mixedmean] = remmean(mixedsig);
+
+[Dim, NumOfSampl] = size(mixedsig);
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Default values for optional parameters
+
+% All
+verbose           = 'on';
+
+% Default values for 'pcamat' parameters
+firstEig          = 1;
+lastEig           = Dim;
+interactivePCA    = 'off';
+
+% Default values for 'fpica' parameters
+approach          = 'defl';
+numOfIC           = Dim;
+g                 = 'pow3';
+finetune          = 'off';
+a1                = 1;
+a2                = 1;
+myy               = 1;
+stabilization     = 'off';
+epsilon           = 0.0001;
+maxNumIterations  = 1000;
+maxFinetune       = 5;
+initState         = 'rand';
+guess             = 0;
+sampleSize        = 1;
+displayMode       = 'off';
+displayInterval   = 1;
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Parameters for fastICA - i.e. this file
+
+b_verbose = 1;
+jumpPCA = 0;
+jumpWhitening = 0;
+only = 3;
+userNumOfIC = 0;
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Read the optional parameters
+
+if (rem(length(varargin),2)==1)
+  error('Optional parameters should always go by pairs');
+else
+  for i=1:2:(length(varargin)-1)
+    if ~ischar (varargin{i}),
+      error (['Unknown type of optional parameter name (parameter' ...
+	      ' names must be strings).']);
+    end
+    % change the value of parameter
+    switch lower (varargin{i})
+     case 'stabilization'
+      stabilization = lower (varargin{i+1});
+     case 'maxfinetune'
+      maxFinetune = varargin{i+1};
+     case 'samplesize'
+      sampleSize = varargin{i+1};
+     case 'verbose'
+      verbose = lower (varargin{i+1});
+      % silence this program also
+      if strcmp (verbose, 'off'), b_verbose = 0; end
+     case 'firsteig'
+      firstEig = varargin{i+1};
+     case 'lasteig'
+      lastEig = varargin{i+1};
+     case 'interactivepca'
+      interactivePCA = lower (varargin{i+1});
+     case 'approach'
+      approach = lower (varargin{i+1});
+     case 'numofic'
+      numOfIC = varargin{i+1};
+      % User has supplied new value for numOfIC.
+      % We'll use this information later on...
+      userNumOfIC = 1;
+     case 'g'
+      g = lower (varargin{i+1});
+     case 'finetune'
+      finetune = lower (varargin{i+1});
+     case 'a1'
+      a1 = varargin{i+1};
+     case 'a2'
+      a2 = varargin{i+1};
+     case {'mu', 'myy'}
+      myy = varargin{i+1};
+     case 'epsilon'
+      epsilon = varargin{i+1};
+     case 'maxnumiterations'
+      maxNumIterations = varargin{i+1};
+     case 'initguess'
+      % no use setting 'guess' if the 'initState' is not set
+      initState = 'guess';
+      guess = varargin{i+1};
+     case 'displaymode'
+      displayMode = lower (varargin{i+1});
+     case 'displayinterval'
+      displayInterval = varargin{i+1};
+     case 'pcae'
+      % calculate if there are enought parameters to skip PCA
+      jumpPCA = jumpPCA + 1;
+      E = varargin{i+1};
+     case 'pcad'
+      % calculate if there are enought parameters to skip PCA
+      jumpPCA = jumpPCA + 1;
+      D = varargin{i+1};
+     case 'whitesig'
+      % calculate if there are enought parameters to skip PCA and whitening
+      jumpWhitening = jumpWhitening + 1;
+      whitesig = varargin{i+1};
+     case 'whitemat'
+      % calculate if there are enought parameters to skip PCA and whitening
+      jumpWhitening = jumpWhitening + 1;
+      whiteningMatrix = varargin{i+1};
+     case 'dewhitemat'
+      % calculate if there are enought parameters to skip PCA and whitening
+      jumpWhitening = jumpWhitening + 1;
+      dewhiteningMatrix = varargin{i+1};
+     case 'only'
+      % if the user only wants to calculate PCA or...
+      switch lower (varargin{i+1})
+       case 'pca'
+	only = 1;
+       case 'white'
+	only = 2;
+       case 'all'
+	only = 3;
+      end
+      
+     otherwise
+      % Hmmm, something wrong with the parameter string
+      error(['Unrecognized parameter: ''' varargin{i} '''']);
+    end;
+  end;
+end
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% print information about data
+if b_verbose
+  fprintf('Number of signals: %d\n', Dim);
+  fprintf('Number of samples: %d\n', NumOfSampl);
+end
+
+% Check if the data has been entered the wrong way,
+% but warn only... it may be on purpose
+
+if Dim > NumOfSampl
+  if b_verbose
+    fprintf('Warning: ');
+    fprintf('The signal matrix may be oriented in the wrong way.\n');
+    fprintf('In that case transpose the matrix.\n\n');
+  end
+end
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Calculating PCA
+
+% We need the results of PCA for whitening, but if we don't
+% need to do whitening... then we dont need PCA...
+if jumpWhitening == 3
+  if b_verbose,
+    fprintf ('Whitened signal and corresponding matrises supplied.\n');
+    fprintf ('PCA calculations not needed.\n');
+  end;
+else
+  
+  % OK, so first we need to calculate PCA
+  % Check to see if we already have the PCA data
+  if jumpPCA == 2,
+    if b_verbose,
+      fprintf ('Values for PCA calculations supplied.\n');
+      fprintf ('PCA calculations not needed.\n');
+    end;
+  else
+    % display notice if the user entered one, but not both, of E and D.
+    if (jumpPCA > 0) & (b_verbose),
+      fprintf ('You must suply all of these in order to jump PCA:\n');
+      fprintf ('''pcaE'', ''pcaD''.\n');
+    end;
+    
+    % Calculate PCA
+    [E, D]=pcamat(mixedsig, firstEig, lastEig, interactivePCA, verbose);
+  end
+end
+
+% skip the rest if user only wanted PCA
+if only > 1
+  
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Whitening the data
+  
+  % Check to see if the whitening is needed...
+  if jumpWhitening == 3,
+    if b_verbose,
+      fprintf ('Whitening not needed.\n');
+    end;
+  else
+    
+    % Whitening is needed
+    % display notice if the user entered some of the whitening info, but not all.
+    if (jumpWhitening > 0) & (b_verbose),
+      fprintf ('You must suply all of these in order to jump whitening:\n');
+      fprintf ('''whiteSig'', ''whiteMat'', ''dewhiteMat''.\n');
+    end;
+    
+    % Calculate the whitening
+    [whitesig, whiteningMatrix, dewhiteningMatrix] = whitenv ...
+						     (mixedsig, E, D, verbose);
+  end
+  
+end % if only > 1
+
+% skip the rest if user only wanted PCA and whitening
+if only > 2
+  
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Calculating the ICA
+  
+  % Check some parameters
+  % The dimension of the data may have been reduced during PCA calculations.
+  % The original dimension is calculated from the data by default, and the
+  % number of IC is by default set to equal that dimension.
+  
+  Dim = size(whitesig, 1);
+  
+  % The number of IC's must be less or equal to the dimension of data
+  if numOfIC > Dim
+    numOfIC = Dim;
+    % Show warning only if verbose = 'on' and user supplied a value for 'numOfIC'
+    if (b_verbose & userNumOfIC)
+      fprintf('Warning: estimating only %d independent components\n', numOfIC);
+      fprintf('(Can''t estimate more independent components than dimension of data)\n');
+    end
+  end
+  
+  % Calculate the ICA with fixed point algorithm.
+  [A, W] = fpica (whitesig,  whiteningMatrix, dewhiteningMatrix, approach, ...
+		  numOfIC, g, finetune, a1, a2, myy, stabilization, epsilon, ...
+		  maxNumIterations, maxFinetune, initState, guess, sampleSize, ...
+		  displayMode, displayInterval, verbose);
+  
+  % Check for valid return
+%   if ~isempty(W)   % ORIGINAL VERSION
+
+% MODIFIED VERSION: CHECK ALSO IF ICASIG IS RETURNED AT ALL, before we
+% comput it
+% CHANGED BY kaigoe (kai.goergen@bccn-berlin.de)
+
+    % modified version
+  if ~isempty(W)  ...
+          && nargout ~= 2  %% if nargout == 2, we return [W. A], and NOT ICASIG
+    % Add the mean back in.
+    if b_verbose
+      fprintf('Adding the mean back to the data.\n');
+    end
+    icasig = W * mixedsig + (W * mixedmean) * ones(1, NumOfSampl);
+    %icasig = W * mixedsig;
+    if b_verbose & ...
+	  (max(abs(W * mixedmean)) > 1e-9) & ...
+	  (strcmp(displayMode,'signals') | strcmp(displayMode,'on'))
+      fprintf('Note that the plots don''t have the mean added.\n');
+    end
+  else
+    icasig = [];
+  end
+
+end % if only > 2
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% The output depends on the number of output parameters
+% and the 'only' parameter.
+
+if only == 1    % only PCA
+  Out1 = E;
+  Out2 = D;
+elseif only == 2  % only PCA & whitening
+  if nargout == 2
+    Out1 = whiteningMatrix;
+    Out2 = dewhiteningMatrix;
+  else
+    Out1 = whitesig;
+    Out2 = whiteningMatrix;
+    Out3 = dewhiteningMatrix;
+  end
+else      % ICA
+  if nargout == 2
+    Out1 = A;
+    Out2 = W;
+  else
+    Out1 = icasig;
+    Out2 = A;
+    Out3 = W;
+  end
+end