태양을 도는 길 위에서, 올챙이와 말굽이 태어나는 까닭
0. 서론: 행성과 같은 길을 달리는데, 왜 부딪히지 않을까?
태양계 지도를 보면 목성 앞뒤에 작은 천체가 무더기로 모여 있습니다. 앞쪽에는 그리스 진영, 뒤쪽에는 트로이 진영이라는 이름이 붙습니다. 조금 안쪽에는 삼각형처럼 늘어선 힐다족도 있습니다. 그들의 움직임을 보여 주는 영상에는 또 다른 이름이 등장합니다. 올챙이 궤도(tadpole orbit)와 말굽 궤도(horseshoe orbit) 입니다.
이름만 외우면 오히려 더 헷갈립니다. 그리스 천체와 트로이 천체는 서로 다른 종류일까요? 올챙이 궤도는 태양 주위를 올챙이 모양으로 돈다는 뜻일까요? 말굽 궤도에서는 천체가 행성 앞에서 실제로 후진할까요?
공궤도 운동(co-orbital motion) 은 두 천체가 1:1 평균운동 공명(mean-motion resonance)에 묶인 운동입니다. 궤도 크기가 비슷하고 평균 공전 횟수가 같다는 뜻이지, 매 순간 같은 원 위에 있다는 뜻은 아닙니다.
이 글에서는 세 가지를 차례로 연결합니다. 먼저 이름이 무엇을 분류하는지, 다음으로 어느 좌표계에서 그 모양을 보는지, 마지막으로 중력이 궤도의 크기와 공전 주기를 어떻게 바꾸는지입니다. 이 셋을 연결하면 올챙이와 말굽은 이상한 그림이 아니라, 같은 궤도를 공유하는 천체의 움직임을 압축한 지도가 됩니다.
아래 그림은 모두 직접 계산하거나 구성한 설명용 그림입니다. 천체의 크기는 실제 비율이 아니며, 올챙이·말굽 그림의 작은 안팎 차이는 눈에 보이도록 확대했습니다. 실제 천체의 특정 날짜 위치를 나타내는 천체력은 아닙니다.
1. 그리스 천체도 트로이 천체다: 먼저 이름표를 정리하자
목성의 공전 방향을 따라 약 60° 앞선 곳이 L₄, 약 60° 뒤처진 곳이 L₅입니다. 태양, 목성, L₄ 또는 L₅를 연결하면 이상적인 원형 모형에서 정삼각형이 됩니다. 이 두 곳이 목성 트로이 소행성의 중심 영역입니다.

그림 1. 목성은 오른쪽에 고정하고 공전 방향은 반시계 방향으로 표시했습니다. 점들의 분포는 실제 소행성 목록이 아니라 집단의 위치를 설명하는 개념도입니다.
| 이름 | 뜻 | 목성과의 관계 |
|---|---|---|
| 트로이 천체·트로이 소행성(Trojan object / Trojan asteroid), 넓은 뜻 | 행성의 L₄ 또는 L₅ 부근에서 공명하며 도는 천체 | 평균 공전 횟수의 비가 1:1 |
| 그리스 진영, Greek camp | 목성의 L₄ 쪽 집단 | 목성보다 약 60° 앞선 영역 |
| 트로이 진영, Trojan camp | 목성의 L₅ 쪽 집단 | 목성보다 약 60° 뒤처진 영역 |
| 올챙이 궤도(tadpole orbit)·말굽 궤도(horseshoe orbit) | 행성과 함께 회전하며 본 상대 경로의 유형 | 주로 1:1 공명의 운동 형태를 구분 |
| 힐다군(Hilda group), 흔히 힐다족이라고 부름 | 목성 안쪽의 3:2 공명 소행성 집단 | 목성이 두 번 도는 동안 세 번 공전 |
따라서 ‘그리스 진영과 트로이 진영’을 합쳐 ‘목성 트로이 소행성’이라고 부를 수 있습니다. 넓은 이름과 그 안의 한 진영 이름이 겹쳐 생긴 혼동입니다. 공궤도 천체(co-orbital object)가 더 넓은 범주이고, 트로이 천체는 그중 L₄ 또는 L₅ 부근에서 올챙이 운동을 하는 유형입니다. 말굽 천체까지 모두 트로이 천체라고 부르지는 않습니다. 그리스 진영에 있다고 물리 법칙이 달라지는 것도 아닙니다.
목성 L₄의 소행성에는 그리스 측 인물, L₅에는 트로이 측 인물의 이름을 붙이는 관례가 생겼습니다. 초기 명명에는 예외가 있습니다. 트로이의 영웅 이름인 헥토르(Hektor)는 그리스 진영, 그리스 측 인물 이름인 파트로클로스(Patroclus)는 트로이 진영에 있습니다. 두 천체가 진영을 바꾼 것이 아니라 명명 관례보다 이름이 먼저 정해졌습니다. NASA의 발견·명명 역사
2. 올챙이와 말굽은 ‘행성과 함께 도는 카메라’에 나타난다
우선 태양 위쪽에 카메라를 놓고, 카메라의 방향을 먼 별에 고정했다고 생각해 봅시다. 행성과 소행성은 둘 다 태양 주위를 돕니다. 태양의 작은 흔들림을 생략한 이 태양 중심 좌표계(heliocentric frame)에서는 소행성이 태양 주위의 궤도를 따라 계속 전진합니다. 엄밀하게는 태양도 움직이므로 태양 중심 좌표계 전체를 관성계(inertial frame)와 동일시하지는 않겠습니다.
이번에는 카메라를 행성의 평균 공전 각속도로 돌립니다. 이것이 행성과 함께 도는 회전 좌표계(rotating frame / co-rotating frame) 입니다. 이상적인 원형 모형에서는 행성이 화면 오른쪽에 그대로 멈춥니다. 소행성이 행성보다 조금 빨리 돌면 화면에서 앞쪽으로 움직이고, 조금 느리게 돌면 뒤쪽으로 움직입니다. 여러 번의 공전 동안 쌓인 이 작은 차이를 그린 것이 상대 경로입니다.

그림 2. 왼쪽은 태양 주위의 공전, 오른쪽은 빠른 공전을 평균낸 상대 운동의 개념도입니다. 오른쪽의 반지름 방향 차이는 20배 확대했습니다.
태양을 도는 큰 공전 위에 겹친 느린 상대 운동을, 행성과 함께 도는 카메라로 펼쳐 본 모양이 올챙이와 말굽입니다. 행성을 실제로 멈추거나 중력을 끈 것이 아닙니다. 소행성이 L₄라는 별도 천체를 위성처럼 도는 것도 아닙니다.
시계의 두 바늘을 떠올리면 도움이 됩니다. 두 바늘이 거의 같은 속도로 돌더라도, 한쪽 바늘을 기준으로 다른 바늘을 보면 둘 사이의 각도만 천천히 변합니다. 공궤도 천체에서는 여기에 중력이 더해져 그 각도 차이가 한 방향으로 계속 쌓이지 않고 되돌아옵니다.
이 글에서는 그 차이를 상대각 φ라고 부르겠습니다. 정밀하게는 소행성과 행성의 평균경도(mean longitude) 차이입니다. 평균경도는 타원 운동에서 들쭉날쭉한 순간 각도 대신 공전의 평균적인 시계와 궤도의 방향을 합쳐 나타내는 각도입니다.
$$ \phi=\lambda_{\mathrm{asteroid}}-\lambda_P. $$$\lambda$는 평균경도, 아래첨자 $P$는 행성을 뜻합니다. 거의 원형인 궤도에서는 화면에서 읽는 위치 각도 차이와 가깝습니다.
| 상대각 φ | 행성과의 관계 |
|---|---|
| 0° 또는 360° | 행성과 같은 방향 |
| 60° | L₄, 앞쪽 평형 영역 |
| 180° | 태양을 사이에 둔 반대 방향, L₃ 부근 |
| 300° 또는 −60° | L₅, 뒤쪽 평형 영역 |
여기서 말하는 ‘되돌아옴’은 φ가 증가하다 감소하거나, 감소하다 증가하는 것입니다. 태양을 도는 공전 자체를 거꾸로 한다는 뜻은 아닙니다. 실제 목성의 궤도는 완전한 원이 아니므로, 현실의 회전계에서는 목성도 작은 위치 변화를 보일 수 있습니다.
3. 핵심 원리: 안쪽에서는 앞서가고, 바깥쪽에서는 뒤처진다
올챙이와 말굽을 이해하는 데 가장 중요한 관계는 이것입니다.
행성과 거의 같은 크기의 궤도에서, 궤도의 장반경이 조금 작아지면 평균 공전이 빨라지고, 조금 커지면 평균 공전이 느려집니다.
장반경 또는 반장축(semi-major axis)은 타원의 긴 지름의 절반입니다. 거의 원형인 궤도에서는 궤도의 반지름과 비슷하므로, 여기서는 ‘궤도의 크기’라고 읽어도 좋습니다. 어느 순간 태양에 더 가까운가와 궤도의 장반경이 더 작은가는 구별해야 합니다. 타원궤도에서는 같은 궤도 안에서도 태양까지 거리가 계속 바뀝니다.
케플러의 제3법칙(Kepler’s third law)을 식으로 쓰면, 태양 질량이 지배적인 근사에서
$$ T=2\pi\sqrt{\frac{a^3}{GM_\odot}},\qquad n=\frac{2\pi}{T}. $$$T$는 공전주기(orbital period), $n$은 평균운동(mean motion), $G$는 중력상수입니다. 행성과의 장반경 차이를 $\Delta a=a-a_P$라고 하면 작은 차이에 대해
$$ \dot\phi\simeq n-n_P\simeq-\frac32n_P\frac{\Delta a}{a_P}. $$점을 붙인 $\dot\phi$는 시간에 따른 상대각의 변화율입니다. $\Delta a<0$이면 $\dot\phi>0$, $\Delta a>0$이면 $\dot\phi<0$입니다. 안쪽 길과 바깥쪽 길에서 상대 진행 방향이 반대가 되는 이유를 한 줄로 보여 줍니다.
그림을 만든 파이썬 코드 보기
import numpy as np
import matplotlib.pyplot as plt
bg, fg, muted = '#0d1117', '#e6edf3', '#aebbd0'
ratio = np.linspace(.98, 1.02, 401)
period = ratio**1.5
fig, ax = plt.subplots(figsize=(10, 4.8))
fig.patch.set_facecolor(bg)
ax.set_facecolor(bg)
ax.plot(100*(ratio-1), 100*(period-1), color='#79c0ff', lw=2.5)
ax.axhline(0, color='#566477', lw=1)
ax.axvline(0, color='#566477', lw=1)
for a, color, offset in [(.99, '#7ee7da', (-60, 25)), (1.01, '#ffa657', (-125, -40))]:
x, y = 100*(a-1), 100*(a**1.5-1)
ax.scatter(x, y, color=color, s=55, zorder=3)
ax.annotate(f'a / aP = {a:.2f}\nT / TP = {a**1.5:.5f}', (x, y),
xytext=offset, textcoords='offset points', color=color,
arrowprops={'arrowstyle':'->', 'color':color})
ax.set(xlabel='Semi-major axis difference (%)', ylabel='Orbital period difference (%)')
ax.xaxis.label.set_color(fg)
ax.yaxis.label.set_color(fg)
ax.tick_params(colors=fg)
ax.grid(color='#30363d', alpha=.6)
for spine in ax.spines.values():
spine.set_color('#566477')
fig.suptitle('Inner orbit: shorter period. Outer orbit: longer period.', color=fg)
fig.tight_layout()
plt.show()

