File wfm_compose.h¶
FileList > inc > wfm > wfm_compose.h
Go to the source code of this file
Multi-segment waveform composer (Phase B). More...
#include "clib_common.h"#include "wfm_synth/wfm_synth_core.h"
Classes¶
| Type | Name |
|---|---|
| struct | wfm_segment_t One composer segment: one or more sources summed over the same span, then a trailing off-time gap. |
| struct | wfm_source_t One additive source within a segment: a synth config + its level. |
Public Types¶
| Type | Name |
|---|---|
| enum | wfm__compose_8h_1abc6126af1d45847bc59afa0aa3216b04 Per-field "draw uniformly each repeat" flags ( ranged bitmask). |
| typedef struct wfm_compose_state | wfm_compose_state_t |
| enum | wfm_seed_advance_t Per-repeat seed policy for a looped/continuous stream. |
Public Functions¶
| Type | Name |
|---|---|
| wfm_synth_state_t * | wfm_compose_build_synth (const wfm_source_t * src, double fs, size_t on_len, double freq, double snr, double f_end, unsigned epoch, int seed_advance) Construct + configure the synth for one resolved source. |
| wfm_compose_state_t * | wfm_compose_create (const wfm_segment_t * segs, size_t n_segs, int repeat, int continuous) Build a composer over a copy of segs . |
| void | wfm_compose_destroy (wfm_compose_state_t * state) Destroy a composer and its active synth. |
| size_t | wfm_compose_execute (wfm_compose_state_t * state, float complex * out, size_t max) Emit up to max samples of the composed stream. |
| wfm_compose_state_t * | wfm_compose_from_file (const char * path) Build a composer from a JSON spec file. |
| wfm_compose_state_t * | wfm_compose_from_json (const char * json) Build a composer from a JSON spec string (for from-file). |
| const wfm_segment_t * | wfm_compose_segments (const wfm_compose_state_t * state, size_t * n_out, int * repeat, int * continuous) Borrow the composer's stored segment list (for record / SigMF). |
| void | wfm_compose_set_seed_advance (wfm_compose_state_t * state, int mode) Choose how the seed advances on each repeat of a looped/continuous stream (a wfm_seed_advance_t ): |
| int | wfm_resolve_noise (wfm_segment_t * segs, size_t n) Resolve a segment list's noise model in place (Phase 4b). |
| double | wfm_snr_over_fs (int snr_mode, int type, int sps, double snr) SNR (dB) referred to fs, from a source's snr/snr_mode/sps/type. |
| double | wfm_spec_headroom (const char * json) The top-level headroom (dB) from a spec JSON, or 0 if absent. |
| char * | wfm_spec_template_json (void) A ready-to-edit example spec in the canonical from-file schema. |
| char * | wfm_spec_to_json (const wfm_segment_t * segs, size_t n_segs, int repeat, int continuous, double headroom) Serialise a spec to a JSON string (for record). |
Detailed Description¶
Sequences a list of segments — each one a synth configuration plus an on-time and a trailing off-time gap — into a single IQ stream, optionally repeating the whole sequence or running forever. The composer owns one synth at a time (the active segment) and reuses the Phase-A engine verbatim, so every waveform type / SNR mode / MLS behaviour is identical to the single-waveform path; a one-segment spec is byte-identical to calling synth directly.
Lifecycle: wfm_compose_create -> wfm_compose_execute* -> wfm_compose_destroy
wfm_source_t tone = {.type = 0, .freq = 1e5, .snr = 100.0};
wfm_source_t qpsk = {.type = 4, .sps = 8, .snr = 9.0};
wfm_segment_t segs[2] = {
{.sources = &tone, .n_sources = 1, .fs = 1e6,
.num_samples = 1000, .off_samples = 500}, // tone, then a gap
{.sources = &qpsk, .n_sources = 1, .fs = 1e6,
.num_samples = 4096, .off_samples = 0}, // qpsk
};
wfm_compose_state_t *c = wfm_compose_create(segs, 2, 0, 0);
float complex buf[4096];
size_t n;
while ((n = wfm_compose_execute(c, buf, 4096)) > 0) { ... }
wfm_compose_destroy(c);
Public Types Documentation¶
enum wfm__compose_8h_1abc6126af1d45847bc59afa0aa3216b04¶
Per-field "draw uniformly each repeat" flags ( ranged bitmask).
enum wfm__compose_8h_1abc6126af1d45847bc59afa0aa3216b04 {
WFM_RANGE_FREQ = 1u << 0,
WFM_RANGE_SNR = 1u << 1,
WFM_RANGE_LEVEL = 1u << 2,
WFM_RANGE_FEND = 1u << 3,
WFM_RANGE_NUM_SAMPLES = 1u << 4,
WFM_RANGE_OFF_SAMPLES = 1u << 5
};
A scalar field is a constant; a ranged field carries a [lo, hi] span (the scalar holds lo, a companion *_hi holds hi) and is redrawn uniformly in [lo, hi] at the start of every repeat (composer epoch) — so a looped / continuous stream can vary Doppler (freq), arrival jitter (off_samples), etc. burst-to-burst while staying reproducible: the draw is a deterministic hash of the source seed, the epoch, the segment/source index, and the field, so --record stores the span (not a drawn value) and --from-file replays the same sequence byte-for-byte. Bits 0–3 live on wfm_source_t.ranged; bits 4–5 on wfm_segment_t.ranged.
typedef wfm_compose_state_t¶
Opaque composer state.
enum wfm_seed_advance_t¶
Per-repeat seed policy for a looped/continuous stream.
enum wfm_seed_advance_t {
WFM_SEED_ADVANCE_NONE = 0,
WFM_SEED_ADVANCE_NOISE = 1,
WFM_SEED_ADVANCE_ALL = 2
};
A source's single seed feeds two RNGs: the PN LFSR (spreading code and data bits — one register) and the AWGN generator. The clean cut is therefore signal (code+data) vs. noise, exposed as an ordered, cumulative level.
Public Functions Documentation¶
function wfm_compose_build_synth¶
Construct + configure the synth for one resolved source.
wfm_synth_state_t * wfm_compose_build_synth (
const wfm_source_t * src,
double fs,
size_t on_len,
double freq,
double snr,
double f_end,
unsigned epoch,
int seed_advance
)
THE single synth-construction path (create + chirp-span pin + bits/symbols/RRC attach + per-repeat NOISE reseed) shared by the streaming composer and the Plan stimulus cache, so a cached per-source render is byte-identical to the composed one. freq/snr/f_end are passed already ranged-resolved by the caller; on_len pins a chirp's sweep to the on-time; epoch/seed_advance (a wfm_seed_advance_t) drive the per-repeat seed policy — epoch == 0 yields the unmodified seed.
Returns:
A heap synth (caller wfm_synth_destroy()s it), or NULL on failure.
function wfm_compose_create¶
Build a composer over a copy of segs .
wfm_compose_state_t * wfm_compose_create (
const wfm_segment_t * segs,
size_t n_segs,
int repeat,
int continuous
)
Parameters:
segsSegment list (copied; caller keeps ownership).n_segsNumber of segments (>= 1).repeatNon-zero: loop the whole sequence after the last segment.continuousNon-zero: never finish (implies repeat); execute always returnsmax.
Returns:
Heap state, or NULL on bad args / allocation / synth failure.
Note:
Caller must wfm_compose_destroy() when done.
function wfm_compose_destroy¶
Destroy a composer and its active synth.
Parameters:
stateMay be NULL.
function wfm_compose_execute¶
Emit up to max samples of the composed stream.
Returns:
Number of samples written: < max (or 0) signals the sequence finished (never, when continuous).
function wfm_compose_from_file¶
Build a composer from a JSON spec file.
Returns:
Composer state, or NULL on read/parse error.
function wfm_compose_from_json¶
Build a composer from a JSON spec string (for from-file).
Returns:
Composer state, or NULL on parse error / bad type / no segments.
function wfm_compose_segments¶
Borrow the composer's stored segment list (for record / SigMF).
const wfm_segment_t * wfm_compose_segments (
const wfm_compose_state_t * state,
size_t * n_out,
int * repeat,
int * continuous
)
Parameters:
statethe composer.n_outreceives the segment count.repeatreceives the repeat flag (may be NULL).continuousreceives the continuous flag (may be NULL).
Returns:
Pointer to the internal segments (owned by the composer; valid until wfm_compose_destroy).
function wfm_compose_set_seed_advance¶
Choose how the seed advances on each repeat of a looped/continuous stream (a wfm_seed_advance_t ):
WFM_SEED_ADVANCE_NONE(default): byte-identical repeats.WFM_SEED_ADVANCE_NOISE: advance only the AWGN seed → a fresh noise realization each pass while the signal (LO / PN code / data / pulse) stays bit-identical (so a fixed preamble/code re-acquires every burst).WFM_SEED_ADVANCE_ALL: advance the whole seed → code, data, and noise all change (a fully stochastic stream).
Set before the first execute(); the first pass is always unchanged. An out-of-range mode is ignored.
Parameters:
stateCompose state (may be NULL).modeA wfm_seed_advance_t value.
function wfm_resolve_noise¶
Resolve a segment list's noise model in place (Phase 4b).
No-op for 1-source segments (keeps the bundled-synth path byte-identical). For a multi-source segment it sets one shared noise floor (from an explicit WFM_SYNTH_NOISE source, else the first snr-bearing source), cleans the signal sources, and appends a WFM_SYNTH_NOISE source at the floor — so the composer's accumulator just sums. May realloc each segment's sources. Idempotent.
wfm_compose_create() calls this on its private copy, so every face (CLI, JSON, Python) resolves identically.
Returns:
0 on success; -1 if a non-anchor source over-specifies (snr + level) or on allocation failure.
function wfm_snr_over_fs¶
SNR (dB) referred to fs, from a source's snr/snr_mode/sps/type.
The single source of truth for the Es/No, Eb/No, and over-fs conventions (snr_mode 0 auto / 1 fs / 2 ebno / 3 esno). wfm_resolve_noise() uses it to place the shared noise floor at level(anchor) − wfm_snr_over_fs(anchor), and the Plan stimulus engine reuses it to recompute the floor at an arbitrary swept SNR — so both agree to the bit.
Parameters:
snr_mode0 auto, 1 fs, 2 ebno, 3 esno.typeA WFM_SYNTH_* waveform type (selects the auto convention).spsSamples per symbol/chip (≥1; <1 treated as 1).snrThe declared SNR in dB.
Returns:
SNR over fs in dB.
function wfm_spec_headroom¶
The top-level headroom (dB) from a spec JSON, or 0 if absent.
Lets --from-file reproduce a recorded --headroom; the value is a writer gain, so it lives outside the composer state.
function wfm_spec_template_json¶
A ready-to-edit example spec in the canonical from-file schema.
Returns a representative multi-segment template — an inline tone, an RRC-shaped QPSK-from-bits burst with a trailing gap, and a two-source additive sum mix — serialised with wfm_spec_to_json(), so it is valid by construction and round-trips through wfm_compose_from_json() unchanged. It therefore doubles as a working starting point for wfmgen --from-file, not just documentation: dump it, edit the fields, feed it back.
Returns:
malloc'd JSON (caller frees), or NULL on allocation failure.
function wfm_spec_to_json¶
Serialise a spec to a JSON string (for record).
char * wfm_spec_to_json (
const wfm_segment_t * segs,
size_t n_segs,
int repeat,
int continuous,
double headroom
)
headroom (dB of output backoff applied at the writer, not the composer) is emitted as a top-level field only when non-zero, so an unrecorded run and any pre-headroom spec stay byte-identical. Read it back with wfm_spec_headroom().
Returns:
malloc'd JSON (caller frees), or NULL on allocation failure.
The documentation for this class was generated from the following file native/inc/wfm/wfm_compose.h