Skip to main content

Module scenario

Module scenario 

Source
Expand description

Scenarios and the metrics of a trial.

A Scenario is what one Monte Carlo trial does, the counterpart of a LightningModule:

  • Scenario::setup runs once per condition, before its trials, and returns a state shared (read-only) by all of them: a constellation, a filter, a designed or trained receiver, a fibre plan… (setup hook of Lightning);
  • Scenario::trial runs one trial with its own random generator and records its metrics in a Record (training_step and self.log).

Trials run in parallel, so the scenario and its state are Sync and a trial must not mutate shared data. from_fn makes a scenario from a closure when no state is needed.

A Record maps metric names to Estimates: Record::errors adds error counts (an error rate with a Wilson interval), Record::value adds a real value (a mean with a normal interval). The runner merges the records of all the trials of a condition.

A value that cannot enter its metric is dropped and counted, never folded into the estimate: a non-finite value (the SNR of an error-free trial, +∞ dB), or an addition to a metric of the other kind (errors on a mean, value on a rate). Record::dropped gives the count of a metric; the runner keeps the counts of the merged record and the JSON report lists them (dropped), so that a mean that leaves values out shows it.

§Examples

use comnum_sim::prelude::*;
use comnum_mapping::{constellation::{Constellation, ConstellationKind}, source as sources};
use comnum_channel::awgn as channels;
use comnum_metrics as metrics;

/// SER of M-PSK over AWGN; the constellation is built once per condition.
struct Psk;
impl Scenario for Psk {
    type State = Constellation;
    fn name(&self) -> &str { "psk-ser" }
    fn setup(&self, cond: &Condition) -> Result<Constellation> {
        Constellation::psk(cond.usize("m")?)
    }
    fn trial(&self, c: &Constellation, cond: &Condition, rng: &mut Rng, rec: &mut Record)
        -> Result<()> {
        let (idx, x) = sources::symbols(c, 1000, None, rng)?;
        let b = c.bits_per_symbol();
        let y = channels::awgn_ebn0(&x, cond.f64("ebn0_db")?, b as f64, 1.0, rng);
        let dec = c.decide(&y);
        rec.errors("ser", metrics::symbol_errors(&dec, &idx)? as u64, idx.len() as u64);
        rec.value("snr_db", metrics::snr_db(&y, &x)?);
        Ok(())
    }
}
let grid = Grid::new().axis("m", [8usize]).axis("ebn0_db", [10.0]);
let r = Runner::new().batch(10).stop(Stop::max_trials(20)).run(&Psk, &grid).unwrap();
assert_eq!(r[0].trials, 20);   // the rule is checked after every batch of 10 trials
assert!((r[0].metric("snr_db").unwrap().value() - (10.0 + comnum_math::lin2db(3.0))).abs() < 0.1);

Structs§

FnScenario
A scenario made of a closure (no per-condition state); see from_fn.
Record
The metrics reported by one trial, or merged over many.

Traits§

Scenario
One random trial of a link, evaluated under many conditions.

Functions§

from_fn
A scenario from a name and a closure |condition, rng, record| -> Result<()>.