phase-encoding-method-of-moments.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #!/usr/bin/env python3
  2. # -*- coding: UTF-8 -*-
  3. #from scipy.special import gamma, binom
  4. import numpy as np
  5. import matplotlib.pyplot as plt
  6. from scipy.special import gamma
  7. from mpmath import mp, mpf
  8. mp.dps = 1000
  9. voxel_num = 5
  10. phase_range = np.pi/2
  11. phase_init = np.pi/4 #(0.0)
  12. U_points = voxel_num * 1000
  13. noise_ratio = (0.0*1e-38) #1e8
  14. total_periods = 10
  15. rf_samples_per_period = 20
  16. # max polynomial order equals rf_samples_per_period * total_periods
  17. # B0=1.5T freq=64Mhz, period = 15.6 ns
  18. period = (10) #ms
  19. omega = 2.0*np.pi/period
  20. #T2s_scale = 0.01 #ms # need to be 10ms
  21. T2s_scale = total_periods*period/15 #ms # need to be 10ms
  22. T2s_min = T2s_scale/10.0
  23. #print(period)
  24. #ms
  25. time_steps = np.array(np.linspace((0), (period*total_periods), rf_samples_per_period*total_periods))
  26. tmp = [np.random.rand() for n in range(voxel_num)]
  27. voxel_amplitudes = np.array(tmp)
  28. tmp = [np.random.rand() for n in range(voxel_num)]
  29. voxel_T2s_decay = np.array(tmp)*(T2s_scale-2*T2s_min) + T2s_min
  30. print(voxel_T2s_decay)
  31. voxel_all = np.append(voxel_amplitudes,voxel_T2s_decay/T2s_scale)
  32. if voxel_num == 5:
  33. # voxel_all = np.array([(0.2),(0.6),(0.02),(0.1)])
  34. voxel_all = np.array([(0.822628),(0.691376),(0.282906),(0.226013),(0.90703),(0.144985),(0.228563),(0.340353),(0.462462),(0.720518)])
  35. #voxel_all = np.array([(0.592606),(0.135168),(0.365712),(0.667536),(0.437378),(0.918822),(0.943879),(0.590338),(0.685997),(0.658839)])
  36. voxel_amplitudes = voxel_all[:voxel_num]
  37. voxel_T2s_decay = voxel_all[voxel_num:]*T2s_scale
  38. # a_i = np.array([(0.3),(0.1),(0.15),(0.1)])
  39. # d_i = np.array([(0.7),(0.9),(0.2),(0.67)])
  40. # voxel_num = len(a_i)
  41. voxel_phases = np.array(np.linspace(0,phase_range, voxel_num))
  42. # if len(voxel_amplitudes) != len(voxel_phases):
  43. # print("ERROR! Size of amplitude and phase arrays do not match!")
  44. # raise
  45. ampl = []
  46. def gen_rf_signal(time):
  47. '''Generates demodulated signal at radio frequence using voxels
  48. amplitudes, T2s decays, and phases.
  49. '''
  50. tmp = [(0.0) for n in range(len(time))]
  51. mag_sin = np.array(tmp)
  52. mag_cos = np.array(tmp)
  53. for t in range(len(time)):
  54. #print("time",float(time[t]))
  55. for i in range(voxel_num):
  56. # mag_sin[t] += a_i[i]*(
  57. # (d_i[i] + np.random.rand()*noise_ratio)**time[t]
  58. # )
  59. # print("a_{:d} =".format(i),float(a_i[i]),", ",
  60. # "d_{:d} =".format(i),float(d_i[i]),"+", np.random.rand()*noise_ratio)
  61. amp = voxel_amplitudes[i] * (
  62. np.exp(-time[t]/voxel_T2s_decay[i])
  63. ) + ( 0.0
  64. # + np.random.rand()*noise_ratio
  65. )
  66. if t == 0:
  67. #print("a_{:d}".format(i),float(voxel_amplitudes[i]* np.sin(voxel_phases[i] + phase_init)))
  68. print("d_{:d}".format(i),float( np.exp(-(period/rf_samples_per_period)/voxel_T2s_decay[i]) ))
  69. mag_sin[t] += amp * np.sin(
  70. voxel_phases[i] + phase_init
  71. )
  72. mag_cos[t] += amp * np.cos(
  73. voxel_phases[i] + phase_init
  74. )
  75. return mag_sin, mag_cos
  76. def factorial(n):
  77. return mp.gamma(n+1)
  78. def binom(n,k):
  79. return factorial(n)/(factorial(k)*factorial(n-k))
  80. def shiftedLegendre(n):
  81. coeffs = []
  82. for k in range(n+1):
  83. val = mpf(-1)**mpf(n) * binom(mpf(n),mpf(k)) * binom(mpf(n+k),mpf(k)) * mpf(-1)**mpf(k)
  84. coeffs.insert(0,val*mp.sqrt(2*n+1))
  85. return np.poly1d(coeffs)
  86. def K ( i, j):
  87. polyL = L[i] #precomputed shiftedLegendre(i)
  88. return polyL.coeffs[-j-1]
  89. def GetU (lambdas):
  90. n_max = len(lambdas)
  91. P = np.ones((n_max+1,U_points))
  92. x = np.linspace(0,1, U_points)
  93. P[1] = 2*x-1
  94. for n in range(1,n_max):
  95. P[n+1] = ((2*n+1)/(n+1)) * (2*x-1) * P[n] - (n/(n+1))*P[n-1]
  96. U = np.zeros(U_points)
  97. for i in range (len(lambdas)):
  98. if i%10 == 0: print(i)
  99. #polyL = L[i] #shiftedLegendre(i)
  100. U += lambdas[i]*P[i]*np.sqrt(2*i+1)
  101. return U
  102. def GetLambda(mag_rf):
  103. M_cutoff = len(mag_rf)
  104. all_lambda = []
  105. for i in range(M_cutoff):
  106. # print("M = ", i)
  107. lambd = (0)
  108. for j in range(i+1):
  109. lambd += float(K(i,j))*mag_rf[j]
  110. # print("K({:d},{:d}) =".format(i,j), float(K(i,j)))
  111. all_lambda.append(lambd)
  112. # tmp = [(0.0) for n in range(M_cutoff)]
  113. # all_lambda = np.array(tmp)
  114. # all_lambda[10] = (1.0)
  115. return all_lambda
  116. mag_sin, mag_cos = gen_rf_signal(time_steps)
  117. sign = ""
  118. # for i in range(voxel_num):
  119. # if i%5 == 0:
  120. # sign+="\n"
  121. # sign = sign + '{:3.2g}'.format(float(a_i[i]))+"/"+'{:3.2g}'.format(float(d_i[i]))+", "
  122. # # print(np.exp(-1.0/voxel_T2s_decay[i]))
  123. plt.plot(mag_sin, ls=' ', marker='o')
  124. plt.title("Signal to restore amp/decay_T:"+sign)
  125. plt.savefig("signal.pdf")
  126. plt.clf()
  127. L = [] # Shifted Legendre polinomials
  128. for i in range(len(mag_sin)):
  129. polyL = shiftedLegendre(i)
  130. # print("i=",i," L_i:")
  131. # print(polyL)
  132. L += [polyL]
  133. x = np.linspace(0,1, U_points)
  134. polyL_val = np.array([float(L[-1](x[n])) for n in range(U_points)])
  135. # plt.plot(x,polyL_val)
  136. # plt.title("Legendre polynom of order "+str(len(L)))
  137. # plt.savefig("polyL.pdf")
  138. # plt.clf()
  139. # print("Output of last poly done.")
  140. lambdas = GetLambda(mag_sin)
  141. print(lambdas)
  142. U = GetU(lambdas)
  143. x = np.linspace(0,1, U_points)
  144. mag_x = np.linspace(0,1, len(mag_sin))
  145. plt.plot(x,U)
  146. plt.title(r"$\sum^M \lambda_i L_i(x)$", y=1.02)
  147. plt.savefig("plt.pdf")
  148. plt.clf()