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)
__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
delta_f | Width of the frequency bins of the STFT. [extrait de delta_f.__doc__] |
delta_t | Time increment of STFT. [extrait de delta_t.__doc__] |
dual_win | Canonical dual window. [extrait de dual_win.__doc__] |
f | Frequencies values of the STFT. [extrait de f.__doc__] |
f_pts | Number of points along the frequency axis. [extrait de f_pts.__doc__] |
fac_magnitude | Factor to multiply the STFT values by to scale each frequency slice [extrait de fac_magnitude.__doc__] |
fac_psd | Factor to multiply the STFT values by to scale each frequency slice [extrait de fac_psd.__doc__] |
fft_mode | Mode of utilized FFT ('twosided', 'centered', 'onesided' or [extrait de fft_mode.__doc__] |
fs | Sampling frequency of input signal and of the window. [extrait de fs.__doc__] |
hop | Time increment in signal samples for sliding window. [extrait de hop.__doc__] |
invertible | Check if STFT is invertible. [extrait de invertible.__doc__] |
k_min | The smallest possible signal index of the STFT. [extrait de k_min.__doc__] |
lower_border_end | First signal index and first slice index unaffected by pre-padding. [extrait de lower_border_end.__doc__] |
m_num | Number of samples in window `win`. [extrait de m_num.__doc__] |
m_num_mid | Center index of window `win`. [extrait de m_num_mid.__doc__] |
mfft | Length of input for the FFT used - may be larger than window [extrait de mfft.__doc__] |
onesided_fft | Return True if a one-sided FFT is used. [extrait de onesided_fft.__doc__] |
p_min | The smallest possible slice index. [extrait de p_min.__doc__] |
phase_shift | If set, add linear phase `phase_shift` / `mfft` * `f` to each FFT [extrait de phase_shift.__doc__] |
scaling | Normalization applied to the window function [extrait de scaling.__doc__] |
T | Sampling interval of input signal and of the window. [extrait de T.__doc__] |
win | Window 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
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é
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 :