Surface NMR processing and inversion GUI
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

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()