The multiple spin echo sequence. TR = 6000 ms, TE = 12 ms. The image matrix is 256×256.The number of subvoxels was 1×1×4, 1×1×8, 1×1×16, and 1×1×32. The total number of subvoxels was 13,572,096, 27,174,912, 54,381,568, and 108,793,856. The calculation time was 255.0, 502.7, 978.7, and 1922.4 s using RTX 2080Ti.

Simulation result for subvoxels = 1×1×16.

 

Image intensity vs echo time:

The number of subvoxels = 1×1×4 (sufficient for 4 echoes).

 

The number of subvoxels = 1×1×8 (sufficient for 8 echoes).

 

The number of subvoxels = 1×1×16 (sufficient).

 

The number of subvoxels = 1×1×32 (too much).

 

Pulse sequence chart visualized by the SequenceViewer:

One data acquisition sequence.

 

Python sequence code:

from psdk import *
import numpy as np

gamma = 42.57747892 # [MHz/T]
TR = 4800.0e+3 # [us]
TE = 12.0e+3 # [us]
NR = 256 # Number of readout points
NPE1 = 256 # Number of 1st phase encoding
NEcho = 16 # Number of echoes
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
PW = 3200.0 # [us]
ex_pulse_flip_angle = 90.0 # [degree]

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 multiple SpinEcho'):

    with Block('Excitation', PW + 2.0 * gz_rt):
        GZ(0.0, gz_value, gz_rt)
        RF(gz_rt, sinc_with_hamming(90, PW, 160 * 2), PW / (160 * 2), phase = 0.0)
        GZ(PW + gz_rt, 0.0, gz_rt)

    with Block('Slice_refocus+Prephasing', NR // 2 * dwell_time + gx_rt * 2.0 ):    
         GX(0.0, gx_value, gx_rt)
         GX(NR * dwell_time, 0.0, gx_rt)   
         GZ(0.0, -gz_value, gz_rt)
         GZ(PW * 0.5 + gz_rt, 0.0, gz_rt)              

    with Block('Refocus', PW + 2.0 * gz_rt):
        GZ(0.0, gz_value, gz_rt)
        RF(gz_rt, sinc_with_hamming(180, PW, 160 * 2), PW / (160 * 2), phase = 0.5 * np.pi)
        GZ(PW + gz_rt, 0.0, gz_rt)

    with Block('Phase_encoding+Acquisition', TE/2 + 1.5 * NR * dwell_time - PW * 0.5 - gz_rt - gx_rt + gy_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(TE/2 - PW * 0.5 - gz_rt - NR * dwell_time - 0.5 * gx_rt, gx_value, gx_rt)
        AD(TE/2 - PW * 0.5 - gz_rt - NR // 2 * dwell_time, NR, dwell_time)
        GX(TE/2 - PW * 0.5 - gz_rt + NR * dwell_time - gx_rt * 0.5, 0, gx_rt)
        GY(TE/2 - PW * 0.5 - gz_rt + NR * dwell_time - gx_rt * 0.5, ([-gy_value * (i - NPE1 // 2) / NPE1 for i in range(NPE1)], ['PE1']), gy_rt)
        GY(TE/2 - PW * 0.5 - gz_rt + NR * dwell_time - gx_rt * 0.5 + NR // 2 * dwell_time, 0.0, gy_rt)

    with Main():
        with Loop("PE1", NPE1):
            BlockRef("Excitation")
            BlockRef("Slice_refocus+Prephasing")
            WaitUntil(TE * 0.5)
            with Loop("Echo", NEcho):
                BlockRef("Refocus")
                BlockRef('Phase_encoding+Acquisition')
                WaitUntil(TE * 1.0)
            WaitUntil(TR)