Pulseq Sequence Interpreter#

The pulseq sequence interpreter consists of two sub-components. The SequenceProvider reads all the events from a pulseq sequence and calculates RF and gradient waveform. The unrolled pulse sequence is provided as UnrolledSequence which contains the unrolled waveforms and some additional data.

See also

User guide on the sequence calculation.

Sequence Provider#

Sequence provider class.

class console.pulseq_interpreter.sequence_provider.SequenceProvider(gradient_efficiency: list[float], gpa_gain: list[float], high_impedance: list[bool], output_limits: list[int] | None = None, spcm_dwell_time: float = 5e-08, rf_to_mvolt: float = 1, system: ~pypulseq.opts.Opts = <pypulseq.opts.Opts object>)[source]#

Bases: Sequence

Sequence provider class.

This object is inherited from pulseq sequence object, so that all methods of the pypulseq Sequence object can be accessed.

The main functionality of the SequenceProvider is to unroll a given pulseq sequence. Usually the first step is to read a sequence file. The unrolling step can be achieved using the unroll_sequence() function.

Example

>>> seq = SequenceProvider()
>>> seq.read("./seq_file.seq")
>>> sqnc, gate, total_samples = seq.unroll_sequence()
add_adc_gate(block: SimpleNamespace, gate: ndarray, clk_ref: ndarray) None[source]#

Add ADC gate signal and reference signal during gate inplace to gate and reference arrays.

Parameters:
  • block – ADC event of sequence block.

  • gate – Gate array, predefined by zeros. If ADC event is present, the corresponding range is set to one.

  • clk_ref – Phase reference array, predefined by zeros. Digital signal during ADC which encodes the signal phase.

calculate_gradient(block: SimpleNamespace, unroll_arr: ndarray, fov_scaling: float) None[source]#

Calculate spectrum-card sample points of a pypulseq gradient block event.

Parameters:
  • block – Gradient block from pypulseq sequence, type must be grad or trap

  • unroll_arr – Section of numpy array which will contain the unrolled gradient event

  • fov_scaling – Scaling factor to adjust the FoV. Factor is applied to the whole gradient waveform, excepton the amplitude offset.

Return type:

Array with sample points of RF waveform as int16 values

Raises:
  • ValueError – Invalid block type (must be either grad or trap), gradient amplitude exceeds channel maximum output level

  • IndexError – Unrolled gradient waveform does not fit in unrolled array shape

calculate_rf(block: SimpleNamespace, unroll_arr: ndarray, b1_scaling: float, unblanking: ndarray, num_samples_rf_start: int = 0) None[source]#

Calculate RF sample points to be played by TX card.

Parameters:
  • block – Pulseq RF block

  • unroll_arr – Section of numpy array which will contain unrolled RF event

  • b1_scaling – Experiment dependent scaling factor of the RF amplitude

  • unblanking – Unblanking signal which is updated in-place for the calculated RF event

  • num_samples_rf_start – Number of samples until the first RF event in the sequence. This value is important to calculate the correct carrier wave phase offset.

Return type:

Array with sample points of RF waveform as int16 values

Raises:

ValueError – Invalid RF block

dict() dict[source]#

Abstract method which returns variables for logging in dictionary.

from_pypulseq(seq: Sequence) None[source]#

Cast a pypulseq Sequence instance to this SequenceProvider.

If argument is a valid Sequence instance, all the attributes of Sequence are set in this SequenceProvider (inherits from Sequence).

Parameters:

seq – Pypulseq Sequence instance

Raises:
  • ValueError – seq is not a valid pypulseq Sequence instance

  • AttributeError – Key of Sequence instance not

plot_unrolled(time_range: tuple[float, float] = (0, -1)) tuple[Figure, ndarray][source]#

Plot unrolled waveforms for replay.

Parameters:
  • time_range – Specify the time range of the plot in seconds. If the second value is smaller then the first or -1, the whole sequence is plotted.

  • (0 (default =) – Specify the time range of the plot in seconds. If the second value is smaller then the first or -1, the whole sequence is plotted.

  • -1) – Specify the time range of the plot in seconds. If the second value is smaller then the first or -1, the whole sequence is plotted.

Return type:

Matplotlib figure and axis

unroll_sequence() UnrolledSequence[source]#

Unroll the pypulseq sequence description.

TODO: Update this docstring

