Physics: fitting, FMUs and Modelica
A physical network fitted to what was measured, FMUs in the simulation, and the network in Modelica. The equations themselves are in the specification.
Fitting the model to measurements#
archec fit finds the parameters of a physical network from what the real system did — the system
identification MuJoCo is used for, with the model's own network. The measured inputs drive the network,
its outputs are compared with the measured ones, and least squares moves the parameters until they agree.
archec physics examples/dc-motor/main.arche Drive --for 3s --every 10ms --print load.w,motor.la.i --csv run.csv # or a real run
archec fit examples/dc-motor/main.arche Drive run.csv --params motor.r,motor.k,friction.d --html fit.html
fit Drive — 2 signals, 3 parameters; Levenberg–Marquardt, 7 iterations, 41 runs
parameter before fitted uncertainty (1σ)
motor.r 1 Ω 1.30017 Ω ± 0.00025 Ω (0.019 %)
motor.k 0.01 0.0119581 ± 0.000037 (0.31 %)
friction.d 0.1 0.0797134 ± 0.00025 (0.32 %)
signal samples RMS error before after
motor.la.i 301 2.142 A 0.02115 A
load.w 301 0.1955 rad/s 0.005155 rad/s
The data is a CSV (time first, a column per signal, named as the network's variables) or any log
archec replay reads, each message field a series MSG.field: --signals load.w=MOTOR.speed maps one to a
variable. A parameter is a part's (motor.r), the system's, or a parameter, kept within its tolerance.
Two parameters the data cannot tell apart are named (fit-correlated), one it does not see at all is left
alone (fit-no-influence). --write puts the values in the model, the rest of the file as it was. See
docs/commands.md.
FMUs in the simulation#
An FMU (FMI 2.0 for co-simulation, from Modelica, Simulink, Amesim… or archec fmi) can be a component's
continuous behaviour:
archec import plant.fmu -o plant.arche # writes the component below
component Plant {
fmu "plant.fmu"
solver 1ms
in power: data // an input: the flow linked into it
var temp: float64 = 20 // an output (or a parameter): readable by Python and tests
}
The FMU is copied into the project (fmus/) and stepped by Arche's simulation at the solver step, next to the
components with equations: its inputs take the flows arriving at its in ports (or its variables) of the same
name, its outputs go to its out ports (or its variables; upper.level is upper_level). The step uses the
inputs of the step before (co-simulation's usual one-step lag). It runs in arche-cli (and so archec test), in a
small native host: the FMU's binary for this platform, or its sources/ built with the system's C compiler.
Real, Integer, Enumeration and Boolean variables are exchanged (an Integer becomes int32, a Boolean bool); a String one is left out, with a note. The Arche app in the browser cannot run an FMU and says so.
In Modelica#
archec gen --target modelica writes the systems whose parts have equations or physical ports as one
Modelica package, modelica/<project>.mo (the project's name, else the file's — a main.arche's folder),
for OpenModelica, Dymola or any Modelica tool, and an OpenModelica script per system,
modelica/simulate_<System>.mos (omc simulate_Drive.mos there writes Drive_res.csv).
archec gen examples/dc-motor/main.arche --target modelica -o generated
model Drive "A DC motor turning a load"
Modelica.Electrical.Analog.Sources.ConstantVoltage supply(V = 12);
Modelica.Electrical.Analog.Basic.Ground gnd;
DcMotor motor;
Modelica.Mechanics.Rotational.Components.Inertia load(J = 0.01, w(start = 0, fixed = true), phi(start = 0, fixed = true));
…
equation
connect(supply.p, motor.p);
connect(motor.flange, load.flange_a);
…
annotation(experiment(StartTime = 0, StopTime = 3, Interval = 0.006, Tolerance = 1e-06));
end Drive;
- A part of
std/physicsis the Modelica Standard Library (4.0) component it is, its parameters renamed and its states fixed at their start (below). The others — the project's components, and the std parts MSL has no exact match for — are models of their own, with their parameters, variables and equations as written:tistime,clamp(x, lo, hi)ismin(max(x, lo), hi),lnislog,step(x)isif x >= 0 then 1 else 0, a constant its value. - A physical port is MSL's connector (
pin→Interfaces.Pin,flange→Translational.Interfaces.Flange_a,shaft→Rotational.Interfaces.Flange_a,heat→HeatTransfer.Interfaces.HeatPort_a); MSL's mechanical connectors carry a position, so a velocity potential is its derivative (flange.visder(flange.s),shaft.wisder(shaft.phi)). A port type MSL has not (std'sfluid, the project's own) is a connector of the package, its potentials and flows (flow Real q). - A signal (
in/outof a part with equations) is aRealInput/RealOutput; an input fed by several outputs takes their sum, as Arche's simulator adds them; an input nothing in the network feeds is 0. - A composite stays one: its parts and links inside its own model, its parameters passed on
(
Resistor(r = r)isra(R = r)). fn mainthat only waits and sets variables (wait 800ms; valve = 0) iswhen time >= 0.8 then valve := 0;on adiscrete Real; other code (handlers, state machines, any other statement) is left out, with a note.- The experiment runs to the last time the system's test plans check (else 1 s), at its
solverstep (else a 500th of the run), with a tolerance of 1e-6.
| std/physics | Modelica Standard Library | parameters |
|---|---|---|
Resistor |
Electrical.Analog.Basic.Resistor |
r → R |
Capacitor |
Electrical.Analog.Basic.Capacitor |
c → C, v0 → v(start) |
Inductor |
Electrical.Analog.Basic.Inductor |
l → L, i0 → i(start) |
Ground |
Electrical.Analog.Basic.Ground |
|
VoltageSource |
Electrical.Analog.Sources.ConstantVoltage |
v → V |
SignalVoltage |
Electrical.Analog.Sources.SignalVoltage |
its input u is v |
CurrentSource |
Electrical.Analog.Sources.ConstantCurrent |
i → I |
Emf |
Electrical.Analog.Basic.EMF |
k |
Mass |
Mechanics.Translational.Components.Mass (flange_a) |
m, s0 → s(start), v0 → v(start) |
Damper |
Mechanics.Translational.Components.Damper (a, b → flange_a, flange_b) |
d |
Fixed |
Mechanics.Translational.Components.Fixed |
|
Force |
Mechanics.Translational.Sources.ConstantForce |
f → f_constant |
Inertia |
Mechanics.Rotational.Components.Inertia (flange_a) |
j → J, w0 → w(start); phi starts at 0 |
RotationalDamper |
Mechanics.Rotational.Components.Damper |
d |
FixedShaft |
Mechanics.Rotational.Components.Fixed |
|
Torque |
Mechanics.Rotational.Sources.ConstantTorque |
tau → tau_constant |
SpeedSensor |
Mechanics.Rotational.Sensors.SpeedSensor |
its output w |
HeatCapacitor |
Thermal.HeatTransfer.Components.HeatCapacitor |
c → C, t0 → T(start); temp is T |
ThermalConductor |
Thermal.HeatTransfer.Components.ThermalConductor (a, b → port_a, port_b) |
g → G; q is Q_flow |
FixedTemperature |
Thermal.HeatTransfer.Sources.FixedTemperature |
temp → T |
HeatSource |
Thermal.HeatTransfer.Sources.FixedHeatFlow |
q → Q_flow |
Spring, RotationalSpring |
their own equations | their extension is a state of their own, where MSL's reads it from the flanges' positions |
Orifice, Volume, PressureSource |
their own equations, on the package's FluidPort |
MSL's fluids are not lumped linear parts |
Checked against Modelica#
archec verify --modelica simulates each system that has test plans with OpenModelica (omc on the PATH,
or OMC=/path/to/omc), reads the test plans' expectations on its results — at 600ms expect …, within,
never:, always:, a step's expect at 600s: …, over the network's names (tuile.puces.temp, or Arche's
physics.tuile_puces_temp), a value between two samples interpolated — and runs archec physics on the same
network beside it: each state's largest gap, against --tol (1 %) of its span.
archec verify examples/kacao/physique.arche --modelica --system VentilationDegradee # omc runs it
archec verify examples/kacao/physique.arche --modelica --system VentilationDegradee --results run.csv # a run made elsewhere
Here with run.csv from archec physics … VentilationDegradee --for 180s --every 1s --csv run.csv — the gap
is what a sample every second loses against archec physics' 100 ms run:
VentilationDegradee — physique.VentilationDegradee, 180 s (run.csv)
✓ TC-PHY-02 La sonde T/H avant les BFIC (TP-PHY-DEGRADE)
✓ archec physics beside it: 2 states, the largest gap 0.270754 % of a span (allowed 1 %)
tuile.puces.temp max |Δ| 0.0826471 K at 500 ms, span 30.5248
tuile.semelle.temp max |Δ| 0.0109792 K at 500 ms, span 25.926
With no OpenModelica it says so, writes the Modelica anyway and exits 2: simulate it with any Modelica tool and
give its results with --results S_res.csv (--system S), a CSV with the time first (time or t) and a
column per variable by its Modelica name ("tuile.puces.T") or the network's — OpenModelica's CSV, or
archec physics --csv. A case that does things (do …) has no place in a Modelica run and is an error; so is a
name the results do not have (a state machine's state). Exit 1 when a case fails or archec physics disagrees.
The structure of the Modelica written is checked without a Modelica parser by checkModelica (in the
library): classes opened and closed in order, parentheses, each statement's ;, every class used one of the
package's or an MSL class of the table with the modifiers set there, every connect between declared
instances — the tests run it on the examples, and run OpenModelica on them when it is installed.