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 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  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, 0::2] = np.cos( np.arange(nK)*2*np.pi*(f0/fs)*irow )
  96. #A[irow, 1::2] = np.sin( np.arange(nK)*2*np.pi*(f0/fs)*irow )
  97. A[irow,:] = np.exp( 1j* np.arange(nK)*2*np.pi*(f0/fs)*irow )
  98. v = np.linalg.lstsq(A, sN, rcond=None) # rcond=None) #, rcond=1e-8)
  99. #v = sclstsq(A, sN) #, rcond=1e-6)
  100. alpha = np.real(v[0]) #[0::2]
  101. beta = np.imag(v[0]) #[1::2]
  102. #print("Solving A A.T")
  103. #v = lin.solve(np.dot(A,A.T).T, sN) #, rcond=1e-6)
  104. #v = np.dot(A.T, v)
  105. #v = np.dot(np.linalg.inv(np.dot(A.T, A)), np.dot(A.T, sN))
  106. #alpha = v[0::2]
  107. #beta = v[1::2]
  108. amp = np.abs(v[0]) #np.sqrt( alpha**2 + beta**2 )
  109. phase = np.angle(v[0]) # np.arctan(- beta/alpha)
  110. #print("amp:", amp, " phase", phase)
  111. h = np.zeros(len(t))
  112. for ik in range(nK):
  113. h += 2*amp[ik] * np.cos( 2.*np.pi*ik * (f0/fs) * np.arange(0, len(t), 1 ) + phase[ik] )
  114. #plt.matshow(np.imag(A), aspect='auto')
  115. #plt.colorbar()
  116. #plt.figure()
  117. #plt.plot(alpha)
  118. #plt.plot(beta)
  119. #plt.plot(amp)
  120. #plt.figure()
  121. #plt.plot(h)
  122. #plt.title("modelled noise")
  123. return sN-h
  124. def jacobian( f0, sN, fs, nK, t):
  125. print("building Jacobian matrix ")
  126. A = np.zeros( (len(t), 2*nK) )
  127. for irow, tt in enumerate(t):
  128. #A[irow, 0::2] = np.cos( np.arange(nK)*2*np.pi*(f0/fs)*irow )
  129. #A[irow, 1::2] = np.sin( np.arange(nK)*2*np.pi*(f0/fs)*irow )
  130. # brutal
  131. for k, ik in enumerate( np.arange(0, 2*nK, 2) ):
  132. #A[irow, ik ] = np.cos( k*2*np.pi*(f0/fs)*irow )
  133. #A[irow, ik+1] = np.sin( k*2*np.pi*(f0/fs)*irow )
  134. A[irow, ik ] = - (2.*np.pi*k*irow * sin((2.*np.pi*irow*f0)/fs)) / fs
  135. A[irow, ik+1] = (2.*np.pi*k*irow * cos((2.*np.pi*irow*f0)/fs)) / fs
  136. def harmonicNorm ( f0, sN, fs, nK, t ):
  137. return np.linalg.norm( harmonicEuler(f0, sN, fs, nK, t))
  138. def harmonic2Norm ( f0, sN, fs, nK, t ):
  139. return np.linalg.norm(harmonic2(f0[0], f0[1], sN, fs, nK, t))
  140. def minHarmonic(f0, sN, fs, nK, t):
  141. f02 = guessf0(sN, fs)
  142. print("minHarmonic", f0, fs, nK, " guess=", f02)
  143. res = minimize( harmonicNorm, np.array((f0)), args=(sN, fs, nK, t)) #, method='Nelder-Mead' )# jac=None, hess=None, bounds=None )
  144. print(res)
  145. return harmonicEuler(res.x[0], sN, fs, nK, t)
  146. def minHarmonic2(f1, f2, sN, fs, nK, t):
  147. #f02 = guessf0(sN, fs)
  148. #print("minHarmonic2", f0, fs, nK, " guess=", f02)
  149. #methods with bounds, L-BFGS-B, TNC, SLSQP
  150. 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' )
  151. print(res)
  152. return harmonic2(res.x[0], res.x[1], sN, fs, nK, t)
  153. def guessf0( sN, fs ):
  154. S = np.fft.fft(sN)
  155. w = np.fft.fftfreq( len(sN), 1/fs )
  156. imax = np.argmax( np.abs(S) )
  157. #plt.plot( w, np.abs(S) )
  158. #plt.show()
  159. #print(w)
  160. #print ( w[imax], w[imax+1] )
  161. return abs(w[imax])
  162. if __name__ == "__main__":
  163. import matplotlib.pyplot as plt
  164. f0 = 60 # Hz
  165. f1 = 60 # Hz
  166. delta = np.random.rand()
  167. delta2 = 0 #np.random.rand()
  168. print("delta", delta)
  169. fs = 10000 # GMR
  170. t = np.arange(0, 1, 1/fs)
  171. phi = np.random.rand()
  172. phi2 = 0 # np.random.rand()
  173. A = 1.0
  174. A2 = 0.0
  175. A3 = 0.0
  176. nK = 35
  177. T2 = .200
  178. sN = A *np.sin( ( 1*(delta +f0))*2*np.pi*t + phi ) + \
  179. A2*np.sin( ( 1*(delta2 +f1))*2*np.pi*t + phi2 ) + \
  180. np.random.normal(0,.1,len(t)) + \
  181. + A3*np.exp( -t/T2 )
  182. sNc = A *np.sin( (1*(delta +f0))*2*np.pi*t + phi ) + \
  183. A2*np.sin( (1*(delta2+f1))*2*np.pi*t + phi2 ) + \
  184. + A3*np.exp( -t/T2 )
  185. guessf0(sN, fs)
  186. #h = harmonicEuler( f0, sN, fs, nK, t)
  187. #h = minHarmonic2( f0, f1, sN, fs, nK, t)
  188. #h = harmonic2( f0, f1, sN, fs, nK, t)
  189. h = minHarmonic( f0, sN, fs, nK, t)
  190. plt.figure()
  191. plt.plot(t, sN, label="sN")
  192. #plt.plot(t, sN-h, label="sN-h")
  193. plt.plot(t, h, label='h')
  194. plt.title("harmonic")
  195. plt.legend()
  196. plt.figure()
  197. plt.plot(t, sN-sNc, label='true noise')
  198. plt.plot(t, h, label='harmonic removal')
  199. plt.plot(t, np.exp(-t/T2), label="nmr")
  200. plt.legend()
  201. plt.title("true noise")
  202. plt.show()