import numpy as np
from scipy.integrate import solve_ivp
import matplotlib.pyplot as plt
from matplotlib import animation
Here I solve the differential equations for the duffing oscillator with scipy and animate the solution with matplotlib. The oscillator exhibits chaotic behavior.
= -1
alpha = 1
beta = 0.1
gamma = 1.4
omega # interesting values for epsilon: 0.1, 0.4, 1.0
= 0.4
epsilon
def V(x):
return alpha * x ** 2 / 2 + beta * x ** 4 / 4
def ode(t, y):
= y
x, xdot = -(gamma * xdot + alpha * x + beta * x ** 3)
xdotdot += epsilon * np.cos(omega * t)
xdotdot return xdot, xdotdot
# solve equation of motion
= 0, 0
x0, v0 = 50
n_samples_per_period = 100
n_period = 2 * np.pi / omega
period = n_period * period
tmax
= np.linspace(0, tmax, n_samples_per_period * n_period)
t = solve_ivp(ode, (0, tmax), (x0, v0), t_eval=t)
sol
= sol.y
x, xdot
# setup animation
= plt.subplots(2, 2)
fig, ax
0,0])
plt.sca(ax["potential energy")
plt.title(= max(np.max(np.abs(x)) * 1.05, 1.5)
xext = np.linspace(-xext, xext)
x1 = V(x1)
y1
plt.plot(x1, y1)= plt.plot([], [], 'mo')
ln1, r'$x$')
plt.xlabel(r'$V(x)$')
plt.ylabel(-xext - 0.05, xext + 0.05)
plt.xlim(min(y1) - 0.05, np.max(y1))
plt.ylim(np.
= ax[1, 0]
ax2
plt.sca(ax2)"position vs. time")
plt.title(r'$t$')
plt.xlabel(r'$x$')
plt.ylabel(= plt.plot([], [])
ln2, -xext, xext)
plt.ylim(
0, 1])
plt.sca(ax["Poincaré section")
plt.title(r'$x$')
plt.xlabel(r'$\dot{x}$')
plt.ylabel(=1, lw=0)
plt.scatter(x[::n_samples_per_period], xdot[::n_samples_per_period], s-xext, xext)
plt.xlim(min(xdot), np.max(xdot))
plt.ylim(np.
1,1])
plt.sca(ax["phase space")
plt.title(r'$x$')
plt.xlabel(r'$\dot{x}$')
plt.ylabel(= plt.plot([], [])
ln3, = plt.plot([], [], 'mo')
ln3a, -xext, xext)
plt.xlim(= np.max(np.abs(xdot))
vext -vext, vext)
plt.ylim(
plt.tight_layout()
def animate(i):
ln1.set_data([x[i]], [V(x[i])])= max(0, i - 10 * n_samples_per_period)
j = slice(j, i+1)
sl
ln2.set_data(t[sl], x[sl])+1])
ax2.set_xlim(t[j], t[i= slice(0, i+1)
sl
ln3.set_data(x[sl], xdot[sl])
ln3a.set_data([x[i]], [xdot[i]])return (ln1, ln2, ln3, ln3a)
= animation.FuncAnimation(fig, animate, frames=len(x), interval=2) anim
To see the animation in action, run this code in a Jupyter notebook and prepend the %matplotlib notebook
to the first cell.