Skip to content

DiscreteControlLoopSimulator

Bases: BaseSimulator

Closed-loop simulator: simulate, observe, filter, and decide controls online.

Unlike DiscreteTimeSimulator, which requires the entire control trajectory as a pre-supplied ctrl_values array, DiscreteControlLoopSimulator computes each \(u_k\) online from the current belief via control_policy.

Which control an observation sees is set by the model's dynamics.observation_control_alignment -- the same field that governs open-loop simulation.

With convention "previous_transition", the control \(u_k\) is chosen after seeing the observation \(y_k\) (which uses the previous control). The policy therefore sees the filtered belief \(\hat p_k\). This is the only convention the filtered closed loop supports for now, and it is what an unspecified (None) field resolves to, with a warning.

With convention "same_time", the control \(u_k\) would be chosen before seeing the observation \(y_k\) it drives, so the policy would see the predicted belief \(\tilde p_k\). That needs separate prediction and analysis filter steps, which cuthbert does not expose; an explicit "same_time" raises NotImplementedError until they are built.

Both loops are written out in full on the Closed-loop control page.

With use_true_state=True the loop skips filtering altogether and hands the policy the true state \(x_k\). Both conventions run.

The one-step filter update runs on the cuthbert backend (filter_source="cuthbert"). See the filters page for the available filters, and build_cuthbert_filter in discrete_filter.py for which of them the online update supports. Plated controlled simulation is not yet supported; see Issue #318.

Attributes:

Name Type Description
control_policy

Control policy \(\pi\); see PolicyCallable. Its initial state \(s_0\) is exactly simulate's initial_policy_state argument (default None, for a stateless policy) -- control_policy is never introspected for an initial_state() method; a stateful policy's initial state must always be passed explicitly.

filter_config

Selects the filtering algorithm; any config build_cuthbert_filter accepts (see above). Defaults to _default_filter_config(dynamics) when None. The online one-step update currently requires filter_source="cuthbert". Its record_filtered_states_mean/record_max_elems fields gate whether the filtered_states_mean output is recorded, exactly as they do for Filter (see dynestyx.utils.recording._should_record_field). Must not be given together with use_true_state=True, which filters nothing.

use_true_state

Give the policy the true state \(x_k\) instead of a filtered belief, and run no filter at all. Defaults to False. Observations are still emitted and returned, but nothing consumes them, and filtered_states_mean is always None.

n_simulations int

Currently only 1 is supported.

simulate(dynamics: DynamicalModel, *, rng_key: PRNGKeyArray, ctrl_times: Real[Array, ' ctrl_time'] | None = None, ctrl_values: Real[Array, 'ctrl_time control_dim'] | Real[Array, ' ctrl_time'] | None = None, predict_times: Real[Array, ' predict_time'] | None = None, initial_policy_state: PyTree | None = None, **kwargs: Any) -> ControlledSimulatedResult

Simulate one online controlled trajectory.

Parameters:

Name Type Description Default
dynamics DynamicalModel

Discrete-time dynamical model.

required
rng_key PRNGKeyArray

Root key for environment and fallback filter randomness.

required
ctrl_times Real[Array, ' ctrl_time'] | None

Unsupported because controls are selected online.

None
ctrl_values Real[Array, 'ctrl_time control_dim'] | Real[Array, ' ctrl_time'] | None

Unsupported because controls are selected online.

None
predict_times Real[Array, ' predict_time'] | None

Strictly increasing simulation times.

None
initial_policy_state PyTree | None

Initial state passed to control_policy.

None
**kwargs Any

Additional shared simulator-handler metadata, ignored here.

{}

Returns:

Type Description
ControlledSimulatedResult

States, observations, controls, filtered beliefs and policy states

ControlledSimulatedResult

on all predict_times.

ControlledSimulatedResult

Under the "same_time" convention, the states are of length len(predict_times), but the controls and observations are of length len(predict_times) - 1.

ControlledSimulatedResult

Under the previous_transition convention, the states are of length len(predict_times), but the controls and observations are of length len(predict_times) - 1.

Raises:

Type Description
ValueError

If inputs are incompatible with online discrete control.

NotImplementedError

If the requested simulation mode is unsupported, including an explicit observation_control_alignment="same_time" while filtering (use_true_state=False).

Warns:

Type Description
UserWarning

If dynamics.observation_control_alignment is unspecified (None); "previous_transition" is used.

ControlledSimulatedResult

Bases: SimulatedResult

SimulatedResult extended with the control loop's extra outputs.

Registered as deterministic sites the same generic way as SimulatedResult's own fields.

Both conventions return \(N+1\) states and \(N\) controls, so the array lengths alone do not say which one ran: consult obs_times, which is \([t_0, \dots, t_{N-1}]\) under "same_time" and \([t_1, \dots, t_N]\) under "previous_transition".

unflatten(layout: LayoutCollection) -> StructuredControlledSimulatedResult

Return a structured copy of this result.

Converts fields as SimulatedResult.unflatten does. filtered_states_mean is converted by layout.state, and policy_states is copied unchanged.

StructuredControlledSimulatedResult

Bases: StructuredSimulatedResult

A ControlledSimulatedResult with structured values.

Returned by ControlledSimulatedResult.unflatten. filtered_states_mean shares the structure of the state fields; policy_states is unchanged. flatten(layout) converts back to a ControlledSimulatedResult.

flatten(layout: LayoutCollection) -> ControlledSimulatedResult

Return the flat result that unflatten(layout) converted.

layout must be the LayoutCollection passed to unflatten. Raises ValueError if a structured field has no sublayout.