C Code Generation
Turning a block diagram into standalone C99, and proving the C still solves the same problem.
What comes out
to_c lowers the assembled model to self-contained C99 — libm and nothing else. All state lives in one instance struct, so the code is reentrant and several generated models can link into the same binary. That is what makes it usable on a microcontroller, in a HIL rig, or inside an FMU.
The generated code is not a transcription of the Python. The model first becomes the typed IR, where every block is reduced to scalar operations; the C is emitted from that.
Simulation.to_c() returns the sources as a dict, and Simulation.verify_c() compiles them, integrates both the C and the engine over the same trajectory, and compares state by state.
The Model
A DC motor under PI speed control — a small system with a controller, an integrator and feedback, which is the shape most embedded models have:
MATHDISPLAY0ENDMATH
The Reference Run
Generating the C
to_c returns the sources keyed by file name.
The interface
The header is the whole contract: one struct holding the state, an enum naming every addressable signal, and a handful of functions.
Nothing is global, so two instances of the model can run side by side in one process — the property that makes the code safe to drop into an RTOS task or an FMU.
Signals are reached by name through the enum rather than by digging into the struct layout: motor_get_signal(&m, MOTOR_SIG_ODE_y) is the motor's output wherever the code generator decided to put it.
Verification: Software in the Loop
Reading the C is not evidence. verify_c compiles it with a local C compiler, integrates the binary and the engine over the same trajectory, and compares the state vector at every step.
The figure it reports is a scaled error, MATHINLINE0ENDMATH, so a value below 1 means the C stayed inside the tolerance at every step of every state.
Compiling and Running It Ourselves
The same C, driven the way an application would: write the files out, add a main that steps the model, compile, and run it.
Code Generation Options
The same model lowers several ways. The axes are independent, and every combination is checked by the test suite against the engine.
numeric="float" is the one that changes the answer rather than just the shape: single precision costs about seven digits, which matters on a target without a double-precision FPU. The verification above is what tells you whether that is affordable for a given model.