Skip to content

Multichannel and Performance

phonometry natively supports multichannel signals (e.g., Stereo, 5.1, Microphone Arrays) using fully vectorized operations. Input arrays of shape (N_channels, N_samples) are processed in parallel, offering significant performance gains over iterative loops.

Stereo analysis: pink noise and logarithmic sweep resolved per channel in one-third-octave bandsStereo analysis: pink noise and logarithmic sweep resolved per channel in one-third-octave bands

Simultaneous analysis of a Stereo signal: Left Channel (Pink Noise) vs Right Channel (Log Sine Sweep).

The convention is consistent across the whole library: time is always the last axis. This applies to octavefilter, OctaveFilterBank, weighting_filter, time_weighting, leq, laeq, ln_levels and spectrogram.

import numpy as np
from phonometry import octavefilter
stereo = np.stack([left, right]) # (2, n_samples)
spl, freq = octavefilter(stereo, fs, fraction=3)
# spl has shape (2, n_bands): one row per channel
InputInterpreted asTypical output
(n,) 1D arrayone channelscalar level / (bands,)
(ch, n) 2D arraych channels, n samples each(ch,) levels / (ch, bands)
list of floatsone channel (converted)as 1D
(ch, n) into spectrogrammultichannel STFT-style(ch, bands, frames)

Everything vectorizes across the leading channel axis — one filter design is applied to all channels in a single SciPy call, so 8 channels cost far less than 8 separate runs. Convention: channels first, like most DSP code (soundfile returns (n, ch): transpose with x.T).

The OctaveFilterBank class is highly optimized for real-time and batch processing. It uses NumPy vectorization to handle multichannel audio arrays (e.g., 64-channel microphone arrays) without explicit Python loops, ensuring maximum throughput.

from phonometry import OctaveFilterBank
bank = OctaveFilterBank(fs=48000, fraction=3, filter_type='butter')
# Access computed properties
# bank.freq (center), bank.freq_d (lower), bank.freq_u (upper), bank.sos (coefficients)
# Process multiple signals efficiently
for frame in stream:
# detrend=True (default) removes DC offset to improve low-freq accuracy
spl, freq = bank.filter(frame, detrend=True)

Additional performance notes:

  • Design cache: octavefilter() reuses filter bank designs across calls with identical parameters (LRU cache, 32 entries), so calling it in a loop does not redesign the bank each time. OctaveFilterBank gives you explicit control over the design lifetime.
  • Multirate decimation: low-frequency bands are filtered at a decimated rate, which is both faster and numerically more stable (see Theory).
  • Optional numba: the impulse time weighting kernel is JIT-compiled when numba is installed (pip install phonometry[perf]).
Created and maintained by· GitHub· PyPI