Signal Analysis

Time-domain analysis tools for characterising signal properties, detecting features, and estimating pitch.

pyminidsp.bessel_i0(x)[source]

Compute the zeroth-order modified Bessel function of the first kind.

Compute the zeroth-order modified Bessel function of the first kind, \(I_0(x)\). Used internally for Kaiser window generation, but also useful for filter design and statistical distributions.

Parameters:

x (float) – Input value.

Returns:

\(I_0(x)\) as a float.

Return type:

float

pyminidsp.sinc(x)[source]

Compute the normalized sinc function: sin(pi*x) / (pi*x), with sinc(0) = 1.

Compute the normalized sinc function:

\[\begin{split}\mathrm{sinc}(x) = \begin{cases} 1 & x = 0 \\ \frac{\sin(\pi x)}{\pi x} & x \ne 0 \end{cases}\end{split}\]

Used in ideal filter design, interpolation, and resampling.

Parameters:

x (float) – Input value.

Returns:

sinc(x) as a float.

Return type:

float

pyminidsp.rms(a)[source]

Compute the root mean square (RMS) of a signal.

Compute the root mean square (RMS) of a signal — the standard measure of signal “loudness”:

\[\mathrm{RMS} = \sqrt{\frac{1}{N}\sum_{n=0}^{N-1} x[n]^2}\]

Equivalently, sqrt(power(a)). A unit-amplitude sine wave has RMS ≈ 0.707. A DC signal of value c has RMS = \(|c|\).

signal = md.sine_wave(44100, amplitude=1.0, freq=440.0, sample_rate=44100.0)
rms = md.rms(signal)  # ≈ 0.707
Parameters:

a (ArrayLike)

Return type:

float

pyminidsp.zero_crossing_rate(a)[source]

Compute the zero-crossing rate of a signal.

Count how often the signal changes sign, normalised by the number of adjacent pairs:

\[\mathrm{ZCR} = \frac{1}{N-1}\sum_{n=1}^{N-1} \mathbf{1}\bigl[\mathrm{sgn}(x[n]) \ne \mathrm{sgn}(x[n-1])\bigr]\]

Returns a value in [0.0, 1.0]. High ZCR indicates noise or high-frequency content; low ZCR indicates tonal or low-frequency content.

signal = md.sine_wave(16000, freq=1000.0, sample_rate=16000.0)
zcr = md.zero_crossing_rate(signal)
# zcr ≈ 2 * 1000 / 16000 = 0.125
Parameters:

a (ArrayLike)

Return type:

float

pyminidsp.autocorrelation(a, max_lag)[source]

Compute the normalised autocorrelation of a signal.

Parameters:
  • a (ArrayLike) – Input signal.

  • max_lag (int) – Number of lag values to compute.

Returns:

numpy array of autocorrelation values, length max_lag.

Return type:

ndarray[tuple[Any, …], dtype[float64]]

Compute the normalised autocorrelation — measures the similarity between a signal and a delayed copy of itself:

\[R[\tau] = \frac{1}{R[0]} \sum_{n=0}^{N-1-\tau} x[n]\,x[n+\tau]\]

The output satisfies out[0] = 1.0 and |out[tau]| <= 1.0. A silent signal (all zeros) produces all-zero output.

Parameters:
  • a (ArrayLike) – Input signal.

  • max_lag (int) – Number of lag values to compute. Must be > 0 and < N.

Returns:

Array of autocorrelation values, length max_lag.

Return type:

ndarray[tuple[Any, …], dtype[float64]]

signal = md.sine_wave(1024, freq=100.0, sample_rate=1000.0)
acf = md.autocorrelation(signal, 50)
# acf[0] = 1.0, acf[10] ≈ 1.0 (lag = one period of 100 Hz at 1 kHz)
pyminidsp.peak_detect(a, threshold=0.0, min_distance=1)[source]

Detect peaks (local maxima) in a signal.

Parameters:
  • a (ArrayLike) – Input signal.

  • threshold (float) – Minimum value for a peak.

  • min_distance (int) – Minimum index gap between peaks.

Returns:

numpy array of peak indices.

Return type:

ndarray[tuple[Any, …], dtype[uint32]]

Detect peaks (local maxima) in a signal. A sample a[i] is a peak if it is strictly greater than both immediate neighbours and above the given threshold. The min_distance parameter suppresses nearby secondary peaks.

Peaks are found left-to-right. Endpoint samples are never peaks because they lack two neighbours.

Parameters:
  • a (ArrayLike) – Input signal.

  • threshold (float) – Minimum value for a peak.

  • min_distance (int) – Minimum index gap between accepted peaks (>= 1).

Returns:

Array of peak indices.

Return type:

ndarray[tuple[Any, …], dtype[uint32]]

import numpy as np
signal = np.array([0, 1, 3, 1, 0, 2, 5, 2, 0], dtype=float)
peaks = md.peak_detect(signal, threshold=0.0, min_distance=1)
# peaks == [2, 6]  (values 3 and 5)
pyminidsp.f0_autocorrelation(signal, sample_rate, min_freq_hz=80.0, max_freq_hz=400.0)[source]

Estimate F0 using autocorrelation.

Estimate the fundamental frequency (F0) using autocorrelation. Searches for the strongest local peak in the normalised autocorrelation over lags corresponding to the requested frequency range:

\[f_0 = \frac{f_s}{\tau_\text{peak}}\]
Parameters:
  • signal (ArrayLike) – Input signal.

  • sample_rate (float) – Sampling rate in Hz (must be > 0).

  • min_freq_hz (float) – Minimum search frequency (must be > 0).

  • max_freq_hz (float) – Maximum search frequency (must be > min_freq_hz).

Returns:

Estimated F0 in Hz, or 0.0 if no reliable pitch is found.

Return type:

float

pyminidsp.f0_fft(signal, sample_rate, min_freq_hz=80.0, max_freq_hz=400.0)[source]

Estimate F0 using FFT peak picking.

Estimate F0 using FFT peak picking. The signal is internally Hann-windowed, transformed, then the dominant magnitude peak in the requested frequency range is mapped back to Hz:

\[f_0 = \frac{k_\text{peak} \cdot f_s}{N}\]

Simple and fast, but generally less robust than f0_autocorrelation() for noisy or strongly harmonic signals.

Parameters:
  • signal (ArrayLike)

  • sample_rate (float)

  • min_freq_hz (float)

  • max_freq_hz (float)

Return type:

float

pyminidsp.mix(a, b, w_a=0.5, w_b=0.5)[source]

Mix (weighted sum) two signals.

Parameters:
  • a (ArrayLike) – Input signals of the same length.

  • b (ArrayLike) – Input signals of the same length.

  • w_a (float) – Weights for signals a and b.

  • w_b (float) – Weights for signals a and b.

Returns:

numpy array of the mixed signal.

Return type:

ndarray[tuple[Any, …], dtype[float64]]

Mix (weighted sum) two signals element-wise:

\[\mathrm{out}[n] = w_a \cdot a[n] + w_b \cdot b[n]\]
Parameters:
  • a (ArrayLike) – First input signal.

  • b (ArrayLike) – Second input signal (same length as a).

  • w_a (float) – Weight for signal a.

  • w_b (float) – Weight for signal b.

Returns:

Mixed signal array.

Return type:

ndarray[tuple[Any, …], dtype[float64]]

sine = md.sine_wave(1024, amplitude=1.0, freq=440.0, sample_rate=44100.0)
noise = md.white_noise(1024, amplitude=0.1, seed=42)
mixed = md.mix(sine, noise, w_a=0.8, w_b=0.2)