계산 그림. 행성의 궤도 크기와 공전주기를 각각 1로 놓았습니다. 안쪽 궤도에서는 주기가 짧아지고 바깥쪽에서는 길어집니다.
궤도의 크기가 1% 작으면 주기는 약 1.5% 짧아집니다. 차이는 작지만 수십·수백 번 공전하면서 상대 위치에 누적됩니다. 행성과 나란히 달리는 상태에서 작은 차이가 생기면 다음과 같이 누적됩니다.

그림 3. 저이심률 공궤도 운동에서의 변화입니다. ‘더 가속되었으니 앞으로 더 달아난다’고 순간 속도만 보면 이후의 상대 운동을 잘못 판단하기 쉽습니다.
일상에서 뒤에서 밀어 주면 더 빨리 앞으로 갑니다. 궤도에서는 밀어 준 결과가 이후의 길 자체를 바꿉니다. 원형에 가까운 순행 궤도에서 진행 방향으로 속도를 받으면, 에너지와 각운동량이 늘어 더 큰 궤도로 이동할 수 있습니다. 그 궤도에서는 공전 주기가 길어지므로 장기적으로 행성보다 뒤처질 수 있습니다. 반대로 각운동량을 잃어 더 작은 궤도로 내려가면 평균 공전은 빨라집니다.
물론 한순간의 힘이 즉시 완성된 다른 원궤도로 옮겨 놓는 것은 아닙니다. 실제 이동은 연속적입니다. 여기서 필요한 것은 순간 속도와 이후의 평균 공전 속도를 나누어 보는 습관입니다.
1:1 공명도 매 순간 속도와 반지름이 같다는 뜻은 아닙니다. 안쪽에서 앞서가는 구간과 바깥쪽에서 뒤처지는 구간이 서로 보상해, 긴 시간 평균에서 공전 횟수가 같아지는 것입니다.
4. 왜 하필 60°인가: 멈춘 점이 아니라, 되돌리는 운동의 중심
라그랑주점(Lagrange point / Lagrangian point)은 두 큰 천체와 같은 각속도로 도는 좌표계에서, 질량이 매우 작은 세 번째 천체가 상대 위치를 유지할 수 있는 다섯 평형점입니다. 이상적인 원형 제한 삼체 모형의 태양–목성계를 그리면 다음과 같습니다.

