Source code for pyrfu.pyrf.psd

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Built-in imports
import logging

# 3rd party imports
import numpy as np
import xarray as xr
from scipy import signal

__author__ = "Louis Richard"
__email__ = "louisr@irfu.se"
__copyright__ = "Copyright 2020-2023"
__license__ = "MIT"
__version__ = "2.4.2"
__status__ = "Prototype"


[docs]def psd( inp, n_fft: int = 256, n_overlap: int = 128, window: str = "hamming", d_flag: str = "constant", scaling: str = "density", ): r"""Estimate power spectral density using Welch's method. Welch's method [11]_ computes an estimate of the power spectral density by dividing the data into overlapping segments, computing a modified periodogram for each segment and averaging the periodograms. Parameters ---------- inp : xarray.DataArray Time series of measurement values. n_fft : int, Optional Length of the FFT used, if a zero padded FFT is desired. Default to 256. n_overlap : int, Optional Number of points to overlap between segments. Default to 128. window : str, Optional Desired window to use. It is passed to `get_window` to generate the window values, which are DFT-even by default. See "get_window" or a list of windows and required parameters. Default Hanning d_flag : str, Optional Specifies how to detrend each segment. It is passed as the "type" argument to the"detrend" function. Default to "constant". scaling : str, Optional Selects between computing the power spectral density ('density') where `Pxx` has units of V**2/Hz and computing the power spectrum ("spectrum") where "Pxx" has units of V**2, if `x` is measured in V and "fs" is measured in Hz. Default to 'density' Returns ------- out : xarray.DataArray Power spectral density or power spectrum of inp. References ---------- .. [11] P. Welch, "The use of the fast Fourier transform for the estimation of power spectra: A method based on time averaging over short, modified periodograms", IEEE Trans. Audio Electroacoust. vol. 15, pp. 70-73, 1967. """ if inp.ndim == 2 and inp.shape[-1] == 3: inp = np.abs(inp) if n_overlap is None: n_persegs = 256 n_overlap = n_persegs / 2 else: n_persegs = 2 * n_overlap if n_fft < n_persegs: n_fft = n_persegs logging.warning("nfft < n_persegs. set to n_persegs") f_samp = 1e9 / np.median(np.diff(inp.time.data)).astype(np.float64) freqs, p_xx = signal.welch( inp.data, nfft=n_fft, fs=f_samp, window=window, noverlap=n_overlap, detrend=d_flag, nperseg=n_persegs, scaling=scaling, return_onesided=True, axis=-1, ) out = xr.DataArray(p_xx, coords=[freqs], dims=["f"]) return out