Preface


This section studies some first order nonlinear ordinary differential equations describing the time evolution (or “motion”) of those hamiltonian systems provided with a first integral linking implicitly both variables to a motion constant. An application has been performed on the Lotka--Volterra predator-prey system, turning to a strongly nonlinear differential equation in the phase variables.

Return to computing page for the first course APMA0330
Return to computing page for the second course APMA0340
Return to Mathematica tutorial for the first course APMA0330
Return to Mathematica tutorial for the second course APMA0340
Return to the main page for the first course APMA0330
Return to the main page for the second course APMA0340
Return to Part III of the course APMA0340
Introduction to Linear Algebra with Mathematica

Double pendulum


Double pendulum.
Double compound pendulum.
Animation of double pendulum.

A double pendulum consists of one pendulum attached to another. Double pendula are an example of a simple physical system which can exhibit chaotic behavior with a strong sensitivity to initial conditions. Several variants of the double pendulum may be considered. The two limbs may be of equal or unequal lengths and masses; they may be simple pendulums/pendula or compound pendulums (also called complex pendulums) and the motion may be in three dimensions or restricted to the vertical plane.

Consider a double bob pendulum with masses m1 and m2, attached by rigid massless wires of lengths \( \ell_1 \) and \( \ell_2 . \) Further, let the angles the two wires make with the vertical be denoted \( \theta_1 \) and \( \theta_2 , \) as illustrated at the left. Let the origin of the Cartesian coordinate system is taken to be at the point of suspension of the first pendulum, with vertical axis pointed up. Finally, let gravity be given by g. Then the positions of the bobs are given by