그림 4. 다섯 라그랑주점의 전체 배치와 목성 부근 확대도입니다. L₁·L₂·L₃는 작은 어긋남이 커질 수 있는 불안정한 평형점이고, 태양–목성의 이상적 원형 모형에서 L₄·L₅는 작은 변화에 대해 안정합니다. 현실의 섭동까지 고려한 모든 궤도의 영구 안정성을 뜻하지는 않습니다.
| 점 | 위치 | 이상적인 태양–목성 모형에서의 성질 |
|---|---|---|
| L₁ | 태양과 목성 사이, 목성 가까이 | 불안정 |
| L₂ | 목성을 지나 더 바깥쪽 | 불안정 |
| L₃ | 태양을 사이에 둔 목성 반대편 | 불안정 |
| L₄ | 목성보다 60° 앞선 정삼각형 꼭짓점 | 작은 변화에 대해 안정, 그리스 진영의 중심 |
| L₅ | 목성보다 60° 뒤처진 정삼각형 꼭짓점 | 작은 변화에 대해 안정, 트로이 진영의 중심 |
역사적으로 일직선 배치의 세 점 L₁·L₂·L₃는 오일러(Euler) 의 해, 정삼각형 배치의 두 점 L₄·L₅는 라그랑주(Lagrange) 의 해와 연결됩니다. 다섯 점을 함께 라그랑주점이라고 부릅니다. 오일러의 일직선 해, 삼각형 점의 발견과 운동
다섯 점의 공통 질문은 “이 위치에서 행성과 같은 박자로 태양을 돌 수 있을까?” 입니다.
- L₁: 행성보다 안쪽이라 태양만 있다면 더 빨리 돌 자리입니다. 행성이 바깥쪽으로 당기는 효과를 더하면, 같은 박자의 공전을 유지할 수 있는 위치가 생깁니다.
- L₂: 행성보다 바깥쪽이라 태양만 있다면 같은 박자로 돌기에 안쪽 가속도가 부족합니다. 행성도 태양 쪽으로 당겨 주어 그 차이를 채우는 위치가 생깁니다.
- L₃: 태양을 사이에 두고 행성과 반대편에 있습니다. 여기서는 태양과 행성이 모두 같은 쪽으로 천체를 당깁니다. 다만 태양 자신도 행성에 끌려 가속하므로, 그 움직임까지 포함해 같은 박자의 공전에 필요한 가속도를 맞추는 위치를 찾습니다.
- L₄·L₅: 세 천체가 정삼각형을 이룰 때 합성 중력이 같은 박자의 공전에 맞습니다. 공전 방향으로 앞선 꼭짓점이 L₄, 뒤처진 꼭짓점이 L₅입니다.
이것은 우주 공간에서 멈춘다는 뜻이 아니라 함께 도는 화면에서 자리를 유지한다는 뜻입니다. L₁은 태양과 목성의 중간 지점이 아닙니다. 두 천체의 질량 차이 때문에 목성 가까이에 있습니다. L₄·L₅의 안정성이 어떤 두 천체에서도 자동으로 성립하는 것은 아니지만, 태양–목성의 질량비는 이상적 모형의 안정 조건을 만족합니다.
L₄와 L₅를 ‘태양 중력과 행성 중력이 정확히 상쇄되어 중력이 0인 곳’이라고 설명하면 틀립니다. 그곳의 천체도 태양 주위를 돌려면 구심 가속도가 필요합니다. 이상적인 L₄·L₅ 배치에서는 합성 중력이 행성과 같은 각속도의 공전을 유지할 수 있게 해 줍니다.
회전계에서는 중력뿐 아니라 원심 효과와 움직이는 천체에 작용하는 코리올리 효과도 고려합니다. L₄·L₅의 안정성을 단순한 ‘중력 구덩이’로 설명할 수 없는 이유입니다. NASA의 라그랑주점 설명
그런데 ‘안정하다’는 말만으로는 왜 상대각이 돌아오는지 알기 어렵습니다. 빠른 공전을 평균내고 궤도가 거의 원형이라고 가정하면, L₄ 앞뒤에서의 변화는 다음처럼 읽을 수 있습니다.
| L₄ 쪽의 상대각 | 평균적인 궤도 변화 | 이후 상대각의 변화 |
|---|---|---|
| 0° < φ < 60° | 각운동량 감소 쪽으로 작용 → 장반경 감소 | 평균 공전이 빨라져 φ를 증가시키는 방향으로 작용 |
| 60° < φ < 180° | 각운동량 증가 쪽으로 작용 → 장반경 증가 | 평균 공전이 느려져 φ를 감소시키는 방향으로 작용 |
따라서 60°보다 작아지면 더 큰 각도 쪽으로, 60°보다 커지면 더 작은 각도 쪽으로 상대 운동을 되돌리는 변화가 생깁니다. L₅에서는 좌우를 뒤집은 같은 원리가 작동합니다.
여기에는 자주 빠지는 항목이 하나 있습니다. 태양도 행성의 중력에 끌려 움직입니다. 태양을 중심으로 천체의 운동을 기술하려면 천체에 대한 행성의 직접적인 힘뿐 아니라, 기준점인 태양의 가속도도 빼 주어야 합니다. 이를 간접항(indirect term)이라고 합니다. 특히 60°보다 멀리 앞선 구간을 ‘목성이 뒤로 당기니 무조건 각운동량을 잃는다’고 설명하면, 위 표의 복원을 얻지 못합니다.
그 차이를 아래 세 장면에서 보십시오. 태양–행성 거리를 a, 행성–작은 천체 거리를 d라고 하겠습니다. 작은 천체도 태양에서 거의 a만큼 떨어져 있다고 단순화했습니다. 태양도 작은 천체도 같은 행성에 끌립니다. 태양을 기준으로 천체가 어떻게 움직이는지를 알려면, 작은 천체가 받는 가속도에서 태양이 받는 가속도를 빼야 합니다.
그림을 만든 파이썬 코드 보기
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
bg, fg, muted = '#0d1117', '#e6edf3', '#aebbd0'
direct_color, correction_color, tangent_color = '#ff8fa3', '#79c0ff', '#7ee7da'
fig, axes = plt.subplots(1, 3, figsize=(13.4, 6.4))
fig.patch.set_facecolor(bg)
arrow_scale = .22
planet = np.array([1., 0.])
theta = np.linspace(0, np.deg2rad(112), 300)
chains = [
'Smaller mean orbit -> shorter period\nRelative angle tends to grow',
'Tangential effects balance\nGravity still keeps the orbit',
'Larger mean orbit -> longer period\nRelative angle tends to shrink',
]
for ax, degrees, chain in zip(axes, [40, 60, 90], chains):
phi = np.deg2rad(degrees)
body = np.array([np.cos(phi), np.sin(phi)])
tangent = np.array([-np.sin(phi), np.cos(phi)])
distance = np.linalg.norm(planet-body)
direct = (planet-body)/distance**3
correction = np.array([-1., 0.])
tangent_effect = np.dot(direct+correction, tangent)
ax.set_facecolor(bg)
ax.plot(np.cos(theta), np.sin(theta), '--', color='#566477', lw=1)
ax.plot([0,1],[0,0],color='#566477',lw=1)
ax.plot([0,body[0]],[0,body[1]],color='#566477',lw=1)
ax.plot([body[0],1],[body[1],0],':',color=muted,lw=1.3)
arc = np.linspace(0,phi,80)
ax.plot(.32*np.cos(arc),.32*np.sin(arc),color=muted,lw=1)
ax.text(.40*np.cos(phi/2),.40*np.sin(phi/2),f'{degrees} deg',color=muted,ha='center',fontsize=9)
ax.scatter([0,1],[0,0],s=[110,65],color=['#e3b341','#79c0ff'],zorder=5)
ax.text(-.04,.08,'Sun',color=fg,ha='right',fontsize=10)
ax.text(1,-.09,'Planet',color=fg,ha='center',fontsize=10)
ax.scatter(*body,s=60,color=fg,zorder=6)
ax.text(body[0]+.02,body[1]+.09,'L4 / body' if degrees==60 else 'Body',color=fg,ha='center',fontsize=10)
ax.text(.5,-.08,'a',color=muted,ha='center',fontsize=10)
middle=(body+planet)/2
relation='d < a' if degrees<60 else 'd = a' if degrees==60 else 'd > a'
ax.text(middle[0]+.09,middle[1]+.02,relation,color=fg,fontsize=10)
# Direct pull and origin-acceleration correction share the same scale.
for vector,color,style in [(direct,direct_color,'-'),(correction,correction_color,'--')]:
ax.annotate('',xy=body+arrow_scale*vector,xytext=body,
arrowprops={'arrowstyle':'->','color':color,'lw':2,'linestyle':style})
if abs(tangent_effect)>1e-10:
origin=body+np.array([-.02,-.12])
ax.annotate('',xy=origin+arrow_scale*tangent_effect*tangent,xytext=origin,
arrowprops={'arrowstyle':'->','color':tangent_color,'lw':3})
else:
ax.text(.05,.53,'Net tangential\neffect = 0',color=tangent_color,ha='left',fontsize=10)
ax.annotate('',xy=(.24,0),xytext=(0,0),
arrowprops={'arrowstyle':'->','color':correction_color,'lw':1.5})
ax.text(.12,-.19,"Sun accelerates too",color=correction_color,ha='center',fontsize=8)
ax.set(xlim=(-.22,1.34),ylim=(-.26,1.27),aspect='equal')
ax.set_axis_off()
ax.set_title(f'{degrees} deg: '+('nearer the planet' if degrees<60 else 'equal distances' if degrees==60 else 'farther from the planet'),
color=fg,pad=14,fontsize=11)
ax.text(.5,-.09,chain,transform=ax.transAxes,color=tangent_color,ha='center',va='top',fontsize=10,linespacing=1.6)
print(f'{degrees} deg: d/a = {distance:.4f}; relative tangential acceleration = {tangent_effect:.4f} GMp/a^2')
fig.suptitle('Why 60 degrees? Compare the pulls, then use the orbital period.',color=fg,fontsize=14,y=.98)
handles=[Line2D([0],[0],color=direct_color,lw=2,label='Planet pulls the body'),
Line2D([0],[0],color=correction_color,lw=2,ls='--',label="Subtract the Sun's acceleration"),
Line2D([0],[0],color=tangent_color,lw=3,label='Net tangential effect')]
fig.legend(handles=handles,loc='lower center',bbox_to_anchor=(.5,.065),ncol=3,
facecolor=bg,edgecolor='#566477',labelcolor=fg,fontsize=9)
fig.text(.5,.015,'Only planet-related accelerations are drawn. The dashed arrow corrects the moving origin; it is not another force.',
color=muted,ha='center',fontsize=9)
fig.tight_layout(rect=(0,.24,1,.94))
plt.show()
40 deg: d/a = 0.6840; relative tangential acceleration = -1.3655 GMp/a^2
60 deg: d/a = 1.0000; relative tangential acceleration = -0.0000 GMp/a^2
90 deg: d/a = 1.4142; relative tangential acceleration = 0.6464 GMp/a^2

