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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  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 harmonicEuler ( sN, fs, t, f0, k1, kN, ks ):
  7. """
  8. Performs inverse calculation of harmonics contaminating a signal.
  9. Args:
  10. sN = signal containing noise
  11. fs = sampling frequency
  12. t = time samples
  13. f0 = base frequency of the sinusoidal noise
  14. nK = number of harmonics to calculate
  15. """
  16. KK = np.arange(k1, kN+1, 1/ks )
  17. nK = len(KK)
  18. A = np.exp(1j* np.tile(KK,(len(t), 1)) * 2*np.pi* (f0/fs) * np.tile(np.arange(1, len(t)+1, 1),(nK,1)).T)
  19. v = np.linalg.lstsq(A, sN, rcond=None)
  20. alpha = np.real(v[0])
  21. beta = np.imag(v[0])
  22. amp = np.abs(v[0])
  23. phase = np.angle(v[0])
  24. h = np.zeros(len(t))
  25. for ik, k in enumerate(KK):
  26. h += 2*amp[ik] * np.cos( 2.*np.pi*(k) * (f0/fs) * np.arange(1, len(t)+1, 1 ) + phase[ik] )
  27. return sN-h
  28. def harmonicNorm (f0, sN, fs, t, k1, kN, ks):
  29. #return np.linalg.norm( harmonicEuler(sN, fs, t, f0, k1, kN, ks))
  30. ii = sN < (3.* np.std(sN))
  31. return np.linalg.norm( harmonicEuler(sN, fs, t, f0, k1, kN, ks)[ii] )
  32. def minHarmonic(sN, fs, t, f0, k1, kN, ks):
  33. # CG, BFGS, Newton-CG, L-BFGS-B, TNC, SLSQP, dogleg, trust-ncg, trust-krylov, trust-exact and trust-constr
  34. res = minimize(harmonicNorm, np.array((f0)), args=(sN, fs, t, k1, kN, ks), jac='2-point', method='BFGS') # hess=None, bounds=None )
  35. #############
  36. # Reduced N #
  37. #############
  38. #print("min 10")
  39. #res = minimize(harmonicNorm, np.array((f0)), args=(sN, fs, t, k1, 10, ks), jac='2-point', method='BFGS') # hess=None, bounds=None )
  40. ##########
  41. # Bounds #
  42. ##########
  43. #print("bounded search for f0 with 10", f0)
  44. #bnds = ( (f0-0.125, f0+0.125), )
  45. #print("len f0", len( [f0,] ))
  46. #print("len bnds", len(bnds) )
  47. #res = minimize(harmonicNorm, (f0,), args=(sN, fs, t, k1, kN, ks), jac='2-point', method='L-BFGS-B', bounds=bnds ) # hess=None, bounds=None )
  48. #res = minimize(harmonicNorm, (f0,), args=(sN, fs, t, k1, 10, ks), jac='2-point', method='L-BFGS-B', bounds=bnds ) # hess=None, bounds=None )
  49. #print(res)
  50. #print ( "guess", guessf0( harmonicEuler(sN, fs, t, res.x[0], k1, kN, ks), fs ) )
  51. return harmonicEuler(sN, fs, t, res.x[0], k1, kN, ks), res.x[0]#[0]
  52. def harmonicEuler2 ( sN, fs, t, f0, f0k1, f0kN, f0ks, f1, f1k1, f1kN, f1ks ):
  53. """
  54. Performs inverse calculation of harmonics contaminating a signal.
  55. Args:
  56. sN = signal containing noise
  57. fs = sampling frequency
  58. t = time samples
  59. f0 = first base frequency of the sinusoidal noise
  60. f0k1 = First harmonic to calulate for f0
  61. f0kN = Last base harmonic to calulate for f0
  62. f0ks = subharmonics to calculate
  63. f1 = second base frequency of the sinusoidal noise
  64. f1k1 = First harmonic to calulate for f1
  65. f1kN = Last base harmonic to calulate for f1
  66. f1ks = subharmonics to calculate at f1 base frequency
  67. """
  68. KK0 = np.arange(f0k1, f0kN+1, 1/f0ks)
  69. nK0 = len(KK0)
  70. A0 = np.exp(1j* np.tile(KK0,(len(t), 1)) * 2*np.pi* (f0/fs) * np.tile( np.arange(1, len(t)+1, 1), (nK0,1)).T)
  71. KK1 = np.arange(f1k1, f1kN+1, 1/f1ks)
  72. nK1 = len(KK1)
  73. A1 = np.exp(1j* np.tile(KK1,(len(t), 1)) * 2*np.pi* (f1/fs) * np.tile( np.arange(1, len(t)+1, 1),(nK1,1)).T)
  74. A = np.concatenate((A0, A1), axis=1)
  75. v = np.linalg.lstsq(A, sN, rcond=None) # rcond=None) #, rcond=1e-8)
  76. amp0 = np.abs(v[0][0:nK0])
  77. phase0 = np.angle(v[0][0:nK0])
  78. amp1 = np.abs(v[0][nK0::])
  79. phase1 = np.angle(v[0][nK0::])
  80. h = np.zeros(len(t))
  81. for ik, k in enumerate(KK0):
  82. h += 2*amp0[ik] * np.cos( 2.*np.pi*(k) * (f0/fs) * np.arange(1, len(t)+1, 1 ) + phase0[ik] )
  83. for ik, k in enumerate(KK1):
  84. h += 2*amp1[ik] * np.cos( 2.*np.pi*(k) * (f0/fs) * np.arange(1, len(t)+1, 1 ) + phase1[ik] )
  85. return sN-h
  86. def harmonic2Norm (f0, sN, fs, t, f0k1, f0kN, f0ks, f1k1, f1kN, f1ks):
  87. #return np.linalg.norm(harmonicEuler2(f0[0], f0[1], sN, fs, nK, t))
  88. ii = sN < (3.* np.std(sN))
  89. return np.linalg.norm( harmonicEuler2(sN, fs, t, f0[0], f0k1, f0kN, f0ks, f0[1], f1k1, f1kN, f1ks)[ii] )
  90. def minHarmonic2(sN, fs, t, f0, f0k1, f0kN, f0ks, f1, f1k1, f1kN, f1ks):
  91. # CG, BFGS, Newton-CG, L-BFGS-B, TNC, SLSQP, dogleg, trust-ncg, trust-krylov, trust-exact and trust-constr
  92. #res = minimize(harmonic2Norm, np.array((f0, f1)), args=(sN, fs, t, f0k1, f0kN, f0ks, f1k1,f1kN, f1ks), jac='2-point', method='BFGS') # hess=None, bounds=None )
  93. print("search 10")
  94. res = minimize(harmonic2Norm, np.array((f0, f1)), args=(sN, fs, t, f0k1, 10, f0ks, f1k1, 10, f1ks), jac='2-point', method='BFGS') # hess=None, bounds=None )
  95. #print(res)
  96. #print ( "guess", guessf0(harmonicEuler2(sN, fs, t, res.x[0], f0k1, f0kN, f0ks, res.x[1], f1k1, f1kN, f1ks), fs) )
  97. return harmonicEuler2(sN, fs, t, res.x[0], f0k1, f0kN, f0ks, res.x[1], f1k1, f1kN, f1ks), res.x[0], res.x[1]#[0]
  98. def guessf0( sN, fs ):
  99. S = np.fft.fft(sN)
  100. w = np.fft.fftfreq( len(sN), 1/fs )
  101. imax = np.argmax( np.abs(S) )
  102. #plt.plot( w, np.abs(S) )
  103. #plt.show()
  104. #print(w)
  105. #print ( w[imax], w[imax+1] )
  106. return abs(w[imax])
  107. if __name__ == "__main__":
  108. import matplotlib.pyplot as plt
  109. f0 = 60 # Hz
  110. f1 = 60 # Hz
  111. delta = np.random.rand() - .5
  112. delta2 = np.random.rand() - .5
  113. print("delta", delta)
  114. print("delta2", delta2)
  115. fs = 10000 # GMR
  116. t = np.arange(0, 1, 1/fs)
  117. phi = 2.*np.pi*np.random.rand() - np.pi
  118. phi2 = 2.*np.pi*np.random.rand() - np.pi
  119. print("phi", phi, phi2)
  120. A = 1.0
  121. A2 = 0.0
  122. A3 = 1.0
  123. nK = 10
  124. T2 = .200
  125. sN = A *np.sin( ( 1*(delta +f0))*2*np.pi*t + phi ) + \
  126. A2*np.sin( ( 1*(delta2 +f1))*2*np.pi*t + phi2 ) + \
  127. np.random.normal(0,.1,len(t)) + \
  128. + A3*np.exp( -t/T2 )
  129. sNc = A *np.sin( (1*(delta +f0))*2*np.pi*t + phi ) + \
  130. A2*np.sin( (1*(delta2+f1))*2*np.pi*t + phi2 ) + \
  131. + A3*np.exp( -t/T2 )
  132. guessf0(sN, fs)
  133. # single freq
  134. #h = harmonicEuler( f0, sN, fs, nK, t)
  135. h = minHarmonic( f0, sN, fs, nK, t)
  136. # two freqs
  137. #h = minHarmonic2( f0+1e-2, f1-1e-2, sN, fs, nK, t)
  138. #h = harmonicEuler2( f0, f1, sN, fs, nK, t)
  139. plt.figure()
  140. plt.plot(t, sN, label="sN")
  141. #plt.plot(t, sN-h, label="sN-h")
  142. plt.plot(t, h, label='h')
  143. plt.title("harmonic")
  144. plt.legend()
  145. plt.figure()
  146. plt.plot(t, sN-sNc, label='true noise')
  147. plt.plot(t, h, label='harmonic removal')
  148. plt.plot(t, np.exp(-t/T2), label="nmr")
  149. plt.legend()
  150. plt.title("true noise")
  151. plt.show()