stft
birdnet_stm32.audio.stft
¶
Reference implementation of the spectrogram inputs (hybrid and precomputed mel).
This module is the definition, not a convenience wrapper: the training, the
evaluation, the conversion calibration and the firmware (firmware/Src/
audio_stft.c, fft.c, audio_mel.c) all compute exactly this, and
docs/dev/spectrogram-input.md specifies it step by step for anyone
re-implementing it on another device. It needs numpy; scipy.fft is used
when installed because it transforms float32 without widening to float64.
Arithmetic is float32 throughout, as on the device. The float64 result differs by ~1e-7 relative, far below one INT8 input step.
Pipeline for one chunk of N samples, with W = spec_width frames:
hop = N // W.- Pad
n_fft // 2zeros on both sides (centered frames). - Frame
tcovers padded samples[t * hop, t * hop + n_fft),t < W. - Multiply by a periodic Hann window of length
n_fft. |rfft|, keeping bins0 .. n_fft // 2 - 1(Nyquist dropped).- Precomputed mel only: multiply by the Slaney mel filterbank (below).
- Optional compression:
sqrt, orlogwith a floor 80 dB below the chunk's peak. - Min-max normalize the whole chunk to
[0, 1]with1e-10in the denominator.
Output layout is [rows, W]: rows are frequency bins (hybrid, n_fft // 2)
or mel bands (precomputed), columns are frames.
hann_window(n_fft)
cached
¶
Periodic Hann window, 0.5 - 0.5 cos(2 pi n / n_fft) for n < n_fft.
Periodic (divide by n_fft), not symmetric (n_fft - 1): the
symmetric window is a different input by up to ~0.6% per sample.
Source code in birdnet_stm32/audio/stft.py
stft_magnitude(audio, n_fft, spec_width)
¶
Centered STFT magnitude, Nyquist dropped: [n_fft // 2, frames] float32.
frames is spec_width whenever the chunk is long enough, which every
fixed-length model chunk is; a shorter signal yields every complete frame.
Source code in birdnet_stm32/audio/stft.py
hz_to_mel(hz)
¶
Slaney mel of a frequency in Hz.
Source code in birdnet_stm32/audio/stft.py
mel_to_hz(mel)
¶
Frequency in Hz of a Slaney mel value.
Source code in birdnet_stm32/audio/stft.py
mel_frequencies(n_points, fmin, fmax)
¶
n_points frequencies equally spaced on the Slaney mel scale, in Hz.
mel_filterbank(sample_rate, n_fft, n_mels, fmin, fmax)
cached
¶
Slaney-normalized triangular mel filters over bins 0 .. n_fft // 2 - 1.
Returns [n_mels, n_fft // 2] float32. Band m rises linearly from
edge m to edge m + 1 and falls to edge m + 2 of
mel_frequencies(n_mels + 2, fmin, fmax), and is scaled by
2 / (edge[m + 2] - edge[m]) so every band has the same area.
The Nyquist bin is excluded, as in the STFT. With fmax at Nyquist the
top band's weight there is exactly zero, so nothing is lost.
Source code in birdnet_stm32/audio/stft.py
compress(spectrogram, compression)
¶
Input compression applied before normalization: none, sqrt or log.
Source code in birdnet_stm32/audio/stft.py
minmax_normalize(spectrogram)
¶
(S - min) / (max - min + 1e-10) over the whole chunk.
Source code in birdnet_stm32/audio/stft.py
spectrogram_input(audio, sample_rate, n_fft, spec_width, n_mels=0, compression='none')
¶
The model input for one chunk: hybrid (n_mels=0) or precomputed mel.
Returns [n_fft // 2 or n_mels, spec_width] float32 in [0, 1].