2D balanced SSFP (steady state free precession). TR = 10 ms, TE = 5 ms. The image matrix is 256×256. The number of subvoxels is 1×1×4. The total number of subvoxels is 13,572,096. The calculation time was 8.8 s.

        FA = 15º                                             FA = 30º

        FA = 45º                                             FA = 60º

 

Signal intensity vs Flip angle: S ∝ sinα/(1+cosα+(1-cosα)*(T1/T2))

 

Pulse sequence visualized by the SequenceViewer:

Two data-acquisition sequence. TR = 10 ms, TE = 5 ms. The phase of the RF pulse alternates between + and –. 

 

Entire sequence. The half flip angle pulse is applied initially to shorten the time to establish the steady state.

 

Python sequence code:

from psdk import *
import numpy as np

gamma = 42.57747892 # [MHz/T]
TR = 10.0e+3 # [us]
TE = 5.0e+3 # [us]
NR = 256 # Number of readout points
NPE1 = 128 # 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 = 2.5 / (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 = 1600.0 # [us]
ex_pulse_flip_angle = 60.0 # [degree]
delta = -80.0

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 Balanced_SSFP'):

    with Block('Excitation_half-', ex_pulse_width * 1.5 + 3.5 * gz_rt):
        GZ(0.0, gz_value, gz_rt)
        RF(gz_rt, sinc_with_hamming(ex_pulse_flip_angle * 0.5, ex_pulse_width, 160), ex_pulse_width / 160, phase = np.pi)
        GZ(ex_pulse_width + gz_rt, -gz_value, gz_rt * 2.0)
        GZ(ex_pulse_width * 1.5 + gz_rt * 2.0 - delta, 0.0, gz_rt )        

    with Block('Excitation+', ex_pulse_width + 1.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 = 0.0)

    with Block('Excitation-', ex_pulse_width + 1.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 = np.pi) 

    with Block('PhaseEncoding+', 1650 + gx_rt * 2.5):
        GX(0.0, -gx_value, gx_rt)
        GY(gz_rt, ([gy_value * (2 * i - NPE1) / NPE1 for i in range(NPE1)], ['PE1']), gy_rt)
        GY(NR // 2 * dwell_time + gz_rt, 0.0, gy_rt)
        GX(1650 + gx_rt * 0.5, gx_value, gx_rt * 2.0)
        GZ(0.0, -gz_value, gz_rt * 2.0)
        GZ(ex_pulse_width * 0.5 + gz_rt * 2.0 - delta, 0.0, gz_rt) 

    with Block('PhaseEncoding-', 1650 + gx_rt * 2.5):
        GX(0.0, -gx_value, gx_rt)
        GY(gz_rt, ([gy_value * (2 * i + 1 - NPE1) / NPE1 for i in range(NPE1)], ['PE1']), gy_rt)
        GY(NR // 2 * dwell_time + gz_rt, 0.0, gy_rt)
        GX(1650 + gx_rt * 0.5, gx_value, gx_rt * 2.0)
        GZ(0.0, -gz_value, gz_rt * 2.0)
        GZ(ex_pulse_width * 0.5 + gz_rt * 2.0 - delta, 0.0, gz_rt) 

    with Block('Readout+', 1650 * 2.0):
        AD(370, NR, dwell_time, phase = 0.0)

    with Block('Readout-', 1650 * 2.0):
        AD(370, NR, dwell_time, phase = np.pi)

    with Block('Rewinding+', 1650 + gx_rt * 2.5):
        GX(0.0, -gx_value, gx_rt * 2.0)       
        GX(1650 + gx_rt * 1.5, 0.0, gx_rt)
        GY(1650 + gx_rt * 1.5 - NR // 2 * dwell_time, ([gy_value * (NPE1 - 2 * i) / NPE1 for i in range(NPE1)], ['PE1']), gy_rt)
        GY(1650 + gx_rt * 1.5, 0.0, gy_rt)
        GZ(1650 + gx_rt * 0.5 - ex_pulse_width * 0.5 + delta, -gz_value, gz_rt)
        GZ(1650 + gx_rt * 1.5, 0.0, gz_rt)

    with Block('Rewinding-', 1650 + gx_rt * 2.5):
        GX(0.0, -gx_value, gx_rt * 2.0)       
        GX(1650 + gx_rt * 1.5, 0.0, gx_rt)
        GY(1650 + gx_rt * 1.5 - NR // 2 * dwell_time, ([gy_value * (NPE1 - (i * 2 + 1)) / NPE1 for i in range(NPE1)], ['PE1']), gy_rt)
        GY(1650 + gx_rt * 1.5, 0.0, gy_rt)
        GZ(1650 + gx_rt * 0.5 - ex_pulse_width * 0.5 + delta, -gz_value, gz_rt)
        GZ(1650 + gx_rt * 1.5, 0.0, gz_rt)

    with Main():
        BlockRef('Excitation_half-')
        WaitFor(TR * 0.5 - ex_pulse_width * 1.5 - gz_rt * 3.5)
        with Loop('PE1', NPE1):
            BlockRef('Excitation+')
            BlockRef('PhaseEncoding+')
            BlockRef('Readout+')
            BlockRef('Rewinding+')
            BlockRef('Excitation-')
            BlockRef('PhaseEncoding-')
            BlockRef('Readout-')
            BlockRef('Rewinding-')