원리 그림. 빨간 화살표는 행성이 작은 천체를 당기는 가속도, 파란 점선은 태양의 가속도를 빼는 좌표계 보정, 초록 화살표는 그 둘을 합친 공전 접선 방향 효과입니다. 태양이 천체를 당기는 큰 중력은 생략했습니다. 점선은 새로운 중력이 아닙니다.
- 60°보다 행성에 가까우면: d가 a보다 작아서 작은 천체가 받는 행성의 당김이 더 큽니다. 평균적으로 궤도를 작게 바꾸는 효과가 생기고, 이후 평균 공전이 빨라져 상대각을 키우는 쪽으로 갑니다.
- 정확히 60°이면: 정삼각형이 되어 d = a입니다. 행성 때문에 생기는 두 가속도의 접선 방향 효과가 상쇄됩니다. 전체 중력은 여전히 남아 태양 주위 공전을 유지합니다.
- 60°보다 행성에서 멀면: d가 a보다 커져 두 당김의 차이가 반대가 됩니다. 평균적으로 궤도를 크게 바꾸는 효과가 생기고, 이후 평균 공전이 느려져 상대각을 줄이는 쪽으로 갑니다.
작은 어긋남이 생겼을 때 궤도 크기 → 공전 주기 → 상대각이 이어지며, 그 어긋남이 계속 커지는 대신 되돌아오게 하는 것입니다. 마찰이 없으므로 한 번 돌아와 L₄에 달라붙지 않고, 반대쪽으로 지나쳤다가 다시 돌아옵니다. 그 왕복이 다음 절의 올챙이 운동으로 이어집니다. L₅는 위아래를 뒤집어 같은 방식으로 읽을 수 있습니다.
이상적인 거의 같은 반지름의 배치에서, 직접항과 간접항을 합친 접선 방향 효과의 부호가 바로 60°에서 바뀝니다. 정삼각형의 기하와 궤도의 주기 변화가 만나 60°를 중심으로 되돌아오는 운동을 만드는 셈입니다. 위 표는 그 순간 상대각이 반드시 그 방향으로 움직인다는 뜻이 아니라, 상대각의 변화 속도를 그 방향으로 바꾼다는 뜻입니다. 이미 앞서가던 천체는 얼마 동안 더 앞서간 뒤 멈추고 돌아옵니다.
실제 사례: 제임스 웹은 태양–지구 L₂ 주변을 돈다
앞 그림은 태양–목성계였습니다. 이번에는 행성을 지구로 바꾸어 보겠습니다. 현재 제임스 웹 우주망원경(James Webb Space Telescope, JWST)이 관측하는 곳은 태양–지구 L₂ 주변의 헤일로 궤도(halo orbit) 입니다. L₂는 태양에서 보아 지구 너머, 지구에서 약 150만 km 떨어진 곳입니다. 웹은 그 점에 정지해 있지 않고, 지구의 공전 평면 위아래로도 움직이는 입체적인 궤도를 대략 6개월에 한 번 돕니다. 동시에 지구와 보조를 맞추어 태양 주위를 공전합니다. NASA: 웹의 궤도
그림을 만든 파이썬 코드 보기
import numpy as np
import matplotlib.pyplot as plt
bg, fg, muted = '#0d1117', '#e6edf3', '#aebbd0'
gold, blue, mint = '#e3b341', '#79c0ff', '#7ee7da'
fig = plt.figure(figsize=(12.6, 5.5), facecolor=bg)
left = fig.add_subplot(121)
right = fig.add_subplot(122, projection='3d')
left.set_facecolor(bg)
right.set_facecolor(bg)
# Layout positions are schematic; the two physical distances are labelled.
sun_x, earth_x, l2_x = .06, .57, .87
left.plot([sun_x, l2_x], [.52, .52], color=muted, lw=1.2)
left.scatter([sun_x, earth_x], [.52, .52], s=[600, 140], c=[gold, blue], zorder=4)
left.scatter([l2_x], [.52], s=90, c=mint, marker='+', linewidths=2.5, zorder=5)
for x, name, color in [(sun_x, 'Sun', gold), (earth_x, 'Earth', blue), (l2_x, 'L2', mint)]:
left.text(x, .63, name, color=color, ha='center', fontsize=13)
for start, stop, text in [(sun_x, earth_x, '~149.6 million km'), (earth_x, l2_x, '~1.5 million km')]:
left.annotate('', xy=(stop, .34), xytext=(start, .34),
arrowprops={'arrowstyle':'<->', 'color':muted, 'lw':1.2})
left.text((start+stop)/2, .24, text, color=fg, ha='center', fontsize=10)
left.text(.46, .07, 'Beyond Earth, away from the Sun\nDistance layout is not to scale',
color=muted, ha='center', fontsize=11, linespacing=1.7)
left.set(xlim=(-.04, 1.03), ylim=(0, 1))
left.set_axis_off()
left.set_title('1. Which L2? The Sun-Earth system', color=fg, fontsize=13, pad=18)
# An illustrative out-of-plane loop, not an integrated halo solution or
# a real-time ephemeris. L2 has no mass; it is a reference equilibrium.
t = np.linspace(0, 2*np.pi, 500)
x = 1 + .055*np.cos(2*t)
y = .29*np.cos(t)
z = .19*np.sin(t)
plane_x, plane_y = np.meshgrid([-.12, 1.37], [-.42, .42])
right.plot_surface(plane_x, plane_y, np.zeros_like(plane_x),
color=blue, alpha=.08, shade=False)
right.plot([-.17, 1.35], [0, 0], [0, 0], color=muted, lw=1.1, ls='--')
right.plot(x, y, z, color=mint, lw=2.8)
right.scatter([0], [0], [0], s=85, c=blue, depthshade=False)
right.text(0, -.04, -.09, 'Earth', color=blue, ha='center', fontsize=11)
right.scatter([1], [0], [0], s=70, c=fg, marker='+', depthshade=False)
right.text(1, -.05, -.08, 'L2', color=fg, ha='center', fontsize=11)
example = 78
right.scatter([x[example]], [y[example]], [z[example]], s=55, c=gold, depthshade=False)
right.text(x[example], y[example]+.02, z[example]+.05,
'Webb\n(example position)', color=gold, ha='center', fontsize=10)
right.text(.53, -.43, -.025, "Earth's orbital plane", color=muted, ha='center', fontsize=10)
right.text(-.16, .025, .04, 'Sunward', color=gold, ha='right', fontsize=10)
right.set(xlim=(-.25, 1.4), ylim=(-.45, .45), zlim=(-.28, .35))
right.set_box_aspect((1.65, .9, .63), zoom=1.3)
right.view_init(elev=24, azim=-57)
right.set_axis_off()
right.set_title('2. A halo orbit, viewed with Earth fixed', color=fg, fontsize=13, pad=18)
fig.suptitle('Webb moves around Sun-Earth L2; it does not park on the point.',
color=fg, fontsize=15, y=.98)
fig.text(.5, .025, 'Schematic loop, no physical scale. One halo circuit: about 6 months. Together with Earth, Webb also orbits the Sun.',
color=muted, ha='center', fontsize=9)
fig.subplots_adjust(left=.035, right=.975, bottom=.13, top=.81, wspace=.08)
plt.show()

위치와 운동의 개념도. 왼쪽은 태양–지구–L₂의 순서와 거리, 오른쪽은 함께 도는 화면에서 본 L₂ 주변의 입체적인 고리를 보여 줍니다. 거리와 고리 모양은 축척을 맞추지 않았으며, 표시한 웹의 점은 실제 시각의 위치가 아닌 예시입니다.
지구보다 태양에서 먼데, 왜 지구와 같은 박자로 돌 수 있을까요? 태양 중력만 있다면 더 긴 공전주기가 필요하지만, L₂ 부근에서는 지구도 태양 쪽으로 당겨 줍니다. 두 중력을 합하면 지구와 같은 박자를 유지하는 데 필요한 안쪽 가속도를 얻습니다. L₂ 자체에 질량이 있어 웹을 끌어당기는 것이 아닙니다. 두 천체의 중력과 함께 도는 좌표계에서 나타나는 주변 운동입니다.
이 위치에서는 웹이 보는 태양·지구·달을 대체로 같은 쪽에 둘 수 있습니다. 차광막(sunshield) 을 그쪽으로 향하면 거울과 관측기기를 빛과 열에서 보호하기 좋습니다. 약한 적외선을 보는 망원경은 자기 자신이 따뜻해져 내는 적외선도 줄여야 합니다. 헤일로 궤도는 지구·달의 그림자를 피하게 하여 태양전지에 햇빛을 공급하고 급격한 온도 변화를 줄입니다. 차가운 이유를 “지구 그림자에 숨어 있어서”라고 이해하면 안 됩니다. NASA: 망원경과 열 환경
L₂ 주변의 운동은 작은 오차가 저절로 사라지는 안정된 주차장이 아니므로, 웹은 주기적으로 작은 추진 보정을 합니다. 이어서 볼 올챙이 궤도는 L₄·L₅ 한쪽 주변의 운동이며, 웹의 L₂ 헤일로 궤도와 구별해야 합니다.
5. 올챙이 궤도(tadpole orbit): 한 진영 안에서 안쪽 길과 바깥쪽 길을 오간다
이제 천체를 L₄ 근처에 두되, 정확한 평형 상태에서 조금 벗어나게 해 봅시다. 상대각은 60°를 중심으로 진동합니다. 여기서 공명각의 진동(libration, 칭동) 은 같은 방향으로 각도가 계속 누적되는 순환과 달리, 일정한 범위 안에서 왔다 갔다 한다는 뜻입니다.
하지만 천체가 같은 원호를 앞뒤로 왕복하기만 하는 것은 아닙니다. 앞서갈 때에는 평균적인 궤도가 조금 안쪽이고, 뒤처질 때에는 조금 바깥쪽입니다. 따라서 회전계의 길을 그리면 안쪽 가지와 바깥쪽 가지가 연결된 닫힌 경로가 됩니다.
그림을 만든 파이썬 코드 보기
ENERGY = 1.05
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import brentq
# ENERGY is set to 1.05 or 2.00 in the corresponding independent notebook cell.
mu, scale = 3e-6, 20
U = lambda phi: -np.cos(phi) + 1/np.sqrt(2-2*np.cos(phi))
low = brentq(lambda phi: U(phi)-ENERGY, 1e-5, np.pi/3)
high = (brentq(lambda phi: U(phi)-ENERGY, np.pi/3, np.pi)
if ENERGY < 1.5 else 2*np.pi-low)
alpha = np.linspace(0, 2*np.pi, 1401)
phi = low+(high-low)*(1-np.cos(alpha))/2
v = np.sign(np.sin(alpha))*np.sqrt(np.maximum(0, 2*(ENERGY-U(phi))))
v[[0, 700, -1]] = 0
da = -(2/3)*np.sqrt(3*mu)*v
bg, fg, muted = '#0d1117', '#e6edf3', '#aebbd0'
inner, outer = '#7ee7da', '#ffa657'
fig, axes = plt.subplots(1, 2, figsize=(12.2, 5.4), gridspec_kw={'width_ratios':[1.05, 1]})
fig.patch.set_facecolor(bg)
for ax in axes:
ax.set_facecolor(bg)
ax.tick_params(colors=fg)
for spine in ax.spines.values():
spine.set_color('#566477')
ax = axes[0]
for idx, color, label in [(slice(0,701), inner, 'Inner: relative angle increases'),
(slice(700,None), outer, 'Outer: relative angle decreases')]:
ax.plot(np.degrees(phi[idx]), 100*da[idx], color=color, lw=2.5, label=label)
ax.axhline(0, color='#566477', ls='--', lw=1)
for angle, label in [(60,'L4'), (180,'L3'), (300,'L5')]:
if np.degrees(low)-5 < angle < np.degrees(high)+5:
ax.axvline(angle, color='#566477', lw=.7, alpha=.65)
ax.text(angle, -.015, label, color=muted, ha='center', va='top',
transform=ax.get_xaxis_transform())
angle_margin = max(5, .035*np.degrees(high-low))
ax.set_xlim(np.degrees(low)-angle_margin, np.degrees(high)+angle_margin)
for i, color in [(310,inner), (1010,outer)]:
ax.annotate('', xy=(np.degrees(phi[i+30]),100*da[i+30]),
xytext=(np.degrees(phi[i-30]),100*da[i-30]),
arrowprops={'arrowstyle':'->','color':color,'lw':2})
ax.set_xlabel('Relative mean longitude (degrees)', color=fg, labelpad=20)
ax.set_ylabel('Semi-major axis difference (%)', color=fg)
ax.set_title('1. Unwrap the circular track', color=fg, pad=14)
ax.grid(color='#30363d', alpha=.5)
ax.legend(loc='upper center', facecolor=bg, edgecolor='#566477', labelcolor=fg, fontsize=8)
ax = axes[1]
theta = np.linspace(0, 2*np.pi, 600)
ax.plot(np.cos(theta), np.sin(theta), color='#566477', ls='--', lw=1)
radius = 1+scale*da
xx, yy = radius*np.cos(phi), radius*np.sin(phi)
ax.plot(xx[:701], yy[:701], color=inner, lw=2.8)
ax.plot(xx[700:], yy[700:], color=outer, lw=2.8)
for i, color in [(310,inner), (1010,outer)]:
ax.annotate('', xy=(xx[i+25],yy[i+25]), xytext=(xx[i-25],yy[i-25]),
arrowprops={'arrowstyle':'->','color':color,'lw':2})
ax.scatter([0,1],[0,0], color=['#e3b341','#79c0ff'], s=[110,60], zorder=4)
ax.text(0, -.13, 'Sun', color=fg, ha='center')
ax.text(1.04, -.15, 'Planet', color=fg, ha='center')
for angle,label in [(np.pi/3,'L4'), (np.pi,'L3'), (5*np.pi/3,'L5')]:
ax.scatter(np.cos(angle),np.sin(angle),s=18,color=muted)
ax.text(1.16*np.cos(angle),1.16*np.sin(angle),label,color=muted,ha='center',va='center')
for angle,label in [(low,'A'), (high,'B')]:
ax.scatter(np.cos(angle),np.sin(angle),s=45,facecolor=bg,edgecolor=fg,zorder=5)
ax.text(1.12*np.cos(angle),1.12*np.sin(angle),label,color=fg,ha='center',va='center')
ax.set(xlim=(-1.38,1.38),ylim=(-1.32,1.32),aspect='equal')
ax.set_axis_off()
ax.set_title('2. Wrap it around the Sun', color=fg, pad=14)
kind = 'Tadpole' if ENERGY < 1.5 else 'Horseshoe'
fig.suptitle(f'{kind}: the same two branches, unwrapped and rotating (E = {ENERGY:.2f})',color=fg)
fig.text(.5,.015,f'A = {np.degrees(low):.1f} deg; B = {np.degrees(high):.1f} deg. Radial difference x{scale}; averaged model, not an ephemeris.',
ha='center',color=muted,fontsize=9)
fig.tight_layout(rect=(0,.04,1,.94))
plt.show()
print(f'{kind} turning angles: {np.degrees(low):.3f} to {np.degrees(high):.3f} degrees')

