- class sdr.Decimator(sdr.FIR)
Implements a polyphase decimating FIR filter.
Notes¶
The polyphase decimating filter is equivalent to first filtering the input signal \(x[n]\) with the prototype FIR filter with feedforward coefficients \(h_{i}\) and then decimating the filtered signal by \(r\) (by discarding \(r-1\) samples between each sample).
Instead, the polyphase decimating filter first decomposes the prototype FIR filter into \(r\) polyphase filters with feedforward coefficients \(h_{i, j}\). The polyphase filters are then applied to the commutated input signal \(x[n]\) in parallel. The outputs of the polyphase filters are then summed. This prevents the need to compute outputs that will be discarded, as is done in the first case.
Polyphase 3x Decimating FIR Filter Block Diagram¶+------------------------+ ..., x[6], x[3], x[0] -->| h[0], h[3], h[6], h[9] |---+ +------------------------+ | +------------------------+ v ..., x[5], x[2], 0 -->| h[1], h[4], h[7], 0 |-->@--> ..., y[1], y[0] +------------------------+ ^ +------------------------+ | ..., x[4], x[1], 0 -->| h[2], h[5], h[8], 0 |---+ +------------------------+ Input Commutator Output Summation (bottom-to-top) x[n] = Input signal with sample rate fs y[n] = Output signal with sample rate fs/r h[n] = Prototype FIR filter @ = Adder
The polyphase feedforward taps \(h_{i, j}\) are related to the prototype feedforward taps \(h_i\) by
\[h_{i, j} = h_{i + j r} .\]Examples¶
Create an input signal to interpolate.
In [1]: x = np.cos(np.pi / 64 * np.arange(280))
Create a polyphase filter that decimates by 7 using the Kaiser window method.
In [2]: fir = sdr.Decimator(7); fir Out[2]: sdr.Decimator(7, 'kaiser', streaming=False) In [3]: y = fir(x) In [4]: plt.figure(figsize=(8, 4)); \ ...: sdr.plot.time_domain(x, marker=".", label="Input"); \ ...: sdr.plot.time_domain(y, sample_rate=1/fir.rate, marker="o", label="Decimated"); \ ...: plt.title("Decimation by 7 with the Kaiser window method"); \ ...: plt.tight_layout(); ...:
Create a streaming polyphase filter that decimates by 7 using the Kaiser window method. This filter preserves state between calls.
In [5]: fir = sdr.Decimator(7, streaming=True); fir Out[5]: sdr.Decimator(7, 'kaiser', streaming=True) In [6]: y1 = fir(x[0:70]); \ ...: y2 = fir(x[70:140]); \ ...: y3 = fir(x[140:210]); \ ...: y4 = fir(x[210:280]); \ ...: y5 = fir.flush() ...: In [7]: plt.figure(figsize=(8, 4)); \ ...: sdr.plot.time_domain(x, marker=".", label="Input"); \ ...: sdr.plot.time_domain(y1, sample_rate=1/fir.rate, offset=-fir.delay*fir.rate + 0, marker="o", label="Decimated $y_1[n]$"); \ ...: sdr.plot.time_domain(y2, sample_rate=1/fir.rate, offset=-fir.delay*fir.rate + 70, marker="o", label="Decimated $y_2[n]$"); \ ...: sdr.plot.time_domain(y3, sample_rate=1/fir.rate, offset=-fir.delay*fir.rate + 140, marker="o", label="Decimated $y_3[n]$"); \ ...: sdr.plot.time_domain(y4, sample_rate=1/fir.rate, offset=-fir.delay*fir.rate + 210, marker="o", label="Decimated $y_4[n]$"); \ ...: sdr.plot.time_domain(y5, sample_rate=1/fir.rate, offset=-fir.delay*fir.rate + 280, marker="o", label="Decimated $y_5[n]$"); \ ...: plt.title("Streaming decimation by 7 with the Kaiser window method"); \ ...: plt.tight_layout(); ...:
Constructors¶
-
Decimator(rate: int, taps: 'kaiser' | ArrayLike =
'kaiser'
, ...) Creates a polyphase FIR decimating filter.
Special methods¶
-
__call__(x: ArrayLike, mode: 'rate' | 'full' =
'rate'
) NDArray Filters and decimates the input signal \(x[n]\) with the polyphase FIR filter.
Streaming mode only¶
- reset()
Resets the filter state. Only useful when using streaming mode.
- flush() NDArray
Flushes the filter state by passing zeros through the filter. Only useful when using streaming mode.
- property state : NDArray
The filter state consisting of the previous \(N\) inputs.
Methods¶
-
impulse_response(N: int | None =
None
) NDArray Returns the impulse response \(h[n]\) of the FIR filter. The impulse response \(h[n]\) is the filter output when the input is an impulse \(\delta[n]\).
-
step_response(N: int | None =
None
) NDArray Returns the step response \(s[n]\) of the FIR filter. The step response \(s[n]\) is the filter output when the input is a unit step \(u[n]\).
- frequency_response(...) tuple[numpy.ndarray[Any, numpy.dtype[numpy.float64]], numpy.ndarray[Any, numpy.dtype[numpy.complex128]]]
- frequency_response(freqs: float, ...) complex
- frequency_response(freqs, ...) ndarray[Any, dtype[complex128]]
Returns the frequency response \(H(\omega)\) of the FIR filter.
- group_delay(...) tuple[NDArray, NDArray]
Returns the group delay \(\tau_g(\omega)\) of the FIR filter.
- phase_delay(...) tuple[NDArray, NDArray]
Returns the phase delay \(\tau_{\phi}(\omega)\) of the FIR filter.
Properties¶
- property method : 'kaiser' | 'custom'
The method used to design the multirate filter.
- property taps : NDArray
The prototype feedforward taps \(h_i\).
- property polyphase_taps : NDArray
The polyphase feedforward taps \(h_{i, j}\).
- property delay : int
The delay of FIR filter in samples. The delay indicates the output sample index that corresponds to the first input sample.
-
Decimator(rate: int, taps: 'kaiser' | ArrayLike =