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.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  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. v = np.linalg.lstsq(A, sN, rcond=None) # rcond=None) #, rcond=1e-8)
  97. alpha = np.real(v[0]) #[0::2]
  98. beta = np.imag(v[0]) #[1::2]
  99. amp = np.abs(v[0]) #np.sqrt( alpha**2 + beta**2 )
  100. phase = np.angle(v[0]) # np.arctan(- beta/alpha)
  101. h = np.zeros(len(t))
  102. for ik in range(nK):
  103. h += 2*amp[ik] * np.cos( 2.*np.pi*(ik+1) * (f0/fs) * np.arange(0, len(t), 1 ) + phase[ik] )
  104. return sN-h
  105. def harmonicEuler2 ( f0, f1, sN, fs, nK, t ):
  106. """
  107. Performs inverse calculation of harmonics contaminating a signal.
  108. Args:
  109. f0 = base frequency of the sinusoidal noise
  110. sN = signal containing noise
  111. fs = sampling frequency
  112. nK = number of harmonics to calculate
  113. t = time samples
  114. """
  115. print("building Euler matrix 2 ")
  116. A = np.zeros( (len(t), 2*nK), dtype=np.complex64)
  117. for irow, tt in enumerate(t):
  118. A[irow,0:nK] = np.exp( 1j* np.arange(1,nK+1)*2*np.pi*(f0/fs)*irow )
  119. A[irow,nK:2*nK] = np.exp( 1j* np.arange(1,nK+1)*2*np.pi*(f1/fs)*irow )
  120. v = np.linalg.lstsq(A, sN, rcond=None) # rcond=None) #, rcond=1e-8)
  121. amp = np.abs(v[0][0:nK])
  122. phase = np.angle(v[0][0:nK])
  123. amp1 = np.abs(v[0][nK:2*nK])
  124. phase1 = np.angle(v[0][nK:2*nK])
  125. h = np.zeros(len(t))
  126. for ik in range(nK):
  127. h += 2*amp[ik] * np.cos( 2.*np.pi*(ik+1) * (f0/fs) * np.arange(0, len(t), 1 ) + phase[ik] ) + \
  128. 2*amp1[ik] * np.cos( 2.*np.pi*(ik+1) * (f1/fs) * np.arange(0, len(t), 1 ) + phase1[ik] )
  129. return sN-h
  130. def jacEuler( f0, sN, fs, nK, t):
  131. print("building Jacobian matrix ")
  132. J = np.zeros( (len(t), nK), dtype=np.complex64 )
  133. for it, tt in enumerate(t):
  134. for ik, k in enumerate( np.arange(0, nK) ):
  135. c = 1j*2.*np.pi*(ik+1.)*it
  136. J[it, ik] = c*np.exp( c*f0/fs ) / fs
  137. #plt.matshow(np.imag(J), aspect='auto')
  138. #plt.show()
  139. return J
  140. def harmonicNorm ( f0, sN, fs, nK, t ):
  141. return np.linalg.norm( harmonicEuler(f0, sN, fs, nK, t) )
  142. def harmonic2Norm ( f0, sN, fs, nK, t ):
  143. return np.linalg.norm(harmonicEuler2(f0[0], f0[1], sN, fs, nK, t))
  144. def minHarmonic(f0, sN, fs, nK, t):
  145. f02 = guessf0(sN, fs)
  146. print("minHarmonic", f0, fs, nK, " guess=", f02)
  147. # CG, BFGS, Newton-CG, L-BFGS-B, TNC, SLSQP, dogleg, trust-ncg, trust-krylov, trust-exact and trust-constr
  148. res = minimize( harmonicNorm, np.array((f0)), args=(sN, fs, nK, t)) #, method='CG', jac=jacEuler) #, hess=None, bounds=None )
  149. print(res)
  150. return harmonicEuler(res.x[0], sN, fs, nK, t)
  151. def minHarmonic2(f1, f2, sN, fs, nK, t):
  152. #f02 = guessf0(sN, fs)
  153. #print("minHarmonic2", f0, fs, nK, " guess=", f02)
  154. #methods with bounds, L-BFGS-B, TNC, SLSQP
  155. res = minimize( harmonic2Norm, np.array((f1,f2)), args=(sN, fs, nK, t)) #, bounds=((f1-1.,f1+1.0),(f2-1.0,f2+1.0)), method='TNC' )
  156. print(res)
  157. return harmonicEuler2(res.x[0], res.x[1], sN, fs, nK, t)
  158. def guessf0( sN, fs ):
  159. S = np.fft.fft(sN)
  160. w = np.fft.fftfreq( len(sN), 1/fs )
  161. imax = np.argmax( np.abs(S) )
  162. #plt.plot( w, np.abs(S) )
  163. #plt.show()
  164. #print(w)
  165. #print ( w[imax], w[imax+1] )
  166. return abs(w[imax])
  167. if __name__ == "__main__":
  168. import matplotlib.pyplot as plt
  169. f0 = 60 # Hz
  170. f1 = 62 # Hz
  171. delta = np.random.rand()
  172. delta2 = np.random.rand()
  173. print("delta", delta)
  174. fs = 10000 # GMR
  175. t = np.arange(0, 1, 1/fs)
  176. phi = np.random.rand()
  177. phi2 = np.random.rand()
  178. A = 1.0
  179. A2 = 0.25
  180. A3 = 1.0
  181. nK = 35
  182. T2 = .200
  183. sN = A *np.sin( ( 1*(delta +f0))*2*np.pi*t + phi ) + \
  184. A2*np.sin( ( 1*(delta2 +f1))*2*np.pi*t + phi2 ) + \
  185. np.random.normal(0,.1,len(t)) + \
  186. + A3*np.exp( -t/T2 )
  187. sNc = A *np.sin( (1*(delta +f0))*2*np.pi*t + phi ) + \
  188. A2*np.sin( (1*(delta2+f1))*2*np.pi*t + phi2 ) + \
  189. + A3*np.exp( -t/T2 )
  190. guessf0(sN, fs)
  191. # single freq
  192. #h = harmonicEuler( f0, sN, fs, nK, t)
  193. #h = minHarmonic( f0, sN, fs, nK, t)
  194. # two freqs
  195. h = minHarmonic2( f0, f1, sN, fs, nK, t)
  196. #h = harmonic2( f0, f1, sN, fs, nK, t)
  197. #h = harmonicEuler2( f0, f1, sN, fs, nK, t)
  198. plt.figure()
  199. plt.plot(t, sN, label="sN")
  200. #plt.plot(t, sN-h, label="sN-h")
  201. plt.plot(t, h, label='h')
  202. plt.title("harmonic")
  203. plt.legend()
  204. plt.figure()
  205. plt.plot(t, sN-sNc, label='true noise')
  206. plt.plot(t, h, label='harmonic removal')
  207. plt.plot(t, np.exp(-t/T2), label="nmr")
  208. plt.legend()
  209. plt.title("true noise")
  210. plt.show()