Surface NMR processing and inversion GUI
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

harmonic.py 5.5KB

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