Controlling determinism¶
InertialSim allows users to fully control the level of determinism in sensor
simulations. Each sensor class (Gyro,
Accelerometer,
Magnetometer,
IMU, and INS)
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
intorarray_like[ints]is passed, then all values must be non-negative and will be passed toSeedSequenceto derive the initialBitGeneratorstate. One may also pass in aSeedSequenceinstance. Additionally, when passed aBitGenerator, it will be wrapped byGenerator. If passed aGenerator, it will be returned unaltered. When passed a legacyRandomStateinstance it will be coerced to aGenerator.
Determinism options¶
We demonstrate the basic options with an accelerometer.
import numpy as np
from inertialsim.devices.imu import example_imu
from inertialsim.geometry import Vector
from inertialsim.sensors import InertialSensorModel
from inertialsim.sensors.accelerometer import Accelerometer
model = InertialSensorModel()
model.data_interface.simulate_quantization = False
model.data_interface.simulate_sample_rate = False
zero_input = Vector.from_xyz([[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.0036563 0.05947886 0.03297517]
Run 2 (seed = None): [-0.01338499 -0.000842 -0.00951671]
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,
Accelerometer,
Magnetometer, and
INS classes contains the entire
simulation state. The IMU state
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
Rotation.from_random.