Parameters & Data

Centralized parameter management: $references, workspace and model data contexts, user-defined types, and calibration data in generated code.

Hardcoded numbers scattered across a diagram are the modeling equivalent of magic numbers in code. Modeloop provides a data system that centralizes parameters, types, and calibration values, and lets blocks reference them by name.

$references

Any block parameter can be a reference instead of a literal. Prefix a name with $ and the value is resolved from the data context:

Constant block:   value = $Kp          →  2.5
Multiply gain:    gain  = $speed_scale →  0.10471975  (rpm → rad/s)

The benefits compound as models grow:

  • One definition, many uses. Change $Kp once; every block that references it follows.
  • Meaningful diffs. A tuning change is a change to one named value, not edits to a dozen blocks.
  • Reviewable models. $wheel_radius_m documents intent; 0.334 does not.

Data contexts

Parameters live in a data context with two scopes:

ScopeContentsTypical use
WorkspaceData shared across the projectPhysical constants, shared calibration, conversion factors
ModelData local to one modelController gains, model-specific limits

Model scope shadows workspace scope on name collisions, so components can specialize shared defaults locally.

Fail-fast resolution

Reference resolution is validated before anything executes. When you build, simulate, or generate code, Modeloop first traverses the entire diagram — every block, every container level — and verifies that each $reference resolves in the data context.

If any reference is missing, the operation aborts with the complete list of unresolved names before a single line of code is generated. There are no partially resolved builds and no runtime “undefined parameter” surprises: a model either resolves completely or does not build.

After validation, all references are substituted with their values — simulation and code generation always work with a fully resolved model.

User-defined types

The data system also owns type definitions. You can declare enumeration types once and use them across the model:

Type: DriveMode
  ECO    = 0
  NORMAL = 1
  SPORT  = 2

Enum types are usable everywhere a type appears: constants and model inputs can hold DriveMode.SPORT, comparators and state chart guards can test against members, and MDL accepts qualified literals inline. In generated C the type becomes a proper typedef enum with named constants; generated Python uses the same symbolic names. See Signals.

Calibration data in generated code

Parameters intended for post-build tuning can be marked with the calibration storage class. In generated C they are emitted as addressable calibration symbols — grouped in a dedicated, build-level calibration unit shared across components — rather than folded into expressions as anonymous literals.

This is the contract calibration tools expect: stable names and addresses for every tunable value. Two rules follow:

  • A calibration parameter shared by several components is defined once at build level; components reference the shared definition.
  • Two models defining the same calibration name with different values is a build error, not a silent pick-one. Conflicts are surfaced honestly.

Ordinary (non-calibration) parameters are resolved at generation time and embedded directly in the generated code.

Practical guidance

  1. Reference anything you might tune. Gains, limits, thresholds, physical constants — if a value could change without changing the model’s structure, make it a $reference.
  2. Keep literals for structure. The number of inputs on a sum block or a table’s breakpoint count are structural; inline values are fine there.
  3. Name with units. $max_torque_nm, $sample_offset_v. The name is the documentation.
  4. Prefer workspace scope for shared truths. Physical constants defined per-model drift apart; define them once.
  5. Use enums for modes. Any signal whose values are “one of a small set of meanings” should be an enum type, not an integer convention.