Applications as packages
An estimator, a soft sensor, a controller or a plant model reaches taktwerk the same way: as a model package, an FMU or a raw C library with its descriptor. The package carries the computation; a project file per plant binds it. This page is about designing that interface so one package serves many plants and is safe to put in a loop.
Format
- FMI 3 is the recommended format: any tool that exports FMI 3 co-simulation for Linux works, the sizes are structural parameters, and the same FMU runs in other importers. See FMI 3.
- C in the recommended shape:
taktwerk import-header --shapewrites a confirmed descriptor from the header, nothing to review.taktwerk fmu-wrapturns the package into an FMI 3 FMU for other importers. - An existing C interface stays as it is behind a hand-confirmed descriptor.
The interface
| what the application has | declare it as |
|---|---|
| measurements, set points from the PLC, results of other instances | inputs |
| estimates, manipulated values, predictions, diagnostics | outputs |
| values an operator changes while it runs: set points, weights, enable flags, limits | tunables, with a range |
| values fixed for a plant: model constants, initial state, matrices | parameters |
| sizes: states, channels, horizon, measurement count | dimensions, with min, max and a default |
| whether its outputs may be used | a status output, see Status and the write gate |
| random draws | a seed parameter or tunable (Seeds) |
| a configuration or data file name | a text parameter |
- Size-generic. A dimension instead of a literal length lets one package serve a plant with three measurements and one with twelve; the project binds the length per instance.
- Units and descriptions on every variable (an FMU’s
unitanddescription, a comment in the recommended C shape) show ininspect,check, on the OPC UA server and in the workbench. - Start values for inputs and tunables make a fresh instance sensible before anything
writes them: an FMU’s
start, a descriptor’sstart. - Inputs carry no validity of their own. An input is a value; whether it is fresh is the
engine’s job (
max_age_ms: a stale input skips the tick), whether it is plausible is the package’s: check it and report it in the status. - A failed step is for bugs. A non-success return stops the engine and every instance in it
(or, with the instance’s
on_error = "hold"or"safe", takes the instance down until a re-init, the status degraded and the heartbeat held; see Faults). A step that can go on (a bad measurement, a solver that did not converge this step) returns success, holds or flags its outputs and sets a status bit. - No allocation and no blocking I/O in a step. Read files and allocate at init.
Files the application reads
A data file named by a text parameter is opened by the library itself, relative to the engine’s
working directory: on a device the release directory of the bundle
(Units), so a path relative to the bundle’s top works there. Such a
file is not part of the package’s hash: run.json and a campaign’s spec hash cover the
descriptor and lib/ of a raw package, and an FMU’s description, binaries and resources/. Data
that belongs to the model goes into an FMU’s resources/; data that belongs to a plant goes
into the bundle, whose manifest hashes every file.
Shipping
A bundle carries the package with a project file per stage of commissioning, so one deploy
holds them all and start --project picks one:
estimator-line-1/
taktwerk-bundle.toml name, projects = ["sim.toml", "dry-run.toml", "loop.toml"]
packages/estimator/ the package: descriptor and lib/<arch>/, or an .fmu
packages/plant/ a plant model for the simulated stage
sim.toml plant model and application wired in the image, no plant connector
dry-run.toml the plant connector with writes = "dry-run"
loop.toml writes = "on", a write gate on the application's status
scenarios/ tests of the package, see Testing
See Bundle for the bundle file and Commissioning for the stages.