Parameters:
  • larmor_freq – (Larmor) frequency of the carrier RF waveform

  • b1_scaling – Factor for the RF waveform, which is to be calibrated per coil and phantom (load), by default 1.0

  • optional – Factor for the RF waveform, which is to be calibrated per coil and phantom (load), by default 1.0

  • fov_scaling – Per channel factor for the gradient waveforms to scale the field of fiew (FOV), by default Dimensions(1.0, 1.0, 1.0)

  • optional – Per channel factor for the gradient waveforms to scale the field of fiew (FOV), by default Dimensions(1.0, 1.0, 1.0)

Returns:

Instance of an unrolled sequence object which contains a list of numpy arrays with the block-wise calculated sample points in correct spectrum card order (Fortran).

The list of unrolled sequence arrays is returned as uint16 values which contain a digital signal encoded by 15th bit. Only the RF channel does not contain a digital signal. In addition, the adc and unblanking signals are returned as list of numpy arrays in the unrolled sequence instance.

Return type:

UnrolledSequence

Raises:
  • ValueError – Larmor frequency too large

  • ValueError – No block events defined

  • ValueError – Sequence timing check failed

  • ValueError – Amplitude limits not provided

Examples

For channels ch0, ch1, ch2, ch3, data values n = 0, 1, …, N are ordered the following way.

>>> data = [ch0_0, ch1_0, ch2_0, ch3_0, ch0_1, ch1_1, ..., ch0_n, ..., ch3_N]

Per channel data can be extracted by the following code.

>>> rf = seq[0::4]
>>> gx = (seq[1::4] << 1).astype(np.int16)
>>> gy = (seq[2::4] << 1).astype(np.int16)
>>> gz = (seq[3::4] << 1).astype(np.int16)

All the gradient channels contain a digital signal encoded by the 15th bit. - gx: ADC gate signal - gy: Reference signal for phase correction - gz: RF unblanking signal The following example shows, how to extract the digital signals

>>> adc_gate = seq[1::4].astype(np.uint16) >> 15
>>> reference = seq[2::4].astype(np.uint16) >> 15
>>> unblanking = seq[3::4].astype(np.uint16) >> 15

As the 15th bit is not encoding the sign (as usual for int16), the values are casted to uint16 before shifting.

console.pulseq_interpreter.sequence_provider.profile(func: Callable[[...], Any]) Callable[[...], Any][source]#

Define placeholder for profile decorator.

Unrolled Sequence#

Interface class for an unrolled sequence.

class console.interfaces.unrolled_sequence.UnrolledSequence(seq: list, adc_gate: list, rf_unblanking: list, sample_count: int, gpa_gain: list[float], gradient_efficiency: list[float], rf_to_mvolt: float, dwell_time: float, larmor_frequency: float, duration: float, adc_count: int)[source]#

Bases: object

Unrolled sequence interface.

This interface is used to share the unrolled sequence between the different components like TxEngine, SequenceProvider and AcquisitionControl. An unrolled sequence is generated by a SequenceProvider() instance using the unroll_sequence function.

adc_count: int#

Number of adc events in the sequence.

adc_gate: list#

ADC gate signal in binary logic where 0 corresponds to ADC gate off and 1 to ADC gate on.

duration: float#

Total duration of the unrolled sequence in s.

dwell_time: float#

Dwell time of the spectrum card replay data (unrolled sequence). Defines the distance in time between to sample points. Note that this dwell time does not correlate to the larmor frequecy. Due to the sampling theorem dwell_time < 1/(2*larmor_frequency) must be satisfied. Usually a higher factor is chosen.

gpa_gain: list[float]#

The gradient waveforms in pulseq are defined in Hz/m. The translation to mV is calculated by 1e3 / (gyro * gpa_gain * grad_efficiency). The gpa gain is given in V/A and accounts for the voltage required to generate an output of 1A. The gyromagnetic ratio defined by 42.58e6 MHz/T.

gradient_efficiency: list[float]#

The gradient waveforms in pulseq are defined in Hz/m. The translation to mV is calculated by 1e3 / (gyro * gpa_gain * grad_efficiency). The gradient efficiency is given in mT/m/A and accounts for the gradient field which is generated per 1A. The gyromagnetic ratio defined by 42.58e6 MHz/T.

larmor_frequency: float#

Larmor frequency of the MR scanner which defines the frequency of the RF pulse carrier signal.

rf_to_mvolt: float#

If sequence values are given as float values, they can be interpreted as output voltage [mV] directly. This conversion factor represents the scaling from original pulseq RF values [Hz] to card output voltage.

rf_unblanking: list#

Unblanking signal for the RF power amplifier (RFPA) in binary logic. 0 corresponds to blanking state and 1 to unblanking state.

sample_count: int#

Total number of samples per channel.

seq: list#

Replay data as int16 values in a list of numpy arrays. The sequence data already contains the digital adc and unblanking signals in the channels gx and gy.