phase-encoding-simple.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #!/usr/bin/env python3
  2. # -*- coding: UTF-8 -*-
  3. from scipy.optimize import differential_evolution
  4. from scipy.optimize import minimize
  5. import numpy as np
  6. voxel_num = 5
  7. phase_range = np.pi/2
  8. phase_init = 0.0
  9. noise_ratio = 0.0 #1e8
  10. total_periods = 50
  11. rf_samples_per_period = 1
  12. # B0=1.5T freq=64Mhz, period = 15.6 ns
  13. period = 15.6/1000/1000 #ms
  14. omega = 2.0*np.pi/period
  15. #T2s_scale = 0.01 #ms # need to be 10ms
  16. T2s_scale = total_periods*period #ms # need to be 10ms
  17. T2s_min = T2s_scale/1000.0
  18. #print(period)
  19. #ms
  20. time_steps = np.linspace(0, period*total_periods, rf_samples_per_period*total_periods)
  21. voxel_amplitudes = np.random.rand(voxel_num)
  22. voxel_T2s_decay = np.random.rand(voxel_num)*(T2s_scale-T2s_min) + T2s_min
  23. voxel_all = np.append(voxel_amplitudes,voxel_T2s_decay/T2s_scale)
  24. if voxel_num == 5:
  25. voxel_all = [0.822628,0.691376,0.282906,0.226013,0.90703,0.144985,0.328563,0.440353,0.662462,0.720518]
  26. #voxel_amplitudes = [0.4, 0.8, 0]
  27. #voxel_amplitudes = [0.9, 0.092893218813452, 0.5]
  28. #voxel_amplitudes = [0.6, 0.517157287525381, 0.4]
  29. test_amplitudes = np.zeros(voxel_num)
  30. test_amplitudes = voxel_amplitudes
  31. voxel_phases = np.linspace(0,phase_range, voxel_num)
  32. #print(voxel_phases)
  33. if len(voxel_amplitudes) != len(voxel_phases):
  34. print("ERROR! Size of amplitude and phase arrays do not match!")
  35. raise
  36. def gen_rf_signal(time):
  37. mag_sin = 0.0
  38. mag_cos = 0.0
  39. for i in range(voxel_num):
  40. amp = voxel_amplitudes[i] * (
  41. np.exp(-time/voxel_T2s_decay[i])
  42. ) + ( 0.0
  43. # + np.random.rand()*noise_ratio
  44. )
  45. mag_sin += amp * np.sin(
  46. voxel_phases[i] + phase_init
  47. )
  48. mag_cos += amp * np.cos(
  49. voxel_phases[i] + phase_init
  50. )
  51. return mag_sin, mag_cos
  52. def assumed_signal(time, values):
  53. amplitudes = values[:voxel_num]
  54. T2s_decay = values[voxel_num:]*T2s_scale
  55. mag_sin = 0.0
  56. mag_cos = 0.0
  57. for i in range(voxel_num):
  58. amp = amplitudes[i] * (
  59. np.exp(-time/T2s_decay[i])
  60. )
  61. mag_sin += amp * np.sin(
  62. voxel_phases[i] + phase_init
  63. )
  64. mag_cos += amp * np.cos(
  65. voxel_phases[i] + phase_init
  66. )
  67. return mag_sin, mag_cos
  68. mag_sin, mag_cos = gen_rf_signal(time_steps)
  69. def fitness(amplitudes, *args):
  70. assumed_sin, assumed_cos = assumed_signal(time_steps, amplitudes)
  71. diff = 0
  72. #amp = np.sqrt(mag_sin**2 + mag_cos**2)
  73. # diff += np.sqrt(np.mean(np.square((mag_sin - assumed_sin)/amp)))
  74. # diff += np.sqrt(np.mean(np.square((mag_cos - assumed_cos)/amp)))
  75. diff += np.sqrt(np.mean(np.square((mag_sin - assumed_sin))))
  76. diff += np.sqrt(np.mean(np.square((mag_cos - assumed_cos))))
  77. diff += np.sqrt(np.mean(np.square(mag_sin/mag_cos - assumed_sin/assumed_cos)))
  78. return diff
  79. def hyper_fit(amplitudes, *args):
  80. result = minimize(fitness, amplitudes, bounds = bounds, method='L-BFGS-B', options={'ftol': 1e-16,'gtol': 1e-16, 'disp': False})
  81. print (result.fun)
  82. return result.fun
  83. #print(voxel_phases)
  84. #print (voxel_amplitudes)
  85. # import matplotlib.pyplot as plt
  86. # plt.plot(time_steps, mag_sin)
  87. # plt.plot(time_steps, mag_cos)
  88. # plt.show()
  89. # #print(fitness(test_amplitudes))
  90. bounds = []
  91. amplitude_minmax = (0,1)
  92. T2s_minmax = (T2s_min/T2s_scale,1)
  93. for i in range(voxel_num):
  94. bounds.append(amplitude_minmax)
  95. for i in range(voxel_num):
  96. bounds.append(T2s_minmax)
  97. x0 = np.full(2*voxel_num,0.5)
  98. result = minimize(hyper_fit, x0, bounds = bounds, method='L-BFGS-B', options={'ftol': 1e-16,'gtol': 1e-16, 'disp': True})
  99. # result = differential_evolution(hyper_fit, bounds, polish=True
  100. # , maxiter = voxel_num*2*500
  101. # , disp = True
  102. # )
  103. # bestresult = minimize(fitness, x0, bounds = bounds, method='L-BFGS-B', options={'ftol': 1e-16,'gtol': 1e-16, 'disp': True})
  104. # for x in range(50):
  105. # print("Try to solve: ", x)
  106. # x0 = np.random.rand(2*voxel_num)
  107. # result = minimize(fitness, x0, bounds = bounds, method='L-BFGS-B', options={'ftol': 1e-16,'gtol': 1e-16, 'disp': False})
  108. # if result.fun < bestresult.fun:
  109. # bestresult = result
  110. # print("new best: ", bestresult.fun)
  111. # result = bestresult
  112. #result = minimize(fitness, x0, bounds = bounds, method='COBYLA', tol=1e-16, options={ 'maxiter':20000,'disp': True})
  113. #result = minimize(fitness, result.x, bounds = bounds, method='L-BFGS-B', options={'gtol': 1e-16, 'disp': True})
  114. #result = minimize(hyper_fit, x0, bounds = bounds, method='Nelder-Mead', tol=1e-16, options={'maxiter':100,'disp': True})
  115. #result.x[voxel_num:] = result.x[voxel_num:]/T2s_scale
  116. print("amp/decay", voxel_amplitudes,voxel_T2s_decay)
  117. print("all ", voxel_all)
  118. print("eval ",result.x, "\n=====> fun=",result.fun)
  119. # print("Diff")
  120. # print((voxel_amplitudes-result.x))
  121. # print("percent")
  122. print("percent",np.abs(voxel_all-result.x)*100)
  123. if np.max(np.abs(voxel_all[:voxel_num]-result.x[:voxel_num])*100)>0.5:
  124. print ("============== !!!LARGE!!! ===============")
  125. print("\n")