split_gradient.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. from types import SimpleNamespace
  2. from typing import Tuple
  3. import numpy as np
  4. from seqgen.pypulseq.calc_duration import calc_duration
  5. from seqgen.pypulseq.make_extended_trapezoid import make_extended_trapezoid
  6. from seqgen.pypulseq.opts import Opts
  7. def split_gradient(
  8. grad: SimpleNamespace, system: Opts = Opts()
  9. ) -> Tuple[SimpleNamespace, SimpleNamespace, SimpleNamespace]:
  10. """
  11. Splits a trapezoidal gradient into slew up, flat top and slew down. Returns the individual gradient parts (slew up,
  12. flat top and slew down) as extended trapezoid gradient objects. The delays in the individual gradient events are
  13. adapted such that addGradients(...) produces an gradient equivalent to 'grad'.
  14. See also:
  15. - `pypulseq.split_gradient()`
  16. - `pypulseq.make_extended_trapezoid()`
  17. - `pypulseq.make_trapezoid()`
  18. - `pypulseq.Sequence.sequence.Sequence.add_block()`
  19. - `pypulseq.opts.Opts`
  20. Parameters
  21. ----------
  22. grad : SimpleNamespace
  23. Gradient event to be split into two gradient waveforms.
  24. system : Opts, default=Opts()
  25. System limits.
  26. Returns
  27. -------
  28. grad1, grad2 : SimpleNamespace
  29. Split gradient waveforms.
  30. Raises
  31. ------
  32. ValueError
  33. If arbitrary gradients are passed.
  34. If non-gradient event is passed.
  35. """
  36. grad_raster_time = system.grad_raster_time
  37. total_length = calc_duration(grad)
  38. if grad.type == "trap":
  39. channel = grad.channel
  40. grad.delay = np.round(grad.delay / grad_raster_time) * grad_raster_time
  41. grad.rise_time = np.round(grad.rise_time / grad_raster_time) * grad_raster_time
  42. grad.flat_time = np.round(grad.flat_time / grad_raster_time) * grad_raster_time
  43. grad.fall_time = np.round(grad.fall_time / grad_raster_time) * grad_raster_time
  44. times = np.array([0, grad.rise_time])
  45. amplitudes = np.array([0, grad.amplitude])
  46. ramp_up = make_extended_trapezoid(
  47. channel=channel,
  48. system=system,
  49. times=times,
  50. amplitudes=amplitudes,
  51. skip_check=True,
  52. )
  53. ramp_up.delay = grad.delay
  54. times = np.array([0, grad.fall_time])
  55. amplitudes = np.array([grad.amplitude, 0])
  56. ramp_down = make_extended_trapezoid(
  57. channel=channel,
  58. system=system,
  59. times=times,
  60. amplitudes=amplitudes,
  61. skip_check=True,
  62. )
  63. ramp_down.delay = total_length - grad.fall_time
  64. ramp_down.t = ramp_down.t * grad_raster_time
  65. flat_top = SimpleNamespace()
  66. flat_top.type = "grad"
  67. flat_top.channel = channel
  68. flat_top.delay = grad.delay + grad.rise_time
  69. flat_top.t = np.arange(
  70. step=grad_raster_time,
  71. stop=ramp_down.delay - grad_raster_time - grad.delay - grad.rise_time,
  72. )
  73. flat_top.waveform = grad.amplitude * np.ones(len(flat_top.t))
  74. flat_top.first = grad.amplitude
  75. flat_top.last = grad.amplitude
  76. return ramp_up, flat_top, ramp_down
  77. elif grad.type == "grad":
  78. raise ValueError("Splitting of arbitrary gradients is not implemented yet.")
  79. else:
  80. raise ValueError("Splitting of unsupported event.")