\begin{eqnarray*} x_1 &=& \ell_1 \sin \theta_1 , \\ y_1 &=& -\ell_1 \cos \theta_1 , \\ x_2 &=& \ell_1 \sin \theta_1 + \ell_2 \sin \theta_2 , \\ y_2 &=& -\ell_1 \cos \theta_1 - \ell_2 \cos \theta_2 . \end{eqnarray*}
The potential energy of the system is then given by
\[ \Pi = g\, m_1 \left( \ell_1 + y_1 \right) + g\,m_2 \left( \ell_1 + \ell_2 + y_2 \right) = g\,m_1 \left( 1- \cos \theta_1 \right) + g\, m_2 \left( \ell_1 + \ell_2 - \ell_1 \cos \theta_1 - \ell_2 \cos \theta_2 \right) , \]
and the kinetic energy by
\begin{eqnarray*} \mbox{K} &=& \frac{1}{2}\, m_1 v_1^2 + \frac{1}{2}\, m_2 v_2^2 \\ &=& \frac{1}{2}\, m_1 \ell_1^2 \dot{\theta}_1^2 + \frac{1}{2}\, m_2 \left[ \ell_1^2 \dot{\theta}_1^2 + \ell_2^2 \dot{\theta}_2^2 +2\ell_1 \ell_2 \dot{\theta}_1 \dot{\theta}_2 \cos \left( \theta_1 - \theta_2 \right) \right] \end{eqnarray*}
because
\[ v_1^2 = \dot{x}_1^2 + \dot{y}_1^2 = \ell_1^2 \dot{\theta}_1^2 , \qquad v_2^2 = \dot{x}_2^2 + \dot{y}_2^2 = \left( \ell_1 \cos\theta_1 \,\dot{\theta}_1 + \ell_2 \cos \theta_2 \,\dot{\theta}_2 \right)^2 + \left( \ell_1 \sin\theta_1 \,\dot{\theta}_1 + \ell_2 \sin \theta_2 \,\dot{\theta}_2 \right)^2 . \]
The Lagrangian is then
\begin{eqnarray*} {\cal L} &=& \mbox{K} - \Pi \\ &=& \frac{1}{2}\, m_1 \ell_1^2 \dot{\theta}_1^2 + \frac{1}{2}\, m_2 \left[ \ell_1^2 \dot{\theta}_1^2 + \ell_2^2 \dot{\theta}_2^2 +2\ell_1 \ell_2 \dot{\theta}_1 \dot{\theta}_2 \cos \left( \theta_1 - \theta_2 \right) \right] + \left( m_1 + m_2 \right) g\ell_1 \cos \theta_1 + m_2 g \ell_2 \cos \theta_2 . \end{eqnarray*}
Therefore, for θ1 we have
\begin{eqnarray*} \frac{\partial {\cal L}}{\partial \dot{\theta}_1} &=& m_1 \ell_1^2 \dot{\theta}_1 + m_2 \ell_1^2 \dot{\theta}_1 + m_2 \ell_1 \ell_2 \dot{\theta}_2 \cos \left( \theta_1 - \theta_2 \right) , \\ \frac{{\text d}}{{\text d}t} \left( \frac{\partial {\cal L}}{\partial \dot{\theta}_1} \right) &=& \left( m_1 + m_2 \right) \ell_1^2 \ddot{\theta}_1 + m_2 \ell_1 \ell_2 \ddot{\theta}_2 \cos \left( \theta_1 - \theta_2 \right) - m_2 \ell_1 \ell_2 \dot{\theta}_2 \sin \left( \theta_1 - \theta_2 \right) \left( \dot{\theta}_1 - \dot{\theta}_2 \right) , \\ \frac{\partial {\cal L}}{\partial \theta_1} &=& - \ell_1 g \left( m_1 + m_2 \right) \sin \theta_1 - m_2 \ell_1 \ell_2 \dot{\theta}_1 \dot{\theta}_2 \sin \left( \theta_1 - \theta_2 \right) . \end{eqnarray*}
So the Euler-Lagrange differential equation \( \frac{{\text d}}{{\text d}t} \left( \frac{\partial {\cal L}}{\partial \dot{q}} \right) = \frac{\partial {\cal L}}{\partial q} \) for θ1 becomes
\[ \left( m_1 + m_2 \right) \ell_1^2 \ddot{\theta}_1 + m_2 \ell_1 \ell_2 \ddot{\theta}_2 \cos \left( \theta_1 - \theta_2 \right) + m_2 \ell_1 \ell_2 \dot{\theta}_2^2 \sin \left( \theta_1 - \theta_2 \right) + \ell_1 g \left( m_1 + m_2 \right) \sin \theta_1 =0 . \]
Dividing through by \( \ell_1 , \) this simplifies to
\[ \left( m_1 + m_2 \right) \ell_1 \ddot{\theta}_1 + m_2 \ell_2 \ddot{\theta}_2 \cos \left( \theta_1 - \theta_2 \right) + m_2 \ell_2 \dot{\theta}_2^2 \sin \left( \theta_1 - \theta_2 \right) + g \left( m_1 + m_2 \right) \sin \theta_1 =0 . \]
Similarly, for θ2, we have
\begin{eqnarray*} \frac{\partial {\cal L}}{\partial \dot{\theta}_2} &=& m_2 \ell_2^2 \dot{\theta}_2 + m_2 \ell_1 \ell_2 \dot{\theta}_1 \cos \left( \theta_1 - \theta_2 \right) , \\ \frac{{\text d}}{{\text d}t} \left( \frac{\partial {\cal L}}{\partial \dot{\theta}_2} \right) &=& m_2 \ell_2^2 \ddot{\theta}_2 + m_2 \ell_1 \ell_2 \ddot{\theta}_1 \cos \left( \theta_1 - \theta_2 \right) - m_2 \ell_1 \ell_2 \dot{\theta}_1 \sin \left( \theta_1 - \theta_2 \right) \left( \dot{\theta}_1 - \dot{\theta}_2 \right) , \\ \frac{\partial {\cal L}}{\partial \theta_2} &=& \ell_1 \ell_2 m_2 \dot{\theta}_1 \dot{\theta}_2 \sin \left( \theta_1 - \theta_2 \right) - \ell_2 m_2 g\,\sin \theta_2 , \end{eqnarray*}
which leads to
\[ m_2 \ell_2 \ddot{\theta}_2 + m_2 \ell_1 \ddot{\theta}_1 \cos \left( \theta_1 - \theta_2 \right) - m_2 \ell_1 \dot{\theta}_1^2 \sin \left( \theta_1 - \theta_2 \right) + m_2 g \, \sin \theta_2 =0 . \]
The coupled second-order ordinary differential equations
\begin{eqnarray*} \left( m_1 + m_2 \right) \ell_1 \ddot{\theta}_1 + m_2 \ell_2 \ddot{\theta}_2 \cos \left( \theta_1 - \theta_2 \right) + m_2 \ell_2 \dot{\theta}_2^2 \sin \left( \theta_1 - \theta_2 \right) + g \left( m_1 + m_2 \right) \sin \theta_1 &=& 0 , \\ m_2 \ell_2 \ddot{\theta}_2 + m_2 \ell_1 \ddot{\theta}_1 \cos \left( \theta_1 - \theta_2 \right) - m_2 \ell_1 \dot{\theta}_1^2 \sin \left( \theta_1 - \theta_2 \right) + m_2 g \, \sin \theta_2 &=& 0 \end{eqnarray*}
Here is the code for anumation:
Clear[phi1, phi2, t];
sol = First[ NDSolve[{2*phi1''[t] + phi2''[t]*Cos[phi1[t] - phi2[t]] +
phi2'[t]^(2)*Sin[phi1[t] - phi2[t]] + 2*9.81*Sin[phi1[t]] == 0,
phi2''[t] + phi1''[t]*Cos[phi1[t] - phi2[t]] - phi1'[t]^(2)*Sin[phi1[t] - phi2[t]] + 9.81*Sin[phi2[t]] == 0,
phi1[0] == Pi/2, phi2[0] == Pi, phi1'[0] == 0,
phi2'[0] == 0}, {phi1[t], phi2[t]}, {t, 0, 10}]];

x1[t_] := Evaluate[Sin[phi1[t]] /. sol]
y1[t_] := Evaluate[-Cos[phi1[t]] /. sol]
x2[t_] := Evaluate[Sin[phi1[t]] + Sin[phi2[t]] /. sol]
y2[t_] := Evaluate[-(Cos[phi1[t]] + Cos[phi2[t]]) /. sol]

frames = Table[ Graphics[{Gray, Thick,
Line[{{0, 0}, {x1[t], y1[t]}, {x2[t], y2[t]}}], Darker[Blue],
Disk[{0, 0}, .1], Darker[Red], Disk[{x1[t], y1[t]}, .1],
Disk[{x2[t], y2[t]}, .1]}, PlotRange -> {{-2.5, 2.5}, {-2.5, 2.5}}], {t, 0, 10, .1}];
ListAnimate[frames]

The equations of motion can also be written in the Hamiltonian formalism. Computing the generalized momenta gives

\begin{eqnarray*} p_1 &=& \frac{\partial {\cal L}}{\partial \dot{\theta}_1} = \left( m_1 + m_2 \right) \ell_1^2 \dot{\theta}_1 + m_2 \ell_1 \ell_2 \dot{\theta}_2 \cos \left( \theta_1 - \theta_2 \right) , \\ p_2 &=& \frac{\partial {\cal L}}{\partial \dot{\theta}_2} = m_2 \ell_2^2 \dot{\theta}_2 + m_2 \ell_1 \ell_2 \dot{\theta}_1 \cos \left( \theta_1 - \theta_2 \right) . \end{eqnarray*}
The Hamiltonian becomes
\[ H = \dot{\theta}_1 p_1 + \dot{\theta}_2 p_2 - {\cal L} . \]
For animation of double pendulum equations, see the following codes taken from the official Wolfram web page for your convenience:

Double pendulum animation:


import sys
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from matplotlib.patches import Circle

# Pendulum rod lengths (m), bob masses (kg).
L1, L2 = 1, 1
m1, m2 = 1, 1
# The gravitational acceleration (m.s-2).
g = 9.81

def deriv(y, t, L1, L2, m1, m2):
    """Return the first derivatives of y = theta1, z1, theta2, z2."""
    theta1, z1, theta2, z2 = y

    c, s = np.cos(theta1-theta2), np.sin(theta1-theta2)

    theta1dot = z1
    z1dot = (m2*g*np.sin(theta2)*c - m2*s*(L1*z1**2*c + L2*z2**2) -
             (m1+m2)*g*np.sin(theta1)) / L1 / (m1 + m2*s**2)
    theta2dot = z2
    z2dot = ((m1+m2)*(L1*z1**2*s - g*np.sin(theta2) + g*np.sin(theta1)*c) + 
             m2*L2*z2**2*s*c) / L2 / (m1 + m2*s**2)
    return theta1dot, z1dot, theta2dot, z2dot

def calc_E(y):
    """Return the total energy of the system."""

    th1, th1d, th2, th2d = y.T
    V = -(m1+m2)*L1*g*np.cos(th1) - m2*L2*g*np.cos(th2)
    T = 0.5*m1*(L1*th1d)**2 + 0.5*m2*((L1*th1d)**2 + (L2*th2d)**2 +
            2*L1*L2*th1d*th2d*np.cos(th1-th2))
    return T + V

# Maximum time, time point spacings and the time grid (all in s).
tmax, dt = 30, 0.01
t = np.arange(0, tmax+dt, dt)
# Initial conditions: theta1, dtheta1/dt, theta2, dtheta2/dt.
y0 = np.array([3*np.pi/7, 0, 3*np.pi/4, 0])

# Do the numerical integration of the equations of motion
y = odeint(deriv, y0, t, args=(L1, L2, m1, m2))

# Check that the calculation conserves total energy to within some tolerance.
EDRIFT = 0.05
# Total energy from the initial conditions
E = calc_E(y0)
if np.max(np.sum(np.abs(calc_E(y) - E))) > EDRIFT:
    sys.exit('Maximum energy drift of {} exceeded.'.format(EDRIFT))

# Unpack z and theta as a function of time
theta1, theta2 = y[:,0], y[:,2]

# Convert to Cartesian coordinates of the two bob positions.
x1 = L1 * np.sin(theta1)
y1 = -L1 * np.cos(theta1)
x2 = x1 + L2 * np.sin(theta2)
y2 = y1 - L2 * np.cos(theta2)

# Plotted bob circle radius
r = 0.05
# Plot a trail of the m2 bob's position for the last trail_secs seconds.
trail_secs = 1
# This corresponds to max_trail time points.
max_trail = int(trail_secs / dt)

def make_plot(i):
    # Plot and save an image of the double pendulum configuration for time
    # point i.
    # The pendulum rods.
    ax.plot([0, x1[i], x2[i]], [0, y1[i], y2[i]], lw=2, c='k')
    # Circles representing the anchor point of rod 1, and bobs 1 and 2.
    c0 = Circle((0, 0), r/2, fc='k', zorder=10)
    c1 = Circle((x1[i], y1[i]), r, fc='b', ec='b', zorder=10)
    c2 = Circle((x2[i], y2[i]), r, fc='r', ec='r', zorder=10)
    ax.add_patch(c0)
    ax.add_patch(c1)
    ax.add_patch(c2)

    # The trail will be divided into ns segments and plotted as a fading line.
    ns = 20
    s = max_trail // ns

   for j in range(ns):
        imin = i - (ns-j)*s
        if imin < 0:
            continue
        imax = imin + s + 1
        # The fading looks better if we square the fractional length along the
        # trail.
        alpha = (j/ns)**2
        ax.plot(x2[imin:imax], y2[imin:imax], c='r', solid_capstyle='butt',
                lw=2, alpha=alpha)

    # Centre the image on the fixed anchor point, and ensure the axes are equal
    ax.set_xlim(-L1-L2-r, L1+L2+r)
    ax.set_ylim(-L1-L2-r, L1+L2+r)
    ax.set_aspect('equal', adjustable='box')
    plt.axis('off')
    plt.savefig('frames/_img{:04d}.png'.format(i//di), dpi=72)
    plt.cla()

# Make an image every di time points, corresponding to a frame rate of fps
# frames per second.
# Frame rate, s-1
fps = 10
di = int(1/fps/dt)
fig = plt.figure(figsize=(8.3333, 6.25), dpi=72)
ax = fig.add_subplot(111)

for i in range(0, t.size, di):
    print(i // di, '/', t.size // di)
    make_plot(i)
The images are saved to a subdirectory, frames/ and can be converted into an animated gif, for example with ImageMagick's convert utility.

 

 

Return to Mathematica page
Return to the main page (APMA0340)
Return to the Part 1 Matrix Algebra
Return to the Part 2 Linear Systems of Ordinary Differential Equations
Return to the Part 3 Non-linear Systems of Ordinary Differential Equations
Return to the Part 4 Numerical Methods
Return to the Part 5 Fourier Series
Return to the Part 6 Partial Differential Equations
Return to the Part 7 Special Functions