- validation.ipynb: Python notebook producing the results and figures in the paper
- simple_example.ipynb: simple and minimal example of ploting the exact solution
- animation.ipynb: Python notebook generating GIF animation using the derived exact solutions
- nonlinear_motion.gif: GIF animation showing the 3 classes of motions
The research article preprint >> https://arxiv.org/abs/2504.16816
Pendulum-like dynamics underlies a wide range of physical systems, from classical nonlinear oscillators to superconducting circuits and tunneling dynamics in cold-atom platforms. Here we present an exact frequency-domain formulation of the pendulum equation that applies uniformly across oscillatory, separatrix, and rotational regimes. The resulting spectral representation reveals a previously hidden unification: all regimes share the same analytic spectral structure and characteristic frequency scale, differing only by parity selection and the emergence of a continuous spectrum at the separatrix. This framework exposes regime transitions as symmetry-driven reorganizations in frequency space rather than changes in timescale, and identifies the stopping trajectory as a dynamical continuum limit reached without system-size scaling. Beyond providing closed-form solutions, the approach offers a transparent spectral insight into a broad class of classical and quantum pendulum-like systems.
In the meantime, if you use any part of this repository please cite the following preprint:
@article{Chachiyo:2025sae,
author = "Teepanis Chachiyo",
title = "{Exact frequency-domain solutions for nonlinear pendulum-like dynamics}",
eprint = "2504.16816",
archivePrefix = "arXiv",
primaryClass = "physics.class-ph",
month = "4",
year = "2026"
}
# exact solution of nonlinear pendulum via spectral analyis
# https://github.com/teepanis/nonlinear-pendulum
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
# physics: amplitude, and OmegaL=sqrt(g/L)
theta0 = 179.9/180*np.pi
OmegaL = np.sqrt(9.8/1)
k = np.sin(theta0/2)
T = 4*sp.special.ellipk(k**2)/OmegaL
Omega0 = 2*np.pi/T
kappa = sp.special.ellipk(1-k**2)
t = np.linspace(0,2*T,200) + T/4
theta = np.zeros(len(t))
# adding odd harmonics
for n in range(1,40,2):
c = 4/n/np.cosh(kappa*n*Omega0/OmegaL)
theta = theta + c*np.sin(n*Omega0*t)
plt.plot(t, theta)
plt.grid()
plt.show()To compare with the traditional perspective we:
- use the initial condition that the pendulum starts at rest, with an amplitude
$\theta_0$ . - For this condition, we shift the time by
$T/4$ . - For convenience, we use the form
$k = \sin(\theta_0/2)$ , which is equipvalent to$k = \omega_m/\omega_c$ .

