write_epi.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. """
  2. Demo low-performance EPI sequence without ramp-sampling.
  3. """
  4. import numpy as np
  5. import pypulseq as pp
  6. def main(plot: bool, write_seq: bool, seq_filename: str = "epi_pypulseq.seq"):
  7. # ======
  8. # SETUP
  9. # ======
  10. seq = pp.Sequence() # Create a new sequence object
  11. # Define FOV and resolution
  12. fov = 220e-3
  13. Nx = 64
  14. Ny = 64
  15. slice_thickness = 3e-3 # Slice thickness
  16. n_slices = 3
  17. # Set system limits
  18. system = pp.Opts(
  19. max_grad=32,
  20. grad_unit="mT/m",
  21. max_slew=130,
  22. slew_unit="T/m/s",
  23. rf_ringdown_time=30e-6,
  24. rf_dead_time=100e-6,
  25. )
  26. # ======
  27. # CREATE EVENTS
  28. # ======
  29. # Create 90 degree slice selection pulse and gradient
  30. rf, gz, _ = pp.make_sinc_pulse(
  31. flip_angle=np.pi / 2,
  32. system=system,
  33. duration=3e-3,
  34. slice_thickness=slice_thickness,
  35. apodization=0.5,
  36. time_bw_product=4,
  37. return_gz=True,
  38. )
  39. # Define other gradients and ADC events
  40. delta_k = 1 / fov
  41. k_width = Nx * delta_k
  42. dwell_time = 4e-6
  43. readout_time = Nx * dwell_time
  44. flat_time = np.ceil(readout_time * 1e5) * 1e-5 # round-up to the gradient raster
  45. gx = pp.make_trapezoid(
  46. channel="x",
  47. system=system,
  48. amplitude=k_width / readout_time,
  49. flat_time=flat_time,
  50. )
  51. adc = pp.make_adc(
  52. num_samples=Nx,
  53. duration=readout_time,
  54. delay=gx.rise_time + flat_time / 2 - (readout_time - dwell_time) / 2,
  55. )
  56. # Pre-phasing gradients
  57. pre_time = 8e-4
  58. gx_pre = pp.make_trapezoid(
  59. channel="x", system=system, area=-gx.area / 2, duration=pre_time
  60. )
  61. gz_reph = pp.make_trapezoid(
  62. channel="z", system=system, area=-gz.area / 2, duration=pre_time
  63. )
  64. gy_pre = pp.make_trapezoid(
  65. channel="y", system=system, area=-Ny / 2 * delta_k, duration=pre_time
  66. )
  67. # Phase blip in the shortest possible time
  68. dur = np.ceil(2 * np.sqrt(delta_k / system.max_slew) / 10e-6) * 10e-6
  69. gy = pp.make_trapezoid(channel="y", system=system, area=delta_k, duration=dur)
  70. # ======
  71. # CONSTRUCT SEQUENCE
  72. # ======
  73. # Define sequence blocks
  74. for s in range(n_slices):
  75. rf.freq_offset = gz.amplitude * slice_thickness * (s - (n_slices - 1) / 2)
  76. seq.add_block(rf, gz)
  77. seq.add_block(gx_pre, gy_pre, gz_reph)
  78. for i in range(Ny):
  79. seq.add_block(gx, adc) # Read one line of k-space
  80. seq.add_block(gy) # Phase blip
  81. gx.amplitude = -gx.amplitude # Reverse polarity of read gradient
  82. ok, error_report = seq.check_timing()
  83. if ok:
  84. print("Timing check passed successfully")
  85. else:
  86. print("Timing check failed! Error listing follows:")
  87. print(error_report)
  88. # ======
  89. # VISUALIZATION
  90. # ======
  91. if plot:
  92. seq.plot() # Plot sequence waveforms
  93. # =========
  94. # WRITE .SEQ
  95. # =========
  96. if write_seq:
  97. seq.write(seq_filename)
  98. if __name__ == "__main__":
  99. main(plot=True, write_seq=True)