www.pudn.com > JnS-1.2.rar > MatlabshibbsR.m
function B = shibbs(X,m)
%
% Developpment version
%================================================================
% Blind separation of real signals with SHIBBS. Version 1.5 Dec. 1997.
%
% Usage:
% * If X is an nxT data matrix (n sensors, T samples) then
% B=shibbsR(X) is a nxn separating matrix such that S=B*X is an nxT
% matrix of estimated source signals.
% * If B=shibbsR(X,m), then B has size mxn so that only m sources are
% extracted. This is done by restricting the operation of shibbsR
% to the m first principal components.
% * Also, the rows of B are ordered such that the columns of pinv(B)
% are in order of decreasing norm; this has the effect that the
% `most energetically significant' components appear first in the
% rows of S=B*X.
%
% Copyright : Jean-Francois Cardoso. cardoso@sig.enst.fr
[n,T] = size(X);
verbose = 0 ; %% Set to 0 for quiet operation
seuil = 0.01/sqrt(T) ; %% A statistically significant threshold for joint diag.
% Finding the number of sources
if nargin==1, m=n ; end; % Number of sources defaults to # of sensors
if m>n , fprintf('shibbs -> Do not ask more sources than sensors here!!!\n'), return,end
if verbose, fprintf('shibbs -> Looking for %d sources\n',m); end ;
% Mean removal
%=============
if verbose, fprintf('shibbs -> Removing the mean value\n'); end
MeanX = mean(X,2) ;
X = X - MeanX(:,ones(1,T));
clear MeanX ;
%%% whitening & projection onto signal subspace
% ===========================================
if verbose, fprintf('shibbs -> Whitening the data\n'); end
[U,D] = eig((X*X')/T) ;
[puiss,k] = sort(diag(D)) ;
rangeW = n-m+1:n ; % indices to the m most significant directions
scales = sqrt(puiss(rangeW)) ; % scales
B = diag(1./scales) * U(1:n,k(rangeW))' ; % whitener
X = B*X;
%%% Estimation of the cumulant matrices.
% ====================================
nbcm = m ; %% number of cumulant matrices
CM = zeros(m,m*nbcm); % Storage for cumulant matrices
%% Mainly Temps
Rk = zeros(m); %%
R = eye(m); %%
Xk = zeros(m,T) ;
xk = zeros(1,T) ;
Uns = ones(m,1) ; % for The Trick
OneMoreStep = 1 ; %
while OneMoreStep ,
if verbose, fprintf('shibbs -> Estimating cumulant matrices\n'); end
%% Computing a `small number' of cumulant matrices.
%% -------------------------------------------------
Range = 1:m ; % will index the columns of CM where to store the cum. mats.
%% fprintf('Cumulant matrices: ')
for k = 1:m
%% if verbose, fprintf('shibbs -> Cum. Mat. #%d\n',k); end
xk = X(k,:) ;
Xk = X .* xk(Uns,:) ; % Oooch
Rk = (Xk*Xk')/T - R ;
Rk(k,k) = Rk(k,k) - 2 ;
CM(:,Range) = Rk ;
Range = Range + m ;
end;
%% fprintf('\n')
%% Joint diagonalization of the cumulant matrices
%% ----------------------------------------------
%% Init
V = eye(m) ; % la rotation initiale
nbrs = 1; % Number of rotations in this sweep. Also used for control
sweep = 0; % Number of sweeps
updates = 0 ;
g = zeros(2,nbcm);
gg = zeros(2,2);
G = zeros(2,2);
c = 0 ;
s = 0 ;
ton = 0 ;
toff = 0 ;
theta = 0 ;
%% Joint diagonalization proper
if verbose, fprintf('shibbs -> Contrast optimization by joint diagonalization\n'); end
while nbrs, nbrs=0; % Will start again unless there is at least one update
sweep=sweep+1; if verbose, fprintf('shibbs -> Sweep #%d',sweep); end
for p=1:m-1,
for q=p+1:m,
Ip = p:m:m*nbcm ;
Iq = q:m:m*nbcm ;
%%% computation of Givens angle
g = [ CM(p,Ip)-CM(q,Iq) ; CM(p,Iq)+CM(q,Ip) ];
gg = g*g';
ton = gg(1,1)-gg(2,2);
toff = gg(1,2)+gg(2,1);
theta = 0.5*atan2( toff , ton+sqrt(ton*ton+toff*toff) );
%%% Givens update
if abs(theta) > seuil, nbrs = nbrs + 1 ;
c = cos(theta);
s = sin(theta);
G = [ c -s ; s c ] ;
pair = [p;q] ;
V(:,pair) = V(:,pair)*G ;
CM(pair,:) = G' * CM(pair,:) ;
CM(:,[Ip Iq]) = [ c*CM(:,Ip)+s*CM(:,Iq) -s*CM(:,Ip)+c*CM(:,Iq) ] ;
%% fprintf('shibbs -> %3d %3d %12.8f\n',p,q,s);
end%%of the if
end%%of the loop on q
end%%of the loop on p
if verbose, fprintf(' completed in %d rotations.\n',nbrs); end
updates = updates + nbrs ;
end%%of the while loop
RotSize = norm(V-eye(m),'fro') ;
if verbose, fprintf('shibbs -> Amount of rotation in this pass: %14.6f \n',RotSize); end
X = V'*X ;
B = V'*B ;
% if updates == 0 , OneMoreStep = 0; end
if RotSize < (m*seuil) , OneMoreStep = 0; end
end ; % ijd
%%% We permut its rows to get the most energetic components first.
%%% Here the **signals** are normalized to unit variance. Therefore,
%%% the sort is according to the norm of the columns of A = pinv(B)
if verbose, fprintf('shibbs -> Sorting the components\n',updates); end
A = pinv(B) ;
[vars,keys] = sort(sum(A.*A)) ;
B = B(keys,:);
B = B(m:-1:1,:) ; % Is this smart ?
% Signs are fixed by forcing the first column of B to have
% non-negative entries.
if verbose, fprintf('shibbs -> Fixing the signs\n',updates); end
b = B(:,1) ;
signs = sign(sign(b)+0.1) ; % just a trick to deal with sign=0
B = diag(signs)*B ;
return ;