write_epi_se.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import math
  2. import numpy as np
  3. import pypulseq as pp
  4. def main(plot: bool, write_seq: bool, seq_filename: str = "epi_se_pypulseq.seq"):
  5. # ======
  6. # SETUP
  7. # ======
  8. seq = pp.Sequence() # Create a new sequence object
  9. fov = 256e-3 # Define FOV and resolution
  10. Nx = 64
  11. Ny = 64
  12. # Set system limits
  13. system = pp.Opts(
  14. max_grad=32,
  15. grad_unit="mT/m",
  16. max_slew=130,
  17. slew_unit="T/m/s",
  18. rf_ringdown_time=20e-6,
  19. rf_dead_time=100e-6,
  20. adc_dead_time=20e-6,
  21. )
  22. # ======
  23. # CREATE EVENTS
  24. # ======
  25. # Create 90 degree slice selection pulse and gradient
  26. rf, gz, _ = pp.make_sinc_pulse(
  27. flip_angle=np.pi / 2,
  28. system=system,
  29. duration=3e-3,
  30. slice_thickness=3e-3,
  31. apodization=0.5,
  32. time_bw_product=4,
  33. return_gz=True,
  34. )
  35. # Define other gradients and ADC events
  36. delta_k = 1 / fov
  37. k_width = Nx * delta_k
  38. readout_time = 3.2e-4
  39. gx = pp.make_trapezoid(
  40. channel="x", system=system, flat_area=k_width, flat_time=readout_time
  41. )
  42. adc = pp.make_adc(
  43. num_samples=Nx, system=system, duration=gx.flat_time, delay=gx.rise_time
  44. )
  45. # Pre-phasing gradients
  46. pre_time = 8e-4
  47. gz_reph = pp.make_trapezoid(
  48. channel="z", system=system, area=-gz.area / 2, duration=pre_time
  49. )
  50. # Do not need minus for in-plane prephasers because of the spin-echo (position reflection in k-space)
  51. gx_pre = pp.make_trapezoid(
  52. channel="x", system=system, area=gx.area / 2 - delta_k / 2, duration=pre_time
  53. )
  54. gy_pre = pp.make_trapezoid(
  55. channel="y", system=system, area=Ny / 2 * delta_k, duration=pre_time
  56. )
  57. # Phase blip in shortest possible time
  58. dur = math.ceil(2 * math.sqrt(delta_k / system.max_slew) / 10e-6) * 10e-6
  59. gy = pp.make_trapezoid(channel="y", system=system, area=delta_k, duration=dur)
  60. # Refocusing pulse with spoiling gradients
  61. rf180 = pp.make_block_pulse(
  62. flip_angle=np.pi, system=system, duration=500e-6, use="refocusing"
  63. )
  64. gz_spoil = pp.make_trapezoid(
  65. channel="z", system=system, area=gz.area * 2, duration=3 * pre_time
  66. )
  67. # Calculate delay time
  68. TE = 60e-3
  69. duration_to_center = (Nx / 2 + 0.5) * pp.calc_duration(
  70. gx
  71. ) + Ny / 2 * pp.calc_duration(gy)
  72. rf_center_incl_delay = rf.delay + pp.calc_rf_center(rf)[0]
  73. rf180_center_incl_delay = rf180.delay + pp.calc_rf_center(rf180)[0]
  74. delay_TE1 = (
  75. TE / 2
  76. - pp.calc_duration(gz)
  77. + rf_center_incl_delay
  78. - pre_time
  79. - pp.calc_duration(gz_spoil)
  80. - rf180_center_incl_delay
  81. )
  82. delay_TE2 = (
  83. TE / 2
  84. - pp.calc_duration(rf180)
  85. + rf180_center_incl_delay
  86. - pp.calc_duration(gz_spoil)
  87. - duration_to_center
  88. )
  89. # ======
  90. # CONSTRUCT SEQUENCE
  91. # ======
  92. # Define sequence blocks
  93. seq.add_block(rf, gz)
  94. seq.add_block(gx_pre, gy_pre, gz_reph)
  95. seq.add_block(pp.make_delay(delay_TE1))
  96. seq.add_block(gz_spoil)
  97. seq.add_block(rf180)
  98. seq.add_block(gz_spoil)
  99. seq.add_block(pp.make_delay(delay_TE2))
  100. for i in range(Ny):
  101. seq.add_block(gx, adc) # Read one line of k-space
  102. seq.add_block(gy) # Phase blip
  103. gx.amplitude = -gx.amplitude # Reverse polarity of read gradient
  104. seq.add_block(pp.make_delay(1e-4))
  105. ok, error_report = seq.check_timing()
  106. if ok:
  107. print("Timing check passed successfully")
  108. else:
  109. print("Timing check failed! Error listing follows:")
  110. print(error_report)
  111. # ======
  112. # VISUALIZATION
  113. # ======
  114. if plot:
  115. seq.plot()
  116. # =========
  117. # WRITE .SEQ
  118. # =========
  119. if write_seq:
  120. seq.write(seq_filename)
  121. if __name__ == "__main__":
  122. main(plot=True, write_seq=True)