Prephasors, Spoilers and arbitrary Waveforms#

This example showcases how to create gradient waveform under a set of constraints.

When designing MRI sequences It’s often necessary to have some way of going from a point A to point B in the kspace. For instance:

  • At the beginning of an acquisition we may want to go from the center of the

k-space to the starting point of the trajectory. This is usually call the “prephasor” or “prewinder” gradient. - At the end of an acquisition we may want to go from the end point of the trajectory back to the center, or to crush any residual magnetization by going to the edge of the k-space. This is usually called a “rewind” or “spoiler” gradient.

However, these gradient waveforms needs to be designed under the hardware system constraints: The maximum gradient strength \(g_\max\), and slew rate \(s_\max\), and the raster time \(\Delta t\).

Once the constraints are defined, the gradient waveforms can be determined using different methods such as linear programming or quadratic programming.

This example shows how to create such gradient waveforms using MRI-NUFFT.

import numpy as np

from mrinufft import initialize_2D_cones
from mrinufft.trajectories.utils import (
    Acquisition,
    convert_gradients_to_trajectory,
    convert_trajectory_to_gradients,
)
from mrinufft.trajectories.gradients import (
    connect_gradient,
    get_prephasors_and_spoilers,
)

We are going to rely on the Acquisition configuration to define the constraints

Create a demo radial trajectory

traj = initialize_2D_cones(Nc=32, Ns=512, tilt="uniform", in_out=True)

traj_grad, init_points = convert_trajectory_to_gradients(traj, acq)


# Create prephasor and spoiler gradients
# =======================================

prephasors = {}
spoilers = {}
full_grads = {}
full_traj = {}
for method in ["lp", "lp-minslew", "osqp"]:
    print(f"Creating prephasor and spoiler gradients using method: {method}")
    p, s = get_prephasors_and_spoilers(
        traj, acq=acq, method=method, spoil_loc=(1, 0, 0)
    )
    g = np.concatenate([p, traj_grad, s], axis=1)

    prephasors[method] = p
    spoilers[method] = s
    # Connect the prephasor and spoiler gradients to the trajectory gradients
    full_grads[method] = g
    full_traj[method] = convert_gradients_to_trajectory(
        g, np.zeros_like(init_points), acq=acq
    )
Creating prephasor and spoiler gradients using method: lp

0it [00:00, ?it/s]
32it [00:00, 319.96it/s]
64it [00:00, 449.62it/s]

0it [00:00, ?it/s]
31it [00:00, 301.99it/s]
62it [00:00, 103.23it/s]
64it [00:00, 112.22it/s]
Creating prephasor and spoiler gradients using method: lp-minslew

0it [00:00, ?it/s]
37it [00:00, 359.37it/s]
64it [00:00, 465.19it/s]

0it [00:00, ?it/s]
31it [00:00, 302.95it/s]
62it [00:00, 103.26it/s]
64it [00:00, 112.44it/s]
Creating prephasor and spoiler gradients using method: osqp

0it [00:00, ?it/s]3
1
3
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1

23it [00:00, 226.11it/s]1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1

64it [00:00, 341.62it/s]
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1

0it [00:00, ?it/s]1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1

31it [00:00, 296.12it/s]1
1
1
3
1
1
1
1
1
1
1
1
3
1
1
3
1
1
1
1
1
1
1
1
3
3
1
3
1
1
1
1
1
1
3
1
1
3
1
1
1
1
1
1
1
3
3
1
3
1
1
1
1
1
1
1
3
3
1
3
1
1
1
1
1
1
3
3
1
3
1
1
1
1
1
1
3
1
1
3
1
1
1
1
1
1
3
3
1
3
1
1
1
1
1
3
1
1
3
1
1
1
1
1
1
3
1
3
1
1
1
1
1
3
3
1
1
1
3
1
1
1
1
1
3
1
1

61it [00:00, 55.84it/s] 1
3
1
1
1
1
1
3
1

64it [00:01, 62.19it/s]
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1
1

Show the results#

Setup the figure

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

fig = plt.figure(figsize=(21, 7))
gs0 = fig.add_gridspec(2, 1, hspace=0.3)

gsgrad = gridspec.GridSpecFromSubplotSpec(2, 1, subplot_spec=gs0[0])
gstraj = gridspec.GridSpecFromSubplotSpec(1, 3, subplot_spec=gs0[1])


grad_ax = gsgrad.subplots(sharex=True)
axs = gstraj.subplots(sharex=True, sharey=True)
time = np.arange(full_grads["lp"].shape[1]) * acq.raster_time  # in ms
example grad connection

Plot gradients

for method in ["lp", "lp-minslew", "osqp"]:
    grad_ax[0].plot(
        np.arange(full_grads[method].shape[1]) * acq.raster_time,
        full_grads[method][0, :, 0],  # show x gradient
        label=f"{method}",
    )
    grad_ax[1].plot(
        np.arange(full_grads[method].shape[1]) * acq.raster_time,
        full_grads[method][0, :, 1],  # show x gradient
        label=f"{method}",
    )
grad_ax[0].set_title("Full gradient waveforms with prephasor and spoiler")
grad_ax[1].set_xlabel("Time (ms)")
grad_ax[0].set_ylabel("Gx (T/m)")
grad_ax[1].set_ylabel("Gy (T/m)")
grad_ax[0].axvline(acq.raster_time * prephasors[method].shape[1], ls="--", c="gray")
grad_ax[0].axvline(
    acq.raster_time * (full_grads[method].shape[1] - spoilers[method].shape[1]),
    ls="--",
    c="gray",
)
grad_ax[1].axvline(acq.raster_time * prephasors[method].shape[1], ls="--", c="gray")
grad_ax[1].axvline(
    acq.raster_time * (full_grads[method].shape[1] - spoilers[method].shape[1]),
    ls="--",
    c="gray",
)

grad_ax[0].legend(loc="upper center")


# Plot trajectories

for i, method in enumerate(["lp", "lp-minslew", "osqp"]):
    t = full_traj[method]
    t_pre = t[:, : prephasors[method].shape[1], :]
    t_post = t[:, -spoilers[method].shape[1] :]
    t_core = t[:, prephasors[method].shape[1] : -spoilers[method].shape[1], :]

    axs[i].scatter(
        t_core.reshape(-1, 2)[:, 0],
        t_core.reshape(-1, 2)[:, 1],
        c="k",
        s=0.5,
    )

    axs[i].scatter(
        t_pre.reshape(-1, 2)[:, 0],
        t_pre.reshape(-1, 2)[:, 1],
        c="tab:blue",
        s=0.5,
    )
    axs[i].scatter(
        t_post.reshape(-1, 2)[:, 0],
        t_post.reshape(-1, 2)[:, 1],
        c="tab:green",
        s=0.5,
    )
    axs[i].set_title(f"'{method}' prephasor/spoiler")
    axs[i].grid()
plt.legend()
plt.show()
example grad connection
/volatile/github-ci-mind-inria/gpu_mind_runner/_work/mri-nufft/mri-nufft/examples/trajectories/example_grad_connection.py:163: UserWarning: No artists with labels found to put in legend.  Note that artists whose label start with an underscore are ignored when legend() is called with no argument.
  plt.legend()

Total running time of the script: (0 minutes 8.442 seconds)

Gallery generated by Sphinx-Gallery