Lekcja 7: Krok po kroku w czasie
Zbuduj w Pythonie wzór „Kulka w wirującym pierścieniu” i po drodze naucz się:
- symulacja: małe kroki czasu w pętli while
- wektory jako tablice numpy
- iloczyn skalarny i odbicie
- kąty z np.arctan2, zawinięte dookoła
- break, żeby wyjść z pętli
Najpierw obejrzyj
Film gra z YouTube po kliknięciu.
"""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
Nie masz Pythona na tym komputerze? Notatnik uruchamia ten sam skrypt, zadania i odpowiedzi w przeglądarce, w Google Colab. Notatnik jest po angielsku.
Linijka po linijce
v[1] -= g * dtGrawitacja: w każdym kroku prędkość pionowa spada o g·dt.
p = p + v * dtKulka przesuwa się o swoją prędkość razy krok czasu. Ten najprostszy sposób liczenia kroków to metoda Eulera.
if r > R - ball:Brzeg kulki dotyka ściany, gdy jej środek jest o jeden promień kulki od pierścienia.
off = abs((angle - centre + np.pi) % (2 * np.pi) - np.pi)Kąt między kulką a środkiem szczeliny, zawinięty do przedziału −π … π, tak żeby 359° liczyło się jako 1° różnicy.
v = v - 2 * np.dot(v, normal) * normalOdbicie: odejmij dwa razy część prędkości wzdłuż normalnej. Obrót pierścienia w ogóle tu nie wchodzi.
p = normal * (R - ball)Postaw kulkę z powrotem na ścianie, żeby żaden krok nie zostawił jej na zewnątrz.
Twoja kolej
Sprawdź energię, ½·|v|² + g·y na jednostkę masy: wypisz ją na początku i na końcu. Czy się nie zmienia?
Podpowiedź
np.dot(v, v) to |v|².
Odpowiedź
Prawie: przez cały przebieg spada o około 2 %, z 3.83 do 3.75. Proste kroki i dosuwanie kulki do ściany trochę jej tracą.
Zmniejsz dt o połowę. Co dzieje się z energią i z chwilą ucieczki kulki?
Podpowiedź
dt = 0.00025.
Odpowiedź
Energia spada teraz o około 1 % zamiast 2 %; kulka nadal ucieka po około 3,9 s.
Dlaczego linijka odbicia w ogóle nie używa spin?
Podpowiedź
W którą stronę porusza się punkt ściany?
Odpowiedź
Bez tarcia ściana może pchać tylko wzdłuż normalnej, a wirująca ściana porusza się wzdłuż stycznej, pod kątem prostym do niej.
Quiz
Fiszki
Przeczytaj przód, powiedz sobie, co jest z tyłu, potem otwórz kartę.
Krok Eulera
położenie += prędkość · dt; prędkość += przyspieszenie · dt.
Odbicie
v − 2·(v · n)·n, gdzie n to jednostkowa normalna ściany.
np.arctan2(y, x)
Kąt punktu (x, y), od −π do π.
break
Od razu wychodzi z pętli, w której jest.
Sprawdzenie energii
Bez tarcia ½·|v|² + g·y powinno być prawie stałe: test symulacji.