CIC Filter Worker - Interpolation (cic_int_csts)
CIC (Cascaded Integrator-Comb) filter combined with interpolator.
Design
This device worker is the equivalent of cic_interpolator_xs component within OpenCPI SDR Components Library (ocpi.comp.sdr).
CIC interpolators are an efficient method of increasing the sample rate of an input signal by an integer factor. CIC interpolators do not require any multiplication operations making them particularly suitable for compact FPGA and ASIC designs.
In a CIC interpolator the comb stage is applied first, then the up sampling is applied before the integrator stage is applied last. CIC filters have an inherent gain that typically needs to be removed; in this component this is done via a right shift operation allowing for power-of-2 gain compensation. A half-up rounding unit is used to minimise the amount of DC bias caused by the right shift operation.
A block diagram representation of the implementation is given in Figure 13:.
Figure 13: Block diagram of CIC interpolator implementation.
Frequency Response
The frequency response of a CIC interpolator is given by in (10).
In (10):
\(H[\omega]\) is the narrowband frequency response.
\(N\) is the order of the CIC filter (
cic_order).\(R\) is the up sampling factor (
up_sample_factor)\(M\) is the delay factor (
cic_delay, this is typically only ever set to 1 or 2).
When up sampling a signal it is typically desirable to minimise the amplitude of any images that occur at multiples of the Nyquist frequency of the lower sample rate. The order and delay factor of the CIC sets the wideband frequency response of a CIC filter, with higher values giving more suppression of images.
The wideband frequency response (i.e. the response after the up sampling operation is performed) is shown in Figure 14: and Figure 15:.
Figure 14: Wideband CIC frequency response. \(M = 1\). \(R = 8\).
Figure 15: Wideband CIC frequency response. \(M = 2\). \(R = 8\).
Gain
Increasing the order and differential delay does not come for free; the larger they are the greater the gain of the CIC. A larger gain means the width of internal registers used by the CIC interpolator (set by the parameter cic_reg_size) must be larger in order to store the calculated values. This in turn means the filter takes up more space on an FPGA.
The gain of a CIC interpolator is given by \(G\) in (11)
The minimum cic_reg_size in bits needed to correctly perform the CIC interpolation is given in (12). In this component inWidth is 16 bits.
Passband Attenuation
CIC interpolators have attenuation in the original passband. The larger the CIC order and delay factor the more attenuation in the passband. The narrowband frequency response of a CIC interpolator is shown in Figure 16:.
Figure 16: Narrowband (before interpolation) CIC frequency response. \(R = 8\).
The narrowband frequency response of a CIC filter is same regardless of the up_sample_factor (\(R\)). This is shown in Figure 17:.
Figure 17: Narrowband (before interpolation) CIC frequency response. \(N = 3\). \(M = 2\).
Mathematical Representation
(13) and (14) give a mathematical representation of the completed CIC filter implementation.
In (13) and (14), \(h[n]\) is the output values and \(x[n]\) is the input data stream.
In (13) and (14) the notation \(\binom{n}{x}\) is the binomial expansion, or more informally described as “\(n\) choose \(x\)”.
After the CIC filter implementation using the above an attenuation stage is applied to allow the option of cancelling out the inherent CIC filter gain, this attenuation is implemented as a right shift, which is equivalent to the expression in (15).
Interface
<componentspec>
<property name="cic_order" type="uchar" parameter="true" writable="false" default="3" description="Number of comb and integrator stages."/>
<property name="cic_diff_delay" type="uchar" parameter="true" writable="false" default="2" description="Number of differential delay stages."/>
<property name="cic_reg_size" type="uchar" parameter="true" writable="false" default="36" description="Internal data size used within the child primitives."/>
<property name="up_sample_factor" type="ushort" writable="true" default="1" description="Up sampling factor"/>
<property name="scale_output" type="uchar" writable="true" default="5" description="Output scale factor. CIC output is divided by :math:`2^{\texttt{scale_output}}`."/>
<property name="flush_length" type="ushort" writable="true" default="0" description="Number of zero samples that should be inserted into the CIC on receipt of a flush opcode."/>
</componentspec>
Ports
Inputs:
input: Primary input samples port.Protocol:
complex_short_timed_sample-protOptional:
False
Outputs:
output: Primary output samples port.Protocol:
complex_short_timed_sample-protOptional:
False
Opcode Handling
Sample opcode messages are up sampled by the CIC interpolator. Output sample opcode messages over ocpi_max_bytes_output/sample_size_bytes bytes are split, otherwise message boundaries are preserved.
Flush opcode message trigger the component to insert flush_length zero samples into the input of the CIC in order to flush out any historical data. On receipt of a flush opcode message backpressure is applied to the input port while the samples are flushed. This will typically result in the output of a sample opcode message that is roughly \(\texttt{flush_length} * \texttt{up_sample_factor}\) samples long. The flush opcode message is then passed from the input to the output.
All other opcode messages pass through this component without any effect on its operation.
Properties
cic_order: Number of comb and integrator stages.Type:
ucharAccess:
Parameter:
TrueWritable:
FalseInitial:
FalseVolatile:
False
Default value:
3
cic_diff_delay: Number of differential delay stages. Must not be set to zero.Type:
ucharAccess:
Parameter:
TrueWritable:
FalseInitial:
FalseVolatile:
False
Default value:
2
cic_reg_size: Internal data size used within the child primitives.Type:
ucharAccess:
Parameter:
TrueWritable:
FalseInitial:
FalseVolatile:
False
Default value:
36
up_sample_factor: Up sampling factor. Must not be set to zero.Type:
ushortAccess:
Parameter:
FalseWritable:
TrueInitial:
FalseVolatile:
False
Default value:
1
scale_output: Output scale factor. CIC output is divided by \(2^{\texttt{scale_output}}\). Must not be set greater than \(\texttt{cic_reg_size} - 16\).Type:
ucharAccess:
Parameter:
FalseWritable:
TrueInitial:
FalseVolatile:
False
Default value:
5
flush_length: Number of zero samples that should be inserted into the CIC on receipt of a flush opcode.Type:
ushortAccess:
Parameter:
FalseWritable:
TrueInitial:
FalseVolatile:
False
Default value:
0
Implementations
cic_int_csts(HDL)
CIC Compensation Filters
Passband attenuation is typically unwanted and can be compensated for by preceding the CIC interpolator with an FIR filter. The frequency response of an idea compensation filter is shown in (16).
Wideband Compensation
The passband frequency response of CIC filter with a compensation filter across the entire passband is shown in Figure 18:.
Figure 18: Narrowband frequency response of CIC with wideband compensation filter
Compensation across the entire passband is typically not recommended as it results in degraded rejection of aliasing signals compared to just a CIC interpolator. This is shown in Figure 19:.
Figure 19: Wideband frequency response of CIC with wideband compensation filter
Narrowband Compensation
Narrowband compensation is when the CIC frequency response is only compensated for during part of the Nyquist bandwidth of the lower sample rate. Most systems use a narrowband compensation filter.
As a rule of thumb the cut-off frequency of the narrowband compensation filter should be \(F_{cutoff} \leq \frac{f_{s[low]}}{4M}\). If this condition is not met the performance of the CIC interpolator, at some frequencies, will be negatively impacted by the compensation filter. This is shown in Figure 20: and Figure 21:.
Figure 20: Narrowband Frequency Response of CIC with narrowband compensation filter
Figure 21: Wideband Frequency Response of CIC with narrowband compensation filter
Generating Filter Taps
The following python code can be used to generate the taps for an FIR compensation filter and to plot the system’s frequency response.
from scipy.signal import firwin2
from scipy.signal import freqz
import numpy as np
import matplotlib.pyplot as plt
np.seterr(divide='ignore', invalid='ignore');
# cutOff is the cut off freq as a fraction of the lower sample rate
# i.e 0.5 = Nyquist frequency
def getFIRCompensationFilter(R,M,N,cutOff,numTaps,calcRes=1024):
w = np.arange(calcRes) * np.pi/(calcRes - 1)
Hcomp = lambda w : ((M*R)**N)*(np.abs((np.sin(w/(2.*R))) /
(np.sin((w*M)/2.)) ) **N)
cicCompResponse = np.array(list(map(Hcomp, w)))
# Set DC response to 1 as it is calculated as 'nan' by Hcomp
cicCompResponse[0] = 1
# Set stopband response to 0
cicCompResponse[int(calcRes*cutOff*2):] = 0
normFreq = np.arange(calcRes) / (calcRes - 1)
taps = firwin2(numTaps, normFreq, cicCompResponse)
return taps
def plotFIRCompFilter(R,M,N,taps,wideband=False):
if wideband: # Interpolate FIR filter to higher sample rate
interp = np.zeros(len(taps)*R)
interp[::R] = taps
freqs,compResponse = freqz(interp)
w = np.arange(len(freqs)) * np.pi/len(freqs) * R
else:
freqs,compResponse = freqz(taps)
w = np.arange(len(freqs)) * np.pi/len(freqs)
Hcic = lambda w : (1/((M*R)**N))*np.abs( (np.sin((w*M)/2.)) / (np.sin(w/(2.*R))) )**N
cicMagResponse = np.array(list(map(Hcic, w)))
combinedResponse = cicMagResponse * compResponse
plt.plot(freqs/(2*np.pi),20*np.log10(abs(cicMagResponse)), label="CIC Filter")
plt.plot(freqs/(2*np.pi),20*np.log10(abs(compResponse)), label="Compensation Filter")
plt.plot(freqs/(2*np.pi),20*np.log10(abs(combinedResponse)), label="Combined Response")
plt.grid(); plt.legend();
axes = plt.gca(); axes.set_ylim([-200,25])
plt.show()
Dependencies
The dependencies to other elements in OpenCPI are:
There is also a dependency on:
ieee.std_logic_1164
ieee.numeric_std
ieee.math_real
Limitations
Limitations of cic_interpolator_xs are:
Up-sample factor must be greater than or equal to 2.
Testing
Tested platforms: None
Component testing not completed.