Tadpole turning angles: 30.296 to 117.774 degrees
그림 5. 아래 위젯과 같은 평균화 모형에서 E = 1.05인 L₄ 올챙이입니다. 상대각은 약 30.3°–117.8°를 오갑니다. 반지름 방향 차이는 20배 확대했습니다.
그림 왼쪽은 원형 길을 잘라 펼친 지도입니다. 가로가 상대각, 세로가 장반경 차이입니다. 아래 가지로 갔다가 위 가지로 돌아오므로 단순한 선분 왕복이 아니라 폭이 있는 고리가 됩니다. 이 지도를 원형 길에 다시 감으면 오른쪽의 휘어진 고리가 됩니다.
과정을 한 번 따라가면 다음과 같습니다.
- 행성에 가까운 쪽 끝에서 출발합니다. 상대각의 변화가 잠시 0이지만 중력 효과는 남아 있습니다. 궤도를 더 작게 바꾸는 효과가 이어져 상대각이 증가하기 시작합니다.
- 안쪽 가지를 따라 앞서갑니다. 평균 공전이 행성보다 빠르므로 φ가 커집니다. 60°를 지나도 이미 쌓인 상대 운동 때문에 바로 멈추지 않습니다.
- 멀리 앞선 쪽 끝에 도달합니다. 60° 바깥에서 이어진 궤도 변화로 상대적인 앞서감이 줄어들고, 마침내 φ의 증가가 멈춥니다.
- 바깥쪽 가지로 돌아옵니다. 이제 평균 공전이 행성보다 느려져 φ가 줄어듭니다. 다시 가까운 쪽 끝에서 방향을 바꾸면 한 번의 진동이 끝납니다.
그런데 왜 대칭적인 타원이 아니라 올챙이일까요? L₄에서 행성 쪽으로 30° 움직인 자리와 반대쪽으로 30° 움직인 자리는 중력의 효과가 대칭적이지 않습니다. 행성에 가까운 쪽에서 효과가 더 급하게 바뀌므로 가까운 끝은 30.3°에서 돌아서지만, 먼 끝은 117.8°까지 길게 뻗습니다. 두 끝 사이의 안쪽·바깥쪽 길을 원형으로 감으면 한쪽이 부풀고 다른 쪽이 길어지는 올챙이 유형의 고리가 됩니다. 이름은 이 비대칭인 상대 경로에서 나왔습니다.
아주 작은 진동에서는 둥근 타원에 가까울 수 있습니다. 올챙이 궤도라는 분류는 모든 경로가 만화 속 올챙이와 똑같이 생겼다는 뜻이 아닙니다. 핵심은 L₄ 또는 L₅ 한쪽을 중심으로 진동하고, 두 진영 사이를 연결하는 영역까지 넘어가지 않는다는 것입니다. 실제 이심률과 궤도 기울기가 있으면 이 느린 경로 위에 더 빠른 흔들림도 겹칩니다.
6. 말굽 궤도(horseshoe orbit): 한쪽 진영을 넘어가지만, 행성 자리까지 통과하지는 않는다
상대 운동의 범위가 더 커지면 한쪽 진영 안에 머물 수 없습니다. 상대각은 L₄ 부근을 지나 180° 반대편을 넘고, L₅ 부근까지 이어집니다. 그러나 안정적인 말굽 운동에서는 행성 바로 옆으로 계속 들어가 추월하지 않고, 접근하는 동안 중력이 궤도의 크기를 바꾸어 상대 진행 방향을 돌려놓습니다.
그림을 만든 파이썬 코드 보기
ENERGY = 2.00
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import brentq
# ENERGY is set to 1.05 or 2.00 in the corresponding independent notebook cell.
mu, scale = 3e-6, 20
U = lambda phi: -np.cos(phi) + 1/np.sqrt(2-2*np.cos(phi))
low = brentq(lambda phi: U(phi)-ENERGY, 1e-5, np.pi/3)
high = (brentq(lambda phi: U(phi)-ENERGY, np.pi/3, np.pi)
if ENERGY < 1.5 else 2*np.pi-low)
alpha = np.linspace(0, 2*np.pi, 1401)
phi = low+(high-low)*(1-np.cos(alpha))/2
v = np.sign(np.sin(alpha))*np.sqrt(np.maximum(0, 2*(ENERGY-U(phi))))
v[[0, 700, -1]] = 0
da = -(2/3)*np.sqrt(3*mu)*v
bg, fg, muted = '#0d1117', '#e6edf3', '#aebbd0'
inner, outer = '#7ee7da', '#ffa657'
fig, axes = plt.subplots(1, 2, figsize=(12.2, 5.4), gridspec_kw={'width_ratios':[1.05, 1]})
fig.patch.set_facecolor(bg)
for ax in axes:
ax.set_facecolor(bg)
ax.tick_params(colors=fg)
for spine in ax.spines.values():
spine.set_color('#566477')
ax = axes[0]
for idx, color, label in [(slice(0,701), inner, 'Inner: relative angle increases'),
(slice(700,None), outer, 'Outer: relative angle decreases')]:
ax.plot(np.degrees(phi[idx]), 100*da[idx], color=color, lw=2.5, label=label)
ax.axhline(0, color='#566477', ls='--', lw=1)
for angle, label in [(60,'L4'), (180,'L3'), (300,'L5')]:
if np.degrees(low)-5 < angle < np.degrees(high)+5:
ax.axvline(angle, color='#566477', lw=.7, alpha=.65)
ax.text(angle, -.015, label, color=muted, ha='center', va='top',
transform=ax.get_xaxis_transform())
angle_margin = max(5, .035*np.degrees(high-low))
ax.set_xlim(np.degrees(low)-angle_margin, np.degrees(high)+angle_margin)
for i, color in [(310,inner), (1010,outer)]:
ax.annotate('', xy=(np.degrees(phi[i+30]),100*da[i+30]),
xytext=(np.degrees(phi[i-30]),100*da[i-30]),
arrowprops={'arrowstyle':'->','color':color,'lw':2})
ax.set_xlabel('Relative mean longitude (degrees)', color=fg, labelpad=20)
ax.set_ylabel('Semi-major axis difference (%)', color=fg)
ax.set_title('1. Unwrap the circular track', color=fg, pad=14)
ax.grid(color='#30363d', alpha=.5)
ax.legend(loc='upper center', facecolor=bg, edgecolor='#566477', labelcolor=fg, fontsize=8)
ax = axes[1]
theta = np.linspace(0, 2*np.pi, 600)
ax.plot(np.cos(theta), np.sin(theta), color='#566477', ls='--', lw=1)
radius = 1+scale*da
xx, yy = radius*np.cos(phi), radius*np.sin(phi)
ax.plot(xx[:701], yy[:701], color=inner, lw=2.8)
ax.plot(xx[700:], yy[700:], color=outer, lw=2.8)
for i, color in [(310,inner), (1010,outer)]:
ax.annotate('', xy=(xx[i+25],yy[i+25]), xytext=(xx[i-25],yy[i-25]),
arrowprops={'arrowstyle':'->','color':color,'lw':2})
ax.scatter([0,1],[0,0], color=['#e3b341','#79c0ff'], s=[110,60], zorder=4)
ax.text(0, -.13, 'Sun', color=fg, ha='center')
ax.text(1.04, -.15, 'Planet', color=fg, ha='center')
for angle,label in [(np.pi/3,'L4'), (np.pi,'L3'), (5*np.pi/3,'L5')]:
ax.scatter(np.cos(angle),np.sin(angle),s=18,color=muted)
ax.text(1.16*np.cos(angle),1.16*np.sin(angle),label,color=muted,ha='center',va='center')
for angle,label in [(low,'A'), (high,'B')]:
ax.scatter(np.cos(angle),np.sin(angle),s=45,facecolor=bg,edgecolor=fg,zorder=5)
ax.text(1.12*np.cos(angle),1.12*np.sin(angle),label,color=fg,ha='center',va='center')
ax.set(xlim=(-1.38,1.38),ylim=(-1.32,1.32),aspect='equal')
ax.set_axis_off()
ax.set_title('2. Wrap it around the Sun', color=fg, pad=14)
kind = 'Tadpole' if ENERGY < 1.5 else 'Horseshoe'
fig.suptitle(f'{kind}: the same two branches, unwrapped and rotating (E = {ENERGY:.2f})',color=fg)
fig.text(.5,.015,f'A = {np.degrees(low):.1f} deg; B = {np.degrees(high):.1f} deg. Radial difference x{scale}; averaged model, not an ephemeris.',
ha='center',color=muted,fontsize=9)
fig.tight_layout(rect=(0,.04,1,.94))
plt.show()
print(f'{kind} turning angles: {np.degrees(low):.3f} to {np.degrees(high):.3f} degrees')

