PhysioModeler¶
PhysioModeler is designed as an educational tool to help model and simulate physiological systems1, as represented by ordinary differential equations (ODEs). The design goal for this package is an explicit, easy to use, easy to read interface.2
A Model is defined by at least two pieces of information: what are the state
components, and how do they change? A state component generally represents a
physical quantity, like volume or distance. The rate of change of the state are
described by differential equations.
pendulum_model = Model(
dynamics=..., # describes how the state change
state_components=..., # which state components to track
parameters=..., # model parameters
inputs=..., # inputs to the model
)
Example: undamped pendulum¶
A classic example is the humble undamped pendulum. If you know the position and angular velocity (i.e. how fast the pendulum is swinging) at any point in time, you can predict the movement of the pendulum in the future. Therefore, we track the angle \(\theta\) and angular velocity \(\frac{d\theta}{dt}\) as state.
The way a pendulum swings can be modelled using the second derivative of the angle the pendulum makes with a vertical line, known as the angular acceleration \(\frac{d^2\theta}{dt}\).
The angular acceleration \(\frac{d^2\theta}{dt^2}\) describes how the angular
velocity \(\frac{d\theta}{dt}\) changes over time, while the angular velocity
describes how the angle \(\theta\) changes over time. The Python-function below
receives the state components \(\theta\) ('theta') and \(\frac{d\theta}{dt}\)
('dtheta'), and returns how they change over time, respectively as
\(\frac{d\theta}{dt}\) ('dtheta') and \(\frac{d^2\theta}{dt^2}\) ('ddtheta').
import math
def update_angle_angular_velocity(time, state, inputs, parameters):
l = parameters['length']
g = inputs['gravity']
return {
"dtheta": state['dtheta'],
"ddtheta": -g / l * math.sin(state['theta'])
}
We now have the minimal amount of information requires to create a Model.
However, there are two pieces of information missing: the parameter \(l\) for the
length of the pendulum, and the gravity \(g\) that pulls on the pendulum. These
can be provided as parameters and inputs. Parameters are constant values
that describe characteristics of the model itself, while inputs describe
external influences which might change over time. In this case, we assume
gravity is constant.
pendulum_model = Model(
state_components=["theta", "dtheta"], # which state components to track
function=update_angle_angular_velocity, # how the state change
parameters={"l": 1}, # model parameters
inputs={"g": 9.81}, # external values
)
We can now run a simulation of this model. If we don't tell it otherwise, the simulation will start with \(\theta=0\,\mathrm{rad}\) and \(\frac{d\theta}{dt}=0\,\mathrm{rad}/\mathrm{s}\). Since a static pendulum is not much fun at all, let's have it start at an angle of \(1\,\mathrm{rad}\).
The simulation result is a pandas DataFrame, which supports easy plotting of the results.
Including the parameters and inputs in the model definition (instead of depending on external dictionaries or hard-coded values) allow for easy comparison of different scenarios: