CIC Interpolator (cic_interpolator_xs)
CIC (cascading integrating comb) filter combined with interpolator.
Design
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 347:.
Figure 347: Block diagram of CIC interpolator implementation.
In Figure 347:
\(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).\(S\) is the power of 2 gain compensation.
Frequency Response
The frequency response of a CIC interpolator is given by in (43).
In (43):
\(H[\omega]\) is the narrowband frequency response.
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 348: and Figure 349:.
Figure 348: Wideband CIC frequency response. \(M = 1\). \(R = 8\).
Figure 349: Wideband CIC frequency response. \(M = 2\). \(R = 8\).
Gain
Increasing the order and differential delay will result in an increase in the gain of the CIC. A larger gain means the width of internal registers used by the CIC interpolator (set by the parameter cic_register_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 (44)
The minimum cic_register_size in bits needed to correctly perform the CIC interpolation is given in (45). 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 350:.
Figure 350: 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 351:.
Figure 351: Narrowband (before interpolation) CIC frequency response. \(N = 3\). \(M = 2\).
Mathematical Representation
(46) and (47) give a mathematical representation of the completed CIC filter implementation.
In (46) and (47), \(h[n]\) is the output values and \(x[n]\) is the input data stream.
In (46) and (47) 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 (48).
Interface
<?xml version="1.0"?>
<componentspec>
<property name="up_sample_factor" type="ushort" writable="true" default="2" 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="cic_order" type="uchar" writable="false" parameter="true" default="3"
description="Number of comb and integrator stages."/>
<property name="cic_differential_delay" type="uchar" writable="false" parameter="true" default="2"
description="Number of differential delay stages."/>
<property name="cic_register_size" type="uchar" writable="false" parameter="true" default="36"
description="Internal data size used within the child primitives."/>
<port name="input" producer="false" protocol="complex_short_timed_sample-prot" optional="true"/>
<port name="output" producer="true" protocol="complex_short_timed_sample-prot" optional="true"/>
</componentspec>
Ports
Inputs:
input: Primary input samples port.Protocol:
complex_short_timed_sample-protOptional:
True
Outputs:
output: Primary output samples port.Protocol:
complex_short_timed_sample-protOptional:
True
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 into multiple sample opcode messages. All other message boundaries are preserved.
Flush opcode messages trigger the component to insert a calculated number of 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 result in the output of a sample opcode message that is \(\texttt{((cic_order*cic_differential_delay)-1)} * \texttt{up_sample_factor}\) samples long. The flush opcode message is then passed from the input to the output.
Discontinuity opcode messages reset the CIC filter buffers to zero. The discontinuity opcode message is then passed from the input to the output.
Sample interval opcode messages adjusted for the interpolation by dividing the interval value by the up sample factor. The sample interval opcode message with the new value is sent to the output.
Time opcode messages are forwarded to the output.
Metadata opcode messages are forwarded to the output.
Properties
up_sample_factor: Up sampling factor. Must not be set to zero. Changing will trigger a reset of the processed data path.Type:
ushortAccess:
Parameter:
FalseWritable:
TrueInitial:
FalseVolatile:
False
Default value:
2
scale_output: Output scale factor. CIC output is divided by \(2^{\texttt{scale_output}}\). Must not be set greater than \(\texttt{cic_register_size} - 16\).Type:
ucharAccess:
Parameter:
FalseWritable:
TrueInitial:
FalseVolatile:
False
Default value:
5
cic_order: Number of comb and integrator stages. Must not be set to zero.Type:
ucharAccess:
Parameter:
TrueWritable:
FalseInitial:
FalseVolatile:
False
Default value:
3
cic_differential_delay: Number of differential delay stages. Must not be set to zero.Type:
ucharAccess:
Parameter:
TrueWritable:
FalseInitial:
FalseVolatile:
False
Default value:
2
cic_register_size: Internal data size used within the child primitives. Must meet the requirements given in (45).Type:
ucharAccess:
Parameter:
TrueWritable:
FalseInitial:
FalseVolatile:
False
Default value:
36
Implementations
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 (49).
Wideband Compensation
The passband frequency response of CIC filter with a compensation filter across the entire passband is shown in Figure 352:.
Figure 352: 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 353:.
Figure 353: 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 354: and Figure 355:.
Figure 354: Narrowband Frequency Response of CIC with narrowband compensation filter
Figure 355: 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()
Example Application
<?xml version="1.0"?>
<application done="file_write">
<instance component="ocpi.core.file_read" connect="cic_interpolator_xs">
<property name="filename" value="input.bin"/>
</instance>
<instance component="ocpi.comp.sdr.dsp.cic_interpolator_xs" connect="file_write">
<property name="up_sample_factor" value="2"/>
<property name="scale_output" value="5"/>
<property name="cic_order" value="3"/>
<property name="cic_differential_delay" value="2"/>
<property name="cic_register_size" value="36"/>
</instance>
<instance component="ocpi.core.file_write">
<property name="filename" value="output.bin"/>
</instance>
</application>
Dependencies
The dependencies to other elements in OpenCPI are:
components/dsp/common/cic/cic_core.hh
components/math/common/time_utils.hh
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.