Signal Analysis

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

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
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
pyminidsp.autocorrelation(a, max_lag)[source]

Compute the normalised autocorrelation of a signal.

Parameters:
  • a – Input signal.

  • max_lag – Number of lag values to compute.

Returns:

numpy array of autocorrelation values, length max_lag.

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 – Input signal.

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

Returns:

Array of autocorrelation values, length max_lag.

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 – Input signal.

  • threshold – Minimum value for a peak.

  • min_distance – Minimum index gap between peaks.

Returns:

numpy array of peak indices.

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 – Input signal.

  • threshold – Minimum value for a peak.

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

Returns:

Array of peak indices.

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 – Input signal.

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

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

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

Returns:

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

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.

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

Mix (weighted sum) two signals.

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

  • b – Input signals of the same length.

  • w_a – Weights for signals a and b.

  • w_b – Weights for signals a and b.

Returns:

numpy array of the mixed signal.

Mix (weighted sum) two signals element-wise:

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

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

  • w_a – Weight for signal a.

  • w_b – Weight for signal b.

Returns:

Mixed signal array.

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)