Participer au site avec un Tip
Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Vous êtes un professionnel et vous avez besoin d'une formation ? Calcul scientifique
avec Python
Voir le programme détaillé
Module « scipy.signal »

Classe « ShortTimeFFT »

Informations générales

Héritage

builtins.object
    ShortTimeFFT

Définition

class ShortTimeFFT(builtins.object):

help(ShortTimeFFT)

Provide a parametrized discrete Short-time Fourier transform (stft)
and its inverse (istft).

.. currentmodule:: scipy.signal.ShortTimeFFT

The `~ShortTimeFFT.stft` calculates sequential FFTs by sliding a
window (`win`) over an input signal by `hop` increments. It can be used to
quantify the change of the spectrum over time.

The `~ShortTimeFFT.stft` is represented by a complex-valued matrix S[q,p]
where the p-th column represents an FFT with the window centered at the
time t[p] = p * `delta_t` = p * `hop` * `T` where `T` is  the sampling
interval of the input signal. The q-th row represents the values at the
frequency f[q] = q * `delta_f` with `delta_f` = 1 / (`mfft` * `T`) being
the bin width of the FFT.

The inverse STFT `~ShortTimeFFT.istft` is calculated by reversing the steps
of the STFT: Take the IFFT of the p-th slice of S[q,p] and multiply the
result with the so-called dual window (see `dual_win`). Shift the result by
p * `delta_t` and add the result to previous shifted results to reconstruct
the signal. If only the dual window is known and the STFT is invertible,
`from_dual` can be used to instantiate this class.

Due to the convention of time t = 0 being at the first sample of the input
signal, the STFT values typically have negative time slots. Hence,
negative indexes like `p_min` or `k_min` do not indicate counting
backwards from an array's end like in standard Python indexing but being
left of t = 0.

More detailed information can be found in the :ref:`tutorial_stft` section
of the :ref:`user_guide`.

Note that all parameters of the initializer, except `scale_to` (which uses
`scaling`) have identical named attributes.

Parameters
----------
win : np.ndarray
    The window must be a real- or complex-valued 1d array.
hop : int
    The increment in samples, by which the window is shifted in each step.
fs : float
    Sampling frequency of input signal and window. Its relation to the
    sampling interval `T` is ``T = 1 / fs``.
fft_mode : 'twosided', 'centered', 'onesided', 'onesided2X'
    Mode of FFT to be used (default 'onesided').
    See property `fft_mode` for details.
mfft: int | None
    Length of the FFT used, if a zero padded FFT is desired.
    If ``None`` (default), the length of the window `win` is used.
dual_win : np.ndarray | None
    The dual window of `win`. If set to ``None``, it is calculated if
    needed.
scale_to : 'magnitude', 'psd' | None
    If not ``None`` (default) the window function is scaled, so each STFT
    column represents  either a 'magnitude' or a power spectral density
    ('psd') spectrum. This parameter sets the property `scaling` to the
    same value. See method `scale_to` for details.
phase_shift : int | None
    If set, add a linear phase `phase_shift` / `mfft` * `f` to each
    frequency `f`. The default value 0 ensures that there is no phase shift
    on the zeroth slice (in which t=0 is centered). See property
    `phase_shift` for more details.

Examples
--------
The following example shows the magnitude of the STFT of a sine with
varying frequency :math:`f_i(t)` (marked by a red dashed line in the plot):

