spectrogram¶
MATLAB equivalent:
sidSpectrogram
spectrogram ¶
Short-time FFT spectrogram for time-frequency analysis.
spectrogram ¶
spectrogram(x: ndarray, *, window_length: int = 256, overlap: int | None = None, nfft: int | None = None, window: str | ndarray = 'hann', sample_time: float = 1.0) -> SpectrogramResult
Compute the short-time FFT spectrogram of one or more signals.
Divides the signal into overlapping segments, applies a window, and
computes the one-sided power spectral density via FFT. This is a
dependency-free replacement for the Signal Processing Toolbox
spectrogram function.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ndarray, shape ``(N,)``, ``(N, n_ch)``, or ``(N, n_ch, n_traj)``
|
Real-valued signal data. A 1-D array is treated as a
single-channel signal. Each column of a 2-D array is a separate
channel. A 3-D array |
required |
window_length
|
int
|
Segment length L. Must be a positive integer. Default is
|
256
|
overlap
|
int or None
|
Overlap P between consecutive segments, |
None
|
nfft
|
int or None
|
FFT length. Must be an integer >= L. Default is
|
None
|
window
|
str or ndarray
|
Window function applied to each segment before FFT. Accepted
strings are |
'hann'
|
sample_time
|
float
|
Sample time in seconds. Must be positive. Default is |
1.0
|
Returns:
| Type | Description |
|---|---|
SpectrogramResult
|
Frozen dataclass with fields:
|
Raises:
| Type | Description |
|---|---|
SidError
|
If x is complex (code: |
SidError
|
If x contains NaN or Inf (code: |
SidError
|
If window_length is not a positive integer
(code: |
SidError
|
If the signal is shorter than window_length
(code: |
SidError
|
If sample_time is not positive
(code: |
SidError
|
If overlap is not an integer in |
SidError
|
If nfft is not an integer >= L
(code: |
SidError
|
If the data is too short for even one segment
(code: |
SidError
|
If the window name is unrecognised
(code: |
Examples:
Spectrogram of a chirp signal:
>>> import numpy as np
>>> import sid
>>> Fs = 1000; Ts = 1 / Fs; N = 5000
>>> t = np.arange(N) * Ts
>>> x = np.cos(2 * np.pi * (50 + 100 * t / t[-1]) * t)
>>> result = sid.spectrogram(x, window_length=256, sample_time=Ts)
>>> result.power.shape
(129, 18)
Multi-channel input:
>>> x2 = np.column_stack([x, 0.5 * x])
>>> result = sid.spectrogram(x2, window_length=256, sample_time=Ts)
>>> result.power.shape
(129, 18, 2)
Multi-trajectory ensemble averaging:
>>> rng = np.random.default_rng(0)
>>> x3d = rng.standard_normal((1000, 1, 5))
>>> result = sid.spectrogram(x3d, window_length=128)
>>> result.num_trajectories
5
Notes
Algorithm (SPEC.md S7):
- Divide the signal into
Koverlapping segments of length L with stepL - P. - Apply the time-domain window to each segment.
- Compute the FFT of each windowed segment (zero-padded to nfft).
- Compute the one-sided power spectral density per segment:
P_k(m) = (1 / (Fs * S1)) * |X_k(m)|^2, whereS1 = sum(w**2)is the window power. Positive-frequency bins (excluding DC and Nyquist for even nfft) are doubled. - For multi-trajectory data, PSD and complex STFT coefficients are ensemble-averaged across trajectories.
The time-domain window reduces spectral leakage; it is distinct from
the lag-domain Hann window used in :func:sid.freq_bt.
Specification: SPEC.md S7 -- Short-Time Spectral Analysis
References
.. [1] Oppenheim, A.V. and Schafer, R.W., "Discrete-Time Signal Processing", 3rd ed., Prentice Hall, 2010.
See Also
sid.freq_bt : Blackman-Tukey spectral analysis. sid.freq_etfe : Empirical transfer function estimate. sid.spectrogram_plot : Plot a spectrogram result.
Changelog
2026-04-08 : First version (Python port) by Pedro Lourenco.