Ticket 047: Stochastic State Propagation for Path-Dependent Risk¶
Goal¶
Add a time-stepped stochastic propagator that carries a belief state forward through a full mission trajectory, accumulating correlated uncertainty across legs and producing a time-series of per-step risk metrics — principally the probability of reserve violation at any point mid-flight.
Current Gap¶
run_monte_carlo runs N fully independent deterministic estimates with
perturbed scalar inputs. Each sample is a fresh deterministic execution: wind
estimation error from leg 2 does not carry into leg 3, and energy shortfalls
that compound across climb and cruise segments are invisible until the final
reserve check. The only risk output is a distribution over total-mission
scalars (total_time_s, reserve_at_landing_wh).
This means the simulator cannot produce the kind of probabilistic safety evidence needed for BVLOS operational risk assessments: "what is the probability the aircraft has insufficient reserve to reach its divert zone at any point during the mission?" The Monte Carlo gives a spread over end-states; it does not give path-dependent risk.
Scope¶
- Define a
stochastic.v1YAML input schema (StochasticPropagationPlan) that extendsuncertainty.v1parameters with time-step configuration and process-noise settings. - Add a
run_stochastic_propagationexecution path that propagates a belief state (position, energy, wind estimate) forward at configurable Δt using Gaussian (EKF-style) representation for MVP. - Emit a
PropagationTimelinePointat each time step recording position statistics, energy distribution, andp_reserve_violation. - Add a
propagateCLI command producing astochastic-envelope.v1JSON envelope and optional Markdown report. - Preserve all existing deterministic and Monte Carlo interfaces; this is a new parallel execution mode.
Belief State¶
At each time step t the propagator maintains a distribution over:
StateVector:
lat float # degrees
lon float # degrees
alt_amsl_m float # metres
energy_remaining_wh float # Wh
wind_east_mps float # m/s — estimated, not true
wind_north_mps float # m/s — estimated, not true
The initial distribution is constructed from UncertaintyParameters (reuse
existing schema). Wind state evolves with configurable process noise
(wind_process_noise_std_mps, default 0.5 m/s) at each step to model
temporal variability within the flight.
New Public API¶
def run_stochastic_propagation(
plan: StochasticPropagationPlan,
mission: MissionPlan,
vehicle: VehicleProfile,
*,
wind_provider: WindProviderProtocol | None = None,
) -> StochasticPropagationResult:
...
Exported from estimator/__init__.py alongside the existing
run_monte_carlo.
StochasticPropagationPlan (schemas/stochastic.py, stochastic.v1)¶
class StochasticPropagationPlan(BaseModel):
model_config = ConfigDict(extra="forbid")
schema_version: Literal["stochastic.v1"]
propagation_id: str
mission_file: str
vehicle_file: str
dt_s: float = 1.0 # gt=0
samples: int # ge=1
seed: int
wind_process_noise_std_mps: float = 0.5
parameters: UncertaintyParameters # reuse from schemas/uncertainty.py
StochasticPropagationResult (schemas/stochastic.py)¶
class PropagationTimelinePoint(BaseModel):
elapsed_time_s: float
lat_mean: float
lon_mean: float
energy_remaining_wh: SampleStats
p_reserve_violation: float # fraction of samples with reserve < threshold
class StochasticPropagationResult(BaseModel):
propagation_id: str
seed: int
dt_s: float
sample_count: int
timeline: list[PropagationTimelinePoint]
reserve_at_landing_wh: SampleStats | None
feasibility_rate: float
baseline: MissionEstimate
CLI¶
New sub-command propagate:
Output schema: stochastic-envelope.v1. Exit codes follow the existing
CliExitCode convention.
File Plan¶
New files:
| File | Purpose |
|---|---|
schemas/stochastic.py |
StochasticPropagationPlan, StochasticPropagationResult, PropagationTimelinePoint |
estimator/execution/propagator.py |
Core propagation loop |
estimator/execution/propagator_gaussian.py |
Gaussian belief representation |
adapters/stochastic_envelope.py |
JSON envelope builder, STOCHASTIC_ENVELOPE_SCHEMA_VERSION |
adapters/stochastic_markdown.py |
Markdown report renderer |
tests/test_stochastic_propagator.py |
Unit and integration tests |
examples/stochastic/pipeline_demo_001_stochastic.yaml |
Example plan |
Modified files:
estimator/__init__.py— exportrun_stochastic_propagation,StochasticPropagationPlan,StochasticPropagationResultadapters/cli.py— addpropagatecommandschemas/__init__.py— export new types
Integration Requirements¶
- Reuse
UncertaintyParametersandSampleStatsfromschemas/uncertainty.pyso the initial distribution is configured identically to Monte Carlo inputs. - Reuse
WindProviderProtocolfor wind sampling at each step; the propagator must compose withLayeredWindProviderandSpatiotemporalWindProvider. - The
propagateCLI must accept the same mission and vehicle YAML files as theestimateandsamplecommands. run_stochastic_propagationwithsamples=1and zero process noise must produce a finalenergy_remaining_wh.meanwithin 1 % of the deterministic baselinereserve_at_landing_wh(same physics, different execution path).
Acceptance Criteria¶
run_stochastic_propagation(samples=1, wind_process_noise_std_mps=0.0)produces atimeline[-1].energy_remaining_wh.meanwithin 1 % of the deterministic baselinereserve_at_landing_wh.p_reserve_violationis monotonically non-decreasing over the timeline.feasibility_rateequals the fraction of samples ending withenergy_remaining_wh.mean >= reserve_threshold_wh.- Same seed produces identical
StochasticPropagationResultacross two runs. - Different seeds produce different
p_reserve_violationtimeline values. propagateCLI exits 0 on the example file; JSON output hasschema_version: "stochastic-envelope.v1".- All existing tests continue to pass.
uv run ruff checkpasses.
Out of Scope (follow-on tickets)¶
- Ticket 048: Observation/update step — simulated GPS fixes and battery voltage measurements narrow the belief state mid-flight.
- Ticket 049: Particle filter representation replacing the Gaussian approximation for non-linear dynamics.
- Ticket 050: Contingency trigger probability — P(lost-link policy fires before waypoint N) derived from the stochastic propagation timeline.
- Ticket 051: Integration with SITL comparison pipeline — use replay telemetry to condition the belief state retrospectively.