7강: 시간을 한 걸음씩
Python으로 “회전하는 고리 속 공” 패턴을 만들면서 배워요:
- 시뮬레이션: while 반복문 안의 작은 시간 간격
- numpy 배열로 나타낸 벡터
- 내적과 반사
- np.arctan2로 구한 각도, 한 바퀴 돌려 맞추기
- 반복문을 빠져나가는 break
먼저 보기
클릭하면 YouTube에서 재생돼요.
"""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
이 컴퓨터에 Python이 없나요? 노트북으로 같은 스크립트와 연습 문제, 정답을 브라우저의 Google Colab에서 실행할 수 있어요. 노트북은 영어로 되어 있어요.
한 줄씩
v[1] -= g * dt중력이에요. 한 단계마다 수직 속도가 g·dt만큼 줄어요.
p = p + v * dt공은 속도에 시간 간격을 곱한 만큼 움직여요. 이렇게 가장 단순하게 한 걸음씩 나아가는 방법을 오일러 방법이라고 해요.
if r > R - ball:공의 중심이 고리에서 공의 반지름만큼 떨어진 곳에 오면 공의 가장자리가 벽에 닿아요.
off = abs((angle - centre + np.pi) % (2 * np.pi) - np.pi)공과 틈 한가운데 사이의 각도로, −π … π 범위로 돌려 맞춰서 359°가 1° 떨어진 것으로 세어지게 해요.
v = v - 2 * np.dot(v, normal) * normal반사예요. 속도에서 법선 방향 성분을 두 번 빼요. 고리의 회전은 이 식에 들어가지 않아요.
p = normal * (R - ball)공을 벽 위로 되돌려 놓아서, 어떤 단계에서도 공이 벽 밖에 남지 않게 해요.
직접 해 보기
단위 질량당 에너지 ½·|v|² + g·y를 확인해 보세요. 처음과 끝에 출력해 보세요. 그대로 유지되나요?
힌트
np.dot(v, v)는 |v|²예요.
정답
거의 그래요. 실행하는 동안 3.83에서 3.75로 약 2 % 줄어요. 단순한 걸음과 벽 위로 되돌려 놓는 처리에서 조금씩 잃어요.
dt를 절반으로 줄여 보세요. 에너지와 공이 빠져나가는 순간은 어떻게 될까요?
힌트
dt = 0.00025.
정답
이제 에너지가 2 % 대신 약 1 % 줄어요. 공은 여전히 약 3.9초 뒤에 빠져나가요.
튕김을 계산하는 줄은 왜 spin을 전혀 쓰지 않을까요?
힌트
벽 위의 한 점은 어느 방향으로 움직이나요?
정답
마찰이 없으면 벽은 법선 방향으로만 밀 수 있는데, 회전하는 벽은 그와 직각인 접선 방향으로 움직여요.
퀴즈
플래시카드
앞면을 읽고, 뒷면의 내용을 스스로 말해 본 다음 카드를 펼쳐 보세요.
오일러 단계
위치 += 속도 · dt; 속도 += 가속도 · dt.
반사
v − 2·(v · n)·n, 여기서 n은 벽의 단위 법선.
np.arctan2(y, x)
점 (x, y)의 각도, −π부터 π까지.
break
자기가 들어 있는 반복문을 바로 빠져나가요.
에너지 확인
마찰이 없으면 ½·|v|² + g·y는 거의 일정해야 해요: 시뮬레이션을 시험하는 방법.