├── README.md ├── .gitignore ├── complex_FastICA_demo.py ├── complex_jadeICA.py ├── complex_acmnICA.py └── complex_FastICA.py /README.md: -------------------------------------------------------------------------------- 1 | # complex_ica 2 | ICA algorithms for complex-valued signals 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | -------------------------------------------------------------------------------- /complex_FastICA_demo.py: -------------------------------------------------------------------------------- 1 | import pdb,os,time 2 | import numpy as np 3 | from math import log,log10 4 | from numpy.linalg import * 5 | from numpy.random import rand 6 | import matplotlib.pyplot as plt 7 | import matplotlib as mpl 8 | from mpl_toolkits.mplot3d import axes3d 9 | import complex_FastICA as cica 10 | reload(cica) 11 | 12 | plt.ion() 13 | 14 | 15 | m = 50000 16 | j = 0 17 | 18 | 19 | # some parameters for the available distributions 20 | 21 | bino1 = np.maximum(2, np.ceil(20*rand())) 22 | bino2 = rand() 23 | exp1 = np.ceil(10*rand()) 24 | gam1 = np.ceil(10*rand()) 25 | gam2 = gam1 + np.ceil(10*rand()) 26 | f1 = np.ceil(10*rand()) 27 | f2 = np.ceil(100*rand()) 28 | poiss1 = np.ceil(10*rand()) 29 | nbin1 = np.ceil(10*rand()) 30 | nbin2 = rand() 31 | hyge1 = np.ceil(900*rand()) 32 | hyge2 = np.ceil(20*rand()) 33 | hyge3 = round(hyge1/np.maximum(2,np.ceil(5*rand()))) 34 | chi1 = np.ceil(20*rand()) 35 | beta1 = np.ceil(10*rand()) 36 | beta2 = beta1 + np.ceil(10*rand()) 37 | unif1 = np.ceil(2*rand()) 38 | unif2 = unif1 + np.ceil(2*rand()) 39 | gam3 = np.ceil(20*rand()) 40 | gam4 = gam3 + np.ceil(20*rand()) 41 | f3 = np.ceil(10*rand()) 42 | f4 = np.ceil(50*rand()) 43 | exp2 = np.ceil(20*rand()) 44 | rayl1 = 10 45 | unid1 = np.ceil(100*rand()) 46 | norm1 = np.ceil(10*rand()) 47 | norm2 = np.ceil(10*rand()) 48 | logn1 = np.ceil(10*rand()) 49 | logn2 = np.ceil(10*rand()) 50 | geo1 = rand() 51 | weib1 = np.ceil(10*rand()) 52 | weib2 = weib1 + np.ceil(10*rand()) 53 | 54 | 55 | 56 | r = np.random.binomial(bino1,bino2,size=(1,m)) 57 | 58 | r = np.vstack([r,np.random.gamma(gam1,gam2,size=(1,m))]) 59 | r = np.vstack([r,np.random.poisson(poiss1,size=(1,m))]) 60 | r = np.vstack([r,np.random.hypergeometric(hyge1,hyge2,hyge3,size=(1,m))]) 61 | r = np.vstack([r,np.random.beta(beta1,beta2,size=(1,m))]) 62 | r = np.vstack([r,np.random.exponential(exp1,size=(1,m))]) 63 | r = np.vstack([r,np.random.uniform(unid1,size=(1,m))]) 64 | r = np.vstack([r,np.random.normal(norm1,norm2,size=(1,m))]) 65 | r = np.vstack([r,np.random.geometric(geo1,size=(1,m))]) 66 | 67 | 68 | 69 | n = r.shape[0] 70 | 71 | #np.random.seed(1234) 72 | 73 | f = np.random.uniform(-2*np.pi,2*np.pi,size=(n,m)) 74 | 75 | S = r*(np.cos(f)+1j*np.sin(f)) 76 | 77 | # Standardize data 78 | S = inv(np.diag(S.std(1))).dot(S) 79 | 80 | # Mixing using complex mixing matrix A 81 | A = rand(n,n)+1j*rand(n,n) 82 | X = A.dot(S) 83 | 84 | alg = 'deflation'#'parallel' 85 | 86 | K,W,Shat,EG = cica.complex_FastICA(X,max_iter=40,algorithm=alg,\ 87 | n_components=n) 88 | 89 | 90 | #Compute the SSE 91 | absKAHW = np.abs((K.dot(A)).conj().T.dot(W)) 92 | 93 | print '\nPermutation matrix: \n%s'%str(np.round(absKAHW)) 94 | 95 | maximum = absKAHW.max(0) 96 | SSE = ((absKAHW**2).sum(0)-maximum**2+(1-maximum)**2).sum() 97 | SIR = 10*log10(((absKAHW*1./maximum).sum(0)-1).mean()) 98 | 99 | print "\nSSE:%.4f"%SSE 100 | print "\nSIR:%.4f"%SIR 101 | 102 | span = 20 103 | start=np.random.randint(m-span) 104 | 105 | 106 | fig = plt.figure('fastICA_demo') 107 | fig.clf() 108 | 109 | ax1 = fig.add_subplot(121) 110 | for j in xrange(n): 111 | ax1.plot(np.ma.masked_invalid(EG[j]),'.-',label='c_%i'%(j+1)) 112 | ax1.set_ylabel('E[G(|W.T*X|^2)]') 113 | ax1.set_xlabel('iteration #') 114 | plt.legend(loc='best') 115 | 116 | ax2 = fig.add_subplot(222) 117 | ax2.plot(np.abs(S[:,start:start+span]).T,lw=3,alpha=.2,color='k') 118 | ax2.plot(np.abs(Shat[:,start:start+span]).T,'--',color='r') 119 | ax2.set_ylabel('Amplitude') 120 | ax2.set_xlabel('Time (a.u.)') 121 | 122 | ax3 = fig.add_subplot(224) 123 | ax3.plot(np.angle(S[:,start:start+span]).T,lw=3,alpha=.2,color='k') 124 | ax3.plot(np.angle(Shat[:,start:start+span]).T,'--',color='b') 125 | ax3.set_ylabel('Angle') 126 | ax3.set_xlabel('Time (a.u.)') 127 | 128 | plt.show() 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /complex_jadeICA.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | import pdb,os,time,warnings 3 | import numpy as np 4 | from math import log 5 | from numpy.linalg import * 6 | from numpy.random import rand 7 | from scipy.linalg import sqrtm 8 | 9 | def jade(X,m=None,max_iter=100,nem=None,tol=None): 10 | """Source separation of complex signals via Joint Approximate 11 | Diagonalization of Eigen-matrices or JADE 12 | 13 | Parameters 14 | ---------- 15 | 16 | X : array, shape (n_mixtures, n_samples) 17 | Matrix containing the mixtures 18 | 19 | m : int, optional 20 | Number of sources. If None, equals the number of mixtures 21 | 22 | max_iter : int, optional 23 | Maximum number of iterations 24 | 25 | nem : int, optional 26 | Number of eigen-matrices to be diagonalized 27 | 28 | tol : float, optional 29 | Threshold for stopping joint diagonalization 30 | 31 | Returns 32 | ------- 33 | 34 | A : array, shape (n_mixtures, n_sources) 35 | Estimate of the mixing matrix 36 | 37 | S : array, shape (n_sources, n_samples) 38 | Estimate of the source signals 39 | 40 | V : array, shape (n_sources, n_mixtures) 41 | Estimate of the un-mixing matrix 42 | 43 | W : array, shape (n_components, n_mixtures) 44 | Sphering matrix 45 | 46 | 47 | Notes 48 | ----- 49 | 50 | Original script in Matlab - version 1.6. Copyright: JF Cardoso. 51 | Url: http://perso.telecom-paristech.fr/~cardoso/Algo/Jade/jade.m 52 | Citation: Cardoso, Jean-Francois, and Antoine Souloumiac. 'Blind 53 | beamforming for non-Gaussian signals.'IEE Proceedings F (Radar 54 | and Signal Processing). Vol. 140. No. 6. IET Digital Library, 55 | 1993. 56 | 57 | Author (python script): Alex Bujan 58 | Date: 20/01/2016 59 | """ 60 | 61 | n,T = X.shape 62 | 63 | if m==None: 64 | m = n 65 | 66 | if nem==None: 67 | nem = m 68 | 69 | if tol==None: 70 | tol = 1/(np.sqrt(T)*1e2) 71 | 72 | ''' 73 | whitening 74 | ''' 75 | 76 | X-=X.mean(1,keepdims=True) 77 | 78 | if mtol: 168 | pair = np.hstack((p,q)) 169 | G = np.vstack(([c,-s.conj()],[s,c])) 170 | V[:,pair] = V[:,pair].dot(G) 171 | M[pair,:] = G.conj().T.dot(M[pair,:]) 172 | ids = np.hstack((Ip,Iq)) 173 | M[:,ids] = np.hstack((c*M[:,Ip]+s*M[:,Iq],\ 174 | -s.conj()*M[:,Ip]+c*M[:,Iq])) 175 | else: 176 | encore = False 177 | 178 | if encore==False: 179 | break 180 | 181 | if n_iter+1==max_iter: 182 | warnings.warn('JadeICA did not converge. Consider increasing ' 183 | 'the maximum number of iterations or decreasing the ' 184 | 'threshold for stopping joint diagonalization.') 185 | 186 | ''' 187 | estimation of the mixing matrix and sources 188 | ''' 189 | A = IW.dot(V) 190 | S = V.conj().T.dot(Y) 191 | 192 | return A,S,W,V 193 | -------------------------------------------------------------------------------- /complex_acmnICA.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | import pdb 3 | import numpy as np 4 | from numpy.linalg import * 5 | from math import log,gamma 6 | from numpy.random import rand 7 | from scipy.special import psi,polygamma 8 | 9 | 10 | """ 11 | Author: Alex Bujan 12 | Adapted from: 13 | Mike Novey and T. Adali, "ADAPTABLE NONLINEARITY FOR COMPLEX 14 | MAXIMIZATION OF NONGAUSSIANITY AND A FIXED-POINT ALGORITHM" in 15 | IEEE MLSP 2006.,Adaptable ICA algorithm based on complex 16 | generalized Gaussian distribution 17 | Date: 12/11/2015 18 | """ 19 | 20 | 21 | def ACMNsym(X,model='circ',p_init=1.25,\ 22 | max_iter=40,tol=1e-4,epsilon=.01): 23 | """ 24 | ICA of a complex-valued signal 25 | 26 | Input: 27 | X : vector of mixtures 28 | model : specifies MLE algorithm. Options: 29 | + noncirc uses MLE 30 | that has noncircular model 31 | + circ assumes circular and 32 | runs mutch faster 33 | """ 34 | 35 | n,m = X.shape 36 | 37 | #Whitening 38 | X-=X.mean(1,keepdims=True) 39 | Dx,Ex = eig(np.cov(X)) 40 | K = np.sqrt(inv(np.diag(Dx))).dot(Ex.conj().T) 41 | X = K.dot(X) 42 | 43 | #cache the pseudo-covariance 44 | pC = X.dot(X.T)/m 45 | 46 | #initialized shape parameter 'p' for each source 47 | params = np.repeat(p_init,n) 48 | 49 | ''' 50 | FIXED POINT ALGORITHM 51 | ''' 52 | 53 | #initialize the unmixing matrix 54 | W = np.random.normal(size=(n,n))+\ 55 | 1j*np.random.normal(size=(n,n)) 56 | 57 | for k in xrange(max_iter): 58 | 59 | Wold = np.copy(W) 60 | 61 | 62 | for kk in xrange(n): 63 | 64 | ''' 65 | 1) Calculate current source estimate y = WHX 66 | ''' 67 | 68 | y = W[:,kk].reshape((n,1)).conj().T.dot(X) 69 | 70 | ''' 71 | 2) Update W 72 | ''' 73 | 74 | if model=='noncirc': 75 | 76 | p = params[kk] 77 | 78 | elif model=='circ': 79 | 80 | p = params[kk]/2 81 | 82 | abs_y = abs(y)**2 83 | 84 | u = abs_y + epsilon 85 | 86 | u1 = p * u**(p-1) 87 | u2 = p * (p-1) * u**(p-2) 88 | 89 | gRad = ((u1*y.conj())*X).mean(1) 90 | ggg = (u2*abs_y+u1).mean() 91 | B = (u2*y.conj()**2).mean()*pC 92 | 93 | W[:,kk] = Wold[:,kk]*ggg - gRad + B.dot(Wold[:,kk].conj()) 94 | 95 | ''' 96 | 3) Estimate p 97 | ''' 98 | 99 | if model=='noncirc': 100 | 101 | aug_y = np.concatenate([y.T,y.conj().T],axis=1).conj().T 102 | 103 | params[kk] = estimateGGDCovShapeIn(aug_y,params[kk]) 104 | 105 | elif model=='circ': 106 | 107 | # Newton estimate of p 108 | 109 | p = params[kk] 110 | 111 | abs_y = abs(y) 112 | 113 | u = abs_y + epsilon 114 | 115 | up = u**p 116 | 117 | sigP = (abs_y**p).mean()**(1/p) 118 | 119 | gp = -(1/p**2) * log(p) + (1/p**2) - \ 120 | psi(1+1/p) * (1/p**2) + \ 121 | ( (1/(sigP**p*p)) * up * (np.log(u) - \ 122 | ((1/p) + log(sigP)) ) ).mean() 123 | 124 | ggp = 2*(1/p**3)*log(p) - 3*(1/p**3) + \ 125 | float(polygamma(1,1+1/p))*(1/p**4) + \ 126 | 2*psi(1+1/p)*(1/p**3) + \ 127 | ( (1/(p*sigP**p)) * up * \ 128 | ( np.log(u)**2 - 2*(1/p)*np.log(u) - \ 129 | 2*log(sigP)*np.log(u) + \ 130 | (2*(1/p**2) + 2*log(sigP)*(1/p) + \ 131 | log(sigP)**2) ) ).mean() 132 | 133 | p-=(gp/ggp) 134 | p = np.maximum(p,.2) 135 | p = np.minimum(p,3) 136 | 137 | params[kk] = p 138 | 139 | ''' 140 | 4) Normalize W (symmetric decorrelation) 141 | ''' 142 | 143 | D,E = eig(W.conj().T.dot(W)) 144 | W = W.dot(E.dot(inv(np.sqrt(np.diag(D))).dot(E.conj().T))) 145 | 146 | ''' 147 | 5) Check for convergence 148 | ''' 149 | 150 | if (abs(abs(Wold)-abs(W))).sum() < tol: 151 | break 152 | 153 | S = W.conj().T.dot(X) 154 | A = inv(K).dot(W) 155 | 156 | return A,S,K,W 157 | 158 | def estimateGGDCovShapeIn(X,p_init): 159 | 160 | N = X.shape[1] 161 | R = np.cov(X) 162 | 163 | #start at Gaussian 164 | bestC = p_init 165 | c = bestC 166 | 167 | Rold = np.zeros((2,2),dtype=np.complex) 168 | 169 | xRxC = 0 170 | dirXRX = 0 171 | dirXRX2 = 0 172 | 173 | for n in xrange(N): 174 | temp = X[:,n].conj().T.dot(inv(R)).dot(X[:,n]) 175 | xRxC += (temp**c).real 176 | dirXRX += (log(temp)*temp**c).real 177 | dirXRX2 += (log(temp)**2*temp**c).real 178 | 179 | c2 = gamma(2*1/c)/(2*gamma(1/c)) 180 | 181 | c2p = log(c2) - (1/c) * 2*psi(2*1/c) - psi(1/c) 182 | 183 | gc = N * ( (1/c) - (1/c**2) * 2*psi(2*1/c) + \ 184 | (1/c**2) * 2*psi(1/c) ) - \ 185 | (c2**c) * (c2p*xRxC + dirXRX) 186 | 187 | ##Second dir 188 | A = N * ( (4*psi(2*1/c)/c**3) + \ 189 | (4*polygamma(1,2*1/c)/c**4) - \ 190 | (1/c**2) - (4*psi(1/c)/c**3) - \ 191 | (2*polygamma(1,1/c)/c**4) ) 192 | 193 | #Dir c2**c 194 | dc2C = log(c2)*(c2**c) - \ 195 | c*(c2**(c-1))*(c2*2*psi(2*1/c)/c**2 - \ 196 | c2*psi(1/c)/c**2) 197 | 198 | dc2p = -((psi(1/c) - 2*psi(2*1/c))/c**2) - \ 199 | ((polygamma(1,1/c) - 4 * polygamma(1,2*1/c))/c**3)-\ 200 | ((2*psi(2*1/c)/c**2) - psi(1/c)/c**2) 201 | 202 | B = dc2C*c2p*xRxC + c2**c * (dc2p*xRxC + c2p*dirXRX) 203 | 204 | C = dc2C*dirXRX + c2**c * dirXRX2 205 | 206 | ggc = A-B-C 207 | cold = c 208 | cn = c - (1/ggc) * gc 209 | 210 | #Newton update with no negatives 211 | c = np.minimum(4,np.maximum(.05,cn)) 212 | 213 | return c 214 | 215 | -------------------------------------------------------------------------------- /complex_FastICA.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | import pdb,os,time,warnings 3 | import numpy as np 4 | from math import log 5 | from numpy.linalg import * 6 | from numpy.random import rand 7 | 8 | """ 9 | Author: Alex Bujan 10 | Adapted from: Ella Bingham, 1999 11 | 12 | Original article citation: 13 | Ella Bingham and Aapo Hyvaerinen, "A fast fixed-point algorithm for 14 | independent component analysis of complex valued signals", 15 | International Journal of Neural Systems, Vol. 10, No. 1 (February, 2000) 1-8 16 | 17 | Original code url: 18 | http://users.ics.aalto.fi/ella/publications/cfastica_public.m 19 | 20 | Date: 12/11/2015 21 | 22 | TODO: include arbitrary contrast functions 23 | """ 24 | 25 | def abs_sqr(W,X): 26 | return abs(W.conj().T.dot(X))**2 27 | 28 | def complex_FastICA(X,epsilon=.1,algorithm='parallel',\ 29 | max_iter=100,tol=1e-4,whiten=True,\ 30 | w_init=None,n_components=None): 31 | """Performs Fast Independent Component Analysis of complex-valued 32 | signals 33 | 34 | Parameters 35 | ---------- 36 | 37 | X : array, shape (n_features,n_samples) 38 | Input signal X = A S, where A is the mixing 39 | matrix and S the latent sources. 40 | 41 | epsilon : float, optional 42 | Arbitrary constant in the contrast G function 43 | used in the approximation to neg-entropy. 44 | 45 | algorithm : {'parallel', 'deflation'}, optional 46 | Apply a parallel or deflational FASTICA algorithm. 47 | 48 | w_init : (n_components, n_components) array, optional 49 | Initial un-mixing array.If None (default) then an 50 | array of normally distributed r.v.s is used. 51 | 52 | tol: float, optional 53 | A positive scalar giving the tolerance at which the 54 | un-mixing matrix is considered to have converged. 55 | 56 | max_iter : int, optional 57 | Maximum number of iterations. 58 | 59 | whiten : boolean, optional 60 | If True, perform an initial whitening of the data. 61 | If False, the data is assumed to be already white. 62 | 63 | n_components : int, optional 64 | Number of components to extract. If None, 65 | n_components = n_features. 66 | 67 | Returns 68 | ------- 69 | 70 | W : array, shape (n_components, n_components) 71 | Estimated un-mixing matrix. 72 | 73 | K : array, shape (n_components, n_features) 74 | If whiten is 'True', K is the pre-whitening matrix 75 | projecting the data onto the principal components. 76 | If whiten is 'False', K is 'None'. 77 | 78 | EG : array, shape(n_components,max_iter) 79 | Expectation of the contrast function E[G(|W'*X|^2)]. 80 | This array may be padded with NaNs at the end. 81 | 82 | S : array, shape (n_samples, n_components) 83 | Estimated sources (S = W K X). 84 | """ 85 | 86 | n,m = X.shape 87 | 88 | if n_components!=None: 89 | n = n_components 90 | 91 | if whiten: 92 | X-=X.mean(1,keepdims=True) 93 | Ux,Sx = eig(np.cov(X)) 94 | K = np.sqrt(inv(np.diag(Ux))).dot(Sx.conj().T)[:n] 95 | X = K.dot(X) 96 | del Ux,Sx 97 | else: 98 | K = None 99 | 100 | EG = np.ones((n,max_iter))*np.nan 101 | 102 | if algorithm=='deflation': 103 | 104 | W = np.zeros((n,n),dtype=np.complex) 105 | 106 | for k in xrange(n): 107 | if w_init!=None: 108 | w = w_init[:,k] 109 | else: 110 | w = np.random.normal(size=(n,1))+\ 111 | 1j*np.random.normal(size=(n,1)) 112 | 113 | w/=norm(w) 114 | 115 | n_iter = 0 116 | 117 | for i in xrange(max_iter): 118 | 119 | wold = np.copy(w) 120 | 121 | #derivative of the contrast function 122 | g = 1/(epsilon+abs_sqr(w,X)) 123 | #derivative of g 124 | dg = -1/(epsilon+abs_sqr(w,X))**2 125 | 126 | w = (X * (w.conj().T.dot(X)).conj() * g).mean(1).reshape((n,1))-\ 127 | (g + abs_sqr(w,X) * dg).mean() * w 128 | 129 | del g,dg 130 | 131 | w/=norm(w) 132 | 133 | # Decorrelation 134 | w-=W.dot(W.conj().T).dot(w) 135 | w/=norm(w) 136 | 137 | EG[k,n_iter] = (np.log(epsilon+abs_sqr(w,X))).mean() 138 | 139 | n_iter+=1 140 | 141 | lim = (abs(abs(wold)-abs(w))).sum() 142 | if limtol: 146 | warnings.warn('FastICA did not converge. Consider increasing ' 147 | 'tolerance or the maximum number of iterations.') 148 | 149 | W[:,k] = w.ravel() 150 | 151 | elif algorithm=='parallel': 152 | 153 | if w_init!=None: 154 | W = w_init 155 | else: 156 | W = np.random.normal(size=(n,n))+\ 157 | 1j*np.random.normal(size=(n,n)) 158 | 159 | n_iter = 0 160 | 161 | #cache the covariance matrix 162 | C = np.cov(X) 163 | 164 | for i in xrange(max_iter): 165 | 166 | Wold = np.copy(W) 167 | 168 | for j in xrange(n): 169 | 170 | #derivative of the contrast function 171 | g = (1/(epsilon+abs_sqr(W[:,j],X))).reshape((1,m)) 172 | #derivative of g 173 | dg = -(1/(epsilon+abs_sqr(W[:,j],X))**2).reshape((1,m)) 174 | 175 | W[:,j] = (X * (W[:,j].conj().T.dot(X)).conj() * g).mean(1)-\ 176 | (g + abs_sqr(W[:,j],X) * dg).mean() * W[:,j] 177 | del g,dg 178 | 179 | # Symmetric decorrelation 180 | Uw,Sw = eig(W.conj().T.dot(C.dot(W))) 181 | W = W.dot(Sw.dot(inv(np.sqrt(np.diag(Uw))).dot(Sw.conj().T))) 182 | del Uw,Sw 183 | 184 | EG[:,n_iter] = (np.log(epsilon+abs_sqr(W,X))).mean(1) 185 | 186 | n_iter+=1 187 | 188 | lim = (abs(abs(Wold)-abs(W))).sum() 189 | if lim < tol: 190 | break 191 | 192 | if n_iter==max_iter and lim>tol: 193 | warnings.warn('FastICA did not converge. Consider increasing ' 194 | 'tolerance or the maximum number of iterations.') 195 | 196 | S = W.conj().T.dot(X) 197 | 198 | return K,W,S,EG 199 | --------------------------------------------------------------------------------