gr7_amp = [gr_acq.amplitude, gr_spr.amplitude, gr_spr.amplitude, 0] gr7 = pp.make_extended_trapezoid(channel='x', times=gr7_times, amplitudes=gr7_amp) # Fill-times t_ex = gs1.t[-1] + gs2.t[-1] + gs3.t[-1] t_ref = gs4.t[-1] + gs5.t[-1] + gs7.t[-1] + readout_time t_end = gs4.t[-1] + gs5.t[-1] TE_train = t_ex + n_echo * t_ref + t_end TR_fill = (TR - n_slices * TE_train) / n_slices TR_fill = system.grad_raster_time * round(TR_fill / system.grad_raster_time) # Round to gradient raster if TR_fill < 0: TR_fill = 1e-3 warnings.warn(f'TR too short, adapted to include all slices to: {1000 * n_slices * (TE_train + TR_fill)} ms') else: print(f'TR fill: {1000 * TR_fill} ms') delay_TR = pp.make_delay(TR_fill) # ====== # CONSTRUCT SEQUENCE # ====== for k_ex in range(n_ex + 1): for s in range(n_slices): rf_ex.freq_offset = gs_ex.amplitude * slice_thickness * (s - (n_slices - 1) / 2) rf_ref.freq_offset = gs_ref.amplitude * slice_thickness * (s - (n_slices - 1) / 2) rf_ex.phase_offset = rf_ex_phase - 2 * np.pi * rf_ex.freq_offset * pp.calc_rf_center(rf_ex)[0] rf_ref.phase_offset = rf_ref_phase - 2 * np.pi * rf_ref.freq_offset * pp.calc_rf_center(rf_ref)[0] seq.add_block(gs1) seq.add_block(gs2, rf_ex) seq.add_block(gs3, gr3)
# Calculate delay time TE = 60e-3 duration_to_center = (Nx / 2 + 0.5) * pp.calc_duration(gx) + Ny / 2 * pp.calc_duration(gy) rf_center_incl_delay = rf.delay + pp.calc_rf_center(rf)[0] rf180_center_incl_delay = rf180.delay + pp.calc_rf_center(rf180)[0] delay_TE1 = TE / 2 - pp.calc_duration(gz) + rf_center_incl_delay - pre_time - pp.calc_duration( gz_spoil) - rf180_center_incl_delay delay_TE2 = TE / 2 - pp.calc_duration(rf180) + rf180_center_incl_delay - pp.calc_duration(gz_spoil) - duration_to_center # ====== # CONSTRUCT SEQUENCE # ====== # Define sequence blocks seq.add_block(rf, gz) seq.add_block(gx_pre, gy_pre, gz_reph) seq.add_block(pp.make_delay(delay_TE1)) seq.add_block(gz_spoil) seq.add_block(rf180) seq.add_block(gz_spoil) seq.add_block(pp.make_delay(delay_TE2)) for i in range(Ny): seq.add_block(gx, adc) # Read one line of k-space seq.add_block(gy) # Phase blip gx.amplitude = -gx.amplitude # Reverse polarity of read gradient seq.add_block(pp.make_delay(1e-4)) # ====== # VISUALIZATION # ====== seq.plot()
# Insert adiabatic inversion here if chosen - 12 ms - for demo purposes only for i in range(Ny): for j in range(len(TE)): rf.phase_offset = rf_phase / 180 * np.pi adc.phase_offset = rf_phase / 180 * np.pi rf_inc = divmod(rf_inc + rf_spoiling_inc, 360.0)[1] rf_phase = divmod(rf_phase + rf_inc, 360.0)[1] if ext_pulse_type == 'hypsec': if np.mod(i, 64) == 0: print('Mag prep now') for n in range(len(rf_inv)): seq.add_block(rf_inv[n]) seq.add_block(pp.make_delay(300e-3)) # seq.plot() seq.add_block(rf, gz) gy_pre = pp.make_trapezoid(channel='y', area=phase_areas[i], duration=pp.calc_duration(gx_pre), system=system) seq.add_block(gx_pre, gy_pre, gz_reph) seq.add_block(pp.make_delay(delay_TE[j])) seq.add_block(gx, adc) gy_pre.amplitude = -gy_pre.amplitude seq.add_block(pp.make_delay(delay_TR[j]), gx_spoil, gy_pre, gz_spoil) ok, error_report = seq.check_timing(
grc = copy(gx) grs = copy(gx) grc.amplitude = gx.amplitude * np.cos(phi) grs.amplitude = gx.amplitude * np.sin(phi) grs.channel = 'y' gsc = copy(gx_spoil) gss = copy(gx_spoil) gsc.amplitude = gx_spoil.amplitude * np.cos(phi) gss.amplitude = gx_spoil.amplitude * np.sin(phi) gss.channel = 'y' seq.add_block(gpc, gps, gz_reph) seq.add_block(grc, grs, adc) seq.add_block(gsc, gss, pp.make_delay(delay_TR)) # ====== # VISUALIZATION # ====== seq.plot() # Plot gradients to check for gaps and optimality of the timing gw = seq.gradient_waveforms() plt.plot(gw.T) # Plot the entire gradient shape # Trajectory calculation ktraj_adc, ktraj, t_excitation, t_refocusing, t_adc = seq.calculate_kspace() # Plot k-spaces time_axis = np.arange(ktraj.shape[1]) * seq.grad_raster_time
gx_pre.delay = 0 gx_pre.delay = delay_TE2 - pp.calc_duration(gx_pre) assert (gx_pre.delay >= pp.calc_duration(rf180)) # gx_pre may not overlap with the RF gy_pre.delay = pp.calc_duration(rf180) assert (pp.calc_duration(gy_pre) <= pp.calc_duration(gx_pre)) # gyPre may not shift the timing # ====== # CONSTRUCT SEQUENCE # ====== # Define sequence blocks for s in range(n_slices): seq.add_block(rf_fs, gz_fs) rf.freq_offset = gz.amplitude * slice_thickness * (s - (n_slices - 1) / 2) rf180.freq_offset = gz180.amplitude * slice_thickness * (s - (n_slices - 1) / 2) seq.add_block(rf, gz, trig) seq.add_block(pp.make_delay(delay_TE1)) seq.add_block(rf180, gz180n, pp.make_delay(delay_TE2), gx_pre, gy_pre) for i in range(1, Ny_meas + 1): if i == 1: seq.add_block(gx, gy_blipup, adc) # Read the first line of k-space with a single half-blip at the end elif i == Ny_meas: # Read the last line of k-space with a single half-blip at the beginning seq.add_block(gx, gy_blipdown, adc) else: # Read an intermediate line of k-space with a half-blip at the beginning and a half-blip at the end seq.add_block(gx, gy_blipdownup, adc) gx.amplitude = -gx.amplitude # Reverse polarity of read gradient ok, error_report = seq.check_timing() # Check whether the timing of the sequence is correct if ok: print('Timing check passed successfully')
# CONSTRUCT SEQUENCE # ====== # Loop over slices for s in range(n_slices): rf.freq_offset = gz.amplitude * slice_thickness * (s - (n_slices - 1) / 2) # Loop over phase encodes and define sequence blocks for i in range(Ny): rf.phase_offset = rf_phase / 180 * np.pi adc.phase_offset = rf_phase / 180 * np.pi rf_inc = divmod(rf_inc + rf_spoiling_inc, 360.0)[1] rf_phase = divmod(rf_phase + rf_inc, 360.0)[1] seq.add_block(rf, gz) gy_pre = pp.make_trapezoid(channel='y', area=phase_areas[i], duration=pp.calc_duration(gx_pre), system=system) seq.add_block(gx_pre, gy_pre, gz_reph) seq.add_block(pp.make_delay(delay_TE)) seq.add_block(gx, adc) gy_pre.amplitude = -gy_pre.amplitude spoil_block_contents = [pp.make_delay(delay_TR), gx_spoil, gy_pre, gz_spoil] if i != Ny - 1: spoil_block_contents.append(pp.make_label(type='INC', label='LIN', value=1)) else: spoil_block_contents.extend([pp.make_label(type='SET', label='LIN', value=0), pp.make_label(type='INC', label='SLC', value=1)]) seq.add_block(*spoil_block_contents) ok, error_report = seq.check_timing() if ok: print('Timing check passed successfully') else: