This page describes the implementation details of modeling a stochastic system in Drake and writing algorithms that explicitly leverage the stochastic modeling framework.
A discrete-time system in Drake can be viewed as having the state-space dynamics
xₙ₊₁ = f(n, xₙ, uₙ, wₙ; p), yₙ = g(n, xₙ, uₙ, wₙ; p),
where n is the step index, x is the state, y is the output, u is the input, and p are the (constant) parameters. This form also calls out w explicitly as a random "disturbance" input. These random inputs are implemented and evaluated using exactly the same methods as the deterministic inputs; any input port can optionally be annotated as "random" when they are being declared (see System<T>::DeclareInputPort() ). Once randomness exists in a system, many signals will throughout the diagram become random variables, but this label is used to denote the "point of entry" for an independent random variable.
The rule in Drake is that every method that can be called during the lifetime of a simulation, (e.g. calculating discrete updates, time derivatives, and/or outputs) must be a completely deterministic function. Any randomness must come in through a random input port. The only exception to this rule is the one specially-implemented internal::RandomSource system, which goes to some length to store the state of the random number generator in its Context so that all simulation and analysis methods are deterministic given a Context. In almost every application, random input ports will be wired up to internal::RandomSource system blocks; we have provided the AddRandomInputs() method to facilitate this.
Algorithms written for Systems can query the property of the InputPort to find the input ports that are labeled as random, and the random vector distribution type. The list of supported distributions for random input ports is intentionally very limited (to simplify algorithm development); we place the burden on the System author to e.g. transform a Gaussian random input with zero mean and unit covariance into the desired shape inside the update and output methods.
In order to specify distributions over random initial conditions and random parameters, System classes may override the methods System<T>::SetRandomState() and System<T>::SetRandomParameters(). Algorithms written for systems may call System<T>::SetRandomContext() (which calls both of these). These methods must be deterministic functions of their input arguments – a (mutable) drake::RandomGenerator is passed in and must be the only source of "randomness". Their implementations are expected to draw samples from random distributions satisfying the C++ Standard Library RandomNumberDistribution concept. Because these distributions can have internal state, we encourage authors to allocate the distribution locally inside the implementation of the SetRandomState() or SetRandomParameters() methods; do not be tempted to create a mutable member variable of your System.
Finally, in some cases the actual constitution of a System is random. A common example of this is when we perform a multibody simulation with a different number of objects generated in the environment for each random simulation. APIs to support this functionality use a systems::analysis::SimulatorFactory method which constructs the random System and its simulation parameters as a deterministic function of the drake::RandomGenerator.
Modules | |
Configuring distributions | |
This page describes how to use classes such as schema::Distribution to denote stochastic quantities, as a bridge between loading a scenario specification and populating the corresponding symbolic::Expression quantities into a systems::System. | |
Configuring transforms | |
This page describes how to use classes such as schema::Rotation and schema::Transform to denote stochastic quantities, as a bridge between loading a scenario specification and populating the corresponding math::RigidTransform quantities. | |