Set up
Runs on your computer. Pick your agent and operating system.
Before you start
- uv (`curl -LsSf https://astral.sh/uv/install.sh | sh`)
{
"mcpServers": {
"cicwave": {
"command": "uvx",
"args": [
"cicwave"
]
}
}
}same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12
Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs
README
synced Oct 25, 2026cicwave
Waveform viewer with PyQtGraph backend for high-performance visualization of simulation data.
Full documentation: https://wulffern.github.io/cicwave/
cicwave is a standalone package extracted from cicsim, focused on providing the best possible waveform viewing experience with PyQtGraph and Qt6.
Background
I made my first waveform viewer (https://github.com/wulffern/NextGenLab.Chart) back in 2001 during a summer internship. NextGenLab.Chart evolved into https://github.com/wulffern/SystemDotNet.Report during my Ph.D. In I always had in my plan to port SdnReport to Mac and Linux, but I never really did (no coding time).
In December 2023 I needed a waveform viewer for cicsim (read ngspice raw files), so I wrote one by hand. It was pretty basic.
Enter March 2026, and the advent of agentic coding. It was finally possible to revive SdnReport in the form of a Qt port to cicwave. Initially it lived inside cicsim, however, in May 2026 it became clear that cicwave deserved it's own repo. As such, you're here.
Features
- High-performance rendering with PyQtGraph and GPU acceleration
- Multiple file format support:
- ngspice
.rawfiles - Xyce
.prnprint waveform files - Whitespace-separated text (
.dat,.spe,.cou,.chi) - CSV, TSV, plain
.txt, Excel, OpenDocument spreadsheets - Parquet, HDF5, Feather for big data
- JSON, HTML, XML, fixed-width tables
- Pickle (
.pkl) for cached DataFrames - VCD digital waveforms
- LitePoint
.iqvsaIQ capture files - SigMF IQ recordings (
.sigmf-meta+.sigmf-data, or.sigmfarchives) - STDF (
.stdf,.stdf.gz) semiconductor ATE test results - Raw
uint32counter captures (.u32) with a JSON sidecar - Audio:
.wavnatively; FLAC, Ogg, AIFF, MP3 withcicwave[audio] - Statistical formats: Stata (
.dta), SAS (.sas7bdat), SPSS (.sav)
- ngspice
- URL data sources: load CSV/JSON/Excel/Parquet/... straight from an
http(s)://URL — REST APIs, hosted datasets, anything pandas can read - API data sources: a pivot spec with a
source:block fetches its own data from a JSON REST API — nested records, one request per row of another, no data file — see docs - Fetch on demand: a
catalog:block builds the wave tree from a cheap listing and downloads a series only when you plot it, so a database of thousands of sweeps opens instantly - Multi-dimensional data pivoting with YAML specifications
- Digital waveform support with separate analog/digital panes
- Session save/restore with
.cicwave.yamlfiles - Export capabilities to PDF, PNG, SVG formats, and the underlying
data itself (CSV/TSV/Parquet/Feather/HDF5) via
--export-data - Engineering unit formatting and auto-detection
- GPU-accelerated plotting for smooth interaction with large datasets
- MCP server (
cicwave-mcp, optional): plot/analyze tools for an agent driving tests to call directly — see docs - Plugins: private file formats, annotations, analyses and constellation
presets from separately installed packages, listed under Help → Plugins —
see docs and the examples:
a UART decoder (
examples/cicwave-uart) and a Touchstone reader with Smith chart (examples/cicwave-smith)
Installation
pip install cicwave
For the MCP server (agent-driven plotting/analysis; requires Python 3.10+):
pip install "cicwave[mcp]"
For FLAC, Ogg, AIFF and MP3 audio (WAV works without it):
pip install "cicwave[audio]"
For development installation:
git clone https://github.com/wulffern/cicwave.git
cd cicwave
pip install -e .
Usage
Basic Usage
Open waveform files directly:
# Single file
cicwave data.raw
# Multiple files
cicwave sim1.csv sim2.csv results.xlsx
# Glob patterns (useful on PowerShell)
cicwave --glob "results/*.csv" --glob "**/*.raw"
# Force a CSV delimiter (disables auto-sniffing for this run)
cicwave --csv-sep ';' european_data.csv
cicwave --csv-sep tab measurements.csv
# Strip comment lines from text files (CSV/TSV/.dat/.spe/.cou/.chi)
cicwave --csv-comment '#' results.csv # strip '#' banners
cicwave --csv-comment '*' spice_log.csv # SPICE-style comments
cicwave --csv-comment '//' c_style_dump.csv # multi-char marker
cicwave --csv-comment '' eldo.cou # disable default for .cou
Advanced Features
Load data from a URL:
cicwave https://raw.githubusercontent.com/owid/co2-data/master/owid-co2-data.csv
# Extension-less REST endpoint: force the format
cicwave https://api.example.com/v1/measurements --format json
Multi-dimensional data reshaping:
cicwave --pivot analysis.yaml dataset.csv
Fetch from a JSON REST API (spec carries the URL, no data file):
cicwave measurements.yaml
Session management:
# Save your current plot configuration in the GUI (File → Save Session)
cicwave --session my_analysis.cicwave.yaml
# Export plots without opening GUI
cicwave --session config.yaml --export results.pdf
Data exploration:
# Preview pivot dimensions before plotting
cicwave --pivot spec.yaml --pivot-info data.csv
File Format Support
cicwave dispatches on file extension. Any extension not listed below falls
through to the ngspice raw reader, so non-standard suffixes (e.g. .raw0,
.bin) on ngspice output usually still work.
Simulation / measurement formats
| Format | Extension | Description |
|---|---|---|
| ngspice raw | .raw (and unknown extensions) | Binary simulation results, parsed by ngraw.py |
| Xyce print | .prn | Sandia Xyce print/probe waveform output |
| Whitespace text | .dat, .spe, .cou, .chi | Eldo .cou/.chi, ngspice .dat, generic space/tab columns; # comments stripped by default |
| VCD | .vcd | Value Change Dump — digital simulation waveforms |
| LitePoint IQ | .iqvsa | LitePoint IQxstream / IQfact IQ capture data |
| SigMF | .sigmf-meta, .sigmf-data, .sigmf-data.zip, .sigmf | SigMF recordings (open either half of the pair, or a .sigmf archive). A zipped dataset (<name>.sigmf-data.zip) is read in place without unpacking. litepoint:scale converts counts to analyser units; litepoint:channel_offset_hz / litepoint:spectrum_inverted put a low-IF capture's FFT on the RF axis. Each recording also gets magnitude views: mag (|iq|) and power_dBm (dBm for LitePoint analyser captures, matching their burst annotations), power_dBFS (ADC counts with a stated full scale) or power_dB. All core:datatypes (cf32_le, ci16_le, cu8, rf64_be, …), multi-channel and per-capture header bytes. Gives a complex iq column plus I/Q, a time axis from core:sample_rate, and the FFT is centred on the first capture's core:frequency |
| STDF | .stdf, .stdf.gz | Semiconductor ATE test results (SEMI E10/V4) — parametric (PTR) results per part/site, gzip auto-detected |
| Raw counter | .u32 | Bare little-endian uint32 counter records with a .meta.json sidecar giving the tick length and periods per sample; converted to Hz or ns on load, with the dead time between capture chunks preserved |
| Audio | .wav, .flac, .ogg, .opus, .aif/.aiff, .mp3, … | Audio recordings. .wav is read natively (PCM 8/16/24/32-bit, 32/64-bit float, WAVE_FORMAT_EXTENSIBLE, RF64); the other formats need pip install cicwave[audio] (soundfile/libsndfile). Samples are in full scale (±1) with a time axis in seconds, one column per channel: audio (mono), left/right (stereo) or ch0, ch1, … The sample rate prefills the FFT and analysis dialogs |
Tabular text formats
| Format | Extension | Description |
|---|---|---|
| CSV | .csv | Delimiter auto-detected from `, ; \t |
| TSV | .tsv, .txt | Tab separated values |
| Fixed-width | .fwf | Fixed-width columnar text (pandas.read_fwf) |
| HTML | .html | First <table> in the document |
| XML | .xml | pandas.read_xml |
| JSON | .json | pandas.read_json records |
Spreadsheet formats
| Format | Extension | Description |
|---|---|---|
| Excel | .xlsx, .xls | Microsoft Excel workbooks (sheet selectable) |
| OpenDocument | .ods | LibreOffice / OpenOffice spreadsheets (requires odfpy) |
Big-data / binary formats
| Format | Extension | Description |
|---|---|---|
| Parquet | .parquet | Columnar storage (requires pip install pyarrow) |
| Feather | .feather | Arrow IPC file format (requires pip install pyarrow) |
| HDF5 | .h5, .hdf5 | Hierarchical data (requires pip install tables) |
| Pickle | .pkl, .pickle | Serialized pandas DataFrame |
Statistical packages
| Format | Extension | Description |
|---|---|---|
| Stata | .dta, .stata | Stata data files (pandas.read_stata) |
| SAS | .sas7bdat | SAS transport/data files (pandas.read_sas) |
| SPSS | .sav | SPSS data files (requires pyreadstat) |
Environment Variables
CICWAVE_X- Default X-axis column nameCICWAVE_PLUGINS=0- Start without loading any plugins
GUI Features
Waveform Interaction
- Mouse wheel: Zoom in/out
- Middle click + drag: Pan
- Right click: Context menu with analysis tools
- Ctrl+A: Auto-fit all waveforms
- Ctrl+Mouse wheel: Zoom X-axis only
Analysis Tools
Right-click a trace in the wave tree for the analysis menu:
- Cursors: A/B markers measure time / voltage differences
- FFT / PSD: Hanning-windowed spectrum (peak-normalised dB)
- ADC PSD (SNDR, SFDR, harmonics)…: ADC characterisation
- SNR / SNDR / ENOB…: numeric metrics with the same backend
- Histogram: distribution + Gaussian fit
- Differentiate (dy/dx): numerical derivative
- Linear fit…, Difference (this − other)…, X vs Y…
- 2's complement decode submenu: 8 / 10 / 12 / 16-bit signed
- Math expressions: create derived signals
- Digital analysis: bus values and timing
- Export data: save currently visible waveforms
ADC PSD dialog
Tailored for ADC bench data and behavioural simulations, inspired by
oct_dofft.m / dofftsd.m:
| Field | Meaning |
|---|---|
Sample rate F_s | Empty → infer from the time axis |
Fundamental F₀ | Empty / 0 → auto (strongest non-DC bin, with DC and Nyquist guard bands) |
Oversampling OSR | >1 integrates noise only over the in-band slice (1 … N_fft / OSR), σΔ-style |
Max harmonic order | Default 5 (H2…H5 typical for ADC reports) |
Harmonic lobe ±bins | Half-width for the harmonic masks. Hann main lobe is 3 bins; ±3 (7 bins) is a safe default for non-coherent captures |
Fundamental lobe ±bins | Separate width for the fundamental — use a wider window when jitter or drift smears the tone more than the harmonics |
Full-scale amplitude A_FS | Peak FS sine amplitude (same units as y). Empty → spectrum is dBc; set → dBFS plot + Signal level = … dBFS line |
Exclude harmonics from SNR… | Splits SNR vs SNDR (default on); off matches σΔ "in-band noise only" |
Logarithmic frequency axis | Default on; dialog and markers stay aligned in either mode |
Reported metrics (per call, also shown as a banner on the main wave tab):
SNR,SNDR,ENOB(dynamic_parametersbackend)SFDR— IEEE definition: ratio of fundamental lobe to the largest spur, harmonics included (always in dBc)Hntable — for each harmonic up to Max: integratedlobe power(dBc) andpeakbin (dBc)- Fundamental + harmonics drawn as vertical markers, with diamond glyphs at the spectrum peak nearest each tone
All dialog fields are persisted between invocations via QSettings
(cicwave/cicwave/{snr_dialog,adc_psd_dialog}/…), so running ADC PSD on
the next signal reuses the same F_s, A_FS, lobe widths and so on.
Session Management
- File → Save Session: Save current plot configuration
- File → Load Session: Restore previous analysis
- Sessions store: visible signals, zoom levels, cursor positions, analysis setup
Pivot Specifications
For multi-dimensional datasets, use YAML pivot specs to reshape data before visualization:
# analysis.yaml
index: time # X-axis (rows)
columns: [corner, temperature] # Create separate traces for each combination
values: ["v(out)", "v(in)"] # Y-axis signals to plot
conditions: # Filter data
frequency: 1e9
process: tt
cicwave --pivot analysis.yaml monte_carlo_results.csv
Migrating from cicsim
If you previously used cicsim wave or the standalone cicwave from cicsim:
- Install standalone cicwave:
pip install cicwave - Update workflows: Replace
cicsim wave --backend pgwith justcicwave - Session files: Existing
.cicwave.yamlfiles are fully compatible - Tkinter users:
cicsim wave --backend tkstill works in cicsim for lightweight usage
Development
Running Tests
# Run all unit tests
python -m unittest discover -s tests/unittests/ -p 'test_*.py' -v
# Test specific functionality
python -m unittest tests.unittests.test_wavefiles_lazy -v
Project Structure
cicwave/
├── src/cicwave/
│ ├── cli.py # Command-line interface
│ ├── wave_pg.py # Main PyQtGraph viewer
│ ├── wavefiles.py # File I/O and data loading
│ ├── ngraw.py # ngspice binary parser
│ ├── pivot.py # Data reshaping
│ ├── apisource.py # Declarative JSON REST API data sources
│ ├── theme.py # Color themes
│ └── command.py # Logging utilities
├── tests/unittests/ # Unit test suite
└── scripts/ # Windows shortcut generator
License
MIT License - see LICENSE file for details.
Contributing
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request