Note
Go to the end to download the full example code.
The Elastic Pendulum and 1:2 Autoparametric Resonance#
ElasticPendulum is a
mass \(m\) on a Hookean spring of natural length \(L_0\) and
stiffness \(k\), free to both stretch and swing. With generalized
coordinates \(q = (s, \theta)\) – \(s\) the spring’s stretch
beyond \(L_0\) (so the pivot-to-mass distance is \(r = L_0 +
s\)) and \(\theta\) the swing angle from the downward vertical –
its Lagrangian is
The \((L_0+s)^2\dot\theta^2\) term is what couples the (otherwise
independent, linear) stretch and swing motions: whenever the mass
swings, its varying distance from the pivot pumps the spring, and vice
versa. Written alone each mode would oscillate at its own natural
frequency, \(\omega_s = \sqrt{k/m}\) for the stretch and
\(\omega_\theta = \sqrt{g/L_0}\) for the swing; the coupling
becomes strong – and famously resonant – whenever
\(\omega_s \approx 2\,\omega_\theta\) (1:2 autoparametric
resonance), where energy started as pure vertical stretching
oscillation periodically leaks into, and back out of, swinging.
ElasticPendulum’s default parameters (\(k = 4mg/L_0\)) are set
to this 1:2 resonance condition exactly.
import matplotlib.pyplot as plt
from physicskit.classical.systems.lagrangian import ElasticPendulum
from physicskit.classical.visualizers.animations import animate_elastic_pendulum
Energy exchange between stretching and swinging#
Start mostly stretched, with only a small swing seed, and integrate long enough to see the swing amplitude visibly beat.
system = ElasticPendulum(q0=[0.4, 0.05], qdot0=[0.0, 0.0])
result = system.integrate((0.0, 60.0), dt=0.1, method="implicit_midpoint")
fig1, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 6), sharex=True)
ax1.plot(result.t, result.q[:, 0], color="steelblue")
ax1.set_ylabel("s (stretch)")
ax1.set_title("Elastic pendulum: energy leaking between modes")
ax2.plot(result.t, result.q[:, 1], color="firebrick")
ax2.set_ylabel(r"$\theta$ (swing)")
ax2.set_xlabel("t")
fig1.tight_layout()

Animation: the coil stretching and swinging together#
anim = animate_elastic_pendulum(system, result, interval=20, trail=300)
plt.show()
To save the animation to a file instead of (or in addition to) displaying it interactively, use e.g.:
anim.save("elastic_pendulum_animation.gif", writer="pillow", fps=30)
Total running time of the script: (0 minutes 27.288 seconds)