Skip to content

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

typedef struct wfm_compose_state 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:

  • segs Segment list (copied; caller keeps ownership).
  • n_segs Number of segments (>= 1).
  • repeat Non-zero: loop the whole sequence after the last segment.
  • continuous Non-zero: never finish (implies repeat); execute always returns max.

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.

void wfm_compose_destroy (
    wfm_compose_state_t * state
) 

Parameters:

  • state May be NULL.

function wfm_compose_execute

Emit up to max samples of the composed stream.

size_t wfm_compose_execute (
    wfm_compose_state_t * state,
    float complex * out,
    size_t max
) 

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.

wfm_compose_state_t * wfm_compose_from_file (
    const char * path
) 

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).

wfm_compose_state_t * wfm_compose_from_json (
    const char * json
) 

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:

  • state the composer.
  • n_out receives the segment count.
  • repeat receives the repeat flag (may be NULL).
  • continuous receives 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 ):

void wfm_compose_set_seed_advance (
    wfm_compose_state_t * state,
    int mode
) 

  • 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:

  • state Compose state (may be NULL).
  • mode A wfm_seed_advance_t value.

function wfm_resolve_noise

Resolve a segment list's noise model in place (Phase 4b).

int wfm_resolve_noise (
    wfm_segment_t * segs,
    size_t n
) 

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.

double wfm_snr_over_fs (
    int snr_mode,
    int type,
    int sps,
    double snr
) 

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_mode 0 auto, 1 fs, 2 ebno, 3 esno.
  • type A WFM_SYNTH_* waveform type (selects the auto convention).
  • sps Samples per symbol/chip (≥1; <1 treated as 1).
  • snr The 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.

double wfm_spec_headroom (
    const char * json
) 

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.

char * wfm_spec_template_json (
    void
) 

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