Horseshoe turning angles: 19.568 to 340.432 degrees
그림 6. E = 2.00인 평균화 모형의 말굽입니다. 상대각은 약 19.6°–340.4°를 오갑니다. 행성 바로 옆의 틈이 남기 때문에 원환 전체가 아닌 말굽 형태가 됩니다. 반지름 방향 차이는 20배 확대했습니다.
앞 그림의 펼친 지도에서는 고리가 19.6°부터 340.4°까지 길게 늘어납니다. 원형 길에 다시 감으면 거의 한 바퀴를 두르는 안쪽·바깥쪽 가지가 생깁니다. 그런데 0°에 있는 행성 주변은 비어 있고, 두 가지는 그 틈의 양옆에서 각각 연결됩니다. 그래서 꽉 찬 고리 대신 입구가 열린 U자, 곧 말굽(horseshoe)이 됩니다.
말굽은 행성 뒤쪽에서 따라잡기 시작하는 천체를 상상하면 가장 쉽게 이해할 수 있습니다.
| 단계 | 회전계에서 보이는 움직임 | 궤도에 일어나는 변화 |
|---|---|---|
| ① 뒤에서 따라잡는다 | 약간 안쪽 궤도라 행성에 대한 상대각이 증가 | 평균 공전이 더 빠름 |
| ② 뒤쪽 접근 끝에서 돌아선다 | 행성을 바로 추월하기 전에 상대적인 따라잡기가 멈춤 | 행성의 중력으로 각운동량을 받아 궤도가 커짐 |
| ③ 바깥쪽 길에서 뒤처진다 | 행성에서 멀어지며 반대편을 돌아 앞쪽 영역까지 이동 | 더 큰 궤도의 평균 공전이 느림 |
| ④ 앞쪽 접근 끝에서 돌아선다 | 행성이 뒤에서 따라잡기 전에 상대적인 뒤처짐이 멈춤 | 각운동량을 잃어 궤도가 작아지고, 다시 앞서가기 시작 |
②에서 행성은 뒤에 있는 천체를 진행 방향으로 당깁니다. 천체가 속도와 각운동량을 받아 더 큰 궤도로 옮겨가면, 이후 평균 공전은 느려집니다. 그래서 당겨서 가속했는데도 결과적으로 상대적인 추월을 막을 수 있습니다. ④에서는 반대 변화가 일어나 다시 안쪽 길로 돌아갑니다.
뒤쪽은 그림의 아래쪽에서 상대각이 360°에 가까운 부분, 앞쪽은 위쪽에서 0°에 가까운 부분입니다. ③에서 ‘뒤처지다 앞쪽 영역으로 이동한다’는 말이 이상하게 들릴 수 있습니다. 행성보다 느리게 돌아 상대각이 340°에서 180°, 60° 쪽으로 줄어들면, 행성을 통과하지 않고 태양 반대편을 길게 돌아 그 앞쪽에 도달합니다.
이렇게 안쪽에서는 앞서가고, 바깥쪽에서는 뒤처지며, 양 끝에서는 안팎의 역할이 바뀝니다. 행성 자리 주변에 틈을 남긴 두 가지가 연결되므로 회전계의 경로는 말굽이 됩니다. 중력이 반발해서 튕겨 내는 현상도, 벽에 부딪히는 현상도 아닙니다. 힘은 인력이고, 방향 전환은 연속적인 궤도 변화의 결과입니다.
말굽의 실제 사례로는 지구의 공궤도 소행성 2010 SO₁₆, 그리고 서로 궤도를 교환하는 토성의 위성 야누스와 에피메테우스가 있습니다. 후자는 태양 대신 토성을 중심으로 공궤도 운동을 하는 경우입니다. 목성의 말굽 경로를 유명한 트로이 소행성 무리와 같은 장기 안정 집단으로 여기면 안 됩니다. 행성이 무거워질수록 말굽 운동의 장기 안정성에는 더 강한 제약이 생깁니다. 2010 SO₁₆ 연구, 말굽 공궤도 운동의 안정성 연구
7. 슬라이더로 확인하기: 한쪽에 갇히는 올챙이와 두 쪽을 잇는 말굽
다음 위젯은 상대각과 궤도 크기가 함께 변하는 모습을 보여 줍니다. 저이심률·공평면 공궤도 운동을 평균낸 방정식으로 상대각과 궤도의 크기 변화를 연결했습니다. 시간 슬라이더는 한 번의 느린 진동에서 현재 위치를, 모형의 보존량 E 슬라이더는 가능한 운동의 범위를 바꿉니다.
‘나란히 비교’에서 재생하면 왼쪽에서는 행성이 고정되고, 오른쪽에서는 행성도 태양 주위를 공전합니다. 두 화면은 같은 모형의 같은 시각을 보여 줍니다. 소행성이 왼쪽에서 방향을 바꾸는 동안에도, 오른쪽에서는 행성과 소행성이 모두 태양 주위를 같은 공전 방향으로 움직이는 것을 확인할 수 있습니다. L₃·L₄·L₅ 표시는 오른쪽에서 행성과 함께 움직입니다.
두 화면은 같은 안팎 확대율을 사용합니다. 기본 ×20은 작은 장반경 차이만 넓혀 보여 주며, ×1로 바꾸면 두 화면에 함께 적용됩니다. 왼쪽의 파란 선은 느린 상대 진동 한 주기 전체이고, 붉은 선은 두 화면 모두 최근 행성 1.5공전 동안 지나온 길입니다. 짧은 붉은 궤적과 긴 파란 기준선을 구별해 보십시오. 오른쪽에 파란 올챙이 전체를 돌려 붙이지 않는 이유는 그 선의 각 점을 서로 다른 공전 시각에 지나기 때문입니다.
기본 재생은 행성 한 공전을 4초로 보여 줍니다. 이 모형의 상대 진동에는 행성의 수백 번 공전이 필요하므로, 짧게 재생하면 왼쪽의 상대 위치는 조금만 변합니다. 그것이 두 시간 규모의 실제 관계입니다. 진동 전체를 빠르게 훑으려면 시간 슬라이더를 옮기거나 한 진동을 16초로 압축하는 재생 속도를 선택하십시오. 빠른 모드에서는 화면 갱신 사이에 행성이 여러 바퀴 돌 수 있어 정지하거나 거꾸로 도는 듯 보일 수 있지만, 이는 표시의 시간 해상도 때문에 생기는 현상입니다.
먼저 L₄ 올챙이를 선택하고 시간 슬라이더를 한 바퀴 움직여 보십시오. 앞서가는 구간에서 장반경 차이는 음수이고, 뒤처지는 구간에서는 양수입니다. 양 끝에서는 상대각의 변화가 0을 지나 방향을 바꿉니다. 이 모형의 1차 근사에서는 그때 장반경 차이도 0이 되지만, 모든 실제 천체의 순간 거리가 그때 행성과 같아진다는 뜻은 아닙니다.
정지 상태에서 +1 공전을 몇 번 눌러 보면 오른쪽의 행성은 한 바퀴씩 돌아 같은 자리로 오지만, 소행성은 조금씩 어긋나고 왼쪽에서도 그 차이가 쌓입니다. 이번에는 25%·75% 를 번갈아 누르십시오. 올챙이에서는 같은 상대각을 지날 때도 한 번은 안쪽, 다른 한 번은 바깥쪽 가지에 있습니다. 이것이 상대 궤도에 폭이 생기는 이유입니다.
그다음 모형의 보존량 $E$를 높이십시오. 아래 그래프에서 180°에 있는 경계 높이를 넘으면 허용되는 상대각 범위가 두 진영으로 연결되고 말굽으로 바뀝니다. 정확한 경계에서는 유한한 주기의 닫힌 운동이 되지 않으므로, 위젯도 보통의 순환 재생을 멈춥니다.
같은 공전, 두 카메라: 올챙이·말굽 궤도 비교
같은 운동을 두 카메라로 봅니다. 왼쪽 회전 좌표계(rotating frame)는 카메라가 행성과 함께 돌아 행성이 멈춰 보이고, 오른쪽 태양 중심 좌표계(heliocentric frame)는 카메라 방향을 고정합니다. 행성의 실제 공전은 계속됩니다.
궤도 예시 또는 E를 바꾸면 경과 시간을 0으로 되돌립니다.
E < 1.50: L3의 고개를 넘지 못하므로 L4 또는 L5의 한 골짜기에 갇힙니다.
공전 관찰에서는 공명 한 주기에 수백 회 공전하므로, 전체 왕복은 오래 걸립니다. 시간 슬라이더 또는 공명 관찰로 이동할 수 있습니다.
파란 선은 느린 상대 진동 한 주기 전체입니다. 붉은 선은 두 화면 모두 최근 행성 1.5공전 동안의 이동입니다. ×20은 안팎 폭만 넓힙니다.
① 행성 고정 · Rotating frame
평균 궤도의 안팎 차이 ×20
② 방향 고정 · Heliocentric frame
평균 궤도의 안팎 차이 ×20
붉은 점·선: 작은 천체와 최근 1.5공전의 궤적. 남색: 행성. 확대는 장반경 차이에만 적용하며 각도·시간은 바꾸지 않습니다.
③ 상대각의 평균화 유효함수 U(φ)
모형의 보존량 E가 허용하는 상대각 범위
낮은 이심률·같은 평면·작은 질량에서 적용되는 1:1 공명의 평균화 모델입니다. 평균 상대 경도와 장반경 차이로 구성한 모식도이며, 실제 천체의 위치를 재현하는 천체력은 아닙니다. 표시하는 장반경 차이는 공통 설정을 따릅니다. 두 화면에 같은 확대율을 적용하며 기본은 ×20입니다. 태양의 질량중심 주위 작은 운동은 생략했습니다. 두 화면에서 같은 모식도의 좌표계 변환을 비교할 수 있습니다.질량비 μ = 3 × 10⁻⁶ (지구 정도의 예)
이 위젯의 식과 적용 범위
φ는 행성을 기준으로 측정한 상대 경도이며, μ는 행성 질량을 태양과 행성의 전체 질량으로 나눈 값입니다. 작은 천체의 질량은 무시합니다. 무차원 시간 τ = n√(3μ)t, v = dφ/dτ로 두고 U(φ) = −cos φ + 1 / √(2 − 2 cos φ), E = v² / 2 + U(φ), Δa / aₚ ≈ −(2/3)√(3μ)v를 사용합니다. 각도가 반전되는 지점을 수치적으로 구하고, 시간이 흐르는 속도도 적분했습니다. E = 1.50에서는 주기가 무한대가 되므로 닫힌 주기 운동으로 재생하지 않습니다. 0°의 발산은 평균화 모델의 성질이며 실제 근접 조우를 계산하는 식은 아닙니다. 힐다족의 3:2 공명, 높은 이심률·경사각, 근접 조우, 준위성 궤도는 다루지 않습니다.
태양 중심 화면은 같은 해를 θ행성 = nt = τ / √(3μ), θ천체 = θ행성 + φ로 변환합니다. 표시 반지름은 r / aₚ = 1 + k(Δa / aₚ)이며 k는 1 또는 20입니다. 실제 순간 반지름 대신 평균 장반경을 사용합니다. 경과 시간 τ는 상대 진동이 한 바퀴 돌아도 계속 누적하며, 작은 천체의 최근 궤적도 같은 시간 해에서 계산합니다. 태양의 작은 운동과 빠른 궤도 진동을 생략한 근사이며, 행성과 작은 천체의 속도를 별도로 임의 설정한 애니메이션은 아닙니다.
위젯은 다음 순서로 읽으면 됩니다.
- 올챙이, E = 1.05: 경로가 L₄ 한쪽에만 있습니다. 허용 각도는 약 30.3°–117.8°입니다.
- 경계에 접근: 180° 부근의 상대 운동이 점점 느려집니다. 경계에서는 그 불안정한 평형에 접근하는 데 무한한 시간이 걸리는 이상화된 운동이 됩니다.
- 말굽, E = 2.00: 180°를 지나 L₅ 쪽까지 갑니다. 그러나 0°·360° 가까이에서는 다시 되돌아옵니다.
- 시간 이동: 같은 φ에도 안쪽으로 앞서가는 경우와 바깥쪽으로 뒤처지는 경우가 있습니다. 현재 위치 하나만 보지 말고 장반경 차이와 진행 방향을 함께 보십시오.
그래프의 두 골짜기는 무엇을 뜻할까?

