Files
Entropyk/bindings/fmi/README.md

5.0 KiB

entropyk-fmi — Export FMI 2.0 Co-Simulation (FMU)

Compile un modèle Entropyk (JSON) en une archive .fmu conforme FMI 2.0 Co-Simulation, embarquable sur un PLC / contrôleur industriel (Beckhoff TwinCAT, B&R, Siemens TIA, Codesys) ou testable sur PC avec fmpy / OpenModelica.

Principe

  • Le moteur Entropyk (Rust) est compilé en cdylib et exporte l'ABI C standard fmi2*.
  • Le modèle JSON + la carte d'entrées/sorties (fmu_io.json) sont embarqués dans le binaire à la build (codegen) — aucun accès fichier au runtime.
  • L'hôte (PLC) pilote le scheduler temps réel ; chaque fmi2DoStep re-resout le cycle stationnaire aux entrées courantes (co-simulation quasi-stationnaire).

Générer un FMU

# Cible hôte (PC courant) — pour test avec fmpy
cargo run -p entropyk-cli -- export-fmu \
  -c crates/cli/examples/chiller_aircooled_r134a.json \
  -i bindings/fmi/examples/chiller_aircooled_io.json \
  -t host \
  -o target/chiller.fmu

Cross-compilation (arm / x86)

Installer les cibles Rust voulues, puis :

# Linux x86_64
rustup target add x86_64-unknown-linux-gnu
cargo run -p entropyk-cli -- export-fmu -c <model.json> -i <io.json> \
  -t x86_64-unknown-linux-gnu -o target/model_linux64.fmu

# Linux ARM64 (aarch64)
rustup target add aarch64-unknown-linux-gnu
cargo run -p entropyk-cli -- export-fmu -c <model.json> -i <io.json> \
  -t aarch64-unknown-linux-gnu -o target/model_aarch64.fmu

# Linux ARM32 (Cortex-A, hard-float)
rustup target add arm-unknown-linux-gnueabihf
cargo run -p entropyk-cli -- export-fmu -c <model.json> -i <io.json> \
  -t arm-unknown-linux-gnueabihf -o target/model_arm32.fmu

# Windows x86_64 (PLC TwinCAT sur IPC Windows)
rustup target add x86_64-pc-windows-msvc
cargo run -p entropyk-cli -- export-fmu -c <model.json> -i <io.json> \
  -t x86_64-pc-windows-msvc -o target/model_win64.fmu

Le dossier binaries/<platform>/ est choisi automatiquement depuis le triple cible :

Triple cible Dossier FMI
x86_64-unknown-linux-gnu / musl linux64
aarch64-unknown-linux-gnu / musl linuxaarch64
arm-unknown-linux-gnueabihf linuxarm32
x86_64-pc-windows-msvc / gnu win64
x86_64-apple-darwin / aarch64-apple-darwin darwin64

Cross-compiler Linux depuis Windows : installez les linkers croisés (ex. aarch64-linux-gnu-gcc) et configurez [target.<triple>] linker = "..." dans ~/.cargo/config.toml. Le codegen du crate staged hérite de la config cargo de l'utilisateur.

Contenu de l'archive .fmu

modelDescription.xml          (déclare les entrées/sorties, le GUID, le modelIdentifier)
binaries/<platform>/entropyk_fmi.{so|dll|dylib}
resources/config.json        (le modèle Entropyk, pour référence)
resources/fmu_io.json         (la carte d'entrées/sorties)

Carte d'entrées/sorties (fmu_io.json)

Déclare quelles variables le PLC peut écrire (entrées) et lire (sorties). Les valueReference sont attribués dans l'ordre : entrées d'abord (0..n_inputs), puis sorties (n_inputs..).

{
  "inputs": [
    { "name": "T_air_c",   "component": "cond_air_in",   "param": "t_dry_c",     "kind": "input" },
    { "name": "m_air",     "component": "cond_air_in",   "param": "m_flow_kg_s",  "kind": "input" }
  ],
  "outputs": [
    { "name": "COP",       "kind": "cop" },
    { "name": "Q_cool_kW", "kind": "q_cooling_kw" },
    { "name": "P_kW",      "kind": "compressor_power_kw" },
    { "name": "P_evap_bar","kind": "pressure_bar",    "edge": 3 }
  ]
}

kind pour les sorties : cop, q_cooling_kw, q_heating_kw, compressor_power_kw, pressure_bar, enthalpy_kj_kg, mass_flow_kg_s. Les trois derniers nécessitent edge (index d'arête).

Mode dev (sans codegen)

Pour itérer sans recompiler le FMU à chaque changement de modèle, le runtime peut lire le modèle depuis des variables d'environnement au lieu de la version embarquée :

cargo build -p entropyk-fmi
export ENTROPYK_FMU_MODEL=crates/cli/examples/chiller_aircooled_r134a.json
export ENTROPYK_FMU_IO=bindings/fmi/examples/chiller_aircooled_io.json
# charger target/debug/entropyk_fmi.{so|dll} dans fmpy comme FMU Co-Sim

Test rapide avec fmpy (Python)

uv pip install fmpy
uv run python -c "from fmpy import simulate_fmu; simulate_fmu('target/chiller.fmu', stop_time=1.0)"

Limites actuelles (skeleton)

  • Pas de warm-start : chaque doStep reconstruit le graphe System et relance un Newton à froid. Pour un cycle 100 ms c'est acceptable ; l'optimisation (réutiliser l'état précédent + le System construit) nécessite de scinder execute_simulation en build_system + solve_warm — TODO.
  • Backend fluide : le FMU embarque actuellement le backend déclaré dans le JSON (CoolProp inclus). Pour un petit MCU, préférer le backend tabulaire (tables précalculées hors-ligne) ; vérifier la couverture de la plage de fonctionnement.
  • Itérations bornées : à configurer via solver.max_iterations dans le modèle pour garantir un budget temps réel par pas.