2つの天体が互いに万有引力で運動することを2体問題といいます。太陽系の惑星の運動など,いわゆるケプラーの法則に従う運動で,円ではなく楕円軌道を描くことが大きな発見だったわけです。この運動を再現する(天体の位置を計算で求める)方法は,現在ではコンピューターの数値計算で(中心力を万有引力として計算することが)可能[1]ですが,暦計算的には今でもケプラーの時代と同じ古典的な方法が用いられています。公転する天体の楕円軌道に外接する円への垂線と天体が交わる点$Q’$と,円の中心からの角度(離心近点角)$u$と,楕円の焦点と天体の真近点角$f$の関係式から位置を求めるものです。これは星座早見プログラムでも使っている,公転運動の平均近点離角$nt$から離心近点角$u$を求めるケプラー方程式によって解を求める方法です。
楕円の性質として重要なのが,離心率$e$です。楕円には中心$O$と,2つの焦点$F$($O$に対象)があります。離心率$e$は,この図で$\frac{OF}{OP}$の比で,0から1までの値をとり,楕円のつぶれ具合(0は真円で,1はつぶれた状態)を示します。楕円の大きさと形は,長半径$OP$の長さ($a$で表わす)と$e$で決まります。高校の数学では,ここまでですが,平面座標を使うより半径と角度で表わす極座標で楕円を表わすと,$r=\frac{l}{1 + e \cos \theta}$で表わされます。ここで$\theta$は$f$で,$l$は,図の$F$から$y$軸と楕円の交点までの長さで,半直弦と呼ばれます。ちょっと説明が大変になるのですが,これらの図形と角度との関係を調べていくと,さらに,運動する惑星と中心天体を結ぶ動径$r$は,$r=a(1-e\cos u)$で表わされ,$u$と$f$の関係式も求まります[2]。そして,離心近点角と呼ばれる$u$ですが,惑星の時間にともなう平均運動での位置,平均近点離角$nt$に対して,$nt=u-e\sin u$という関係式が成り立ちます。これをケプラー方程式と言い,この解としての$u$の値が分かれば,$r$,と$f$が求められ惑星(天体)の位置が計算できます。この方程式を解く計算は,はじめに$nt$の値を$u$の近似値として繰り込み計算を行うことで求まります。ケプラーの時代から行われていた方法で,今でこそパソコンであっという間にできますが,ケプラーは,このような方法を駆使して過去の惑星の位置を手計算で求め,聖書にあるベツレヘムの星を紀元前7年の木星と土星の会合現象だと指摘したことに驚かされます。それから,ニュートンの「プリンキピア」が微分や積分を使わず,幾何学的に運動を説明していると言うことが,とても複雑とはいえ,説得力があることだなと思いました。
参考にしました。[1]https://cattech-lab.com/science-tools/simulation-lecture-2-5/
[2]http://fnorio.com/0158Kepler_equation/Kepler_equation.html
[3]長沢工(1985):増補版 天体の位置計算,地人書館
'''ケプラーの楕円運動をアニメーションで示すプログラム
2021年3月5日作成'''
import math
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import animation
def Kepler_EQ(ec,ma): # ケプラー方程式の解を求める関数
ex = ma
ss = ma
while abs(ss) > 1.0e-8:
ss = ex - ec * math.sin(ex) - ma
de = ss / (1 - ec * math.cos(ex))
ex = ex - de
return ex
# 軌道要素
MU = math.radians(1.0) # 日日平均運動 地球の場合は0.9856076°
AX = 1.0 # 軌道長半径 地球は1天文単位
EC = 0.8 # 離心率
# AxesとFigureを設定
fig, ax = plt.subplots(figsize = (9.0, 6.0))
ax.set_xlim(-2.0, 1.0)
ax.set_ylim(-1.0, 1.0)
ax.set_xlabel("x", fontsize = 15)
ax.set_ylabel("y", fontsize = 15)
ax.axhline(y=0)
ax.axvline(x=0)
ax.set_title("AX=1.0 EC=0.8")
p = []
def dot_Ellips(frame):
MA = MU * frame # MA:平均近点角(平均運動の角度 = フレーム値で調整)
EX = Kepler_EQ(EC, MA) # 離心近点角EXをケプラー方程式で求める
T = math.sqrt((1 + EC) / (1 - EC)) * math.tan(EX / 2)
f = 2 * math.atan(T) # 真近点角f
r = (1 - EC * EC) / (1 + EC * math.cos(f)) # r:動径
X = r * math.cos(f) # 近点をx座標とした位置
Y = r * math.sin(f)
if len(p) > 0: # 前の表示を消す処理
item = p.pop(0)
ax.lines.remove(item) #
p.append(ax.plot(X, Y, "bo", c="blue")[0])
ani = animation.FuncAnimation(
fig, # Figureオブジェクト
dot_Ellips, # グラフ描画関数
frames = np.arange(0,360,10), # フレームを設定 360°を10°毎に表示
interval = 40, # 更新間隔(ms)
repeat = True, # 描画を繰り返す
)
ani.save("c04.gif", writer="imagemagick")
plt.show()