그림 7. 실제 우주의 중력 지형이 아니라, 빠른 공전을 평균낸 상대각 운동을 정리한 1차원 유효함수입니다. E의 숫자는 이 모형의 무차원 척도입니다.
그래프를 읽을 때는 ‘공이 움직일 수 있는 높이’를 비유로 쓰면 편리합니다. 수평선이 E이고, 곡선이 상대각별로 필요한 유효함수 값 U입니다. U가 E보다 높은 구간에는 그 운동이 들어갈 수 없습니다. 둘의 차이가 0이 되는 곳에서 상대각의 변화가 멈춥니다.
60°와 300°에는 각각 낮은 영역이 있습니다. 그 사이 180°의 경계 높이보다 E가 낮으면 한쪽 영역 안에서만 왕복합니다. 이것이 올챙이입니다. E가 그 높이보다 높으면 두 영역 사이를 지날 수 있습니다. 하지만 행성이 있는 0°·360° 가까운 부분은 여전히 허용되지 않으므로 그 앞뒤에서 되돌아옵니다. 이것이 말굽입니다.
이 비유를 실제 2차원 회전계의 중력·원심 퍼텐셜과 같다고 생각하지는 마십시오. 여기서의 U는 느린 공명각 하나의 운동을 설명하기 위해 만든 평균화된 함수입니다. 4절에서 설명한 L₄·L₅의 코리올리 안정성과 서로 다른 층위의 설명입니다.
또한 슬라이더를 움직여 E를 바꾸는 것은 서로 다른 초기조건의 해를 비교하는 것입니다. 고립된 모형에서 천체가 저절로 에너지를 얻어 올챙이에서 말굽으로 바뀌는 장면은 아닙니다. 실제 전환에는 다른 천체의 섭동 등 운동을 바꾸는 과정이 필요합니다.
위젯의 식과 근사 범위 보기
행성의 평균 공전 각속도를 n, 별과 행성을 합친 질량 중 행성의 비율을 μ라고 두고, 시간을 τ = n√(3μ)t로 바꾸었습니다. 이 글에서는 설명용으로 μ = 3 × 10⁻⁶을 사용합니다. 지구와 태양 정도의 작은 질량비를 택한 것이며, 목성의 실제 질량비나 특정 소행성의 천체력을 재현한 값이 아닙니다.
거의 원형인 공평면 궤도의 평균화 방정식과 장반경 변화는 Leleu, Robutel & Correia의 식 (3), (5)에 근거합니다. 여기서 도출한 무차원 유효함수는 다음과 같습니다. φ는 라디안이며 프라임은 τ에 대한 미분입니다.
$$ U(\phi)=-\cos\phi+\frac{1}{\sqrt{2-2\cos\phi}}, \qquad \phi''=-\frac{dU}{d\phi}. $$$$ E=\frac12(\phi')^2+U(\phi), \qquad \frac{a-a_P}{a_P}\simeq-\frac23\sqrt{3\mu}\,\phi'. $$이 식으로 계산하면 U(60°) = U(300°) = 0.5, U(180°) = 1.5입니다. 0.5 < E < 1.5에서는 한쪽 영역에 머무는 올챙이, E > 1.5에서는 두 영역을 연결하는 말굽이 됩니다. E는 실제 에너지를 줄 단위로 나타낸 값이 아니라 이 모형에서 정의한 보존량입니다.
반지름 방향은 r/aₚ = 1 + 20(a − aₚ)/aₚ로 표시했습니다. 따라서 화면의 반지름은 실제 순간 거리 대신 평균 궤도의 안팎 차이를 확대해 보여 주는 표시용 좌표입니다. 평균화 과정에서 제거한 빠른 타원운동과 입체적인 흔들림은 그리지 않았습니다. 행성의 매우 가까운 접근, 큰 이심률·경사, 다른 행성의 섭동은 이 단순 모형의 범위 밖입니다.
행성이 움직이는 화면에서는 같은 시간을 사용해 행성의 각도를 θₚ = τ/√(3μ), 소행성의 각도를 θₐ = θₚ + φ로 계산합니다. 기본 반지름은 행성의 경우 1, 소행성의 경우 1 + (a − aₚ)/aₚ입니다. 확대 옵션은 안팎 차이에만 20을 곱하며, 시간과 각도에는 영향을 주지 않습니다. 재생 중 진동 주기가 끝나도 행성의 누적 공전 각도는 초기화하지 않습니다.
이 화면은 평균경도와 장반경으로 그린 안내 중심 운동입니다. 태양의 작은 질량중심 운동과 빠른 타원운동은 생략하므로 엄밀한 관성계의 전체 삼체 적분 또는 실제 천체력과는 다릅니다. 고정 화면과 공전 화면의 차이는 같은 운동을 관찰하는 기준의 차이이며, 두 화면에 서로 다른 물리적 운동을 부여한 것은 아닙니다.
E = 1.5에서는 두 유형을 가르는 분리곡선(separatrix)이 됩니다. 정확히 L₃에 놓이고 상대 속도가 0인 불안정한 평형을 제외하면, 그쪽으로 접근하는 가지는 유한한 주기로 반복되지 않습니다. 위젯은 이 경계를 정상적인 반복 궤도로 재생하지 않습니다. L₄·L₅의 정확한 평형 E = 0.5도 움직이는 올챙이가 아니라 정지한 상대 위치입니다.
8. 힐다족은 다른 리듬이다: 1:1이 아니라 3:2
힐다군(Hilda group)은 목성 트로이 천체와 같은 1:1 공궤도 집단이 아닙니다. 목성이 태양을 두 번 도는 동안 힐다 천체는 세 번 돕니다. 따라서 공전 횟수 또는 평균 각속도 비는 3:2, 공전 주기의 비는 2:3입니다. 비율을 쓸 때 무엇을 비교하는지 밝혀야 두 표현이 서로 모순처럼 보이지 않습니다.
케플러 법칙만 이용하면 힐다 천체의 대표 장반경은 목성의 약 0.763배가 됩니다. 목성의 장반경을 약 5.2 AU로 두면 약 4.0 AU입니다. 이 값은 궤도의 크기이며 원일점 거리와는 다릅니다. 힐다 천체는 타원궤도이므로 원일점에서는 이보다 더 바깥쪽으로 나갈 수 있습니다.

그림 8. 공전 주기비 2:3과 고정된 공명 위상을 택한 케플러 궤도 기하입니다. 힐다 천체의 세 공전과 목성의 두 공전을 따라 그렸습니다. 전체 삼체 운동을 적분한 실제 힐다 천체의 예측 궤도는 아닙니다.
삼각형은 어떻게 만들어질까?
힐다 천체가 타원의 원일점(aphelion), 곧 태양에서 가장 먼 지점에 도착했다고 생각해 봅시다. 다음 원일점에 도착할 때까지 힐다 천체는 한 바퀴를 돕니다. 그동안 목성은 240° 움직입니다. 타원의 방향이 고정된 단순 모형에서는 원일점이 우주 공간에서 같은 방향에 있으므로, 목성에 맞춰 회전한 화면에서는 다음 원일점이 120° 옮겨진 자리에 보입니다. 세 번째에는 다시 120° 이동하고, 네 번째에는 처음 자리로 돌아옵니다.
그래서 회전계에는 세 군데의 원일점 자리가 생깁니다. 안정적인 대표 공명 위상에서는 그 외곽 자리가 목성으로부터 대략 60°, 180°, 300° 떨어집니다. 이 세 점과 그 사이의 길을 보면 삼각형 같은 배열이 나타납니다. 원일점 부근에서는 천체의 움직임도 느려지므로 여러 천체의 분포에 그 배열이 드러납니다.
삼각형은 단단한 선로가 아니며, 힐다 천체가 관성계에서 직선 세 개를 따라 돈다는 뜻도 아닙니다. 각 천체는 태양 주위의 궤도를 돌고, 집단 전체는 서로 다른 이심률과 공명 진동을 가집니다. 실제 분포는 두께가 있고 시간에 따라 변합니다.
같은 주기비만 맞추면 안전해질까?
그렇지는 않습니다. 시계를 3:2 속도로 돌리는 것만으로는 목성과 가까워지는 시점이 안전한 방향에 놓인다는 보장이 없습니다. 공명의 위상도 묶여 있어야 합니다. 힐다 공명에서는 목성과 소행성의 평균경도, 소행성의 근일점 방향을 조합한 공명각이 일정한 범위에서 진동합니다. 이 때문에 원일점 접근이 목성 바로 옆에 반복되도록 흘러가지 않습니다.
앞뒤 60°에 놓이는 힐다 천체가 있다고 그 천체가 L₄·L₅ 트로이 천체인 것은 아닙니다. 그림의 위치가 겹쳐 보여도 궤도 크기와 공명 비율이 다릅니다.
또한 일상적으로 ‘힐다족’이라고 부르는 전체 집단은 여기서는 힐다군(Hilda group) 을 뜻합니다. 충돌로 한 모천체에서 갈라진 조각들을 가리키는 엄밀한 소행성 족(family) 과는 구별합니다. 힐다군 안에 Hilda 족과 Schubart 족 같은 충돌 집단이 따로 있습니다. Brož & Vokrouhlický의 공명 집단·충돌 족 연구
힐다의 세 원일점을 공명각으로 확인하기
목성의 평균경도를 λⱼ, 힐다 천체의 평균경도를 λ, 근일점 경도를 ϖ라고 하면 대표적인 3:2 공명각은 σ = 3λⱼ − 2λ − ϖ입니다. 힐다군의 대표 안정 운동에서는 이 각이 0° 주위를 진동합니다.
평균경도는 λ = M + ϖ이며 M은 평균근점이각입니다. 원일점에서는 M = 180°입니다. 공명각 중심 σ = 0°를 이상화해 대입하면 상대각 λ − λⱼ는 60°, 180°, 300° 중 하나가 됩니다. 실제로 σ가 폭을 가지고 진동하면 원일점 자리도 이 각도 주위에 퍼집니다.
이것은 공전 횟수비 3:2가 세 원일점을 만드는 기하에 더하여, 그 세 자리가 목성을 피하는 방향에 놓이도록 공명 위상이 연결되어 있다는 설명입니다.
출처와 그림·위젯 안내
- NASA — How Were the Trojan Asteroids Discovered and Named?: 그리스·트로이 진영의 명칭과 초기 명명 예외.
- NASA — What are Lagrange Points?: 라그랑주점의 배치와 회전계에서의 안정성.
- Leleu, Robutel & Correia (2015) — Detectability of quasi-circular co-orbital planets: 저이심률 공평면 공궤도 평균화 방정식, 장반경 변화, 분리곡선.
- Christou & Asher (2011) — A long-lived horseshoe companion to the Earth: 2010 SO₁₆의 지구 말굽 공궤도 운동.
- Ćuk, Hamilton & Holman (2012) — Long-Term Stability of Horseshoe Orbits: 말굽 운동의 질량비와 장기 안정성.
- Brož & Vokrouhlický (2008) — Asteroid families in the first order resonances with Jupiter: 힐다군의 3:2 공명과 내부의 충돌 족. 논문은 2008년 출판되었고 arXiv 등록은 2011년입니다.
그림은 위의 운동 조건을 바탕으로 직접 제작했습니다. 그림 1·3은 개념도, 그림 2·5·6·7과 위젯은 평균화 모형, 그림 4는 원형 제한 삼체 모형의 평형점, 그림 8은 공명 위상을 맞춘 케플러 궤도 기하입니다. 실제 천체의 관측 위치나 전 삼체 적분 결과와 구별해 읽어야 합니다.
9. 마무리: 모양은 관찰 기준과 중력의 되먹임이 함께 만든다
지금까지의 설명에서 모양을 결정한 것은 이름이 아니라 운동 조건입니다.
| 운동 조건 | 회전계에서 나타나는 경로 | 그 모양이 생기는 이유 |
|---|---|---|
| 1:1 공명, L₄ 또는 L₅ 한쪽 안의 진동 | 올챙이 | 안쪽의 앞서감과 바깥쪽의 뒤처짐이 한 진영 안에서 연결됨 |
| 1:1 공명, 두 진영을 연결하지만 행성 접근 부근에서 방향 전환 | 말굽 | 넓은 각도 범위를 왕복하며 행성 자리 근처에 틈을 남김 |
| 목성과 3:2 공명, 원일점의 위상 보호 | 힐다의 삼각형 같은 배열 | 원일점이 목성 회전계에서 세 자리를 번갈아 차지함 |
따라서 올챙이 조건에 있는 천체가 한쪽에서 왕복하면서 안팎 차이를 가진다면, 그 상대 경로는 올챙이 유형으로 닫힙니다. 말굽 조건에서 넓게 왕복하되 행성 자리를 통과하지 않는다면, 행성 쪽에 틈이 남은 원환의 두 가지가 연결되는 말굽 유형이 됩니다. 모든 공궤도 천체가 반드시 둘 중 하나여야 한다는 뜻은 아닙니다.
목성의 트로이 진영으로 시작했지만 위젯의 질량비는 지구–태양 정도를 택했습니다. 목성 주위에도 같은 말굽이 장기간 안정하다는 결론으로 옮기면 안 됩니다. 말굽의 안정성은 행성 질량과 접근 거리의 영향을 강하게 받습니다. 말굽의 장기 안정성 연구
이심률(eccentricity)이 있는 공궤도 운동에는 준위성(quasi-satellite)처럼 다른 유형도 있고, 섭동을 받으며 유형이 바뀌거나 공명에서 벗어날 수도 있습니다. 1:1이라는 평균 비율만으로 모든 세부 운동과 영구적인 안정성을 보장하지는 않습니다.
다음에 태양계 영상에서 그리스 진영, 트로이 진영, 힐다족을 보게 되면 점들이 어디에 모여 있는지에 더해 어느 기준으로 카메라가 돌고 있는지, 안쪽과 바깥쪽에서 공전 주기가 어떻게 달라지는지, 접근할 때 중력이 어느 궤도로 옮겨 놓는지를 함께 보십시오. 올챙이의 왕복, 말굽 양 끝의 방향 전환, 힐다의 세 원일점이 서로 다른 공명의 이야기로 읽힐 것입니다.