| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 |
- from types import SimpleNamespace
- from typing import Union, Tuple
- import numpy as np
- from seqgen.pypulseq.calc_rf_center import calc_rf_center
- def calc_rf_bandwidth(
- rf: SimpleNamespace,
- cutoff: float = 0.5,
- return_axis: bool = False,
- return_spectrum: bool = False,
- ) -> Union[float, Tuple[float, np.ndarray], Tuple[float, np.ndarray, float]]:
- """
- Calculate the spectrum of the RF pulse. Returns the bandwidth of the pulse (calculated by a simple FFT, e.g.
- presuming a low-angle approximation) and optionally the spectrum and the frequency axis. The default for the
- optional parameter 'cutoff' is 0.5.
- Parameters
- ----------
- rf : SimpleNamespace
- RF pulse event.
- cutoff : float, default=0.5
- return_axis : bool, default=False
- Boolean flag to indicate if frequency axis of RF pulse will be returned.
- return_spectrum : bool, default=False
- Boolean flag to indicate if spectrum of RF pulse will be returned.
- Returns
- -------
- bw : float
- Bandwidth of the RF pulse.
- """
- time_center, _ = calc_rf_center(rf)
- # Resample the pulse to a reasonable time array
- dw = 10 # Hz
- dt = 1e-6 # For now, 1 MHz
- nn = np.round(1 / dw / dt)
- tt = np.arange(-np.floor(nn / 2), np.ceil(nn / 2) - 1) * dt
- rfs = np.interp(xp=rf.t - time_center, fp=rf.signal, x=tt)
- spectrum = np.fft.fftshift(np.fft.fft(np.fft.fftshift(rfs)))
- w = np.arange(-np.floor(nn / 2), np.ceil(nn / 2) - 1) * dw
- w1 = __find_flank(w, spectrum, cutoff)
- w2 = __find_flank(w[::-1], spectrum[::-1], cutoff)
- bw = w2 - w1
- if return_spectrum and not return_axis:
- return bw, spectrum
- if return_axis:
- return bw, spectrum, w
- return bw
- def __find_flank(x, f, c):
- m = np.max(np.abs(f))
- f = np.abs(f) / m
- i = np.argwhere(f > c)[0]
- return x[i]
|