- class sdr.Interpolator(sdr.PolyphaseFIR)
Implements a polyphase interpolating FIR filter.
Notes
The polyphase interpolating filter is equivalent to first upsampling the input signal
by (by inserting zeros between each sample) and then filtering the upsampled signal with the prototype FIR filter with feedforward coefficients .Instead, the polyphase interpolating filter first decomposes the prototype FIR filter into
polyphase filters with feedforward coefficients . The polyphase filters are then applied to the input signal in parallel. The output of the polyphase filters are then commutated to produce the output signal . This prevents the need to multiply with zeros in the upsampled input, as is needed in the first case.Polyphase 3x Interpolating FIR Filter Block Diagram¶+------------------------+ +-->| h[0], h[3], h[6], h[9] |--> ..., y[3], y[0] | +------------------------+ | +------------------------+ ..., x[1], x[0] --+-->| h[1], h[4], h[7], 0 |--> ..., y[4], y[1] | +------------------------+ | +------------------------+ +-->| h[2], h[5], h[8], 0 |--> ..., y[5], y[2] +------------------------+ Input Hold Output Commutator (top-to-bottom) x[n] = Input signal with sample rate fs y[n] = Output signal with sample rate fs * P h[n] = Prototype FIR filter
The polyphase feedforward taps
are related to the prototype feedforward taps byReferences
fred harris, Multirate Signal Processing for Communication Systems, Chapter 7: Resampling Filters.
Examples
Create an input signal to interpolate.
In [1]: x = np.cos(np.pi / 4 * np.arange(40))
Create a polyphase filter that interpolates by 7 using the Kaiser window method.
In [2]: fir = sdr.Interpolator(7); fir Out[2]: sdr.Interpolator(7, 'kaiser', streaming=False) In [3]: y = fir(x) In [4]: plt.figure(); \ ...: sdr.plot.time_domain(x, marker="o", label="Input"); \ ...: sdr.plot.time_domain(y, sample_rate=fir.rate, marker=".", label="Interpolated"); \ ...: plt.title("Interpolation by 7 with the Kaiser window method"); ...:
Create a streaming polyphase filter that interpolates by 7 using the Kaiser window method. This filter preserves state between calls.
In [5]: fir = sdr.Interpolator(7, streaming=True); fir Out[5]: sdr.Interpolator(7, 'kaiser', streaming=True) In [6]: y1 = fir(x[0:10]); \ ...: y2 = fir(x[10:20]); \ ...: y3 = fir(x[20:30]); \ ...: y4 = fir(x[30:40]); \ ...: y5 = fir.flush() ...: In [7]: plt.figure(); \ ...: sdr.plot.time_domain(x, marker="o", label="Input"); \ ...: sdr.plot.time_domain(y1, sample_rate=fir.rate, offset=-fir.delay/fir.rate + 0, marker=".", label="Interpolated $y_1[n]$"); \ ...: sdr.plot.time_domain(y2, sample_rate=fir.rate, offset=-fir.delay/fir.rate + 10, marker=".", label="Interpolated $y_2[n]$"); \ ...: sdr.plot.time_domain(y3, sample_rate=fir.rate, offset=-fir.delay/fir.rate + 20, marker=".", label="Interpolated $y_3[n]$"); \ ...: sdr.plot.time_domain(y4, sample_rate=fir.rate, offset=-fir.delay/fir.rate + 30, marker=".", label="Interpolated $y_4[n]$"); \ ...: sdr.plot.time_domain(y5, sample_rate=fir.rate, offset=-fir.delay/fir.rate + 40, marker=".", label="Interpolated $y_5[n]$"); \ ...: plt.title("Streaming interpolation by 7 with the Kaiser window method"); ...:
Create a polyphase filter that interpolates by 7 using linear method.
In [8]: fir = sdr.Interpolator(7, "linear"); fir Out[8]: sdr.Interpolator(7, 'linear', streaming=False) In [9]: y = fir(x) In [10]: plt.figure(); \ ....: sdr.plot.time_domain(x, marker="o", label="Input"); \ ....: sdr.plot.time_domain(y, sample_rate=fir.rate, marker=".", label="Interpolated"); \ ....: plt.title("Interpolation by 7 with the linear method"); ....:
Create a polyphase filter that interpolates by 7 using the zero-order hold method. It is recommended to use the
"full"
convolution mode. This way the first upsampled symbol has samples.In [11]: fir = sdr.Interpolator(7, "zoh"); fir Out[11]: sdr.Interpolator(7, 'zoh', streaming=False) In [12]: y = fir(x, mode="full") In [13]: plt.figure(); \ ....: sdr.plot.time_domain(x, marker="o", label="Input"); \ ....: sdr.plot.time_domain(y, sample_rate=fir.rate, offset=-fir.delay/fir.rate, marker=".", label="Interpolated"); \ ....: plt.title("Interpolation by 7 with the zero-order hold method"); ....:
Constructors¶
- Interpolator(interpolation: int, ...)
Creates a polyphase FIR interpolating filter.
Special methods¶
-
__call__(x: ArrayLike, mode: 'rate' | 'full' =
'rate'
) NDArray Filters the input signal
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
inputs.
Methods¶
-
impulse_response(N: int | None =
None
) NDArray Returns the impulse response
of the FIR filter.
-
step_response(N: int | None =
None
) NDArray Returns the step response
of the FIR filter.
- frequency_response(...) tuple[ndarray[Any, dtype[float64]], ndarray[Any, dtype[complex128]]]
- frequency_response(freqs: float, ...) complex
- frequency_response(freqs, ...) ndarray[Any, dtype[complex128]]
Returns the frequency response
of the FIR filter.
- group_delay(...) tuple[NDArray, NDArray]
Returns the group delay
of the FIR filter.
- phase_delay(...) tuple[NDArray, NDArray]
Returns the phase delay
of the FIR filter.
-
noise_bandwidth(sample_rate: float =
1.0
) float Returns the noise bandwidth
of the FIR filter.
Properties¶
- property method : 'kaiser' | 'linear' | 'linear-matlab' | 'zoh' | 'custom'
The method used to design the polyphase interpolating filter.
- property taps : NDArray
The prototype feedforward taps
.
- property polyphase_taps : NDArray
The polyphase feedforward taps
.
- property polyphase_order : int
The order
of each FIR polyphase filter .
- property input : 'hold' | 'top-to-bottom' | 'bottom-to-top'
The input connection method.
- property output : 'sum' | 'top-to-bottom' | 'bottom-to-top' | 'all'
The output connection method.
- property interpolation : int
The integer interpolation rate
.
- property decimation : int
The integer decimation rate
.