FMU Export in Rust

Generate FMUs with rust-fmi

Back when I updated the rust-fmi library in early 2024 to support FMI 3.0, I did it mostly out of interest in learning the new standard and its features. I hadn't had access to a commercial modeling tool such as Dymola for a while, and since OpenModelica didn't (and still doesn't) support FMI3 export, I was limited at the time to testing the new import code with the Modelica reference FMUs.

Even at the beginning of the project several years earlier, I thought it would be cool to also support the creation of FMUs. I didn't have a clear idea about what that would look like, or what a direct Rust implementation would offer over existing tools, and actually my experience with Rust wasn't as extensive then. Now with the recent addition of the FMI layered standards such as fmi-ls-bus, I started imagining how Rust-based FMUs could be used in a heterogeneous HIL/SIL setup, with real controllers and other components implemented in Rust, as well as e.g., gateway FMUs connecting to real CAN or Ethernet networks.

After a few weeks of evening and weekend work, I'm excited to announce experimental support for generating and exporting FMUs (Functional Mockup Units) directly from Rust code using rust-fmi. With both export and import capabilities, this brings the power of Rust to the FMI world, offering a memory-safe alternative to modeling tools and C/C++ implementations.

What is an FMU?

  • An FMU (Functional Mockup Unit) is a self-contained, tool-agnostic simulation component (shared library + XML metadata in a zipfile container).
  • Defined by the FMI standard, enabling standardized integration of models across tools for system integration, HIL testing, protected model exchange, and digital twin scenarios.
  • For Rust developers, FMUs provide a path to plug safe, performant Rust-based controllers and algorithms into established engineering workflows in automotive, aerospace, and industrial automation without necessarily exposing source code.

Existing development

Generating FMUs is typically accomplished with one of two approaches:

  1. Model-based tools - While powerful, the best here require expensive commercial licenses
  2. Manual C/C++ implementation - This requires writing substantial boilerplate code, manually authoring XML model descriptions, and managing complex build processes

🦀 Rust on the scene

With rust-fmi's new export capabilities, you can now define your entire FMU model in a single Rust struct using derive macros. The library automatically generates:

A Simple Example

Here's how easy it is to re-create the VanDerPol oscillator FMU in Rust, complete with array state variables:

/// Van der Pol oscillator FMU model
///
/// This is implemented as a system of first-order ODEs:
/// - der(x0) = x1  
/// - der(x1) = μ(1 - x0²)x1 - x0
#[derive(FmuModel, Default, Debug)]
struct VanDerPol {
    /// State variables (x[0], x[1])
    #[variable(causality = Output, variability = Continuous, state, start = [2.0, 0.0], initial = Exact)]
    x: [f64; 2],

    /// Derivatives of state variables (der(x[0]), der(x[1]))
    #[variable(causality = Local, variability = Continuous, derivative = x, initial = Calculated)]
    der_x: [f64; 2],

    /// Scalar parameter μ
    #[variable(causality = Parameter, variability = Fixed, start = 1.0, initial = Exact)]
    mu: f64,
}

impl UserModel for VanDerPol {
    type LoggingCategory = DefaultLoggingCategory;

    fn calculate_values(&mut self, _context: &ModelContext<Self>) -> Result<Fmi3Res, Fmi3Error> {
        // Calculate the derivatives according to Van der Pol equations:
        // der(x[0]) = x[1]
        self.der_x[0] = self.x[1];

        // der(x[1]) = mu * ((1 - x[0]²) * x[1]) - x[0]
        self.der_x[1] = self.mu * ((1.0 - self.x[0] * self.x[0]) * self.x[1]) - self.x[0];

        Ok(Fmi3Res::OK)
    }
}

// Export the complete FMU with C API
fmi_export::export_fmu!(VanDerPol);

That's it! This single Rust file defines a complete, functional FMU that can be used in any FMI-compliant simulation environment.

This code generator creates the following modelDescription.xml for you automatically:

<?xml version="1.0" encoding="UTF-8"?>
<fmiModelDescription fmiVersion="3.0" modelName="vanderpol" instantiationToken="ec737b5d-a92d-5527-9670-10230e0879f7" description="Van der Pol oscillator FMU example ported from Reference FMUs" version="0.1.0" generationTool="rust-fmi" generationDateAndTime="2025-09-10T14:46:05.166472+00:00">
  <ModelExchange modelIdentifier="vanderpol" canGetAndSetFMUState="false" canSerializeFMUState="false"/>
  <DefaultExperiment startTime="0" stopTime="20" stepSize="0.01"/>
  <ModelVariables>
    <Float64 name="time" valueReference="0" causality="independent" variability="continuous" description="Simulation time"/>
    <Float64 start="2 0" initial="exact" name="x" valueReference="1" causality="output" variability="continuous">
      <Dimension start="2"/>
    </Float64>
    <Float64 initial="calculated" name="der_x" valueReference="2" variability="continuous">
      <Dimension start="2"/>
    </Float64>
    <Float64 start="1" initial="exact" name="mu" valueReference="3" causality="parameter" variability="fixed"/>
  </ModelVariables>
  <ModelStructure>
    <Output valueReference="1"/>
    <ContinuousStateDerivative valueReference="2"/>
    <InitialUnknown valueReference="2"/>
  </ModelStructure>
</fmiModelDescription>

Key Benefits

Architecture Highlights

The implementation leverages several key components:

Current Limitations

This feature is experimental with some important caveats:

Kicking the Tires

Check out the examples of ports of reference FMUs like the VanDerPol, Dahlquist, BouncingBall and Stair. You can build them with Cargo:

cargo xtask bundle --package bouncing_ball

And test using either your favorite FMI importer or the included fmi-sim tool:

cargo run --package fmi-sim -- --model target/fmu/bouncing_ball.fmu model-exchange

The Future

Depending on feedback, interest, and my own time, I'd like to add support for:

Community

The rust-fmi project is open source and actively seeking contributors. Whether you're a simulation expert, Rust developer, or FMI user, I'd love your feedback and contributions.


The rust-fmi project is bringing Rust to the Modelica and FMI community. Try it out and let me know what you think!