Trajectory constraints#

A collection of methods to make trajectories fit hardware constraints.

Hereafter we illustrate different methods to reduce the gradient strengths and slew rates required for the trajectory to match the hardware constraints of MRI machines. A summary table is available below.

Constraint fitting methods#

Gradient strength

Slew rate

Path preserved

Density preserved

Arc-length parameterization

Yes

No

Yes

No

Projection onto convex sets

Yes

Yes

No

No

# Internal
from mrinufft.trajectories import (
    Acquisition,
    compute_gradients_and_slew_rates,
    initialize_2D_spiral,
    project_trajectory,
    parameterize_by_arc_length,
)
from utils import show_trajectory_full

# External
import numpy as np

Script options#

These options are used in the examples below as default values for all trajectories.

# Acquisition parameters
acq = Acquisition.default
# Trajectory parameters
Nc = 4  # Number of shots
Ns = 512  # Number of samples per shot
in_out = False  # Choose between in-out or center-out trajectories
nb_revolutions = 4  # Number of zigzags for base trajectories
# Display parameters
figure_size = 10  # Figure size for trajectory plots
subfigure_size = 6  # Figure size for subplots
one_shot = 2 * Nc // 3  # Highlight one shot in particular
sample_freq = 60  # Frequency of samples to display in the trajectory plots

We will be using a cone trajectory to showcase the different methods as it switches several times between high gradients and slew rates.

example traj projection
Max gradient: 0.058 T/m, Max slew rate: 282.015 T/m/ms

Arc-length parameterization#

Arc-length parameterization is the simplest method to reduce the gradient strength as it resamples the trajectory to have a constant distance between samples. This is technically the lowest gradient strength achievable while preserving the path of the trajectory, but it does not preserve the k-space density and can lead to high slew rates as shown below.

show_trajectory_full(
    projected_trajectory, one_shot, subfigure_size, sample_freq, acq=acq
)

grads, slews = compute_gradients_and_slew_rates(projected_trajectory, acq)
grad_max, slew_max = np.max(grads), np.max(slews)
print(f"Max gradient: {grad_max:.3f} T/m, Max slew rate: {slew_max:.3f} T/m/ms")
example traj projection
Max gradient: 0.029 T/m, Max slew rate: 2382.048 T/m/ms

Projection onto convex sets#

The projection step is a primal-dual algorithm to project any trajectory into the convex constraint set. This step guarantees that the final trajectory is playably by the scanner. Also, as the constraint set if convex, the projection results in unique trajectory which is closest to the original one while being hardware compliant.

