write_3Dt1_mprage.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. from math import pi
  2. import numpy as np
  3. import pypulseq as pp
  4. Nx = 256
  5. Ny = 256
  6. Nz = 32
  7. system = pp.Opts(
  8. max_grad=32,
  9. grad_unit="mT/m",
  10. max_slew=130,
  11. slew_unit="T/m/s",
  12. grad_raster_time=10e-6,
  13. rf_ringdown_time=10e-6,
  14. rf_dead_time=100e-6,
  15. )
  16. seq = pp.Sequence(system)
  17. fov = 256e-3
  18. fov_z = 256e-3
  19. slice_thickness = 1e-3
  20. section_thickness = 5e-3
  21. # =========
  22. # RF preparatory, excitation
  23. # =========
  24. flip_exc = 12 * pi / 180
  25. rf = pp.make_block_pulse(
  26. flip_angle=flip_exc, system=system, duration=250e-6, time_bw_product=4
  27. )
  28. flip_prep = 90 * pi / 180
  29. rf_prep = pp.make_block_pulse(
  30. flip_angle=flip_prep, system=system, duration=500e-6, time_bw_product=4
  31. )
  32. # =========
  33. # Readout
  34. # =========
  35. delta_k = 1 / fov
  36. k_width = Nx * delta_k
  37. readout_time = 3.5e-3
  38. gx = pp.make_trapezoid(
  39. channel="x", system=system, flat_area=k_width, flat_time=readout_time
  40. )
  41. adc = pp.make_adc(num_samples=Nx, duration=gx.flat_time, delay=gx.rise_time)
  42. # =========
  43. # Prephase and Rephase
  44. # =========
  45. delta_kz = 1 / fov_z
  46. phase_areas = (np.arange(Ny) - (Ny / 2)) * delta_k
  47. slice_areas = (np.arange(Nz) - (Nz / 2)) * delta_kz
  48. gx_pre = pp.make_trapezoid(channel="x", system=system, area=-gx.area / 2, duration=2e-3)
  49. gy_pre = pp.make_trapezoid(
  50. channel="y", system=system, area=phase_areas[-1], duration=2e-3
  51. )
  52. # =========
  53. # Spoilers
  54. # =========
  55. pre_time = 6.4e-4
  56. gx_spoil = pp.make_trapezoid(
  57. channel="x",
  58. system=system,
  59. area=(4 * np.pi) / (42.576e6 * delta_k * 1e-3) * 42.576e6,
  60. duration=pre_time * 6,
  61. )
  62. gy_spoil = pp.make_trapezoid(
  63. channel="y",
  64. system=system,
  65. area=(4 * np.pi) / (42.576e6 * delta_k * 1e-3) * 42.576e6,
  66. duration=pre_time * 6,
  67. )
  68. gz_spoil = pp.make_trapezoid(
  69. channel="z",
  70. system=system,
  71. area=(4 * np.pi) / (42.576e6 * delta_kz * 1e-3) * 42.576e6,
  72. duration=pre_time * 6,
  73. )
  74. # =========
  75. # Extended trapezoids: gx, gx_spoil
  76. # =========
  77. t_gx_extended = np.array(
  78. [0, gx.rise_time, gx.flat_time, (gx.rise_time * 2) + gx.flat_time + gx.fall_time]
  79. )
  80. amp_gx_extended = np.array([0, gx.amplitude, gx.amplitude, gx_spoil.amplitude])
  81. t_gx_spoil_extended = np.array(
  82. [
  83. 0,
  84. gx_spoil.rise_time + gx_spoil.flat_time,
  85. gx_spoil.rise_time + gx_spoil.flat_time + gx_spoil.fall_time,
  86. ]
  87. )
  88. amp_gx_spoil_extended = np.array([gx_spoil.amplitude, gx_spoil.amplitude, 0])
  89. gx_extended = pp.make_extended_trapezoid(
  90. channel="x", times=t_gx_extended, amplitudes=amp_gx_extended
  91. )
  92. gx_spoil_extended = pp.make_extended_trapezoid(
  93. channel="x", times=t_gx_spoil_extended, amplitudes=amp_gx_spoil_extended
  94. )
  95. # =========
  96. # Delays
  97. # =========
  98. TE, TI, TR, T_recovery = 4e-3, 140e-3, 10e-3, 1e-3
  99. delay_TE = (
  100. TE - pp.calc_duration(rf) / 2 - pp.calc_duration(gx_pre) - pp.calc_duration(gx) / 2
  101. )
  102. delay_TI = TI - pp.calc_duration(rf_prep) / 2 - pp.calc_duration(gx_spoil)
  103. delay_TR = (
  104. TR
  105. - pp.calc_duration(rf)
  106. - pp.calc_duration(gx_pre)
  107. - pp.calc_duration(gx)
  108. - pp.calc_duration(gx_spoil)
  109. )
  110. for i in range(Ny):
  111. gy_pre = pp.make_trapezoid(
  112. channel="y", system=system, area=phase_areas[i], duration=2e-3
  113. )
  114. seq.add_block(rf_prep)
  115. seq.add_block(gx_spoil, gy_spoil, gz_spoil)
  116. seq.add_block(pp.make_delay(delay_TI))
  117. for j in range(Nz):
  118. gz_pre = pp.make_trapezoid(
  119. channel="z", system=system, area=slice_areas[j], duration=2e-3
  120. )
  121. gz_reph = pp.make_trapezoid(
  122. channel="z", system=system, area=-slice_areas[j], duration=2e-3
  123. )
  124. seq.add_block(rf)
  125. seq.add_block(gx_pre, gy_pre, gz_pre)
  126. # Skip TE: readout_time = 3.5e3 --> TE = -2.168404344971009e-19
  127. # seq.add_block(pp.make_delay(delay_TE))
  128. seq.add_block(gx_extended, adc)
  129. seq.add_block(gx_spoil_extended, gz_reph)
  130. seq.add_block(pp.make_delay(delay_TR))
  131. seq.add_block(pp.make_delay(T_recovery))
  132. seq.set_definition(key="Name", value="3D T1 MPRAGE")
  133. seq.write("256_3d_t1_mprage_pypulseq.seq")
  134. # seq.plot(time_range=(0, TI + TR + 2e-3))