2D RF spoiled gradient echo sequence, TR = 12 ms, TE = 6 ms, FA = 60°
Dependence on the number of subvoxels in the readout direction
subvoxel = 1×1×4 (11.223 s) subvoxel = 2×1×4 (21.944 s)
subvoxel = 4×1×4 (43.421 s) subvoxel = 8×1×4 (88.215 s)
The numbers in red show the calculation time using the RTX 2080Ti.
The total number of subvoxels are 13,572,096, 27,335,680, 54,863,872, and 109,920,256.
Pulse sequence visualized by the SequenceViewer:
One data-acquisition sequence (TR = 12 ms). The amplitude of the phase encoding gradient (Gy) is maximum (-).
Entire pulse sequence. The first 100 TRs are the dummy sequences to establish the steady state. The next 256 TRs are the data-acquisition sequence. The RF pulses have phase (θ) variation for the RF spoiling: RF phase θ = n(n+1)/2 * φ (φ = 117º).
Python sequence code:
from psdk import * import numpy as np gamma = 42.57747892 # [MHz/T] TR = 12.0e+3 # [us] TE = 6.0e+3 # [us] NR = 256 # Number of readout points NPE1 = 256 # Number of 1st phase encoding fov = [220.0, 220.0, 256.0] # [mm] dwell_time = 10.0 # [us] slice_width = 5.0 # [mm] gx_value = 1e+6 / (dwell_time * gamma * fov[0]) # [mT/m] gy_value = 2e+6 / (dwell_time * gamma * fov[1]) * NPE1 / NR # [mT/m] gz_value = 1.25 / (slice_width * 1.0e-3) / gamma # [mT/m] gx_rt = 300.0 # [us] gx rise time gy_rt = 300.0 # [us] gy rise time gz_rt = 300.0 # [us] gz rise time ex_pulse_width = 3200.0 # [us] ex_pulse_flip_angle = 60.0 # [degree] def phase_shift_angle(i): phi = i * (i + 1) / 2 * 117 / 360 phi -= round(phi) return 2.0 * np.pi * phi def sinc_with_hamming(flip_angle, pulse_width, points, *, min = -2.0 * np.pi, max = 2.0 * np.pi): x0 = np.arange(min, max, (max - min) / points) x1 = x0 + (max - min) / points y = (np.sinc(x0 / np.pi) + np.sinc(x1 / np.pi)) * 0.5 * np.hamming(points) return flip_angle * y * points / (y.sum() * pulse_width * 360.0e-6 * gamma) with Sequence('2D Spoiled GRE'): with Block('Dummy', ex_pulse_width + 2.0*gz_rt): GZ(0.0, gz_value, gz_rt) RF(gz_rt, sinc_with_hamming(ex_pulse_flip_angle, ex_pulse_width, 160), ex_pulse_width / 160, phase=([phase_shift_angle(i) for i in range(100)], ['Dummy'])) GZ(ex_pulse_width + gz_rt, 0.0, gz_rt) with Block('Excitation', ex_pulse_width + 2.0*gz_rt): GZ(0.0, gz_value, gz_rt) RF(gz_rt, sinc_with_hamming(ex_pulse_flip_angle, ex_pulse_width, 160), ex_pulse_width / 160, phase=([phase_shift_angle(i+100) for i in range(NPE1)], ['PE1'])) GZ(ex_pulse_width + gz_rt, 0.0, gz_rt) with Block('PhaseEncoding', NR // 2 * dwell_time + gx_rt * 2.5): GX(0.0, -gx_value, gx_rt) GY(0.0, ([gy_value * (i - NPE1 // 2) / NPE1 for i in range(NPE1)], ['PE1']), gy_rt) GY(NR // 2 * dwell_time, 0.0, gy_rt) GX(NR // 2 * dwell_time + gx_rt * 0.5, gx_value, gx_rt * 2.0) GZ(0.0, -gz_value, gz_rt * 0.6) GZ(ex_pulse_width * 0.5 + 150, 0.0, gz_rt * 0.6) with Block('Readout', NR * dwell_time): AD(0.0, NR, dwell_time, phase=([phase_shift_angle(i+100) for i in range(NPE1)], ['PE1'])) with Block('Rewinding', NR // 2 * dwell_time + gx_rt * 2.5): GY(gx_rt * 2.5 - gy_rt, ([gy_value * (NPE1 // 2 - i) / NPE1 for i in range(NPE1)], ['PE1']), gy_rt) GX(NR // 2 * dwell_time + gx_rt * 2.5 - gx_rt, 0.0, gx_rt) GY(NR // 2 * dwell_time + gx_rt * 2.5 - gy_rt, 0.0, gy_rt) with Main(): with Loop('Dummy', 100): BlockRef('Dummy') WaitUntil(TR) with Loop('PE1', NPE1): BlockRef('Excitation') WaitUntil(TE + ex_pulse_width * 0.5 + gz_rt - NR // 2 * 2 * dwell_time - gx_rt * 2.5) BlockRef('PhaseEncoding') BlockRef('Readout') BlockRef('Rewinding') WaitUntil(TR)