projected_trajectory = project_trajectory(
    original_trajectory,
    acq,
    max_iter=10000,
    TE_pos=0,
)
  0%|          | 0/10000 [00:00<?, ?it/s]
  1%|          | 103/10000 [00:00<00:09, 1020.92it/s]
  2%|▏         | 207/10000 [00:00<00:09, 1028.07it/s]
  3%|▎         | 314/10000 [00:00<00:09, 1044.91it/s]
  4%|▍         | 421/10000 [00:00<00:09, 1052.12it/s]
  5%|▌         | 527/10000 [00:00<00:09, 1044.72it/s]
  6%|▋         | 633/10000 [00:00<00:08, 1049.66it/s]
  7%|▋         | 738/10000 [00:00<00:08, 1041.63it/s]
  8%|▊         | 846/10000 [00:00<00:08, 1051.23it/s]
 10%|▉         | 952/10000 [00:00<00:08, 1049.85it/s]
 11%|█         | 1057/10000 [00:01<00:08, 1044.94it/s]
 12%|█▏        | 1162/10000 [00:01<00:08, 1044.06it/s]
 13%|█▎        | 1272/10000 [00:01<00:08, 1059.97it/s]
 14%|█▍        | 1380/10000 [00:01<00:08, 1064.26it/s]
 15%|█▍        | 1487/10000 [00:01<00:08, 1061.32it/s]
 16%|█▌        | 1594/10000 [00:01<00:07, 1061.56it/s]
 17%|█▋        | 1701/10000 [00:01<00:07, 1054.56it/s]
 18%|█▊        | 1807/10000 [00:01<00:07, 1050.14it/s]
 19%|█▉        | 1913/10000 [00:01<00:07, 1051.80it/s]
 20%|██        | 2019/10000 [00:01<00:07, 1040.03it/s]
 21%|██        | 2124/10000 [00:02<00:07, 1042.28it/s]
 22%|██▏       | 2229/10000 [00:02<00:07, 1042.98it/s]
 23%|██▎       | 2334/10000 [00:02<00:07, 1017.73it/s]
 24%|██▍       | 2436/10000 [00:02<00:07, 1010.56it/s]
 25%|██▌       | 2540/10000 [00:02<00:07, 1017.76it/s]
 26%|██▋       | 2642/10000 [00:02<00:07, 1008.18it/s]
 27%|██▋       | 2746/10000 [00:02<00:07, 1016.14it/s]
 28%|██▊       | 2850/10000 [00:02<00:07, 1021.08it/s]
 30%|██▉       | 2953/10000 [00:02<00:06, 1019.10it/s]
 31%|███       | 3055/10000 [00:02<00:06, 1016.49it/s]
 32%|███▏      | 3158/10000 [00:03<00:06, 1018.54it/s]
 33%|███▎      | 3260/10000 [00:03<00:06, 1018.28it/s]
 34%|███▎      | 3364/10000 [00:03<00:06, 1021.79it/s]
 35%|███▍      | 3467/10000 [00:03<00:06, 1019.21it/s]
 36%|███▌      | 3570/10000 [00:03<00:06, 1021.49it/s]
 37%|███▋      | 3673/10000 [00:03<00:06, 1015.85it/s]
 38%|███▊      | 3775/10000 [00:03<00:06, 1001.26it/s]
 39%|███▉      | 3876/10000 [00:03<00:06, 999.52it/s]
 40%|███▉      | 3980/10000 [00:03<00:05, 1008.92it/s]
 41%|████      | 4081/10000 [00:03<00:05, 1004.14it/s]
 42%|████▏     | 4182/10000 [00:04<00:05, 999.86it/s]
 43%|████▎     | 4287/10000 [00:04<00:05, 1011.82it/s]
 44%|████▍     | 4394/10000 [00:04<00:05, 1027.17it/s]
 45%|████▍     | 4497/10000 [00:04<00:05, 1024.88it/s]
 46%|████▌     | 4600/10000 [00:04<00:05, 1023.85it/s]
 47%|████▋     | 4704/10000 [00:04<00:05, 1026.64it/s]
 48%|████▊     | 4807/10000 [00:04<00:05, 1016.92it/s]
 49%|████▉     | 4910/10000 [00:04<00:05, 1017.04it/s]
 50%|█████     | 5013/10000 [00:04<00:04, 1018.70it/s]
 51%|█████     | 5115/10000 [00:04<00:04, 1016.62it/s]
 52%|█████▏    | 5219/10000 [00:05<00:04, 1023.04it/s]
 53%|█████▎    | 5324/10000 [00:05<00:04, 1028.73it/s]
 54%|█████▍    | 5429/10000 [00:05<00:04, 1034.18it/s]
 55%|█████▌    | 5533/10000 [00:05<00:04, 1032.39it/s]
 56%|█████▋    | 5638/10000 [00:05<00:04, 1037.57it/s]
 57%|█████▋    | 5743/10000 [00:05<00:04, 1040.86it/s]
 58%|█████▊    | 5848/10000 [00:05<00:03, 1039.05it/s]
 60%|█████▉    | 5955/10000 [00:05<00:03, 1045.00it/s]
 61%|██████    | 6060/10000 [00:05<00:03, 1041.17it/s]
 62%|██████▏   | 6166/10000 [00:05<00:03, 1044.50it/s]
 63%|██████▎   | 6271/10000 [00:06<00:03, 1043.59it/s]
 64%|██████▍   | 6376/10000 [00:06<00:03, 1041.43it/s]
 65%|██████▍   | 6481/10000 [00:06<00:03, 1041.94it/s]
 66%|██████▌   | 6587/10000 [00:06<00:03, 1047.07it/s]
 67%|██████▋   | 6696/10000 [00:06<00:03, 1059.73it/s]
 68%|██████▊   | 6802/10000 [00:06<00:03, 1051.88it/s]
 69%|██████▉   | 6908/10000 [00:06<00:02, 1045.72it/s]
 70%|███████   | 7014/10000 [00:06<00:02, 1047.00it/s]
 71%|███████   | 7121/10000 [00:06<00:02, 1051.36it/s]
 72%|███████▏  | 7228/10000 [00:06<00:02, 1053.66it/s]
 73%|███████▎  | 7334/10000 [00:07<00:02, 1040.91it/s]
 74%|███████▍  | 7439/10000 [00:07<00:02, 1034.16it/s]
 75%|███████▌  | 7543/10000 [00:07<00:02, 1021.33it/s]
 76%|███████▋  | 7650/10000 [00:07<00:02, 1033.14it/s]
 78%|███████▊  | 7756/10000 [00:07<00:02, 1039.09it/s]
 79%|███████▊  | 7860/10000 [00:07<00:02, 1022.52it/s]
 80%|███████▉  | 7963/10000 [00:07<00:02, 1014.71it/s]
 81%|████████  | 8065/10000 [00:07<00:01, 996.01it/s]
 82%|████████▏ | 8165/10000 [00:07<00:01, 991.24it/s]
 83%|████████▎ | 8265/10000 [00:08<00:01, 989.69it/s]
 84%|████████▎ | 8365/10000 [00:08<00:01, 984.94it/s]
 85%|████████▍ | 8464/10000 [00:08<00:01, 986.05it/s]
 86%|████████▌ | 8563/10000 [00:08<00:01, 986.60it/s]
 87%|████████▋ | 8664/10000 [00:08<00:01, 992.36it/s]
 88%|████████▊ | 8768/10000 [00:08<00:01, 1005.33it/s]
 89%|████████▊ | 8869/10000 [00:08<00:01, 997.35it/s]
 90%|████████▉ | 8970/10000 [00:08<00:01, 999.05it/s]
 91%|█████████ | 9070/10000 [00:08<00:00, 996.28it/s]
 92%|█████████▏| 9170/10000 [00:08<00:00, 991.45it/s]
 93%|█████████▎| 9270/10000 [00:09<00:00, 973.29it/s]
 94%|█████████▎| 9369/10000 [00:09<00:00, 977.22it/s]
 95%|█████████▍| 9467/10000 [00:09<00:00, 975.42it/s]
 96%|█████████▌| 9566/10000 [00:09<00:00, 978.03it/s]
 97%|█████████▋| 9667/10000 [00:09<00:00, 985.10it/s]
 98%|█████████▊| 9766/10000 [00:09<00:00, 986.40it/s]
 99%|█████████▊| 9865/10000 [00:09<00:00, 985.70it/s]
100%|█████████▉| 9964/10000 [00:09<00:00, 984.55it/s]
100%|██████████| 10000/10000 [00:09<00:00, 1022.14it/s]
show_trajectory_full(
    projected_trajectory, one_shot, subfigure_size, sample_freq, acq=acq
)
grads, slews = compute_gradients_and_slew_rates(projected_trajectory, acq)
grad_max, slew_max = np.max(grads), np.max(slews)
print(f"Max gradient: {grad_max:.3f} T/m, Max slew rate: {slew_max:.3f} T/m/ms")
example traj projection
Max gradient: 0.040 T/m, Max slew rate: 197.972 T/m/ms

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

Gallery generated by Sphinx-Gallery