Skip to content

OliverRasmussen/CICDecimator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CIC Decimator (Fixed-Point, 8-bit MCU Model)

A fixed-point implementation of a decimating CIC (Cascaded Integrator–Comb) filter, written in C and designed to explicitly model how it would be implemented on a resource-constrained 8-bit microcontroller.

The project includes:

  • a header-only C implementation using byte-wise arithmetic,
  • a small command-line interface (CLI) for running the filter on input data,
  • a deterministic test-vector pipeline,
  • an independent Python reference model,
  • bit-exact verification,
  • and frequency-domain analysis (magnitude response and −3 dB bandwidth plot).

This implementation was originally developed as part of a bachelor’s project on low-power sigma-delta ADC design and has since been cleaned up and generalized for standalone use.

Features

  • Header-only C implementation

    All logic lives in cic_decimator.h, suitable for embedded integration and with minimal dependencies (stdint.h and string.h only).

  • Explicit 8-bit arithmetic model

    Internal state is stored as byte arrays with explicit carry/borrow handling. Arithmetic wraps modulo 2^B (no saturation), matching typical MCU behavior.

  • Compile-time configurable parameters

    • Number of stages (N)
    • Decimation factor (R)
    • Differential delay (M)
    • Internal word width (e.g. 24-bit, 32-bit)
  • CLI wrapper for easy testing with input/output files

    Compile and run the filter on input sample data from a file, with processed output written to another file.

  • Deterministic verification

    • Fixed test vectors (impulse, step, sine, random)
    • Bit-exact comparison against an independent Python integer reference model
  • Frequency-domain analysis

    • Magnitude response measurement via sine sweep
    • Theoretical magnitude response calculation for comparison
    • −3 dB bandwidth estimation

Repository Structure

.
├── src/
│   ├── cic_decimator.h      # Header-only CIC implementation
│   ├── cic_config.h         # Compile-time parameter configuration
│   └── cic_cli.c            # Small CLI wrapper for running the filter
│
├── python/
│   ├── cic_reference.py          # Integer reference model
│   ├── verify_bitexact.py        # Bit-exact verification against C implementation
│   ├── analyze_cic.py            # Frequency-domain analysis & plots
│   └── cic_config_from_header.py # Reads parameters from cic_config.h
│
├── tests/
│   └── gen_vectors.py       # Test vector generator
│
├── docs/
│   ├── cic_block_diagram.svg
│   └── magnitude_response_sinesweep_norm.png
│
├── Makefile
├── requirements.txt
├── LICENSE
└── README.md

CIC Structure

The CIC decimator implements the standard cascaded integrator–comb structure configured for decimation. It consists of three main sections:

  • N integrator stages running at the input sample rate (Fs_in)
  • Downsampling by a factor of R
  • N comb stages with a differential delay of M running at the output sample rate (Fs_out = Fs_in / R)

CIC block diagram

The block diagram above illustrates the structure of a general second-order (N=2) decimating CIC filter with arbitrary decimation factor R and differential delay M. The 'sign-extend' block on the input side represents the sign-extension applied to the input samples to match the word width of the integrator and comb stages.

CIC Configuration

The parameters of the CIC decimator are configured at compile time and defined in src/cic_config.h as follows:

#define CIC_N          2     // Number of stages (filter order)
#define CIC_R          128   // Decimation factor
#define CIC_M          1     // Differential delay
#define CIC_WORD_BITS  24    // Internal word width

The default values used here are N=2, R=128, M=1, with a 24-bit internal word width.

The included Python scripts read these values to make sure that analysis and verification always match the C build configuration.

Input Format and Word Width

The current implementation assumes a signed 10-bit two’s-complement input signal, packed into the lower 10 bits of a 16-bit value.

  • Valid input range: −512 … +511
  • Internally, input samples are sign-extended to the configured internal word width (e.g. 24-bit) before entering the integrator chain.
  • This choice reflects a typical sigma-delta ADC backend or low-resolution quantizer feeding a high-resolution decimation stage.

The input packing and sign-extension logic is isolated and can be adapted to other input resolutions with minimal changes if required. For a given input resolution B_in, the required internal word width (and output word width) B_out can be calculated as:

B_out = B_in + N * log2(R * M)

where B_in is the input bit width. In this case with B_in = 10 bits and the chosen default values of N, R, and M as defined above (2, 128, and 1), this results in:

B_out = 10 + 2 * log2(128 * 1) = 10 + 2 * 7 = 24 bits

Magnitude Response

The magnitude response below shows the measured baseband response of the CIC decimator (using a sine sweep at the input rate), normalized to DC, together with the theoretical CIC response.

CIC magnitude response

Build & Test

Requirements

  • C compiler (tested with clang)
  • Python 3.10+ (optional, only needed for verification and analysis scripts)

Install Python Dependencies (optional)

To install the required Python packages, run:

pip install -r requirements.txt

Build

To compile the CLI executable, run:

make

Run the CLI

The CLI expects a text file with one signed integer per line (range: [-512, 511]) as well as an output file path. Example usage:

./build/cic_cli input.txt output.txt

The make vectors target can be used to generate test vectors in the tests/ directory. These include impulse, step, sine, and random signals, and can be used to test the filter manually or via the verification pipeline described below.

Run Bit-Exact Verification

To run the bit-exact verification against the Python reference model, execute:

make test

This will:

  1. Generate deterministic test vectors,
  2. Run the C implementation on each vector,
  3. Compare the output against the Python reference model output to verify bit-exactness.

Example output:

PASS (bit-exact): impulse.txt
PASS (bit-exact): step.txt
PASS (bit-exact): sine.txt
PASS (bit-exact): rand.txt

Frequency-Domain Analysis

To generate the magnitude response and −3 dB bandwidth plot (as shown in the Magnitude Response section), run:

make plots

This uses the python/analyze_cic.py script to perform the analysis, in which the default output sample rate is assumed to be 200 Hz.

The measured response is obtained via a sine sweep at the input sample rate and normalized to DC, then compared against the theoretical CIC magnitude response:

|H(e^{jω})| = |sin(ω · R · M / 2) / sin(ω / 2)|^N

where ω = 2πf / fs_in.

Design Notes

  • Decimators are time-varying systems

    Frequency response is therefore measured via sine sweep rather than FFT of a decimated impulse response.

  • Wraparound arithmetic is intentional

    This implementation models fixed-width two’s-complement behavior, not idealized infinite-precision math.

  • Passband droop and compensation

    The inherent sinc^N passband droop of CIC filters is not compensated here. A low-order FIR compensation filter operating at the output sample rate would be a natural extension to improve passband flatness with minimal additional cost.

References

This implementation is based on the CIC filter structure as described in:

Rick Lyons, A Beginner's Guide to Cascaded Integrator–Comb (CIC) Filters

The article was used as a conceptual reference for the filter structure and behavior. All code in this repository is an original implementation.

License

This project is licensed under the MIT License. See the LICENSE file for details.

About

Fixed-point CIC decimator modeled for an 8-bit MCU, with bit-exact verification and frequency-domain analysis.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors