% This code illustrates the idea of multidimensional independent component analysis % applied to the fetal ECG extraction problem as introduced in the paper: % % JF Cardoso, Multidimensional independent component analysis. Proc. ICASSP'98. Seattle % (available as by anonymous FTP at "ftp://sig.enst.fr/pub/jfc/Papers/icassp98.ps") % % However, in the ICASSP paper, due to lack of room, the analysis was restricted to % processing the ouputs of 3 sensors out of 8 in the available data set. In this demo, % we process the whole data set: a better decomposition is achieved. % % More things are available at http://sig.enst.fr/~cardoso % clear %% Getting data disp('Reading data from disk'); load foetal_ecg.dat X = foetal_ecg(:,2:9)'; Time = foetal_ecg(:,1 )'; [m,T] = size(X) ; disp('Running Jade on all sensors'); flops(0) B = jadeR(X,m); %%%% Assumes version 1.5 of JADE Flops = flops ; disp(['JADE ran in ' int2str(Flops) ' flops' ]) ; A = pinv(B) ; %% Estimate of the mixing matrix S = B*X ; %% Estimate of the source signals %% who is where ? mother = [ 1 2 3 4] ; baby = [ 7 8 ] ; noise = [ 5 6 ] ; AM = A(:,mother) ; AB = A(:,baby) ; AN = A(:,noise) ; XM = A(:,mother)*S(mother,:); XB = A(:,baby )*S(baby ,:); XN = A(:,noise )*S(noise ,:); %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% disp('Mixing matrix estimated by JADE:') A disp('Orthogonal projection matrix onto 2D mother subspace:') Pm = A(:,mother)*pinv(A(:,mother)) disp('Orthogonal projection matrix onto 1D fetus subspace:') ; Pb = A(:,baby)*pinv(A(:,baby)) disp('Oblique projection matrix onto 2D mother subspace') disp(' orthogonally to 1D babysubspace:') PTm = A(:,mother)*B(mother,:) disp('Oblique projection matrix onto 1D baby subspace') disp(' orthogonally to 2D mother subspace:') PTb = A(:,baby) *B(baby, :) %%% ---------- Fig.1 : The complete decomposition at sensor level ----------------- %% The scales used for display are manually chosen: Ska = [ -50 50 ; -50 120 ; -100 50 ; -50 30 ; -100 50 ; -1000 500 ; -500 1000 ; -500 1000 ] ; figure(1); clf T = 500 ; %% Displaying only a fraction of the data set. Subtime = 1:T ; Time = Time(Subtime); ncols = 6 ; for cap=1:m subplot(m,ncols,(cap-1)*ncols+1); plot(Time,X(cap,Subtime)); axis([ Time(1) Time(T) Ska(cap,1) Ska(cap,2)] ); set(gca,'Ytick',[ Ska(cap,1) 0 Ska(cap,2) ]) set(gca,'Fontsize',6) set(gca,'FontName','Helvetica') if cap ==1, title('Sensor signals'); end subplot(m,ncols,(cap-1)*ncols+2); plot(Time,S(cap,Subtime)); ca = axis; axis([ Time(1) Time(T) ca(3) ca(4) ] ); set(gca,'Xtick',[]) set(gca,'Fontsize',6) set(gca,'FontName','Helvetica') if cap ==1, title('Source signals'); end subplot(m,ncols,(cap-1)*ncols+3); plot(Time,XM(cap,Subtime)) set(gca,'Xtick',[]) set(gca,'Ytick',[ Ska(cap,1) 0 Ska(cap,2) ]) axis([ Time(1) Time(T) Ska(cap,1) Ska(cap,2)] ); set(gca,'Fontsize',6) set(gca,'FontName','Helvetica') if cap ==1, title('4D Mother MICA component'); end subplot(m,ncols,(cap-1)*ncols+4); plot(Time,XB(cap,Subtime)) set(gca,'Xtick',[]) set(gca,'Ytick',[ Ska(cap,1) 0 Ska(cap,2) ]) axis([ Time(1) Time(T) Ska(cap,1) Ska(cap,2)] ); set(gca,'FontName','Helvetica') set(gca,'Fontsize',6) if cap ==1, title('2D Foetal MICA component'); end subplot(m,ncols,(cap-1)*ncols+5); plot(Time,XB(cap,Subtime)) set(gca,'Xtick',[]) % set(gca,'Ytick',[ Ska(cap,1) 0 Ska(cap,2) ]) % axis([ Time(1) Time(T) Ska(cap,1) Ska(cap,2)] ); set(gca,'FontName','Helvetica') set(gca,'Fontsize',6) if cap ==1, title('Full scale Foetal MICA component'); end subplot(m,ncols,(cap-1)*ncols+6); plot(Time,XN(cap,Subtime)) set(gca,'Xtick',[]) set(gca,'Ytick',[ Ska(cap,1) 0 Ska(cap,2) ]) axis([ Time(1) Time(T) Ska(cap,1) Ska(cap,2)] ); set(gca,'FontName','Helvetica') set(gca,'Fontsize',6) if cap ==1, title('2D Noise MICA component'); end end set(gcf,'PaperOrientation','Landscape') set(gcf,'Paperunits','centimeters') % set(gcf,'PaperPosition',[ 2 2 22 8])