Ordinary Differential Equations in 2D
Phase Planes, Nullclines, and Oscillations
This session moves from time-series thinking to phase-plane thinking. Instead of following one scalar variable, we now track two coupled state variables and interpret trajectories geometrically in the plane (Strogatz 2024; Virtanen et al. 2020).
\[ \dot x = f(x, y; \theta), \qquad \dot y = g(x, y; \theta), \tag{1}\]
where the qualitative behavior can depend strongly on both the initial state \((x_0, y_0)\) and the parameters \(\theta\).
From Scalar ODEs to Planar Systems
The numerical solver workflow does not change:
- write the right-hand side,
- choose parameters and an initial condition,
- integrate with
solve_ivp(), - interpret the result.
What changes is the geometry. In two dimensions, you can study nullclines, fixed points, stability, limit cycles, and excitability directly in the phase plane.
Case Studies
Start with the CDIMA reaction, which gives a full worked example of nullclines, fixed points, stability, and trajectories.
Then study a self-excited oscillator with a stable limit cycle.
Then move to a fast-slow excitable system inspired by neuroscience.
Use the animation template when you build your own interactive visualization.
When the workflow is clear, move to the assignment.
Learning Goals
- Simulate planar dynamical systems with
solve_ivp(). - Plot trajectories in the phase plane.
- Compute and interpret nullclines and fixed points.
- Distinguish stable equilibria, limit cycles, and excitable transients.
- Build simple Matplotlib animations and interactive initial-condition updates.
Flow of This Session
- Start from a worked example in CDIMA.
- Reuse the same pipeline for Van der Pol and FitzHugh–Nagumo.
- Compare trajectories across initial conditions and parameter values.
- Add animation and interaction in Matplotlib.
- Summarize the qualitative behavior of the model you choose for the assignment.
What do we need?
scipy.integrate.solve_ivp
This remains the main numerical solver. The main change from the scalar ODE workflow is that the state now has two components.
matplotlib.pyplot
Use Matplotlib to plot trajectories, nullclines, fixed points, and time traces.
matplotlib.animation
Use frame-by-frame updates to animate trajectories in the phase plane and in time.
matplotlib.backend_bases
Use the Matplotlib event system to make clicks in the phase plane set a new initial condition and restart the simulation.
Why use scripts instead of Streamlit here?
For these sessions, the most direct interactive behavior comes from Matplotlib animations and click events. Those are simpler to prototype in standalone scripts than in a Streamlit app.
Start with CDIMA Reaction. It is the most complete worked example and provides the template for the other two models.