The Solver — The Heart

How Modeloop executes models: the fixed-step solver, deterministic data-flow ordering, hierarchical multi-rate scheduling, and algebraic loop rules.

The solver is the heart of Modeloop: it is the machinery that turns a static diagram into behavior over time. Understanding how it works tells you exactly what your model will do — in simulation and on the target, because generated code follows the same execution model.

Fixed-step execution

Modeloop uses a fixed-step solver. Simulated time advances in constant increments (the base step), and all computation happens at these discrete ticks:

t = 0        t = Δt       t = 2·Δt      t = 3·Δt
  │            │             │             │
  ▼            ▼             ▼             ▼
 step()       step()        step()        step()

At every step, the solver:

  1. Applies inputs — scenario profiles are evaluated at the current time and published to the model’s input signals.
  2. Executes the model — every scheduled part whose period has elapsed (or whose event trigger fired) executes exactly once.
  3. Collects outputs — logged signals are recorded into traces.
  4. Advances timet += Δt, and the cycle repeats.

Why fixed-step?

Variable-step solvers adapt their step size to integration error — useful for stiff continuous physics, but fundamentally at odds with embedded software, where code runs in periodic tasks with hard deadlines. Modeloop targets real-time systems, so it makes the deterministic choice:

  • What you simulate is what runs. A 10 ms task in simulation is a 10 ms task on the target. There is no solver-dependent behavior to re-verify after code generation.
  • Bit-level reproducibility. The same model, inputs, and step size always produce the same trace.
  • Discrete semantics are exact. Unit delays, sampled state charts, and multi-rate scheduling have precise meanings at fixed ticks.

The default sample time is 10 ms; both the base step and every task period are configurable with microsecond resolution.

Deterministic order within a step

Within one activation, block execution order is not something you specify — it is derived from the data flow. Modeloop executes blocks in data-flow order: every block runs only after all of its input producers have run.

This gives single-step convergence: each signal is computed exactly once per step, and every consumer sees the current step’s value. There is no iteration, no “delayed by one step unless…” ambiguity, and no dependence on the order in which you happened to place blocks.

Memory blocks and feedback

A purely instantaneous cycle — A feeds B feeds A, all in the same step — has no valid execution order. This is an algebraic loop, and Modeloop rejects it at validation time rather than trying to iterate to a fixed point.

Feedback is instead expressed through memory blocks (Unit Delay, Integral, Derivative). A memory block’s output depends only on its state from previous steps, so it legally breaks the cycle:

        ┌────────────────────────────┐
        ▼                            │ (state: previous step)
Input ──▶ Sum ──▶ Controller ──▶ Unit Delay

Memory blocks update their state at the end of the step, after all outputs are computed. This two-phase execution (compute outputs, then update states) is what makes feedback well-defined and deterministic.

Hierarchical scheduling

A flat model needs no scheduling decisions at all: everything executes at the base step, in data-flow order. The solver’s hierarchical capabilities come into play when you structure the model into tasks — then scheduling happens at the task level, and each task carries its own rate or trigger.

Multi-rate models

Each periodic task declares its own period. A model can freely mix rates:

Base step: 1 ms

SensorAcquisition   (period  1 ms)  ─ runs every step
ControlLaw          (period 10 ms)  ─ runs every 10th step
Diagnostics         (period 100 ms) ─ runs every 100th step

The solver activates each task when its period elapses. Tasks scheduled at the same tick execute in the scheduling order defined in the build configuration — an explicit, reviewable decision, not an accident of insertion order.

Event-triggered execution

Not everything is periodic. An event task is activated by a boolean control signal: it executes on the trigger’s rising edge, at the tick where the edge is detected.

Inside a task

Hierarchy below the task is structural, not temporal. Containers nested inside a task — at any depth — execute within their task’s activation, in data-flow order across all levels, as if the hierarchy were flattened. Containers organize the model; they never change its timing.

Communication between rates

When a 1 ms task feeds a 10 ms task, the consumer reads the latest published value of each input signal at its own activation. This last-value semantics is simple, deterministic, and identical to sender–receiver communication in embedded middleware — so multi-rate behavior in simulation matches the deployed system.

Runtime safety

While stepping, the solver validates the values it moves. Published outputs are checked for NaN, infinity, and overflow; a detected fault raises a diagnostic with the offending signal and time, and a safe substitute value (0.0) is published so one fault does not corrupt the entire run. See Simulation for the diagnostics reference.

Summary

PropertyModeloop’s choice
Time baseFixed-step, configurable base step (default 10 ms)
OrderingData-flow order — automatic, deterministic
FeedbackOnly through memory blocks; algebraic loops rejected at validation
State updatesTwo-phase: compute outputs, then update states
HierarchyOptional — flat models run at the base step; tasks schedule independently
Multi-ratePer-task periods + explicit scheduling order
EventsEdge-triggered tasks via boolean control signals
Cross-rate dataLast-value semantics through published signals