write_radial_gre.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import numpy as np
  2. import pypulseq as pp
  3. def main(plot: bool, write_seq: bool, seq_filename: str = "gre_radial_pypulseq.seq"):
  4. # ======
  5. # SETUP
  6. # ======
  7. seq = pp.Sequence() # Create a new sequence object
  8. fov = 260e-3
  9. Nx = 320 # Define FOV and resolution
  10. alpha = 10 # Flip angle
  11. slice_thickness = 3e-3 # Slice thickness
  12. TE = 8e-3 # Echo time
  13. TR = 20e-3 # Repetition time
  14. Nr = 256 # Number of radial spokes
  15. N_dummy = 20 # Number of dummy scans
  16. delta = np.pi / Nr # Angular increment
  17. rf_spoiling_inc = 117 # RF spoiling increment
  18. # Set system limits
  19. system = pp.Opts(
  20. max_grad=28,
  21. grad_unit="mT/m",
  22. max_slew=120,
  23. slew_unit="T/m/s",
  24. rf_ringdown_time=20e-6,
  25. rf_dead_time=100e-6,
  26. adc_dead_time=10e-6,
  27. )
  28. # ======
  29. # CREATE EVENTS
  30. # ======
  31. # Create alpha-degree slice selection pulse and gradient
  32. rf, gz, _ = pp.make_sinc_pulse(
  33. apodization=0.5,
  34. duration=4e-3,
  35. flip_angle=alpha * np.pi / 180,
  36. slice_thickness=slice_thickness,
  37. system=system,
  38. time_bw_product=4,
  39. return_gz=True,
  40. )
  41. # Define other gradients and ADC events
  42. deltak = 1 / fov
  43. gx = pp.make_trapezoid(
  44. channel="x", flat_area=Nx * deltak, flat_time=6.4e-3 / 5, system=system
  45. )
  46. adc = pp.make_adc(
  47. num_samples=Nx, duration=gx.flat_time, delay=gx.rise_time, system=system
  48. )
  49. gx_pre = pp.make_trapezoid(
  50. channel="x", area=-gx.area / 2 - deltak / 2, duration=2e-3, system=system
  51. )
  52. gz_reph = pp.make_trapezoid(
  53. channel="z", area=-gz.area / 2, duration=2e-3, system=system
  54. )
  55. # Gradient spoiling
  56. gx_spoil = pp.make_trapezoid(channel="x", area=0.5 * Nx * deltak, system=system)
  57. gz_spoil = pp.make_trapezoid(channel="z", area=4 / slice_thickness, system=system)
  58. # Calculate timing
  59. delay_TE = (
  60. np.ceil(
  61. (
  62. TE
  63. - pp.calc_duration(gx_pre)
  64. - gz.fall_time
  65. - gz.flat_time / 2
  66. - pp.calc_duration(gx) / 2
  67. )
  68. / seq.grad_raster_time
  69. )
  70. * seq.grad_raster_time
  71. )
  72. delay_TR = (
  73. np.ceil(
  74. (
  75. TR
  76. - pp.calc_duration(gx_pre)
  77. - pp.calc_duration(gz)
  78. - pp.calc_duration(gx)
  79. - delay_TE
  80. )
  81. / seq.grad_raster_time
  82. )
  83. * seq.grad_raster_time
  84. )
  85. assert np.all(delay_TR) > pp.calc_duration(gx_spoil, gz_spoil)
  86. rf_phase = 0
  87. rf_inc = 0
  88. # ======
  89. # CONSTRUCT SEQUENCE
  90. # ======
  91. for i in range(-N_dummy, Nr + 1):
  92. rf.phase_offset = rf_phase / 180 * np.pi
  93. adc.phase_offset = rf_phase / 180 * np.pi
  94. rf_inc = divmod(rf_inc + rf_spoiling_inc, 360.0)[1]
  95. rf_phase = divmod(rf_inc + rf_phase, 360.0)[1]
  96. seq.add_block(rf, gz)
  97. phi = delta * (i - 1)
  98. seq.add_block(*pp.rotate(gx_pre, gz_reph, angle=phi, axis="z"))
  99. seq.add_block(pp.make_delay(delay_TE))
  100. if i > 0:
  101. seq.add_block(*pp.rotate(gx, adc, angle=phi, axis="z"))
  102. else:
  103. seq.add_block(*pp.rotate(gx, angle=phi, axis="z"))
  104. seq.add_block(
  105. *pp.rotate(gx_spoil, gz_spoil, pp.make_delay(delay_TR), angle=phi, axis="z")
  106. )
  107. ok, error_report = seq.check_timing()
  108. if ok:
  109. print("Timing check passed successfully")
  110. else:
  111. print("Timing check failed! Error listing follows:")
  112. print(error_report)
  113. # ======
  114. # VISUALIZATION
  115. # ======
  116. if plot:
  117. seq.plot()
  118. # =========
  119. # WRITE .SEQ
  120. # =========
  121. if write_seq:
  122. seq.set_definition(key="FOV", value=[fov, fov, slice_thickness])
  123. seq.set_definition(key="Name", value="gre_rad")
  124. seq.write(seq_filename)
  125. if __name__ == "__main__":
  126. main(plot=True, write_seq=True)