FIR Filters & Convolution ========================= Four complementary methods for filtering and convolution, from educational time-domain approaches to efficient FFT-based processing. Time-domain convolution ----------------------- For signals of length *N* and kernels of length *M*, computes the full linear convolution. Output length is ``N + M - 1``. .. code-block:: python import pyminidsp as md import numpy as np signal = md.impulse(100, amplitude=1.0, position=0) kernel = np.array([1.0, 2.0, 3.0]) out = md.convolution_time(signal, kernel) # out[:3] == [1.0, 2.0, 3.0] # len(out) == 102 .. raw:: html
Moving-average filter --------------------- A simple low-pass filter that computes the running mean over a window. Output matches input length with zero-padded startup. .. code-block:: python signal = md.sine_wave(1024, freq=440.0, sample_rate=44100.0) smoothed = md.moving_average(signal, window_len=5) .. raw:: html
General FIR filter ------------------ Apply a causal FIR filter with arbitrary coefficients: .. math:: \text{out}[n] = \sum_{k=0}^{T-1} \text{coeffs}[k] \cdot \text{signal}[n-k] Output matches input length. .. code-block:: python coeffs = np.array([0.25, 0.5, 0.25]) filtered = md.fir_filter(signal, coeffs) .. raw:: html
FFT overlap-add --------------- Same result as time-domain convolution but **much faster for long kernels** by processing blocks in the frequency domain. .. code-block:: python kernel = md.hann_window(256) out_time = md.convolution_time(signal, kernel) out_fft = md.convolution_fft_ola(signal, kernel) np.testing.assert_allclose(out_time, out_fft, atol=1e-10) .. raw:: html
Comparison ---------- .. list-table:: :header-rows: 1 * - Method - Complexity - Output length - Best for * - ``convolution_time`` - O(NM) - N + M − 1 - Teaching, short kernels * - ``moving_average`` - O(N) - N - Simple smoothing * - ``fir_filter`` - O(NM) - N - Standard FIR design * - ``convolution_fft_ola`` - O(N log N) - N + M − 1 - Long kernels, production .. code-block:: python md.shutdown()