Surface NMR processing and inversion GUI
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

harmonic.py 8.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. import numpy as np
  2. from scipy.optimize import least_squares
  3. from scipy.optimize import minimize
  4. from scipy.linalg import lstsq as sclstsq
  5. import scipy.linalg as lin
  6. def harmonic2 ( f1, f2, sN, fs, nK, t ):
  7. """
  8. Performs inverse calculation of two harmonics contaminating a signal.
  9. Args:
  10. f01 = base frequency of the first sinusoidal noise
  11. f02 = base frequency of the second sinusoidal noise
  12. sN = signal containing noise
  13. fs = sampling frequency
  14. nK = number of harmonics to calculate
  15. t = time samples
  16. """
  17. print("building matrix 2")
  18. A = np.zeros( (len(t), 4*nK) )
  19. #f1 = f1MHz * 1e-3
  20. #f2 = f2MHz * 1e-3
  21. for irow, tt in enumerate(t):
  22. A[irow, 0:2*nK:2] = np.cos( np.arange(nK)*2*np.pi*(f1/fs)*irow )
  23. A[irow, 1:2*nK:2] = np.sin( np.arange(nK)*2*np.pi*(f1/fs)*irow )
  24. A[irow, 2*nK::2] = np.cos( np.arange(nK)*2*np.pi*(f2/fs)*irow )
  25. A[irow, 2*nK+1::2] = np.sin( np.arange(nK)*2*np.pi*(f2/fs)*irow )
  26. v = np.linalg.lstsq(A, sN, rcond=1e-8)
  27. #v = sclstsq(A, sN) #, rcond=1e-6)
  28. alpha = v[0][0:2*nK:2] + 1e-16
  29. beta = v[0][1:2*nK:2] + 1e-16
  30. amp = np.sqrt( alpha**2 + beta**2 )
  31. phase = np.arctan(- beta/alpha)
  32. alpha2 = v[0][2*nK::2] + 1e-16
  33. beta2 = v[0][2*nK+1::2] + 1e-16
  34. amp2 = np.sqrt( alpha2**2 + beta2**2 )
  35. phase2 = np.arctan(- beta2/alpha2)
  36. h = np.zeros(len(t))
  37. for ik in range(nK):
  38. h += np.sqrt( alpha[ik]**2 + beta[ik]**2) * np.cos( 2.*np.pi*ik * (f1/fs) * np.arange(0, len(t), 1 ) + phase[ik] ) \
  39. + np.sqrt(alpha2[ik]**2 + beta2[ik]**2) * np.cos( 2.*np.pi*ik * (f2/fs) * np.arange(0, len(t), 1 ) + phase2[ik] )
  40. return sN-h
  41. def harmonic ( f0, sN, fs, nK, t ):
  42. """
  43. Performs inverse calculation of harmonics contaminating a signal.
  44. Args:
  45. f0 = base frequency of the sinusoidal noise
  46. sN = signal containing noise
  47. fs = sampling frequency
  48. nK = number of harmonics to calculate
  49. t = time samples
  50. """
  51. print("building matrix ")
  52. A = np.zeros( (len(t), 2*nK) )
  53. for irow, tt in enumerate(t):
  54. A[irow, 0::2] = np.cos( np.arange(nK)*2*np.pi*(f0/fs)*irow )
  55. A[irow, 1::2] = np.sin( np.arange(nK)*2*np.pi*(f0/fs)*irow )
  56. v = np.linalg.lstsq(A, sN, rcond=1e-16) # rcond=None) #, rcond=1e-8)
  57. #v = sclstsq(A, sN) #, rcond=1e-6)
  58. alpha = v[0][0::2]
  59. beta = v[0][1::2]
  60. #print("Solving A A.T")
  61. #v = lin.solve(np.dot(A,A.T).T, sN) #, rcond=1e-6)
  62. #v = np.dot(A.T, v)
  63. #v = np.dot(np.linalg.inv(np.dot(A.T, A)), np.dot(A.T, sN))
  64. #alpha = v[0::2]
  65. #beta = v[1::2]
  66. amp = np.sqrt( alpha**2 + beta**2 )
  67. phase = np.arctan(- beta/alpha)
  68. #print("amp:", amp, " phase", phase)
  69. h = np.zeros(len(t))
  70. for ik in range(nK):
  71. h += np.sqrt(alpha[ik]**2 + beta[ik]**2) * np.cos( 2.*np.pi*ik * (f0/fs) * np.arange(0, len(t), 1 ) + phase[ik] )
  72. #plt.matshow(A, aspect='auto')
  73. #plt.colorbar()
  74. #plt.figure()
  75. #plt.plot(alpha)
  76. #plt.plot(beta)
  77. #plt.plot(amp)
  78. #plt.figure()
  79. #plt.plot(h)
  80. #plt.title("modelled noise")
  81. return sN-h
  82. def harmonicEuler ( f0, sN, fs, nK, t ):
  83. """
  84. Performs inverse calculation of harmonics contaminating a signal.
  85. Args:
  86. f0 = base frequency of the sinusoidal noise
  87. sN = signal containing noise
  88. fs = sampling frequency
  89. nK = number of harmonics to calculate
  90. t = time samples
  91. """
  92. #print("building Euler matrix ")
  93. #A = np.zeros( (len(t), nK), dtype=np.complex64)
  94. #for irow, tt in enumerate(t):
  95. # A[irow,:] = np.exp(1j* np.arange(1,nK+1) * 2*np.pi* (f0/fs) * irow)
  96. #AA = np.zeros( (len(t), nK), dtype=np.complex64)
  97. A = np.exp(1j* np.tile( np.arange(1,nK+1),(len(t), 1)) * 2*np.pi* (f0/fs) * np.tile(np.arange(len(t)),(nK,1)).T )
  98. #AA = np.tile(np.arange(len(t)), (nK,1)).T
  99. #plt.matshow( np.imag(A), aspect='auto' )
  100. #plt.matshow( np.real(AA), aspect='auto' )
  101. #plt.show()
  102. #exit()
  103. #print ("A norm", np.linalg.norm(A - AA))
  104. v = np.linalg.lstsq(A, sN, rcond=None) # rcond=None) #, rcond=1e-8)
  105. alpha = np.real(v[0]) #[0::2]
  106. beta = np.imag(v[0]) #[1::2]
  107. amp = np.abs(v[0]) #np.sqrt( alpha**2 + beta**2 )
  108. phase = np.angle(v[0]) # np.arctan(- beta/alpha)
  109. h = np.zeros(len(t))
  110. for ik in range(nK):
  111. h += 2*amp[ik] * np.cos( 2.*np.pi*(ik+1) * (f0/fs) * np.arange(0, len(t), 1 ) + phase[ik] )
  112. return sN-h
  113. def harmonicEuler2 ( f0, f1, sN, fs, nK, t ):
  114. """
  115. Performs inverse calculation of harmonics contaminating a signal.
  116. Args:
  117. f0 = base frequency of the sinusoidal noise
  118. sN = signal containing noise
  119. fs = sampling frequency
  120. nK = number of harmonics to calculate
  121. t = time samples
  122. """
  123. print("building Euler matrix 2 ")
  124. A = np.zeros( (len(t), 2*nK), dtype=np.complex64)
  125. for irow, tt in enumerate(t):
  126. A[irow,0:nK] = np.exp( 1j* np.arange(1,nK+1)*2*np.pi*(f0/fs)*irow )
  127. A[irow,nK:2*nK] = np.exp( 1j* np.arange(1,nK+1)*2*np.pi*(f1/fs)*irow )
  128. v = np.linalg.lstsq(A, sN, rcond=None) # rcond=None) #, rcond=1e-8)
  129. amp = np.abs(v[0][0:nK])
  130. phase = np.angle(v[0][0:nK])
  131. amp1 = np.abs(v[0][nK:2*nK])
  132. phase1 = np.angle(v[0][nK:2*nK])
  133. h = np.zeros(len(t))
  134. for ik in range(nK):
  135. h += 2*amp[ik] * np.cos( 2.*np.pi*(ik+1) * (f0/fs) * np.arange(0, len(t), 1 ) + phase[ik] ) + \
  136. 2*amp1[ik] * np.cos( 2.*np.pi*(ik+1) * (f1/fs) * np.arange(0, len(t), 1 ) + phase1[ik] )
  137. return sN-h
  138. def jacEuler( f0, sN, fs, nK, t):
  139. print("building Jacobian matrix ")
  140. J = np.zeros( (len(t), nK), dtype=np.complex64 )
  141. for it, tt in enumerate(t):
  142. for ik, k in enumerate( np.arange(0, nK) ):
  143. c = 1j*2.*np.pi*(ik+1.)*it
  144. J[it, ik] = c*np.exp( c*f0/fs ) / fs
  145. #plt.matshow(np.imag(J), aspect='auto')
  146. #plt.show()
  147. return J
  148. def harmonicNorm ( f0, sN, fs, nK, t ):
  149. return np.linalg.norm( harmonicEuler(f0, sN, fs, nK, t) )
  150. def harmonic2Norm ( f0, sN, fs, nK, t ):
  151. return np.linalg.norm(harmonicEuler2(f0[0], f0[1], sN, fs, nK, t))
  152. def minHarmonic(f0, sN, fs, nK, t):
  153. f02 = guessf0(sN, fs)
  154. print("minHarmonic", f0, fs, nK, " guess=", f02)
  155. # CG, BFGS, Newton-CG, L-BFGS-B, TNC, SLSQP, dogleg, trust-ncg, trust-krylov, trust-exact and trust-constr
  156. res = minimize(harmonicNorm, np.array((f0)), args=(sN, fs, nK, t)) #, method='CG', jac=jacEuler) #, hess=None, bounds=None )
  157. print(res)
  158. return harmonicEuler(res.x[0], sN, fs, nK, t)
  159. def minHarmonic2(f1, f2, sN, fs, nK, t):
  160. #f02 = guessf0(sN, fs)
  161. #print("minHarmonic2", f0, fs, nK, " guess=", f02)
  162. #methods with bounds, L-BFGS-B, TNC, SLSQP
  163. res = minimize( harmonic2Norm, np.array((f1,f2)), args=(sN, fs, nK, t), jac='2-point') #, bounds=((f1-1.,f1+1.0),(f2-1.0,f2+1.0)), method='TNC' )
  164. print(res)
  165. return harmonicEuler2(res.x[0], res.x[1], sN, fs, nK, t)
  166. def guessf0( sN, fs ):
  167. S = np.fft.fft(sN)
  168. w = np.fft.fftfreq( len(sN), 1/fs )
  169. imax = np.argmax( np.abs(S) )
  170. #plt.plot( w, np.abs(S) )
  171. #plt.show()
  172. #print(w)
  173. #print ( w[imax], w[imax+1] )
  174. return abs(w[imax])
  175. if __name__ == "__main__":
  176. import matplotlib.pyplot as plt
  177. f0 = 60 # Hz
  178. f1 = 61 # Hz
  179. delta = np.random.rand()
  180. delta2 = np.random.rand()
  181. print("delta", delta)
  182. fs = 10000 # GMR
  183. t = np.arange(0, 1, 1/fs)
  184. phi = np.random.rand()
  185. phi2 = np.random.rand()
  186. A = 1.0
  187. A2 = 0.0
  188. A3 = 1.0
  189. nK = 35
  190. T2 = .200
  191. sN = A *np.sin( ( 1*(delta +f0))*2*np.pi*t + phi ) + \
  192. A2*np.sin( ( 1*(delta2 +f1))*2*np.pi*t + phi2 ) + \
  193. np.random.normal(0,.1,len(t)) + \
  194. + A3*np.exp( -t/T2 )
  195. sNc = A *np.sin( (1*(delta +f0))*2*np.pi*t + phi ) + \
  196. A2*np.sin( (1*(delta2+f1))*2*np.pi*t + phi2 ) + \
  197. + A3*np.exp( -t/T2 )
  198. guessf0(sN, fs)
  199. # single freq
  200. #h = harmonicEuler( f0, sN, fs, nK, t)
  201. h = minHarmonic( f0, sN, fs, nK, t)
  202. # two freqs
  203. #h = minHarmonic2( f0, f1, sN, fs, nK, t)
  204. #h = harmonic2( f0, f1, sN, fs, nK, t)
  205. #h = harmonicEuler2( f0, f1, sN, fs, nK, t)
  206. plt.figure()
  207. plt.plot(t, sN, label="sN")
  208. #plt.plot(t, sN-h, label="sN-h")
  209. plt.plot(t, h, label='h')
  210. plt.title("harmonic")
  211. plt.legend()
  212. plt.figure()
  213. plt.plot(t, sN-sNc, label='true noise')
  214. plt.plot(t, h, label='harmonic removal')
  215. plt.plot(t, np.exp(-t/T2), label="nmr")
  216. plt.legend()
  217. plt.title("true noise")
  218. plt.show()