>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> from scipy.signal import ShortTimeFFT
>>> from scipy.signal.windows import gaussian
...
>>> T_x, N = 1 / 20, 1000  # 20 Hz sampling rate for 50 s signal
>>> t_x = np.arange(N) * T_x  # time indexes for signal
>>> f_i = 1 * np.arctan((t_x - t_x[N // 2]) / 2) + 5  # varying frequency
>>> x = np.sin(2*np.pi*np.cumsum(f_i)*T_x) # the signal

The utilized Gaussian window is 50 samples or 2.5 s long. The parameter
``mfft=200`` in `ShortTimeFFT` causes the spectrum to be oversampled
by a factor of 4:

>>> g_std = 8  # standard deviation for Gaussian window in samples
>>> w = gaussian(50, std=g_std, sym=True)  # symmetric Gaussian window
>>> SFT = ShortTimeFFT(w, hop=10, fs=1/T_x, mfft=200, scale_to='magnitude')
>>> Sx = SFT.stft(x)  # perform the STFT

In the plot, the time extent of the signal `x` is marked by vertical dashed
lines. Note that the SFT produces values outside the time range of `x`. The
shaded areas on the left and the right indicate border effects caused
by  the window slices in that area not fully being inside time range of
`x`:

>>> fig1, ax1 = plt.subplots(figsize=(6., 4.))  # enlarge plot a bit
>>> t_lo, t_hi = SFT.extent(N)[:2]  # time range of plot
>>> ax1.set_title(rf"STFT ({SFT.m_num*SFT.T:g}$\,s$ Gaussian window, " +
...               rf"$\sigma_t={g_std*SFT.T}\,$s)")
>>> ax1.set(xlabel=f"Time $t$ in seconds ({SFT.p_num(N)} slices, " +
...                rf"$\Delta t = {SFT.delta_t:g}\,$s)",
...         ylabel=f"Freq. $f$ in Hz ({SFT.f_pts} bins, " +
...                rf"$\Delta f = {SFT.delta_f:g}\,$Hz)",
...         xlim=(t_lo, t_hi))
...
>>> im1 = ax1.imshow(abs(Sx), origin='lower', aspect='auto',
...                  extent=SFT.extent(N), cmap='viridis')
>>> ax1.plot(t_x, f_i, 'r--', alpha=.5, label='$f_i(t)$')
>>> fig1.colorbar(im1, label="Magnitude $|S_x(t, f)|$")
...
>>> # Shade areas where window slices stick out to the side:
>>> for t0_, t1_ in [(t_lo, SFT.lower_border_end[0] * SFT.T),
...                  (SFT.upper_border_begin(N)[0] * SFT.T, t_hi)]:
...     ax1.axvspan(t0_, t1_, color='w', linewidth=0, alpha=.2)
>>> for t_ in [0, N * SFT.T]:  # mark signal borders with vertical line:
...     ax1.axvline(t_, color='y', linestyle='--', alpha=0.5)
>>> ax1.legend()
>>> fig1.tight_layout()
>>> plt.show()

Reconstructing the signal with the `~ShortTimeFFT.istft` is
straightforward, but note that the length of `x1` should be specified,
since the SFT length increases in `hop` steps:

>>> SFT.invertible  # check if invertible
True
>>> x1 = SFT.istft(Sx, k1=N)
>>> np.allclose(x, x1)
True

It is possible to calculate the SFT of signal parts:

>>> p_q = SFT.nearest_k_p(N // 2)
>>> Sx0 = SFT.stft(x[:p_q])
>>> Sx1 = SFT.stft(x[p_q:])

When assembling sequential STFT parts together, the overlap needs to be
considered:

>>> p0_ub = SFT.upper_border_begin(p_q)[1] - SFT.p_min
>>> p1_le = SFT.lower_border_end[1] - SFT.p_min
>>> Sx01 = np.hstack((Sx0[:, :p0_ub],
...                   Sx0[:, p0_ub:] + Sx1[:, :p1_le],
...                   Sx1[:, p1_le:]))
>>> np.allclose(Sx01, Sx)  # Compare with SFT of complete signal
True

It is also possible to calculate the `itsft` for signal parts:

>>> y_p = SFT.istft(Sx, N//3, N//2)
>>> np.allclose(y_p, x[N//3:N//2])
True

Constructeur(s)

Signature du constructeur Description
__init__(self, win: numpy.ndarray, hop: int, fs: float, *, fft_mode: Literal['twosided', 'centered', 'onesided', 'onesided2X'] = 'onesided', mfft: int | None = None, dual_win: numpy.ndarray | None = None, scale_to: Optional[Literal['magnitude', 'psd']] = None, phase_shift: int | None = 0)

Liste des propriétés

Nom de la propriétéDescription
delta_fWidth of the frequency bins of the STFT. [extrait de delta_f.__doc__]
delta_tTime increment of STFT. [extrait de delta_t.__doc__]
dual_winCanonical dual window. [extrait de dual_win.__doc__]
fFrequencies values of the STFT. [extrait de f.__doc__]
f_ptsNumber of points along the frequency axis. [extrait de f_pts.__doc__]
fac_magnitudeFactor to multiply the STFT values by to scale each frequency slice [extrait de fac_magnitude.__doc__]
fac_psdFactor to multiply the STFT values by to scale each frequency slice [extrait de fac_psd.__doc__]
fft_modeMode of utilized FFT ('twosided', 'centered', 'onesided' or [extrait de fft_mode.__doc__]
fsSampling frequency of input signal and of the window. [extrait de fs.__doc__]
hopTime increment in signal samples for sliding window. [extrait de hop.__doc__]
invertibleCheck if STFT is invertible. [extrait de invertible.__doc__]
k_minThe smallest possible signal index of the STFT. [extrait de k_min.__doc__]
lower_border_endFirst signal index and first slice index unaffected by pre-padding. [extrait de lower_border_end.__doc__]
m_numNumber of samples in window `win`. [extrait de m_num.__doc__]
m_num_midCenter index of window `win`. [extrait de m_num_mid.__doc__]
mfftLength of input for the FFT used - may be larger than window [extrait de mfft.__doc__]
onesided_fftReturn True if a one-sided FFT is used. [extrait de onesided_fft.__doc__]
p_minThe smallest possible slice index. [extrait de p_min.__doc__]
phase_shiftIf set, add linear phase `phase_shift` / `mfft` * `f` to each FFT [extrait de phase_shift.__doc__]
scalingNormalization applied to the window function [extrait de scaling.__doc__]
TSampling interval of input signal and of the window. [extrait de T.__doc__]
winWindow function as real- or complex-valued 1d array. [extrait de win.__doc__]

Liste des opérateurs

Opérateurs hérités de la classe object

__eq__, __ge__, __gt__, __le__, __lt__, __ne__

Liste des méthodes

Toutes les méthodes Méthodes d'instance Méthodes statiques Méthodes dépréciées
Signature de la méthodeDescription
extent(self, n: int, axes_seq: Literal['tf', 'ft'] = 'tf', center_bins: bool = False) -> tuple[float, float, float, float] Return minimum and maximum values time-frequency values. [extrait de extent.__doc__]
from_dual(dual_win: numpy.ndarray, hop: int, fs: float, *, fft_mode: Literal['twosided', 'centered', 'onesided', 'onesided2X'] = 'onesided', mfft: int | None = None, scale_to: Optional[Literal['magnitude', 'psd']] = None, phase_shift: int | None = 0) Instantiate a `ShortTimeFFT` by only providing a dual window. [extrait de from_dual.__doc__]
from_window(win_param: str | tuple | float, fs: float, nperseg: int, noverlap: int, *, symmetric_win: bool = False, fft_mode: Literal['twosided', 'centered', 'onesided', 'onesided2X'] = 'onesided', mfft: int | None = None, scale_to: Optional[Literal['magnitude', 'psd']] = None, phase_shift: int | None = 0) Instantiate `ShortTimeFFT` by using `get_window`. [extrait de from_window.__doc__]
istft(self, S: numpy.ndarray, k0: int = 0, k1: int | None = None, *, f_axis: int = -2, t_axis: int = -1) -> numpy.ndarray Inverse short-time Fourier transform. [extrait de istft.__doc__]
k_max(self, n: int) -> int First sample index after signal end not touched by a time slice. [extrait de k_max.__doc__]
nearest_k_p(self, k: int, left: bool = True) -> int Return nearest sample index k_p for which t[k_p] == t[p] holds. [extrait de nearest_k_p.__doc__]
p_max(self, n: int) -> int Index of first non-overlapping upper time slice for `n` sample [extrait de p_max.__doc__]
p_num(self, n: int) -> int Number of time slices for an input signal with `n` samples. [extrait de p_num.__doc__]
p_range(self, n: int, p0: int | None = None, p1: int | None = None) -> tuple[int, int] Determine and validate slice index range. [extrait de p_range.__doc__]
scale_to(self, scaling: Literal['magnitude', 'psd']) Scale window to obtain 'magnitude' or 'psd' scaling for the STFT. [extrait de scale_to.__doc__]
spectrogram(self, x: numpy.ndarray, y: numpy.ndarray | None = None, detr: Union[collections.abc.Callable[[numpy.ndarray], numpy.ndarray], Literal['linear', 'constant'], NoneType] = None, *, p0: int | None = None, p1: int | None = None, k_offset: int = 0, padding: Literal['zeros', 'edge', 'even', 'odd'] = 'zeros', axis: int = -1) -> numpy.ndarray Calculate spectrogram or cross-spectrogram. [extrait de spectrogram.__doc__]
stft(self, x: numpy.ndarray, p0: int | None = None, p1: int | None = None, *, k_offset: int = 0, padding: Literal['zeros', 'edge', 'even', 'odd'] = 'zeros', axis: int = -1) -> numpy.ndarray Perform the short-time Fourier transform. [extrait de stft.__doc__]
stft_detrend(self, x: numpy.ndarray, detr: Union[collections.abc.Callable[[numpy.ndarray], numpy.ndarray], Literal['linear', 'constant'], NoneType], p0: int | None = None, p1: int | None = None, *, k_offset: int = 0, padding: Literal['zeros', 'edge', 'even', 'odd'] = 'zeros', axis: int = -1) -> numpy.ndarray Short-time Fourier transform with a trend being subtracted from each [extrait de stft_detrend.__doc__]
t(self, n: int, p0: int | None = None, p1: int | None = None, k_offset: int = 0) -> numpy.ndarray Times of STFT for an input signal with `n` samples. [extrait de t.__doc__]
upper_border_begin(self, n: int) -> tuple[int, int] First signal index and first slice index affected by post-padding. [extrait de upper_border_begin.__doc__]

Méthodes héritées de la classe object

__delattr__, __dir__, __format__, __getattribute__, __getstate__, __hash__, __init_subclass__, __reduce__, __reduce_ex__, __repr__, __setattr__, __sizeof__, __str__, __subclasshook__

Vous êtes un professionnel et vous avez besoin d'une formation ? Mise en oeuvre d'IHM
avec Qt et PySide6
Voir le programme détaillé