Marketplace › From Ordinate 2D
Pendulum period against amplitude
Release a pendulum from 5° to 150°: the period against 2π√(L/g) and the exact value.
Use in Ordinate 2DOpens in the Script tab: it runs when you press Run. Free, no account needed.
"""Pendulum period against amplitude: T = 2π√(L/g) only holds for small swings.
A 1 m pendulum is released from rest at one angle after another; the script times a full swing (two crossings of the
vertical in the same direction) and records it with the small-angle value and the exact one, T = T₀ / AGM(1, cos(θ₀/2)) (AGM: the arithmetic-geometric mean).
Runs in the studio (Script tab → Run) and locally: python3 pendulum_period.py
"""
import math
import studio as s
L, G = 1.0, 9.81
ANGLES = [5, 20, 40, 60, 90, 120, 150] # release angles, degrees
s.clear()
s.gravity = (0, -G)
anchor = s.box(0, 2.0, 0.3, 0.1, static=True, name="Anchor", color="#8b939b")
bob = s.circle(0, 2.0 - L, 0.08, mass=1, name="Bob", color="#e5484d", collide=False, restitution=0)
s.rod(anchor, bob, at_a=(0, 2.0), at_b=(0, 2.0 - L))
trial, last_cross, last_x = 0, None, 0.0
def agm(a, b):
for _ in range(12):
a, b = (a + b) / 2, math.sqrt(a * b)
return a
def release(deg):
global last_x, last_cross
a = math.radians(deg)
bob.position = (L * math.sin(a), 2.0 - L * math.cos(a))
bob.velocity = (0, 0)
last_x, last_cross = L * math.sin(a), None
@s.on_start
def start():
global trial
trial = 0
release(ANGLES[0])
@s.on_step
def watch(t, dt):
global trial, last_cross, last_x
x = bob.x
if last_x < 0 <= x: # upward crossing of the vertical
if last_cross is None:
last_cross = t
else:
period = t - last_cross
t0 = 2 * math.pi * math.sqrt(L / G)
exact = t0 / agm(1, math.cos(math.radians(ANGLES[trial]) / 2))
s.record(amplitude=ANGLES[trial], period=period, small_angle=t0, exact=exact)
print(f"{ANGLES[trial]:>4}°: T = {period:.4f} s, small-angle {t0:.4f} s, exact {exact:.4f} s")
trial += 1
if trial >= len(ANGLES):
s.stop()
return
release(ANGLES[trial])
return
last_x = x
s.run(40)