braintools.analysis.spectral.multitaper_psd#
- braintools.analysis.spectral.multitaper_psd(x, dt, nw=4.0, n_tapers=None, *, remove_dc=True)#
Estimate the power spectral density with DPSS (Slepian) multitapers.
The signal is multiplied by
n_tapersdiscrete prolate spheroidal sequences [1] with time-half-bandwidth productnw. The one-sided periodograms of the tapered signals are averaged with weights equal to the taper concentration ratioslambda_k(non-adaptive weighting, [2]):\[S(f) = \frac{2}{f_s} \frac{\sum_k \lambda_k |X_k(f)|^2}{\sum_k \lambda_k},\]where the factor 2 is not applied at DC and (even
T) Nyquist.- Parameters:
x (
Array|ndarray|bool|number|bool|int|float|complex|Quantity) – Real signal of shape(T, ...); time is axis 0. Abrainunit.Quantityis accepted.dt (
float|Quantity) – Sampling interval (seconds if a plain number). Static.nw (
float) – Time-half-bandwidth productNW; the frequency resolution (full bandwidth) is2 * nw / (T * dt)Hz. Static,0.5 <= nw < T / 2.n_tapers (
int|None) – Number of tapersK,1 <= K <= T. Static. Defaults toint(2 * nw) - 1(the tapers with good spectral concentration).remove_dc (
bool) – Subtract the mean of each channel before tapering (as MNE does).
- Return type:
Tuple[Array,Array|Quantity]- Returns:
freqs (jax.Array) – Frequencies in Hz, shape
(T // 2 + 1,).psd (jax.Array or brainunit.Quantity) – Power spectral density, shape
(T // 2 + 1, ...). Ifxhas unitU, the result has unitU**2 * second(U**2/Hz).
- Raises:
ValueError – If
nworn_tapersis out of range, ordtis not positive.
See also
spectrogramShort-time Fourier power spectrogram.
band_powerWelch PSD integrated over a frequency band.
Notes
The tapers are periodic (
sym=False) L2-normalised DPSS windows fromscipy.signal.windows.dpss, designed on the host. The result equalsmne.time_frequency.psd_array_multitaper( x.T, sfreq=fs, bandwidth=2 * nw * fs / T, adaptive=False, low_bias=False, normalization='full', remove_dc=True)
when
n_tapers = int(2 * nw): withlow_bias=FalseMNE keepsint(2 * nw)tapers, whereas the default here drops the last, poorly concentrated one.The function is jittable and vmappable and differentiable with respect to
x.References
Examples
>>> import jax.numpy as jnp >>> from braintools.analysis.spectral import multitaper_psd >>> t = jnp.arange(1000) * 1e-3 >>> x = jnp.sin(2 * jnp.pi * 40 * t) >>> freqs, psd = multitaper_psd(x, dt=1e-3, nw=3.0) >>> psd.shape (501,) >>> float(freqs[jnp.argmax(psd)]) 40.0