add_ramps.py 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. from copy import copy
  2. from types import SimpleNamespace
  3. from typing import Union, List
  4. import numpy as np
  5. from MRI_sequences.pypulseq.calc_ramp import calc_ramp
  6. from MRI_sequences.pypulseq.opts import Opts
  7. def add_ramps(
  8. k: Union[list, np.ndarray, tuple],
  9. max_grad: int = 0,
  10. max_slew: int = 0,
  11. rf: SimpleNamespace = None,
  12. system=Opts(),
  13. ) -> List[np.ndarray]:
  14. """
  15. Add segments to the trajectory to ramp to and from the given trajectory.
  16. Parameters
  17. ----------
  18. k : numpy.ndarray, or [numpy.ndarray, ...]
  19. If `k` is a single trajectory: Add a segment to `k` so `k_out` travels from 0 to `k[0]` and a segment so `k_out`
  20. goes from `k[-1]` back to 0 without violating the gradient and slew constraints.
  21. If `k` is multiple trajectoriess: add segments of the same length for each trajectory in the cell array.
  22. system : Opts, default=Opts()
  23. System limits.
  24. rf : SimpleNamespace, default=None
  25. Add a segment of zeros over the ramp times to an RF shape.
  26. max_grad : int, default=0
  27. Maximum gradient amplitude.
  28. max_slew : int, default=0
  29. Maximum slew rate.
  30. Returns
  31. -------
  32. result : [numpy.ndarray, ...]
  33. List of ramped up and ramped down k-space trajectories from `k`.
  34. Raises
  35. ------
  36. ValueError
  37. If `k` is not list, np.ndarray or tuple
  38. RuntimeError
  39. If gradient ramps fail to be calculated
  40. """
  41. if not isinstance(k, (list, np.ndarray, tuple)):
  42. raise ValueError(
  43. f"k has to be one of list, np.ndarray, tuple. Passed: {type(k)}"
  44. )
  45. k_arg = copy(k)
  46. if max_grad > 0:
  47. system.max_grad = max_grad
  48. if max_slew > 0:
  49. system.max_slew = max_slew
  50. k = np.vstack(k)
  51. num_channels = k.shape[0]
  52. k = np.vstack(
  53. (k, np.zeros((3 - num_channels, k.shape[1])))
  54. ) # Pad with zeros if needed
  55. k_up, ok1 = calc_ramp(k0=np.zeros((3, 2)), k_end=k[:, :2], system=system)
  56. k_down, ok2 = calc_ramp(k0=k[:, -2:], k_end=np.zeros((3, 2)), system=system)
  57. if not (ok1 and ok2):
  58. raise RuntimeError("Failed to calculate gradient ramps")
  59. # Add start and end points to ramps
  60. k_up = np.hstack((np.zeros((3, 2)), k_up))
  61. k_down = np.hstack((k_down, np.zeros((3, 1))))
  62. # Add ramps to trajectory
  63. k = np.hstack((k_up, k, k_down))
  64. result = []
  65. if not isinstance(k_arg, list):
  66. result.append(k[:num_channels])
  67. else:
  68. for i in range(num_channels):
  69. result.append(k[i])
  70. if rf is not None:
  71. result.append(
  72. np.concatenate(
  73. (np.zeros(k_up.shape[1] * 10), rf, np.zeros(k_down.shape[1] * 10))
  74. )
  75. )
  76. return result