File awgn_core.h¶
FileList > awgn > awgn_core.h
Go to the source code of this file
Additive White Gaussian Noise generator. More...
#include "doppler/clib_common.h"#include "doppler/dp_state.h"#include "doppler/jm_perf.h"
Classes¶
| Type | Name |
|---|---|
| struct | dp_awgn_state_t |
Public Functions¶
| Type | Name |
|---|---|
| int | dp_awgn (uint64_t seed, float amplitude, size_t n, float _Complex * out) One-shot AWGN generation — no persistent state required. |
| float | dp_awgn_amplitude_for_snr (float snr_db, float signal_power) The amplitude that puts a signal at a target SNR. |
| int | dp_awgn_amplitude_ok (float amplitude) The amplitude domain: finite and ≥ 0. |
| dp_awgn_state_t * | dp_awgn_create (uint64_t seed, float amplitude) Create an AWGN generator. Allocates state and seeds the xoshiro256++ RNG via SplitMix64. The seed is stored so dp_awgn_reset() can reproduce the exact same stream. |
| void | dp_awgn_destroy (dp_awgn_state_t * state) |
| size_t | dp_awgn_generate (dp_awgn_state_t * state, size_t n, float _Complex * out, size_t max_out) Generate n complex CF32 AWGN samples. Uses Box-Muller with xoshiro256++ to fill out with independent complex Gaussians: Re and Im each have zero mean and standard deviationamplitude . Total complex power = 2 × amplitude². |
| size_t | dp_awgn_generate_max_out (dp_awgn_state_t * state) Conservative upper bound on generate() output size. |
| float | dp_awgn_get_amplitude (const dp_awgn_state_t * state) Return the current amplitude (per-component std dev). |
| void | dp_awgn_get_state (const dp_awgn_state_t * state, void * blob) Serialize the RNG state, seed and amplitude into blob . |
| void | dp_awgn_reseed (dp_awgn_state_t * state, uint64_t seed) Reseed the RNG and reset all xoshiro256++ state. Equivalent to calling dp_awgn_destroy() and dp_awgn_create(seed, amplitude) but reuses the existing allocation. amplitude is unchanged. |
| void | dp_awgn_reset (dp_awgn_state_t * state) Reset RNG to the current seed. The current seed is the one create took, or the last one dp_awgn_reseed() or a restored blob set. Re-runs the SplitMix64 seeding procedure with it, so the nextdp_awgn_generate() call produces exactly the same samples as the first call after that seed was set. amplitude is not changed. |
| int | dp_awgn_set_amplitude (dp_awgn_state_t * state, float val) Set amplitude without disturbing RNG state. |
| int | dp_awgn_set_state (dp_awgn_state_t * state, const void * blob) Restore the RNG state, seed and amplitude; DP_OK, or DP_ERR_INVALID if rejected (and nothing changes). |
| size_t | dp_awgn_state_bytes (const dp_awgn_state_t * state) Serialized-state byte size. |
Macros¶
| Type | Name |
|---|---|
| define | AWGN_STATE_MAGIC [**DP\_FOURCC**](dp__state_8h.md#define-dp_fourcc) ('A', 'W', 'G', 'N') |
| define | AWGN_STATE_VERSION 2u |
Detailed Description¶
Generates complex CF32 samples where real and imaginary parts are independent zero-mean Gaussians, each with standard deviation amplitude. Total complex power = 2 * amplitude².
Algorithm¶
RNG: xoshiro256++ — four 64-bit state words, seeded via SplitMix64 from the user-supplied uint64 seed. Period 2^256 − 1.
Transform: Box-Muller. Each call to dp_awgn_generate () consumes two 64-bit RNG outputs per complex output sample:
u1 ∈ (0, 1] (top 24 bits of first 64-bit word, +1 offset, /2^24) u2 ∈ [0, 1) (top 24 bits of second 64-bit word, /2^24) r = amplitude * sqrt(−2 · ln u1) θ = 2π · u2 out = r·cos θ + j·r·sin θ
Usage¶
dp_awgn_state_t *g = dp_awgn_create(42, 1.0f);
float _Complex out[1024];
dp_awgn_generate(g, 1024, out, 1024);
dp_awgn_destroy(g);
Public Functions Documentation¶
function dp_awgn¶
One-shot AWGN generation — no persistent state required.
Creates a temporary generator, fills out, then frees it. Equivalent to:
dp_awgn_state_t *g = dp_awgn_create(seed, amplitude);
dp_awgn_generate (g, n, out, n);
dp_awgn_destroy(g);
Parameters:
seedRNG seed.amplitudePer-component (Re, Im) standard deviation.nNumber of samples to generate.outOutput buffer, capacity ≥ n.
Returns:
DP_OK on success; DP_ERR_INVALID for an amplitude outside dp_awgn_amplitude_ok(), checked before any allocation; DP_ERR_MEMORY on allocation failure.
function dp_awgn_amplitude_for_snr¶
The amplitude that puts a signal at a target SNR.
The inverse of this generator's own convention, and the reason it lives here: dp_awgn_create takes a PER-COMPONENT sigma, so the complex noise power it produces is 2 * amplitude^2. For a signal of power signal_power at snr_db (referenced to the full sample rate),
amplitude = sqrt(signal_power / (2 * 10^(snr_db/10)))
Pass the result straight to dp_awgn_create(). "Is the amplitude per rail or total power?" has two defensible answers and this function is the one place that answers it a caller deriving its own sigma is one factor of two away from a 3 dB error that nothing will fail on.
Parameters:
snr_dbTarget SNR in dB, over the full sample rate.signal_powerSignal power (1.0 for unit-power tones or unit-energy BPSK/QPSK symbols).
Returns:
Per-component sigma for one I or Q rail.
function dp_awgn_amplitude_ok¶
The amplitude domain: finite and ≥ 0.
The one predicate. dp_awgn_create() refuses outside it, dp_awgn_set_state() refuses a blob outside it before it writes anything, and dp_awgn_set_amplitude() refuses such a value. A NaN fails both comparisons, so it is outside.
The domain admits a finite amplitude above about 5.9e37 (FLT_MAX / 5.77), and such an amplitude still produces +/-inf samples: the Box-Muller radius tops out near 5.77 sigma, so the product overflows. It is not a realistic input and the predicate does not refuse it.
Parameters:
amplitudePer-component standard deviation.
Returns:
1 inside the domain, 0 outside it.
function dp_awgn_create¶
Create an AWGN generator. Allocates state and seeds the xoshiro256++ RNG via SplitMix64. The seed is stored so dp_awgn_reset() can reproduce the exact same stream.
Parameters:
seed64-bit RNG seed. Two generators with different seeds produce statistically independent noise streams.amplitudePer-component (Re, Im) standard deviation. Must be finite and ≥ 0 (dp_awgn_amplitude_ok()); total complex power = 2 × amplitude².
Returns:
Heap-allocated state, or NULL on allocation failure or an amplitude outside dp_awgn_amplitude_ok().
function dp_awgn_destroy¶
Free all resources. NULL is a no-op.
function dp_awgn_generate¶
Generate n complex CF32 AWGN samples. Uses Box-Muller with xoshiro256++ to fill out with independent complex Gaussians: Re and Im each have zero mean and standard deviationamplitude . Total complex power = 2 × amplitude².
Parameters:
stateGenerator state returned by dp_awgn_create().nNumber of samples to generate.outOutput buffer; must hold at least n float _Complex values.max_outCapacity ofoutin elements. Emission stops there, so the return value is the number actually written.
Returns:
min(n, max_out) samples.
>>> import numpy as np
>>> from doppler.source import AWGN
>>> gen = AWGN(seed=0, amplitude=1.0)
>>> out = gen.generate(1024)
>>> out.dtype
dtype('complex64')
>>> out.shape
(1024,)
>>> round(float(np.var(out.real)), 1)
1.0
>>> round(float(np.var(out.imag)), 1)
1.0
function dp_awgn_generate_max_out¶
Conservative upper bound on generate() output size.
Returns 65536. The Python extension uses this for the initial buffer allocation; the buffer grows on demand if n > 65536.
function dp_awgn_get_amplitude¶
Return the current amplitude (per-component std dev).
Assigning an invalid value (NaN, infinite or negative) raises ValueError, and the amplitude keeps its old value (doppler#1987).
>>> from doppler.source import AWGN
>>> gen = AWGN(seed=0, amplitude=1.0)
>>> gen.amplitude
1.0
>>> gen.amplitude = 2.0
>>> gen.amplitude
2.0
function dp_awgn_get_state¶
Serialize the RNG state, seed and amplitude into blob .
function dp_awgn_reseed¶
Reseed the RNG and reset all xoshiro256++ state. Equivalent to calling dp_awgn_destroy() and dp_awgn_create(seed, amplitude) but reuses the existing allocation. amplitude is unchanged.
Parameters:
stateGenerator state returned by dp_awgn_create().seedNew 64-bit RNG seed.
function dp_awgn_reset¶
Reset RNG to the current seed. The current seed is the one create took, or the last one dp_awgn_reseed() or a restored blob set. Re-runs the SplitMix64 seeding procedure with it, so the nextdp_awgn_generate() call produces exactly the same samples as the first call after that seed was set. amplitude is not changed.
>>> import numpy as np
>>> from doppler.source import AWGN
>>> gen = AWGN(seed=0, amplitude=1.0)
>>> first = gen.generate(4)
>>> gen.reset()
>>> second = gen.generate(4)
>>> bool(np.all(first == second))
True
function dp_awgn_set_amplitude¶
Set amplitude without disturbing RNG state.
An val outside dp_awgn_amplitude_ok() is refused and the amplitude stays as it was, so a caller that drops the return keeps a valid sigma rather than gaining a bad one. The Python property raises ValueError on the refusal (doppler#1987).
Returns:
DP_OK, or DP_ERR_INVALID for a value outside the domain (nothing changes).
function dp_awgn_set_state¶
Restore the RNG state, seed and amplitude; DP_OK, or DP_ERR_INVALID if rejected (and nothing changes).
function dp_awgn_state_bytes¶
Serialized-state byte size.
Macro Definition Documentation¶
define AWGN_STATE_MAGIC¶
define AWGN_STATE_VERSION¶
The documentation for this class was generated from the following file native/inc/doppler/awgn/awgn_core.h