This example requires external dependencies and cannot be run in the browser.

One Script, Two Engines

Running the same model under PathSim and under FastSim, without changing it.

The idea

FastSim mirrors PathSim's API: the same block names, the same constructor arguments, the same Simulation and Connection, the same Scope.read(). A model written against one runs against the other.

import pathsim as engine    # or:  import fastsim as engine

That is the whole switch. This notebook builds one model, runs it under both, and checks that they agree — and where they do not, says why.

Blocks can also be mixed: fastsim.port.port() accelerates a PathSim block where it can and shims it otherwise, and Simulation ports anything in its blocks list automatically.

The Model

A DC motor under PI speed control — a plant, a controller and feedback, which is enough to exercise algebraic ordering as well as integration:

MATHDISPLAY0ENDMATH

Python
Loading...

System Parameters

Python
Loading...

Block Diagram

The factory takes the engine module and builds the model out of it. Nothing inside depends on which one it is.

Python
Loading...

Simulation

Same call, twice.

Python
Loading...

Results

Python
Loading...

Verification

Both engines record on the same fixed grid, so the trajectories compare sample for sample — no interpolation to blur the answer.

Python
Loading...

Zero — the two engines produce the same doubles here, not merely close ones.

That is not guaranteed in general: two independent implementations of the same recurrence are free to associate their arithmetic differently, and a model with more algebra in it will usually land a few ULP apart instead. What the check is for is the distinction between that and a difference in modelling, which is the kind that grows.

Where They Do Differ

Agreement this close is the normal case, not a universal one. Three things move a model off it, none of them a defect:

  • Stochastic sources. WhiteNoise, PinkNoise and the phase-noise sources draw from engine-specific PRNG streams. Their statistics match; their sample paths do not.
  • Adaptive stepping across a non-smooth point. With adaptive=True, the two step controllers can take different step sequences around a saturation or an event, and then land on slightly different trajectories. Under a fixed step the same models agree to rounding.
  • Event location. An event resolved at a slightly different instant moves everything after it — most visibly for contact events, where a small shift in time is a large shift in state.

The fixed-step run above avoids all three, which is what makes it a clean comparison of the engines rather than of their step controllers.

Mixing Blocks

Models do not have to be all-or-nothing. port turns a PathSim block into a FastSim one — accelerated where its behaviour can be expressed natively, wrapped otherwise. Anything passed in blocks is ported automatically; a block you want to wire has to be ported first, since Connection takes FastSim blocks.

Python
Loading...