%Very basic Matlab code for the unifying model for BSS
%as proposed in my article in Signal Processing, 85(7):1419-1427, 2005
%Aapo Hyvarinen, May 2003 -- Mar 2006

randn('state',1)  %fix random number generator for published results

clear error  %this stores the errors for artificial data

%Main structural parameters
N=5000; %data size
n=6; %number of mixtures and sources 


%THE WHOLE STUFF WILL BE REPEATED 100 TIMES TO EVALUATE THE ALGORITHM

for iter=1:100

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% CREATE ARTIFICIAL DATA FOR TESTING
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%create source signals 
%two nongaussian and two gaussian time-correlated signals
%using only two different time-correlations
%and two nonstatvar signals
%thus only unibss criteria estimates all!


%autoregressive constants

alpha1=.33;  
alpha2=.75;  

iteraatio=iter %show this to user


S=[];
S(:,1)=randn(n,1);
for t=2:N;
  S(1,t)=alpha1*S(1,t-1)+abs(randn).^1.3.*sign(randn);
  S(2,t)=alpha2*S(2,t-1)+abs(randn).^1.3.*sign(randn);
  S(3,t)=alpha1*S(3,t-1)+randn;
  S(4,t)=alpha2*S(4,t-1)+randn;
  S(5,t)=.9*S(5,t-1)+randn;
  S(6,t)=.9*S(6,t-1)+randn;
end
%make nonstatvar signals
S(5:6,:)=S(5:6,:).*sign(randn(2,N));

%normalize

S=S-mean(S')'*ones(1,N);

for t=1:n
S(t,:)=S(t,:)/std(S(t,:));
end


%create mixtures

A=randn(n,n); %mixing matrix
X=A*S; %observed data

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%  THE UNIBSS ALGORITHM           %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%The input to this part is the data matrix X
%and the structural variables n and N (which are simply given by size(X))

%1. PREPROCESSING OF THE DATA
%%%%%%%%%%%%%%%%%%%%%%%%%%

%(it is assumed that the data is already zero-mean)

%whitening

C=cov(X');
V=inv(sqrtm(C));
Z=V*X;

%compute time-delayed data

Zd=[Z(:,N),Z(:,1:(N-1))]; %we could also zero-pad
CZd=Z*Zd'/N; %time-delayed covariance


%2. INITIALIZE ALGORITHM
%%%%%%%%%%%%%%%%%%%%%


W=randn(n,n);
W=inv(sqrtm(W*W'))*W;



%3. THE MAIN ALGORITHM PART:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%this just takes an certain number of steps, 
%I didn't bother to implement a proper stopping criterion.

	    %Also in other respects, the code is extremely basic:
%- a single nonlinearity (-sign(.)) is implemented; this assumes supergaussian innovations
%- no effort is made to estimate the filter "h"
%- only a first-order autoregressive model is used

for t=1:999 


	for i=1:n %for each source do separately
          %compute AR(1) coefficient
  	  alpha=W(i,:)*CZd*W(i,:)';
          %compute estimate of innovations process
	  n_est=W(i,:)*(Z-alpha*Zd);
          %compute local standard deviations
	  sigma=sqrt(filter([1,1,1,1,1,1],1,n_est.^2));
          %compute gradient
          grad(i,:)=((Z-alpha*Zd)*(-sign(n_est)./sigma)')'/N;
	end
        
        %project gradient and do gradient step
        W=W+.1*(grad-W*grad'*W);

        %orthogonalize W
        W=inv(sqrtm(W*W'))*W;

	%evaluate results
	comb=W*V*A;
        %a very simple measure of estimation error, not unlike Amari error
        errornow=(n-sum(max(comb.^2)))^2;
	error(iter,t)=errornow;


end %of algorithm iteration "for t"

end %of the outer iteration that repeats estimation 100 times


%At this point, you can plot the rows of "error", or a median of them,
%to get the figure in the paper

%Here's another simple evaluation of results:
number_of_iterations_not_converged=sum(error(:,999)>.01)

