Double Pendulum ExampleΒΆ

A double pendulum is a dynamic system which has chaotic mostion for many initial conditions.

The derivation of the derivative function for this example is taken from https://myphysicslab.com/pendulum/double-pendulum-en.html

asdf

When the system is defined as a series of first-order differential equations the state vector is

\[ \begin{align}\begin{aligned}\begin{split} X = \begin{bmatrix} \theta_1 \\ \theta_2 \\ \omega_1 \\ \omega_2 \end{bmatrix}\end{split}\\and the derivative of the system is\end{aligned}\end{align} \]
\[\begin{split}\dot{X} = \begin{bmatrix} \dot{\theta_1} \\ \dot{\theta_2} \\ \dot{\omega_1} \\ \dot{\omega_2} \end{bmatrix} = \begin{bmatrix} \omega_1 \\ \omega_2 \\ \frac{-g (2 m_1 + m_2) \sin{\theta_1} - m_2 g \sin(\theta_1 - 2 \theta_2) - 2 \sin(\theta_1 - \theta_2) m_2 (\omega_2^2 L_2 + \omega_1^2 L_1 \cos(\theta_1 - \theta_2))}{L_1 (2 m_1 + m_2 - m_2 \cos(2 \theta_1 - 2 \theta_2))} \\ \frac{2 \sin(\theta_1 - \theta_2)(\omega_1^2 L_1 (m_1 + m_2) + g (m_1 + m_2) \cos{\theta_1} + \omega_2^2 L_2 m_2 \cos(\theta_1 - \theta_2))}{L_2 (2 m_1 + m_2 - m_2 \cos(2 \theta_1 - 2 \theta_2))} \end{bmatrix}.\end{split}\]
[1]:
cd ..
/home/docs/checkouts/readthedocs.org/user_builds/ode-solver/checkouts/master
[2]:
import numpy as np
import ode
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from IPython.display import HTML

def doublependulum(t,X):
    th1, th2, om1, om2 = X
    g = 9.81
    m1 = 1
    m2 = 1
    l1 = 1
    l2 = 1
    k1 = -g * ((2 * m1) + m2) * np.sin(th1)
    k2 = m2 * g * np.sin(th1 - (2 * th2))
    k3 = 2 * np.sin(th1 - th2) * m2
    k4 = ((om2**2) * l2) + ((om1**2) * l1 * np.cos(th1 - th2))
    k5 = m2 * np.cos((2 * th1) - (2 * th2))
    k6 = 2 * np.sin(th1 - th2)
    k7 = ((om1**2) * l1 * (m1 + m2))
    k8 = g * (m1 + m2) * np.cos(th1)
    k9 = (om2**2) * l2 * m2 * np.cos(th1 - th2)
    dX = np.array([
        om1,
        om2,
        (k1 - k2 - (k3 * k4)) / (l1 * ((2 * m1) + m2 - k5)),
        (k6 * (k7 + k8 + k9)) / (l2 * ((2 * m1) + m2 - k5))
    ])
    return dX
[3]:
def angles2xy(th1, th2, om1, om2):
    l1 = 1
    l2 = 1
    x1 = l1 * np.sin(th1)
    y1 = -l1 * np.cos(th1)
    x2 = x1 + (l2 * np.sin(th2))
    y2 = y1 - (l2 * np.cos(th2))
    return x1, y1, x2, y2


et, ex = ode.euler(doublependulum, [np.pi/2,np.pi,0,0], [0,5], .025)
th1, th2, om1, om2 = ex
ex1, ey1, ex2, ey2 = zip(*[angles2xy(*xi) for xi in zip(th1, th2, om1, om2)])

bet, bex = ode.backwardeuler(doublependulum, [np.pi/2,np.pi,0,0], [0,5], .025)
bex1, bey1, bex2, bey2 = zip(*[angles2xy(*xi) for xi in zip(*bex)])

fig, ax = plt.subplots()
ax.plot(ex2, ey2, 'r', bex2, bey2, 'g')
ax.set_aspect('equal', 'datalim')
plt.show()
_images/double-pendulum-example_4_0.png
[4]:
#plt.rcParams['figure.dpi'] = 120
fig, ax = plt.subplots()
ax.axis([-2, 2, -2, 2])
ax.set_aspect('equal')
trace_euler, = plt.plot([], [], 'r', animated=True)
pend_euler, = plt.plot([], [], 'ro-', animated=True)
trace_backeuler, = plt.plot([], [], 'g', animated=True)
pend_backeuler, = plt.plot([], [], 'go-', animated=True)
anim_ex2 = []
anim_ey2 = []
anim_bex2 = []
anim_bey2 = []

def update(frame):
    anim_ex2.append(ex2[frame])
    anim_ey2.append(ey2[frame])
    pend_euler_x = [0, ex1[frame], ex2[frame]]
    pend_euler_y = [0, ey1[frame], ey2[frame]]
    anim_bex2.append(bex2[frame])
    anim_bey2.append(bey2[frame])
    pend_backeuler_x = [0, bex1[frame], bex2[frame]]
    pend_backeuler_y = [0, bey1[frame], bey2[frame]]
    trace_euler.set_data(anim_ex2, anim_ey2)
    pend_euler.set_data(pend_euler_x, pend_euler_y)
    trace_backeuler.set_data(anim_bex2, anim_bey2)
    pend_backeuler.set_data(pend_backeuler_x, pend_backeuler_y)
    return trace_euler, pend_euler, trace_backeuler, pend_backeuler

%matplotlib inline
ani = FuncAnimation(fig, update, frames=range(len(et)), blit=True)

HTML_ani = HTML(ani.to_jshtml())
#HTML_ani = HTML(ani.to_html5_video())
#ani.save('DoublePendulumExample.gif', writer='imagemagick', fps=60)
HTML_ani
[4]: