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

Block diagram of CIC interpolator implementation

Figure 13: Block diagram of CIC interpolator implementation.

Frequency Response

The frequency response of a CIC interpolator is given by in (10).

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

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

Graph of wideband CIC frequency response

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

Graph of wideband CIC frequency response

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)

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

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.

(12)\[\texttt{cic_reg_size} = \text{inWidth} + \left \lceil \frac{Nlog_{2}\left ( RM \right )}{R} \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 16:.

Graph of narrowband CIC frequency response

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

Graph comparing narrowband CIC frequency response for different values of R

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.

(13)\[\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}\]
(14)\[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 (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).

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

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

    • Optional: False

Outputs:

  • output: Primary output samples port.

    • Protocol: complex_short_timed_sample-prot

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

    • Access:

      • Parameter: True

      • Writable: False

      • Initial: False

      • Volatile: False

    • Default value: 3

  • cic_diff_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_reg_size: Internal data size used within the child primitives.

    • Type: uchar

    • Access:

      • Parameter: True

      • Writable: False

      • Initial: False

      • Volatile: False

    • Default value: 36

  • up_sample_factor: Up sampling factor. Must not be set to zero.

    • Type: ushort

    • Access:

      • Parameter: False

      • Writable: True

      • Initial: False

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

    • Access:

      • Parameter: False

      • Writable: True

      • Initial: False

      • Volatile: False

    • Default value: 5

  • flush_length: Number of zero samples that should be inserted into the CIC on receipt of a flush opcode.

    • Type: ushort

    • Access:

      • Parameter: False

      • Writable: True

      • Initial: False

      • Volatile: False

    • Default value: 0

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

(16)\[\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 18:.

Narrowband frequency response of CIC with wideband compensation filter

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

Wideband frequency response of CIC with wideband compensation filter

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

Narrowband Frequency Response of CIC with narrowband compensation filter

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

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