calc_rf_bandwidth

calc_rf_bandwidth#

pypulseqpp.calc_rf_bandwidth()[source]#

Estimate RF bandwidth from the envelope’s Fourier magnitude.

Uses the outermost crossings at cutoff times the peak, with linear interpolation between bins. This is a small-tip approximation, not a Bloch simulation. Frequency offsets shift the returned axis without changing the measured width; ppm offsets use the default system’s gamma and B0. A dynamic pTx pulse is measured as the sum of its channels over their shared time base: the pulse a location equally and in-phase sensitive to every channel sees, as its flip angle is counted.

Parameters:
  • rf (SimpleNamespace or RfEvent) – The RF event.

  • cutoff (float, default=0.5) – Fraction of the peak the flanks are measured at.

  • return_axis (bool, default=False) – Also return the frequency axis.

  • return_spectrum (bool, default=False) – Also return the spectrum.

  • dw (float, default=10) – Spectral resolution, in Hz.

  • dt (float, default=None) – Sampling step, in seconds. The default system’s RF raster when omitted.

  • compat (bool, default=True) – Return upstream’s values, which a drop-in caller unpacks. False returns an RfBandwidth carrying the bandwidth, the spectrum, its axis and the bands, whatever return_axis and return_spectrum say.

  • band_cutoff (float, default=0.3) – Fraction of the peak above which a run of spectral bins is a band. Read only when compat is False.

Returns:

  • bw (float) – The bandwidth, in Hz. A scalar, where upstream hands back the one-element array its flank search indexes with.

  • spectrum (numpy.ndarray, optional) – Present when return_spectrum, second.

  • w (numpy.ndarray, optional) – Present when return_axis: second on its own, third alongside a spectrum. Centred on where the pulse is tuned.

  • RfBandwidth – In place of the above when compat is False.

Examples

>>> import numpy as np
>>> import pypulseqpp as pp
>>> sinc = pp.make_sinc_pulse(flip_angle=np.pi / 2, duration=2e-3, time_bw_product=4)
>>> abs(pp.calc_rf_bandwidth(sinc) - 4 / 2e-3) < 0.1 * 4 / 2e-3
True

A hard pulse is as wide as its duration is short:

>>> hard = pp.make_block_pulse(flip_angle=np.pi / 2, duration=1e-3)
>>> abs(pp.calc_rf_bandwidth(hard) - 1.207 / 1e-3) < 0.1 * 1.207 / 1e-3
True

And an SLR pulse is as wide as its time-bandwidth product says:

>>> slr = pp.make_slr_pulse(np.pi / 9, duration=3e-3, time_bw_product=6)
>>> abs(pp.calc_rf_bandwidth(slr) - 6 / 3e-3) < 0.1 * 6 / 3e-3
True

Retuning a pulse moves its band and leaves its width alone:

>>> sinc.freq_offset = 1500.0
>>> abs(pp.calc_rf_bandwidth(sinc) - 4 / 2e-3) < 0.1 * 4 / 2e-3
True

Without compat, the bands of a simultaneous multi-slice pulse are reported with their offsets from the carrier:

>>> base = pp.make_sinc_pulse(flip_angle=np.pi / 6, duration=2e-3, time_bw_product=4)
>>> sms, offsets, _ = pp.make_sms_pulse(base, 3, 5000.0)
>>> result = pp.calc_rf_bandwidth(sms, compat=False)
>>> result.num_bands, np.round(result.band_offsets).astype(int).tolist()
(3, [-5000, 0, 5000])

See also

sim_rf

the simulated profile, valid at any flip angle.