Skip to content

Waveform Generator — wfmgen

doppler ships a C-first waveform generator: one declarative synth engine (every algorithm in C, exactly once) that goes well past single waveforms —

  • Scenes — multi-segment specs, in JSON or Python, that mix sources, sequence them in time, and can randomize a parameter (frequency, SNR, gap length) per repeat instead of holding it fixed.
  • Self-describing file types & streaming — raw / CSV / BLUE type-1000 / SigMF, plus real-time-paced streaming to NATS.
  • Plan — a bit-exact sweep cache: prepare a scene once, then re-render it at any SNR/gain/phase/seed as a cheap re-weighted sum instead of re-synthesizing the DSP — the engine behind fast Monte Carlo and BER/Pd curves.

All of it is exposed two ways, both driving the same C engine to byte-identical output:

  • wfmgen — the one command-line tool. (A one-segment run is the simple single-waveform case.)
  • doppler.wfm — the same engine as a Python API, one import path: from doppler.wfm import ….

wfmgen engine

Reach for --from-file (or the Python Composer) when you need multiple segments, mixing, BLUE/SigMF, or a NATS stream — otherwise a handful of flags generate a single waveform.

The 30-second version

wfmgen --type qpsk --snr 12 --count 100000 -o capture.cf32   # 100k QPSK samples @ 12 dB Es/No
wfmgen --type tone --freq 0.1 --count 4096                   # a 0.1·Fs tone → stdout (cf32)
wfmgen --type pn --pn-length 9 --file-type csv -o pn.csv      # length-9 MLS as text

Where to go next

Page What it covers
Concepts The object model — Synth · Segment · Timeline · Composer. Read this first.
Waveforms The eight --types, PN/MLS codes, RRC pulse shaping.
Levels & SNR Unit-average-power, full-scale, clipping, headroom, the SNR model.
Scenes Multi-segment specs, sum/add, seeds, ranged values, --record.
Streaming Real-time pacing and streaming to NATS.
Python API The Synth class, the composer builders, reading captures back.
Prepare Once, Sweep Many (Plan) Bit-exact sweep cache — fast Monte Carlo / BER curves, no re-synthesis.
Recipes Copy-paste one-liners and how wfmgen is packaged.

Getting the samples into a file, and back out again, is Capture I/O — a section of its own, because reading a capture has nothing to do with generating one and most captures worth reading were not generated here. Writing captures has the --sample-type / --file-type / --endian / --output reference for the flags above.


Installation

pip install doppler-dsp        # → the `wfmgen` command + the doppler.wfm API

The wheel ships the self-contained wfmgen binary as package data and a wfmgen console-script — a thin shim that execs it — alongside the doppler.wfm Python module. To build from source instead:

git clone https://github.com/doppler-dsp/doppler && cd doppler
cmake -B build -DBUILD_PYTHON=ON && cmake --build build --target wfmgen_cli
# binary: build/native/src/wfmcompose/wfmgen

See also