55sequences. Requires the `pypulseq` package to be installed.
66"""
77
8+ from types import SimpleNamespace
89import numpy as np
910import pypulseq as pp
11+ from numpy .typing import NDArray
12+ from ..trajectories .utils import convert_trajectory_to_gradients
1013
1114
12- def read_pulseq_traj (filename ):
15+ def read_pulseq_traj (filename , traj_delay = 0.0 , grad_offset = 0.0 ):
1316 """Extract k-space trajectory from a Pulseq sequence file.
1417
1518 The sequence should be a valid Pulseq `.seq` file, with arbitrary gradient
1619 waveforms, which all have the same length.
1720
18- Unlike `Sequence.calculate_kspace`, this function returns the k-space
19- trajectory segmented in shots ("blocks" from Pulseq), and works directly
20- from the gradients waveforms stored in the `.seq` file.
21+ Note
2122
2223 Parameters
2324 ----------
@@ -37,5 +38,69 @@ def read_pulseq_traj(filename):
3738 seq = pp .Sequence ()
3839 seq .read (filename )
3940
41+ kspace_adc , kspace , t_exc , t_refocus , t_adc = seq .calculate_kspace (
42+ traj_delay , grad_offset
43+ )
4044
41- gradient_waveforms = seq .waveforms ()
45+
46+ def pulseq_grad_blocks (
47+ trajectory : NDArray , system : pp .Opts = pp .Opts .default
48+ ) -> list [SimpleNamespace ]:
49+ """Create Pulseq gradient blocks from a k-space trajectory.
50+
51+ Parameters
52+ ----------
53+ trajectory : np.ndarray
54+ The k-space trajectory as a numpy array of shape (n_shots, n_samples, 3),
55+ where the last dimension corresponds to the x, y, and z coordinates in k-space.
56+
57+ Returns
58+ -------
59+ list
60+ A list of Pulseq gradient blocks corresponding to the k-space trajectory.
61+ """
62+ grads = convert_trajectory_to_gradients (trajectory )
63+
64+ # TODO add prewind/postwind stuff from #276
65+ # TODO ensure amplitudes are correct
66+
67+ # TODO deduplicate gradients (reduces the size of the file, speed up the sequence loading).
68+ # TODO Are rotation of trajectories supported in pulseq?
69+
70+ grads = convert_trajectory_to_gradients (trajectory )
71+ for g in grads :
72+ for i , c in enumerate (["x" , "y" , "z" ]):
73+ pp_g = pp .make_arbitrary_grad ("x" , g [:, i ])
74+
75+
76+ return blocks_pp
77+
78+
79+ def pulseq_gre_arb_grad (trajectory , pulse , system : pp .Opts = pp .Opts .default ):
80+ """Create a Pulseq GRE sequence with arbitrary gradient waveform.
81+
82+ Parameters
83+ ----------
84+ trajectory : np.ndarray
85+ The k-space trajectory as a numpy array of shape (n_shots, n_samples, 3),
86+ where the last dimension corresponds to the x, y, and z coordinates in k-space.
87+ pulse : pypulseq.Pulse
88+
89+ system : pypulseq.Opts, optional
90+ The system options for the Pulseq sequence. Default is `pp.Opts.default`.
91+
92+ Returns
93+ -------
94+ pp.Sequence
95+ A Pulseq sequence object with the specified arbitrary gradient waveform.
96+ """
97+ seq = pp .Sequence (system = system )
98+ grad_shot_ids , grad_shots = pulseq_grad_blocks (trajectory , system )
99+
100+
101+ # TODO
102+ for grad_shot_id in grad_shot_ids :
103+ pp .add_block () # RF pulse
104+ pp .add_block () # pause for tuning echo time
105+ pp .add_block () # Gradient block with ADC
106+ return seq
0 commit comments