make_arbitrary_grad.py 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. from types import SimpleNamespace
  2. import numpy as np
  3. from seqgen.pypulseq.opts import Opts
  4. def make_arbitrary_grad(
  5. channel: str,
  6. waveform: np.ndarray,
  7. delay: float = 0,
  8. max_grad: float = 0,
  9. max_slew: float = 0,
  10. system: Opts = Opts(),
  11. ) -> SimpleNamespace:
  12. """
  13. Creates a gradient event with arbitrary waveform.
  14. See also `pypulseq.Sequence.sequence.Sequence.add_block()`.
  15. Parameters
  16. ----------
  17. channel : str
  18. Orientation of gradient event of arbitrary shape. Must be one of `x`, `y` or `z`.
  19. waveform : numpy.ndarray
  20. Arbitrary waveform.
  21. system : Opts, default=Opts()
  22. System limits.
  23. max_grad : float, default=0
  24. Maximum gradient strength.
  25. max_slew : float, default=0
  26. Maximum slew rate.
  27. delay : float, default=0
  28. Delay in seconds (s).
  29. Returns
  30. -------
  31. grad : SimpleNamespace
  32. Gradient event with arbitrary waveform.
  33. Raises
  34. ------
  35. ValueError
  36. If invalid `channel` is passed. Must be one of x, y or z.
  37. If slew rate is violated.
  38. If gradient amplitude is violated.
  39. """
  40. if channel not in ["x", "y", "z"]:
  41. raise ValueError(
  42. f"Invalid channel. Must be one of x, y or z. Passed: {channel}"
  43. )
  44. if max_grad <= 0:
  45. max_grad = system.max_grad
  46. if max_slew <= 0:
  47. max_slew = system.max_slew
  48. g = waveform
  49. slew = np.squeeze(np.subtract(g[1:], g[:-1]) / system.grad_raster_time)
  50. if max(abs(slew)) >= max_slew:
  51. raise ValueError(f"Slew rate violation {max(abs(slew)) / max_slew * 100}")
  52. if max(abs(g)) >= max_grad:
  53. raise ValueError(f"Gradient amplitude violation {max(abs(g)) / max_grad * 100}")
  54. grad = SimpleNamespace()
  55. grad.type = "grad"
  56. grad.channel = channel
  57. grad.waveform = g
  58. grad.delay = delay
  59. # True timing and aux shape data
  60. grad.tt = (np.arange(1, len(g) + 1) - 0.5) * system.grad_raster_time
  61. grad.shape_dur = len(g) * system.grad_raster_time
  62. grad.first = (3 * g[0] - g[1]) * 0.5 # Extrapolate by 1/2 gradient raster
  63. grad.last = (g[-1] * 3 - g[-2]) * 0.5 # Extrapolate by 1/2 gradient raster
  64. return grad