Expand description
Monte Carlo dispersion: one rocket flown many times, each time with its uncertain inputs drawn afresh, to see how far its apogee and landing spread.
Guide: Monte Carlo dispersion explains what each dispersion does, with a worked run, and how far to trust the spread it gives.
A MonteCarlo holds the nominal flight (FlightInputs) and a Dispersion: a standard
deviation for each uncertain input. Each sample draws every dispersed input from a normal
distribution about its nominal value, as RocketPy’s stochastic classes do by default
(RocketPy 1.13.0’s rocketpy/stochastic/stochastic_model.py:190-199, a (nominal, standard deviation) pair is a normal
distribution), flies the flight, and keeps what it drew and what the flight came to
(Sample). A Run is the samples in order; Run::apogee is the spread of their
apogees, with the samples that failed counted, not dropped, and Run::landing where they
landed, whose ellipses are in crate::ellipse.
§Reproducibility
Every number a sample draws comes from its own stream, keyed by the run’s seed, the sample’s
index, the input and, for an input with several copies, which copy
(SeededRng::for_stream). So sample k is the same flight whatever the number of samples,
however they are spread over threads (MonteCarlo::run_parallel, with the parallel
feature), and whichever other inputs are dispersed: turning on a drag dispersion doesn’t
change the wind a sample flies. On one platform a run is bit for bit the same every time.
§What each dispersion does
Each is a standard deviation, zero (the default) for an input left at its nominal value. A dispersion of zero draws nothing and changes nothing, so a run with no dispersion flies the nominal flight in every sample, bit for bit.
| Field | Each sample flies |
|---|---|
dry_mass_sd_fraction | each stage’s mass without motors times 1 + σ z, its inertia scaled with it (hpr_design::Overrides) |
cg_sd_m | each stage’s center of mass moved σ z aft (forward when negative), its inertia about the center kept |
drag_sd_fraction | the rocket’s zero-lift drag coefficient times 1 + σ z (Simulation::with_drag_scale) |
impulse_sd_fraction | each motor’s thrust and propellant mass both times 1 + σ z, so its specific impulse is kept (dispersed_motor) |
burn_time_sd_fraction | each motor’s thrust curve stretched in time by 1 + σ z, its thrust divided by the same, so its impulse is kept |
ejection_delay_sd_s | each motor’s ejection delay plus σ z seconds, not below zero |
wind_speed_sd_fraction | the wind at every height times 1 + σ z, calm below zero (DispersedWind) |
wind_heading_sd_rad | the wind at every height turned σ z clockwise, about the nominal (forecast) direction |
rail_elevation_sd_rad | the rail’s angle above the horizon plus σ z; past vertical it leans the other way |
rail_azimuth_sd_rad | the rail’s heading plus σ z, about the nominal heading |
deployment_lag_sd_s | each recovery device’s lag after its trigger plus σ z seconds, not below zero; a tumble (DeviceDrag::Tumble), which starts at the split, keeps its own |
z is a standard normal deviate drawn for that sample, input and copy: a stage, a motor in the
flown configuration (a cluster’s motors share one), or a recovery device. A draw that leaves
an input impossible (a negative mass, a rail below the horizon) fails that sample, which is
counted in the run (Outcome::Failed). The two delays and the wind’s speed are cut at zero
instead, since a charge can’t fire before its event and a wind can’t blow at less than calm: a
normal tail past zero becomes zero.
§Speed
Every sample flies a simulation of its own, built from its draw. None of the dispersed inputs changes the rocket’s shape, so the samples share two things with the nominal design, and a run flies the same either way, bit for bit:
- its parts as laid out (
hpr_design::LaidOut::relay): a sample lays out only its stages again, with their dispersed masses; - its supersonic table (
hpr_aero::AeroModel::share_supersonic_table): a design that flies past Mach 1.2 builds it once for the run, not once a flight.
MonteCarlo::fly shares them too, for draws made by hand; FlightInputs::fly builds its
own every time. A sustainer lit at a powered separation builds its own table in every flight.
§Left out
Dispersions are independent normals: no correlations between inputs, no other
distributions. The rail’s elevation is dispersed in the plane of its heading, so a vertical
rail with only its elevation dispersed leans along one line, as RocketPy’s does (an inclination
and a heading, rocketpy/stochastic/stochastic_flight.py:21-24); a draw past vertical leans
it the other way, so its Draw entry is not then the elevation flown. A cluster’s motors are dispersed as one. Moving a stage’s center of mass keeps
its inertia about the center. The drag scale multiplies the zero-lift drag only, not the
normal force or the moments. A thrust curve stretched in time keeps its shape. Nothing is
dispersed in the atmosphere’s temperature or pressure, a motor’s ignition time, a recovery
device’s drag, a separation’s trigger or delay, or anything of a flight’s events that
FlightInputs doesn’t hold. A staged flight’s separations fly in every sample as the nominal
has them (FlightInputs::separations): a split timed in seconds stays at its time while the
burn time moves, so a sample whose booster still burns then stops with the flight’s error and
counts as failed, unless the split may drop a burning motor (Separation::drops_burning).
A part dropped on the way up with nothing left to burn, its device fired by the split but
waiting out a drawn lag, would climb through the lag with no drag: the flight refuses it, and
the sample counts as failed.
Structs§
- Dispersed
Wind - A wind model’s wind, scaled and turned: at every height the velocity is
speed_scaletimes the base model’s, its horizontal part turnedturn_radclockwise seen from above. Turning the velocity turns the direction the wind blows from by the same angle, so a dispersed heading stays about the forecast’s. - Dispersion
- The standard deviation of each dispersed input; zero, the default, leaves an input at its nominal value. The module’s docs say what each does to a flight.
- Draw
- What one sample drew: the factor or offset for each dispersed input, and its nominal value
(1 or 0) for one left alone. The lists run over the design’s stages, the flown
configuration’s motors and the recovery devices, in order.
MonteCarlo::inputsturns a draw into the flight it flies. - Flight
Inputs - Everything one flight is flown from: the inputs of
Simulation::newand the options a Monte Carlo run disperses.hpr::FlightBuilder::inputsmakes one from the facade’s builder. - Monte
Carlo - A rocket’s nominal flight and the dispersion of its inputs, ready to fly samples.
- Run
- The samples of a run, in order.
- Sample
- One sample of a run: its index, what it drew, and its outcome.
Enums§
- Drag
Override - A drag override for the whole flight, in place of hpr’s drag buildup: another tool’s table or
a model of your own (
Simulation::with_drag_table,Simulation::with_shared_drag_model). - Failed
At - Where a sample failed.
- Outcome
- What a sample’s flight came to.
Functions§
- dispersed_
motor motorwith its total impulse timesimpulse_scaleand its burn time timesburn_time_scale: thrustF′(t) = (k/s) F(t/s)and propellant massk m_p, withkandsthe two factors. The impulse isk Iand the effective exhaust velocityI/m_p(the specific impulse) is kept, as a motor of the same propellant burning more or less of it would; the dry mass, the nozzle and the propellant’s shape are kept. A column’s mass is scaled; BATES grains’ density, so their geometry and regression are kept.