8강: 힘과 적분
Python으로 “삼체 궤도” 패턴을 만들면서 배워요:
- 벡터로 나타낸 뉴턴의 중력
- 천체 쌍을 도는 중첩 반복문
- 적분의 립프로그 방법
- 3차원 배열: 단계 × 천체 × 좌표
- 변하면 안 되는 것으로 시뮬레이션 확인하기
먼저 보기
클릭하면 YouTube에서 재생돼요.
"""Three bodies: the figure-eight orbit, from the starting values computed by Carles Simo
(in Chenciner and Montgomery, 2000). G = 1, three masses of 1.
Run: python three-body-orbits.py (needs: pip install numpy matplotlib)
"""
import numpy as np
import matplotlib.pyplot as plt
plt.style.use("dark_background")
x1 = np.array([0.97000436, -0.24308753])
V = np.array([-0.93240737, -0.86473146]) # the velocity of body 3
pos = np.array([x1, -x1, [0.0, 0.0]])
vel = np.array([-V / 2, -V / 2, V])
period, dt = 6.32591398, 0.0005
turn = 0 # degrees to turn the first velocity by (the film breaks the eight with 15)
a = np.radians(turn)
vel[0] = [vel[0, 0] * np.cos(a) - vel[0, 1] * np.sin(a), vel[0, 0] * np.sin(a) + vel[0, 1] * np.cos(a)]
def pull(p):
"""Each body's acceleration: the sum of the other two's gravity, G*m / r**2 towards each"""
acc = np.zeros_like(p)
for i in range(3):
for j in range(3):
if i != j:
d = p[j] - p[i]
acc[i] += d / np.linalg.norm(d) ** 3
return acc
track = []
acc = pull(pos)
for _ in range(int(3 * period / dt)): # three periods, leapfrog steps (they keep the energy well)
vel += acc * dt / 2
pos += vel * dt
acc = pull(pos)
vel += acc * dt / 2
track.append(pos.copy())
track = np.array(track)
colours = ["#5eead4", "#f0abfc", "#f5c76b"]
plt.figure(figsize=(7, 4))
for body in range(3): # all three run along the same track, a third of a period apart
plt.plot(track[:, body, 0], track[:, body, 1], color=colours[body], linewidth=1)
plt.scatter(track[-1, :, 0], track[-1, :, 1], c=colours, s=80, zorder=3)
plt.axis("equal")
plt.axis("off")
plt.show()
# Try: turn = 15 -> the three tracks no longer close; the eight falls apart
이 컴퓨터에 Python이 없나요? 노트북으로 같은 스크립트와 연습 문제, 정답을 브라우저의 Google Colab에서 실행할 수 있어요. 노트북은 영어로 되어 있어요.
한 줄씩
def pull(p):다른 두 천체의 중력으로 생기는 각 천체의 가속도예요.
acc[i] += d / np.linalg.norm(d) ** 3방향 d / r을 따르는 중력 G·m / r²을 합치면 d / r³이 돼요. 여기서 G와 질량은 1이에요.
vel += acc * dt / 2립프로그예요. 속도를 반 단계, 위치를 한 단계, 그다음 새 힘으로 속도를 나머지 반 단계 움직여요.
pos += vel * dt위치는 절반만 갱신된 속도로 움직여요.
track = np.array(track)모든 단계를 배열 하나로: track[단계, 천체, x 또는 y].
plt.scatter(track[-1, :, 0], track[-1, :, 1], c=colours, s=80, zorder=3)세 천체가 끝난 자리로, 하나의 공유 궤적 위에 주기의 3분의 1씩 떨어져 있어요.
직접 해 보기
끝에서 질량 중심은 어디에 있을까요?
힌트
track[-1].mean(axis=0).
정답
약 10⁻¹³ 이내로 (0, 0)에 있어요. 전체 운동량이 0이라서 질량 중심은 전혀 움직이지 않아요.
영상처럼 turn = 15로 해 보세요. 무슨 일이 일어나고, 이제 질량 중심은 어디로 갈까요?
힌트
출발할 때와 한 주기 뒤의 위치를 비교해 보세요.
정답
궤적이 더 이상 닫히지 않아요. 한 주기 뒤 세 천체는 합쳐서 출발한 자리에서 약 2단위 떨어져 있어요. 속도 하나를 돌리면 계에 운동량도 조금 생겨서 질량 중심이 떠밀려 가고, 끝에는 약 (−0.81, 0.67)에 있어요.
dt를 열 배 크게, 0.005로 해 보세요. 8자는 여전히 닫힐까요?
힌트
한 주기 뒤 천체들이 출발점에서 얼마나 떨어져 있는지 재 보세요.
정답
네, 하지만 덜 정확해요. 한 주기 뒤 세 천체는 합쳐서 출발점에서 약 0.006 떨어져 있어요. dt = 0.0005일 때는 약 0.0001이에요.
퀴즈
플래시카드
앞면을 읽고, 뒷면의 내용을 스스로 말해 본 다음 카드를 펼쳐 보세요.
천체 i에 작용하는 중력
다른 천체 j에 대한 Σ G·mⱼ·(rⱼ − rᵢ) / |rⱼ − rᵢ|³.
립프로그
속도 반 단계, 위치 한 단계, 다시 속도 반 단계.
주기 궤도
한 주기 뒤에 정확히 자기 자신으로 돌아오는 출발.
질량 중심
질량으로 가중한 평균 위치. 전체 운동량이 0이 아닐 때만 움직여요.
혼돈
출발의 아주 작은 변화가 점점 커져서 운동이 완전히 달라지는 것.