PathSim: Differentiable System Simulation
PathSim is a flexible block-based time-domain system simulation framework in Python with automatic differentiation capabilities and an event handling mechanism! It provides a variety of classes that enable modeling and simulating complex interconnected dynamical systems through Python scripting.
All of that with minimal dependencies, only numpy, scipy and matplotlib!
Key Features:
Hot-swappable blocks and solvers during simulation
Blocks are inherently MIMO (Multiple Input, Multiple Output) capable
Wide range of numerical integrators (implicit, explicit, high order, adaptive)
Modular and hierarchical modeling with (nested) subsystems
Event handling system to detect and resolve discrete events (zero-crossing detection)
Automatic differentiation for fully differentiable system simulations
Extensibility by subclassing the base Block class and implementing just a handful of methods
The source code can be found in the GitHub repository.
Quickstart
Install PathSim with pip:
pip install pathsim
Build and simulate a system unsing blocks and connections:
import numpy as np
from pathsim import Simulation, Connection
from pathsim.blocks import Source, Integrator, Scope
Sr = Source(np.sin)
In = Integrator()
Sc = Scope()
Sim = Simulation(
blocks=[Sr, In, Sc],
connections=[
Connection(Sr, In),
Connection(Sr, Sc[0]),
Connection(In, Sc[1]),
],
dt=0.01
)
Sim.run(10)
Sc.plot()
Table of Contents
This documentation is structured in the following way:
An Example
Here’s a simple example of a linear feedback system, simulated with PathSim.
The block diagramm can be translated to a netlist by using the blocks and the connection class provided by PathSim:
from pathsim import Simulation, Connection
from pathsim.blocks import Source, Integrator, Amplifier, Adder, Scope
#values parameters
a, b, x0 = -1, 1, 2
#step function
tau = 3
def s(t):
return b*int(t>tau)
#blocks that define the system
Src = Source(s)
Int = Integrator(x0)
Amp = Amplifier(a)
Add = Adder()
Sco = Scope(labels=["step", "response"])
blocks = [Src, Int, Amp, Add, Sco]
#the connections between the blocks
connections = [
Connection(Src, Add[0], Sco[0]),
Connection(Amp, Add[1]),
Connection(Add, Int),
Connection(Int, Amp, Sco[1])
]
#initialize simulation with the blocks, connections, timestep
Sim = Simulation(blocks, connections, dt=0.01, log=True)
#run the simulation for some time
Sim.run(4*tau)
#plot the results from the scope
Sco.plot()