Skip to main content

cicadc

An interactive desktop program that demonstrates how an analog-to-digital converter (ADC) works. It shows two side-by-side panels rendered with manim inside a PySide6 window:

  • Left panel (analog) - the analog signal drawn as a path that scrolls past "now" (the middle line), with the future at the top and the past at the bottom. A blue car drives along the (clean) analog signal and turns to follow the path. A "shadow" car marks the converter output at now - pale green when a decimator is active (the coarse quantizer/modulator output) or white/gray otherwise (the digital output). Noise is added before the converter, not on the displayed analog curve.
  • Right panel (digital) - the digital signal as a sample-and-hold staircase. Pale green is the coarse quantizer/modulator output and white/gray is the decimated/filtered digital output (normalised to unity gain at the signal frequency). A white/gray car follows the digital output, trailing by the filter's group delay so it lands back on the analog curve (delay-compensated).

Two analysis strips run along the bottom of the view:

  • Quantization noise (bottom left) - the error analog - digital output sampled at each instant and held as a staircase, with time on the x-axis and "now" on the far right. The y-axis is scaled to the quantizer's LSB (±1 LSB), with the LSB-in-FS value annotated.
  • Digital spectrum (bottom right) - a Hann-windowed FFT of the digital output on a logarithmic frequency axis (f / f_s), with magnitude in dBFS (0 dB = full scale). The transform uses a long window (1024 points) and is recomputed only when a new sample arrives.

The ADC can run as a plain Nyquist-rate uniform quantizer or as a 1st- or 2nd-order sigma-delta modulator (with optional dither); a sigma-delta bitstream is decimated by a cascaded sinc^N (CIC-style) moving-average filter matched to the modulator order. When reconstructing, both the decimation filter's gain/group-delay and the modulator's measured in-band signal transfer (gain/phase) are de-embedded, so the quantization-noise strip shows the true noise rather than a residual signal-transfer error. (The 2nd-order loop's coefficients are chosen for single-bit stability, so some residual harmonic distortion of the signal remains visible - a real modulator artifact.)

Project layout

src/cicadc/          package (src layout, mirrors cicwave)
  cli.py             click console entry point (`cicadc`)
  app.py             QApplication bootstrap
  main_window.py     PySide6 window + controls
  manim_scene.py     offscreen manim renderer
  signal_source.py   analog signal model (sinusoid + noise)
  quantizer.py       N-bit quantizer
  render_widget.py   Qt widget + animation loop
  assets/car.png     car sprite
tests/unittests/     unittest suite

Requirements

  • Python 3.9-3.13 (manim does not yet support 3.14). A python3.12 venv is used by the setup steps below.
  • A working manim install (Cairo backend). On macOS you may need the system libraries pkg-config cairo pango via Homebrew if the wheels do not cover your platform.

Setup

python3.12 -m venv .venv
source .venv/bin/activate
pip install -e .          # or: pip install -r requirements.txt

make dev-install runs the editable install for you.

Prebuilt binaries

Standalone, self-contained bundles (no Python install required) are built for Linux, Windows and macOS (Apple Silicon) and attached to each GitHub Release. Download the zip for your platform, unpack it, and run:

  • Linux - unpack the zip, run cicadc/cicadc
  • Windows - unpack the zip, run cicadc\cicadc.exe
  • macOS - open the .dmg and drag cicadc.app into Applications.

On macOS the app is unsigned / not notarized, so Gatekeeper blocks the first launch (often with a cascade of "cannot verify developer" prompts for the bundled libraries). Clear the download quarantine once and it runs normally:

xattr -dr com.apple.quarantine /Applications/cicadc.app
open /Applications/cicadc.app

(Right-click -> Open only whitelists the top-level app, so for this multi-library bundle the xattr one-liner is the reliable fix.)

Intel Macs are not pre-built (GitHub is retiring Intel macOS runners); install from PyPI/source there with pip install cicadc.

The bundles are produced by the Build binaries workflow (PyInstaller); you can also build one locally with pyinstaller --noconfirm packaging/cicadc.spec.

Run

cicadc                   # installed console script
# or, from a checkout without installing:
python main.py

Controls

  • Frequency / Amplitude - the input sinusoid (sliders; amplitude is a fraction of full scale).
  • Speed - how fast the signal scrolls past "now".
  • Bits - resolution of the quantizer / modulator.
  • Sample period - the ADC sample clock interval.
  • Noise - additive noise amplitude, applied before the converter.
  • ADC type - Nyquist quantizer, or 1st-/2nd-order sigma-delta modulator.
  • Dither - deterministic dither for the sigma-delta quantizer (ΣΔ modes only).
  • Avg - decimation/averaging length on the digital output (1 = off); uses a sinc^N cascade matched to the ADC type.
  • Play / Pause - start or stop the animation.
  • Record video - start/stop capturing the animation to an .mp4 (H.264). Pick a file when you start; recording auto-starts playback and writes each rendered frame at the view's native 1280×1152 resolution. Encoding uses the bundled PyAV/ffmpeg, so no separate ffmpeg install is needed.

A signal-chain bar above the view highlights the active path (Analog → Noise → Quantizer/ΣΔ → Filter → Digital).

Development

make test     # run unit tests
make check    # import and print version
make lint     # ruff (if installed)
make build    # build wheel + sdist

Acknowledgements

Big thanks to Domen Visnar for the idea behind this project!

Rendering

The manim scene is rasterised offscreen (Cairo) and painted into the Qt widget. Cost scales with pixel count, so resolution and frame rate trade off; the default is 1280x1152 at 30 fps (the taller frame makes room for the bottom analysis strips), with the static scenery and the FFT curve cached so only the moving content is rebuilt each frame.

Status

Single sinusoid input, adjustable bit depth, noise, Nyquist and 1st-/2nd-order sigma-delta ADCs, a sinc^N decimation filter with delay compensation, the signal-chain bar, the quantization-noise / FFT analysis strips, and MP4 recording of the animation are implemented. Random / multi-sinusoid inputs and a configurable bandwidth filter are planned follow-ups.

Release files for cicadc 0.3.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cicadc 0.3.2
File Size Uploaded
cicadc-0.3.2.tar.gz 1.1 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for cicadc 0.3.2
File Interpreter ABI Platform
cicadc-0.3.2-py3-none-any.whl Python 3 none any Details

Total release size: 2.2 MB

Release files / cicadc-0.3.2.tar.gz

Download URL cicadc-0.3.2.tar.gz
Size 1.1 MB
Tags Source
SHA-256 checksum
How to use checksums
08bc1e9f7378f5e528871d4be3773183ff169f59e7200371d42cc11864dfb613
BLAKE2b-256 checksum
How to use checksums
dd5d0979c2419e78ed1dd367b2a52730a9023e389e2f736015c0e5ae4160dae8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 6, 2026.

Transparency log

Release files / cicadc-0.3.2-py3-none-any.whl

Download URL cicadc-0.3.2-py3-none-any.whl
Size 1.1 MB
Tags Python 3
SHA-256 checksum
How to use checksums
d45b92641d5c5f115d7b3ed631733e51b62ebe87fc270b9099cee79d609b2525
BLAKE2b-256 checksum
How to use checksums
015d6b5e3a0127b60eb6817197fc117b019d8a9b9fb53f97b4ff87ab6bf0fc52
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 6, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.2 This release

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page