| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 |
- import numpy as np
- from matplotlib import pyplot as plt
- import pypulseq as pp
- """
- Read a sequence into MATLAB. The `Sequence` class provides an implementation of the _open file format_ for MR sequences
- described here: http://pulseq.github.io/specification.pdf. This example demonstrates parsing an MRI sequence stored in
- this format, accessing sequence parameters and visualising the sequence.
- """
- # Read a sequence file - a sequence can be loaded from the open MR file format using the `read` method.
- seq_name = "epi_rs.seq"
- system = pp.Opts(
- B0=2.89
- ) # Need system here if we want 'detectRFuse' to detect fat-sat pulses
- seq = pp.Sequence(system)
- seq.read(seq_name, detect_rf_use=True)
- # Sanity check to see if the reading and writing are consistent
- seq.write("read_test.seq")
- # os_system(f'diff -s -u {seq_name} read_test.seq -echo') # Linux only
- """
- Access sequence parameters and blocks. Parameters defined with in the `[DEFINITIONS]` section of the sequence file
- are accessed with the `get_definition()` method. These are user-specified definitions and do not effect the execution of
- the sequence.
- """
- seq_name = seq.get_definition("Name")
- # Calculate and display real TE, TR as well as slew rates and gradient amplitudes
- test_report = seq.test_report()
- print(test_report)
- # Sequence blocks are accessed with the `get_block()` method. As shown in the output the first block is a selective
- # excitation block and contains an RF pulse and gradient and on the z-channel.
- b1 = seq.get_block(1)
- # Further information about each event can be obtained by accessing the appropriate fields of the block struct. In
- # particular, the complex RF signal is stored in the field `signal`.
- rf = b1.rf
- plt.subplot(211)
- plt.plot(rf.t, np.abs(rf.signal))
- plt.ylabel("RF magnitude")
- plt.subplot(212)
- plt.plot(1e3 * rf.t, np.angle(rf.signal))
- plt.xlabel("t (ms)")
- plt.ylabel("RF phase")
- # The next three blocks contain: three gradient events; a delay; and readout gradient with ADC event, each with
- # corresponding fields defining the details of the events.
- b2 = seq.get_block(2)
- b3 = seq.get_block(3)
- b4 = seq.get_block(4)
- # Plot the sequence. Visualise the sequence using the `plot()` method of the class. This creates a new figure and shows
- # ADC, RF and gradient events. The axes are linked so zooming is consistent. In this example, a simple gradient echo
- # sequence for MRI is displayed.
- # seq.plot()
- """
- The details of individual pulses are not well-represented when the entire sequence is visualised. Interactive zooming
- is helpful here. Alternatively, a time range can be specified. An additional parameter also allows the display units to
- be changed for easy reading. Further, the handle of the created figure can be returned if required.
- """
- # seq.plot(time_range=[0, 16e-3], time_disp='ms')
- """
- Modifying sequence blocks. In addition to loading a sequence and accessing sequence blocks, blocks # can be modified.
- In this example, a Hamming window is applied to the # first RF pulse of the sequence and the flip angle is changed to
- 45 degrees. The remaining RF pulses are unchanged.
- """
- rf2 = rf
- duration = rf2.t[-1]
- t = rf2.t - duration / 2 # Centre time about 0
- alpha = 0.5
- BW = 4 / duration # Time bandwidth product = 4
- window = 1.0 - alpha + alpha * np.cos(2 * np.pi * t / duration) # Hamming window
- signal = window * np.sinc(BW * t)
- # Normalise area to achieve 2*pi rotation
- signal = signal / (seq.rf_raster_time * np.sum(np.real(signal)))
- # Scale to 45 degree flip angle
- rf2.signal = signal * 45 / 360
- b1.rf = rf2
- seq.set_block(1, b1)
- # Second check to see what has changed
- seq.write("read_test2.seq")
- # os_system(f'diff -s -u {seq_name} read_test2.seq -echo') # Linux only
- # The amplitude of the first rf pulse is reduced due to the reduced flip-angle. Notice the reduction is not exactly a
- # factor of two due to the windowing function.
- amp1_in_Hz = max(abs(seq.get_block(1).rf.signal))
- amp2_in_Hz = max(abs(seq.get_block(6).rf.signal))
|