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:.

Block diagram of CIC interpolator implementation

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).

(43)\[H\left (\omega \right ) = \left | \frac{sin\left ( \frac{\omega M}{2} \right )}{sin\left ( \frac{\omega }{2R} \right )} \right | ^{N}\]

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:.

Graph of wideband CIC frequency response

Figure 348: Wideband CIC frequency response. \(M = 1\). \(R = 8\).

Graph of wideband CIC frequency response

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)

(44)\[G = \frac{\left ( RM \right )^{N}}{R}\]

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.

(45)\[\texttt{cic_register_size} = \text{inWidth} + \left\lceil \log_{2} \left( \frac{(RM)^{N}}{R} \right) \right\rceil\]

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:.

Graph of narrowband CIC frequency response

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:.

Graph comparing narrowband CIC frequency response for different values of R

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.

(46)\[\begin{split}g[n] = \begin{cases} \sum_{i=0}^{N} (-1)^{i} \binom{N}{i} x[\frac{n}{R}-iM] & \hfil \frac{n}{R} \in \mathbb{Z} \\ \hfil 0 & \hfil \text{otherwise} \end{cases}\end{split}\]
(47)\[h[n] = \sum_{m=0}^{n}\left( \frac{\prod_{l=1}^{N-1} \left( n+N-m-l \right) }{(N-1)!} g[m] \right)\]

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).

(48)\[y[n] = \frac{h[n]}{2^S}\]

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-prot

    • Optional: True

Outputs:

  • output: Primary output samples port.

    • Protocol: complex_short_timed_sample-prot

    • Optional: 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: ushort

    • Access:

      • Parameter: False

      • Writable: True

      • Initial: False

      • Volatile: 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: uchar

    • Access:

      • Parameter: False

      • Writable: True

      • Initial: False

      • Volatile: False

    • Default value: 5

  • cic_order: Number of comb and integrator stages. Must not be set to zero.

    • Type: uchar

    • Access:

      • Parameter: True

      • Writable: False

      • Initial: False

      • Volatile: False

    • Default value: 3

  • cic_differential_delay: Number of differential delay stages. Must not be set to zero.

    • Type: uchar

    • Access:

      • Parameter: True

      • Writable: False

      • Initial: False

      • Volatile: False

    • Default value: 2

  • cic_register_size: Internal data size used within the child primitives. Must meet the requirements given in (45).

    • Type: uchar

    • Access:

      • Parameter: True

      • Writable: False

      • Initial: False

      • Volatile: 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).

(49)\[\begin{split}H\left (\omega \right ) = \begin{cases} \left ( RM \right )^{N}\left | \frac{sin\left ( \frac{\omega }{2R} \right )}{sin\left ( \frac{\omega M}{2} \right )} \right | ^{N} & \omega \leq \omega_{cutoff} \\ 0 & \omega > \omega_{cutoff} \end{cases}\end{split}\]

Wideband Compensation

The passband frequency response of CIC filter with a compensation filter across the entire passband is shown in Figure 352:.

Narrowband frequency response of CIC with wideband compensation filter

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:.

Wideband frequency response of CIC with wideband compensation filter

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:.

Narrowband Frequency Response of CIC with narrowband compensation filter

Figure 354: Narrowband Frequency Response of CIC with narrowband compensation filter

Wideband 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:

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.