Skip to content

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 (N, n_ch, n_traj) provides multiple trajectories; the power spectral density is ensemble-averaged across trajectories within each segment.

required
window_length int

Segment length L. Must be a positive integer. Default is 256.

256
overlap int or None

Overlap P between consecutive segments, 0 <= P < L. Default is floor(L / 2).

None
nfft int or None

FFT length. Must be an integer >= L. Default is max(256, 2**ceil(log2(L))).

None
window str or ndarray

Window function applied to each segment before FFT. Accepted strings are 'hann' (default), 'hamming', 'rect' (or 'rectangular'). Alternatively, pass a 1-D NumPy array of length L.

'hann'
sample_time float

Sample time in seconds. Must be positive. Default is 1.0.

1.0

Returns:

Type Description
SpectrogramResult

Frozen dataclass with fields:

  • time (ndarray, shape (K,)) -- Center time of each segment in seconds.
  • frequency (ndarray, shape (n_bins,)) -- Frequency vector in Hz.
  • frequency_rad (ndarray, shape (n_bins,)) -- Frequency vector in rad/s.
  • power (ndarray, shape (n_bins, K) or (n_bins, K, n_ch)) -- One-sided power spectral density.
  • power_db (ndarray, shape (n_bins, K) or (n_bins, K, n_ch)) -- Power in dB, 10 * log10(max(power, eps)).
  • complex_stft (ndarray, shape (n_bins, K) or (n_bins, K, n_ch)) -- Complex STFT coefficients (ensemble-averaged across trajectories).
  • sample_time (float) -- Sample time in seconds.
  • window_length (int) -- Segment length L.
  • overlap (int) -- Overlap P.
  • nfft (int) -- FFT length.
  • num_trajectories (int) -- Number of trajectories used.
  • method (str) -- Always 'spectrogram'.

Raises:

Type Description
SidError

If x is complex (code: 'complex_data').

SidError

If x contains NaN or Inf (code: 'non_finite').

SidError

If window_length is not a positive integer (code: 'invalid_window_length').

SidError

If the signal is shorter than window_length (code: 'too_short').

SidError

If sample_time is not positive (code: 'invalid_sample_time').

SidError

If overlap is not an integer in [0, L-1] (code: 'invalid_overlap').

SidError

If nfft is not an integer >= L (code: 'invalid_nfft').

SidError

If the data is too short for even one segment (code: 'too_few_segments').

SidError

If the window name is unrecognised (code: 'invalid_window') or a custom window array has the wrong length (code: 'window_size_mismatch').

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):

  1. Divide the signal into K overlapping segments of length L with step L - P.
  2. Apply the time-domain window to each segment.
  3. Compute the FFT of each windowed segment (zero-padded to nfft).
  4. Compute the one-sided power spectral density per segment: P_k(m) = (1 / (Fs * S1)) * |X_k(m)|^2, where S1 = sum(w**2) is the window power. Positive-frequency bins (excluding DC and Nyquist for even nfft) are doubled.
  5. 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.