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
$Kponce; 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_mdocuments intent;0.334does not.
Data contexts
Parameters live in a data context with two scopes:
| Scope | Contents | Typical use |
|---|---|---|
| Workspace | Data shared across the project | Physical constants, shared calibration, conversion factors |
| Model | Data local to one model | Controller 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
- 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. - 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.
- Name with units.
$max_torque_nm,$sample_offset_v. The name is the documentation. - Prefer workspace scope for shared truths. Physical constants defined per-model drift apart; define them once.
- 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.