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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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 mpmath import mp, mpf
  7. mp.dps = 1000
  8. voxel_num = 2
  9. phase_range = mp.pi/2
  10. phase_init = mp.pi/20 #mpf(0.0)
  11. U_points = voxel_num * 1000
  12. # noise_ratio = mpf(0.0) #1e8
  13. total_periods = 10
  14. rf_samples_per_period = 5
  15. # max polynomial order equals rf_samples_per_period * total_periods
  16. # B0=1.5T freq=64Mhz, period = 15.6 ns
  17. period = mpf(15.6/1000/1000) #ms
  18. omega = 2.0*mp.pi/period
  19. #T2s_scale = 0.01 #ms # need to be 10ms
  20. T2s_scale = total_periods*period #ms # need to be 10ms
  21. T2s_min = T2s_scale/1000.0
  22. #print(period)
  23. #ms
  24. time_steps = np.array(mp.linspace(mpf(0), mpf(period*total_periods), rf_samples_per_period*total_periods))
  25. tmp = [mp.rand() for n in range(voxel_num)]
  26. voxel_amplitudes = np.array(tmp)
  27. tmp = [mp.rand() for n in range(voxel_num)]
  28. voxel_T2s_decay = np.array(tmp)*(T2s_scale-T2s_min) + T2s_min
  29. voxel_all = np.append(voxel_amplitudes,voxel_T2s_decay/T2s_scale)
  30. if voxel_num == 5:
  31. voxel_all = np.array([mpf(0.822628),mpf(0.691376),mpf(0.282906),mpf(0.226013),mpf(0.90703),mpf(0.144985),mpf(0.328563),mpf(0.440353),mpf(0.662462),mpf(0.720518)])
  32. #voxel_all = np.array([mpf(0.592606),mpf(0.135168),mpf(0.365712),mpf(0.667536),mpf(0.437378),mpf(0.918822),mpf(0.943879),mpf(0.590338),mpf(0.685997),mpf(0.658839)])
  33. voxel_amplitudes = voxel_all[:voxel_num]
  34. voxel_T2s_decay = voxel_all[voxel_num:]*T2s_scale
  35. voxel_phases = np.array(mp.linspace(0,phase_range, voxel_num))
  36. if len(voxel_amplitudes) != len(voxel_phases):
  37. print("ERROR! Size of amplitude and phase arrays do not match!")
  38. raise
  39. def gen_rf_signal(time):
  40. '''Generates demodulated signal at radio frequence using voxels
  41. amplitudes, T2s decays, and phases.
  42. '''
  43. tmp = [mpf(0.0) for n in range(len(time))]
  44. mag_sin = np.array(tmp)
  45. mag_cos = np.array(tmp)
  46. for t in range(len(time)):
  47. for i in range(voxel_num):
  48. amp = voxel_amplitudes[i] * (
  49. mp.exp(-time[t]/voxel_T2s_decay[i])
  50. ) + ( 0.0
  51. # + np.random.rand()*noise_ratio
  52. )
  53. mag_sin[t] += amp * mp.sin(
  54. voxel_phases[i] + phase_init
  55. )
  56. mag_cos[t] += amp * mp.cos(
  57. voxel_phases[i] + phase_init
  58. )
  59. return mag_sin, mag_cos
  60. def factorial(n):
  61. return mp.gamma(n+1)
  62. def binom(n,k):
  63. return factorial(n)/(factorial(k)*factorial(n-k))
  64. def shiftedLegendre(n):
  65. coeffs = []
  66. for k in range(n+1):
  67. val = mpf(-1)**n * binom(mpf(n),mpf(k)) * binom(n+k,k) * (-1)**k
  68. coeffs.insert(0,val)
  69. return np.poly1d(coeffs)
  70. def K ( i, j):
  71. polyL = L[i] #precomputed shiftedLegendre(i)
  72. return polyL.coeffs[-j-1]
  73. def GetU (lambdas):
  74. x = np.array(mp.linspace(0,1, U_points))
  75. tmp = [mpf(0.0) for n in range(len(lambdas))]
  76. mag_sin = np.array(tmp)
  77. tmp = [mpf(0.0) for n in range(U_points)]
  78. U = np.array(tmp)
  79. for i in range (len(lambdas)):
  80. polyL = L[i] #shiftedLegendre(i)
  81. U += lambdas[i]*polyL(x)
  82. return U
  83. def GetLambda(mag_rf):
  84. M_cutoff = len(mag_rf)
  85. all_lambda = []
  86. for i in range(M_cutoff):
  87. lambd = mpf(0)
  88. for j in range(i+1):
  89. lambd += K(i,j)*mag_rf[i]
  90. all_lambda.append(lambd)
  91. # tmp = [mpf(0.0) for n in range(M_cutoff)]
  92. # all_lambda = np.array(tmp)
  93. # all_lambda[29] = mpf(1.0)
  94. return all_lambda
  95. mag_sin, mag_cos = gen_rf_signal(time_steps)
  96. sign = ""
  97. for i in range(voxel_num):
  98. if i%5 == 0:
  99. sign+="\n"
  100. sign = sign + '{:3.2g}'.format(float(voxel_amplitudes[i] * mp.sin(
  101. voxel_phases[i] + phase_init
  102. )))+"/"+'{:3.2g}'.format(float(voxel_T2s_decay[i]))+", "
  103. plt.plot(mag_sin, ls='-', marker='o')
  104. plt.title("Signal to restore amp/decay_T:"+sign)
  105. plt.savefig("signal.pdf")
  106. plt.clf()
  107. L = [] # Shifted Legendre polinomials
  108. for i in range(len(mag_sin)):
  109. polyL = shiftedLegendre(i)
  110. L += [polyL]
  111. x = np.linspace(0,1, U_points)
  112. polyL_val = np.array([float(L[-1](x[n])) for n in range(U_points)])
  113. plt.plot(x,polyL_val)
  114. plt.title("Legendre polynom of order "+str(len(L)))
  115. plt.savefig("polyL.pdf")
  116. plt.clf()
  117. print("Output of last poly done.")
  118. lambdas = GetLambda(mag_sin)
  119. print(len(lambdas))
  120. U = GetU(lambdas)
  121. x = np.linspace(0,1, U_points)
  122. mag_x = np.linspace(0,1, len(mag_sin))
  123. plt.plot(x,U)
  124. plt.savefig("plt.pdf")
  125. plt.clf()