Lesson 7: Stepping through time
Build the ball in a spinning ring in Python, and learn on the way:
- a simulation: small time steps in a while loop
- vectors as numpy arrays
- the dot product and a reflection
- angles with np.arctan2, wrapped round
- break to leave a loop
Watch it first
Plays from YouTube after a click.
The script
Open in Colab: this lesson as a notebook"""A ball under gravity in a ring with a gap that spins; the bounces are elastic and without friction.
Run: python spinning-ring.py (needs: pip install numpy matplotlib)
"""
import numpy as np
import matplotlib.pyplot as plt
plt.style.use("dark_background")
R, ball, g = 1.0, 0.05, 9.81 # ring radius (m), ball radius, gravity
gap, spin = np.radians(18), 2 * np.pi / 4 # an 18 degree gap, one turn every 4 seconds
p, v = np.array([0.3, 0.2]), np.array([1.8, 0.7])
dt, t, track = 0.0005, 0.0, []
while t < 60:
v[1] -= g * dt
p = p + v * dt
t += dt
track.append(p.copy())
r = np.linalg.norm(p)
if r > R - ball: # the ball touches the wall, or is at the gap
angle = np.arctan2(p[1], p[0])
centre = -np.pi / 2 + spin * t # where the gap is now
off = abs((angle - centre + np.pi) % (2 * np.pi) - np.pi)
if off < gap / 2 - ball / R: # all of the ball fits through: out
break
normal = p / r
v = v - 2 * np.dot(v, normal) * normal # the bounce: the spin plays no part in it
p = normal * (R - ball)
track = np.array(track)
print(f"escaped after {t:.1f} s" if t < 60 else "still inside after 60 s")
plt.figure(figsize=(6, 6))
plt.plot(track[:, 0], track[:, 1], color="#5eead4", linewidth=0.4)
plt.gca().add_patch(plt.Circle((0, 0), R, fill=False, color="white"))
plt.axis("equal")
plt.axis("off")
plt.show()
# Try: spin = 0 and centre = -np.pi / 2 (a still gap at the bottom): the bounces stay the same
No Python on this computer? The notebook runs the same script, the exercises and the answers in your browser, on Google Colab.
Line by line
v[1] -= g * dtGravity: every step, the vertical speed drops by g·dt.
p = p + v * dtThe ball moves by its velocity times the time step. This simplest way to step is called Euler’s method.
if r > R - ball:The ball’s edge reaches the wall when its centre is one ball radius away from the ring.
off = abs((angle - centre + np.pi) % (2 * np.pi) - np.pi)The angle between the ball and the middle of the gap, wrapped into −π … π, so that 359° counts as 1° away.
v = v - 2 * np.dot(v, normal) * normalThe reflection: remove the part of the velocity along the normal twice. The spin of the ring does not enter it.
p = normal * (R - ball)Put the ball back on the wall, so that a step can never leave it outside.
Try it yourself
Check the energy, ½·|v|² + g·y per unit mass: print it at the start and at the end. Does it stay the same?
Hint
np.dot(v, v) is |v|².
Answer
Nearly: it drops by about 2 % over the run, from 3.83 to 3.75. The simple steps and the push back onto the wall lose a little.
Halve dt. What happens to the energy and to the moment the ball escapes?
Hint
dt = 0.00025.
Answer
The energy now drops by about 1 % instead of 2 %; the ball still escapes after about 3.9 s.
Why does the bounce line not use spin at all?
Hint
Which way does a point of the wall move?
Answer
Without friction the wall can only push along the normal, and a spinning wall moves along the tangent, at right angles to it.
Quiz
Flashcards
Read the front, say the back to yourself, then open the card.
Euler step
position += velocity · dt; velocity += acceleration · dt.
Reflection
v − 2·(v · n)·n, with n the wall’s unit normal.
np.arctan2(y, x)
The angle of the point (x, y), from −π to π.
break
Leaves the loop it is in, at once.
Energy check
½·|v|² + g·y should stay nearly constant without friction: a test of a simulation.