Skip to content

File wfm_plan.h

File List > inc > wfm > wfm_plan.h

Go to the documentation of this file

/*
 * wfm_plan.h — "prepare once, materialize many" stimulus engine.
 *
 * A composed multi-source scene is a linear form
 *
 *     out = Σ_k gain_k · signal_k  +  noise
 *
 * (wfm_resolve_noise() cleans every signal source and appends one
 * WFM_SYNTH_NOISE source at the shared floor). The expensive DSP — LFSR
 * spread, RRC convolution, transcendental LO — lives entirely in the signal
 * terms, which are INVARIANT across a parameter sweep. So a Plan renders each
 * source's contribution ONCE (via the composer's own wfm_compose_build_synth,
 * so a cached render is byte-identical to a full compose), caches it, and then
 * re-materializes any variation as a cheap re-weighted sum + a regenerated
 * noise floor:
 *
 *     render(θ) = Σ_k g_k(θ)·e^{jφ_k(θ)}·cache_k  +  gain(snr(θ))·noise(seed(θ))
 *
 * v1 axes (all bit-exact vs a full compose): per-source gain/level, phase,
 * enable/disable, global SNR/noise-floor and Monte-Carlo noise-seed. Frequency
 * (Doppler) and timing (multipath) are staged follow-ups on the same frame.
 *
 * Scope (v1): a single finite, non-ranged ON segment (num_samples, no gap),
 * with at most one noise source (the resolve-appended floor, which must be
 * last). A lone *bundled* noisy source (one source carrying snr) is NOT
 * separable — its private RNG stays entangled — and is rejected.
 *
 * The Plan is a re-creatable derived cache, not evolving state: persist the
 * spec JSON (Composer.to_json()) and rebuild, rather than serializing the
 * multi-MB sample buffers.
 */
#ifndef WFM_PLAN_H
#define WFM_PLAN_H

#include <complex.h>
#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C"
{
#endif

typedef struct wfm_plan wfm_plan_t;

wfm_plan_t *wfm_plan_prepare(const char *spec_json);

size_t wfm_plan_len(const wfm_plan_t *p);

size_t wfm_plan_n_sources(const wfm_plan_t *p);

uint64_t wfm_plan_anchor_seed(const wfm_plan_t *p);

size_t wfm_plan_render(const wfm_plan_t *p, const char *overrides_json,
                       float _Complex *out);

size_t wfm_plan_at(const wfm_plan_t *p, double snr, uint64_t seed,
                   float _Complex *out);

void wfm_plan_destroy(wfm_plan_t *p);

#ifdef __cplusplus
}
#endif

#endif /* WFM_PLAN_H */