Controlling determinism¶
InertialSim allows users to fully control the level of determinism in sensor
simulations. Each sensor class (Gyro,
Accelerometer, and
IMU) takes an optional rng
argument. This
argument is passed to the numpy.random.default_rng class with the following
behavior.
If None, then fresh, unpredictable entropy will be pulled from the OS. If an
int
orarray_like[ints]
is passed, then all values must be non-negative and will be passed toSeedSequence
to derive the initialBitGenerator
state. One may also pass in aSeedSequence
instance. Additionally, when passed aBitGenerator
, it will be wrapped byGenerator
. If passed aGenerator
, it will be returned unaltered. When passed a legacyRandomState
instance it will be coerced to aGenerator
.
Determinism options¶
We demonstrate the basic options with an accelerometer.
import numpy as np
from inertialsim.devices import example_imu
from inertialsim.geometry import Vector
from inertialsim.sensors import SensorModel
from inertialsim.sensors.accelerometer import Accelerometer
model = SensorModel()
model.data_interface.simulate_quantization = False
model.data_interface.simulate_sample_rate = False
zero_input = Vector.from_cartesian([[0, 0, 0], [0, 0, 0]], time=[0.0, 0.01])
# Seed is None means "fresh, unpredictable entropy". None is the default but is
# specified explicitly here for illustration.
seed = None
accelerometer = Accelerometer(model, example_imu, rng=seed)
result = accelerometer.simulate(specific_force=zero_input)
print(f"Run 1 (seed = None): {np.squeeze(result.specific_force.data[0])}")
accelerometer = Accelerometer(model, example_imu, rng=seed)
result = accelerometer.simulate(specific_force=zero_input)
print(f"Run 2 (seed = None): {np.squeeze(result.specific_force.data[0])}")
# Seed is int means repeatable output (a different output per integer).
seed = 7
accelerometer = Accelerometer(model, example_imu, rng=seed)
result = accelerometer.simulate(specific_force=zero_input)
print(f"Run 1 (seed = int): {np.squeeze(result.specific_force.data[0])}")
accelerometer = Accelerometer(model, example_imu, rng=seed)
result = accelerometer.simulate(specific_force=zero_input)
print(f"Run 2 (seed = int): {np.squeeze(result.specific_force.data[0])}")
Run 1 (seed = None): [-0.02138932 -0.02035507 0.01191007]
Run 2 (seed = None): [-0.0526421 0.01983978 -0.02136171]
Run 1 (seed = int): [-0.01568841 0.01027257 0.00906132]
Run 2 (seed = int): [-0.01568841 0.01027257 0.00906132]
Simulation results¶
The state
attribute of the Gyro and
AccelerometerResult
classes contains the entire simulation state. The
IMU attribute returns both the internal
gyro and accelerometer states of the IMU.
The rng field saves the underlying bit generator state numpy.random.PCG64.state when the sensor is initialized. This can be used to recreate a bit generator from a previously saved run.
Other types¶
Other InertialSim types support a similar rng
input with the same behavior
described above. In particular most geometry types support generation of random
samples. For example, see
Vector.from_random.