Introduction Part III - Gridding Sequences#
Imports#
[1]:
from copy import deepcopy
import numpy as np
from pint import Quantity
import matplotlib.pyplot as plt
%matplotlib inline
import sys
sys.path.insert(0, "../../..")
import cmrseq
Construct Sequence from Part I#
[2]:
system_specs = cmrseq.SystemSpec(gamma=Quantity(42.575, "MHz/T"),
grad_raster_time=Quantity(5, "us"),
max_grad=Quantity(40, "mT/m"),
max_slew=Quantity(120, "mT/m/ms"),
rf_raster_time=Quantity(5, "us"),
adc_raster_time=Quantity(0.3, "us"))
rf_excitation = cmrseq.bausteine.SincRFPulse(system_specs=system_specs,
flip_angle=Quantity(np.pi/2, "rad"),
duration=Quantity(1., "ms"),
time_bandwidth_product=4,
name="fid_excitation")
fov_x = Quantity(30, "cm")
kx_max = 2 / fov_x
prephaser_area = kx_max / system_specs.gamma
ro_prephaser = cmrseq.bausteine.TrapezoidalGradient.from_area(system_specs=system_specs,
area=prephaser_area,
orientation=np.array([-1., 0., 0.]),
name="ro_prephaser")
adc_block = cmrseq.bausteine.SymmetricADC(system_specs=system_specs,
num_samples=51,
duration=Quantity(0.8, "ms"))
ro_gradient = cmrseq.bausteine.TrapezoidalGradient.from_fdur_area(system_specs=system_specs,
orientation=np.array([1., 0., 0.]),
flat_duration=adc_block.duration,
area=prephaser_area*2,
name="ro_gradient")
ro_prephaser.shift(rf_excitation.tmax)
ro_gradient.shift(ro_prephaser.tmax)
adc_block.shift(ro_gradient.tmin + ro_gradient.rise_time)
sequence_obj = cmrseq.Sequence(building_blocks=[rf_excitation, ro_prephaser, ro_gradient, adc_block], system_specs=system_specs)
[3]:
sequence_obj.adc_to_grid()
[3]:
(array([0. , 0.005 , 0.01 , ..., 1.885 , 1.8851, 1.89 ]),
array([0., 0., 0., ..., 0., 0., 0.]),
array([0., 0., 0., ..., 0., 0., 0.]),
array([[ 217, 3040]]))
Gridding#
Gradients#
[4]:
time_raster, waveform = sequence_obj.gradients_to_grid()
print("Gridded Gradient time-raster:", time_raster.shape)
print("Gridded Gradient waveform:", waveform.shape)
f, a = plt.subplots(1, 1, figsize=(12, 4))
_ = a.plot(time_raster, waveform.T)
_ = f.suptitle("Unformated Gridded Gradient Plot")
Gridded Gradient time-raster: (379,)
Gridded Gradient waveform: (3, 379)
RF-pulses#
[5]:
time_raster, waveform = sequence_obj.rf_to_grid()
print("Gridded RF time-raster:", time_raster.shape)
print("Gridded RF waveform:", waveform.shape)
f, a = plt.subplots(1, 1, figsize=(12, 4))
_ = a.plot(time_raster, waveform.real)
_ = a.plot(time_raster, waveform.imag)
_= f.suptitle("Unformated Gridded RF Plot")
Gridded RF time-raster: (379,)
Gridded RF waveform: (379,)
ADCs#
force_raster=False
: ADC-points are inserted into gradient raster resulting in a non-uniform raster
[6]:
time_raster, adc_on, adc_phase, start_end = sequence_obj.adc_to_grid(force_raster=False)
print("Gridded ADC time-raster:", time_raster.shape)
print("Gridded ADC on events:", adc_on.shape)
print("Gridded ADC phase:", adc_phase.shape)
print("Start/End time of ADC-block:", start_end.shape)
f, a = plt.subplots(1, 1, figsize=(20, 4))
a.plot(time_raster, adc_on, "x")
a.plot(time_raster, adc_phase, "--")
a.vlines(time_raster[start_end[0]], -1, 1, colors="k")
a.set_xlim([1, 2])
_ = f.suptitle("Exact ADC-events with non-uniform raster")
Gridded ADC time-raster: (3042,)
Gridded ADC on events: (3042,)
Gridded ADC phase: (3042,)
Start/End time of ADC-block: (1, 2)
force_raster=True
: ADC-point that are not on gradient raster are not inserted, but the surrounding points are set to active
[7]:
time_raster, adc_on, adc_phase, start_end = sequence_obj.adc_to_grid(force_raster=True)
print("Gridded ADC time-raster:", time_raster.shape)
print("Gridded ADC on events:", adc_on.shape)
print("Gridded ADC phase:", adc_phase.shape)
print("Start/End time of ADC-block:", start_end.shape)
f, a = plt.subplots(1, 1, figsize=(20, 4))
a.plot(time_raster, adc_on, "x")
a.plot(time_raster, adc_phase, "--")
a.vlines(time_raster[start_end[0]], -1, 1, colors="k")
a.set_xlim([1, 2])
_ = f.suptitle("Exact ADC-events with uniform raster")
Gridded ADC time-raster: (2993,)
Gridded ADC on events: (2993,)
Gridded ADC phase: (2993,)
Start/End time of ADC-block: (1, 2)
Utility: Gridding combined#
Gridding sequences with matching temporal raster:
[8]:
time_raster, rf_raster, gradient_raster, adc_raster = cmrseq.utils.grid_sequence_list([sequence_obj, ], force_uniform_grid=False)
time_raster, rf_raster, gradient_raster, adc_raster = [np.stack(v) for v in [time_raster, rf_raster, gradient_raster, adc_raster]]
print("Gridded time-raster:", time_raster.shape)
print("Gridded rf:", rf_raster.shape, rf_raster.dtype)
print("Gridded gradient:", gradient_raster.shape)
print("Gridded ADCs:", adc_raster.shape)
Gridded time-raster: (1, 3042)
Gridded rf: (1, 3042) complex128
Gridded gradient: (1, 3042, 3)
Gridded ADCs: (1, 3042, 2)
Calculate Moments & k-space#
[9]:
first_moment = sequence_obj.calculate_moment(moment=1)
print("First Moment of all gradient channels:", first_moment)
First Moment of all gradient channels: [0.3022117831278078 0.0 0.0] millisecond ** 2 * millitesla / meter
[10]:
kspace_on_raster, k_adc, t_adc = sequence_obj.calculate_kspace()
print("K-space position for all gradient raster points:", kspace_on_raster.shape)
print("K-space positions of all ADC-events:", k_adc.shape)
print("Time points of all ADC-events:", t_adc.shape)
K-space position for all gradient raster points: (3, 379)
K-space positions of all ADC-events: (3, 51)
Time points of all ADC-events: (51,)