Intermediate · Ball in a spinning ring

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.

spinning-ring.py
"""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

  1. v[1] -= g * dt

    Gravity: every step, the vertical speed drops by g·dt.

  2. p = p + v * dt

    The ball moves by its velocity times the time step. This simplest way to step is called Euler’s method.

  3. if r > R - ball:

    The ball’s edge reaches the wall when its centre is one ball radius away from the ring.

  4. 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.

  5. v = v - 2 * np.dot(v, normal) * normal

    The reflection: remove the part of the velocity along the normal twice. The spin of the ring does not enter it.

  6. p = normal * (R - ball)

    Put the ball back on the wall, so that a step can never leave it outside.

Try it yourself

  1. 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.

  2. 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.

  3. 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

1. What does np.dot(v, normal) measure?
2. What does break do in the while loop?
3. What range does np.arctan2(y, x) return?
4. Why do smaller time steps make the simulation better?
5. What does the spin of the ring change?

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.

These flashcards on their own page →