先日、「パソコンで見る天体の動き」という本を買いました。名前の通り、天体の軌道をパソコンで表示するための数式やサンプルコードなどが載っています。

内容はとても素晴らしいのですが、サンプルコードがBASICやFortranで書かれていたので、理解を深めるためにいくつかの解法をPythonで書き直してみました。

数値解法の詳しい説明を知りたい方は、是非「パソコンで見る天体の動き」をご覧ください。とても面白いですよ。

 

以下の微分方程式をオイラー法とルンゲ・クッタ法、フェールベルグ法を使って解いてみます。

オイラー法(Euler method)で求める

# f(t,x) = x**2 - t**2 - 2*t + 2
# t = 0 のとき、x = 0 であるものとする。

# 初期値
t = 0
x = 0
# 刻み幅
h = 0.125

f = lambda t, x : x**2 - t**2 2*t + 2

for i in range(10):
    
    # 「刻み幅 × 関数の傾き」で増加量が求まる。
    x += h * f(t, x)
    t += h

    print("t:{0}, x:{1}".format(t, x))

 

ルンゲ・クッタ法(Runge-Kutta method)で求める

# f(t,x) = x**2 - t**2 - 2*t + 2
# t = 0 のとき、x = 0 であるものとする。

# 初期値
t = 0
x = 0
# 刻み幅
h = 0.125

f = lambda t, x: x**2 - t**2 - 2*t + 2

for i in range(10):
    f1 = f(t, x)
    f2 = f(t + h/2, x + h * f1/2)
    f3 = f(t + h/2, x + h * f2/2)
    f4 = f(t + h,   x + h * f3)

    x += (h/6)*(f1 + 2*f2 + 2*f3 + f4)
    t += h

    print("t:{0}, x:{1}".format(t, x))

 

フェールベルグ法(Fehlberg method)で求める

# f(t,x) = x**2 - t**2 - 2*t + 2
# t = 0 のとき、x = 0 であるものとする。

# 初期値
t = 0
x = 0
# 刻み幅
h = 0.125
# 誤差条件
alfa_e = 0.0625  # 誤差がこの値に収まるように刻み幅を自動で調整する。

f = lambda t, x: x**2 - t**2 - 2*t + 2

for i in range(10):
    f1 = f(t, x)
    t1 = t + h/4
    x1 = x + (h/4)*f1

    f2 = f(t1, x1)
    t2 = t + 3*h/8
    x2 = x + (h/32) * (3*f1 + 9*f2)

    f3 = f(t2, x2)
    t3 = t + 12*h/13
    x3 = x + (h/2197) * (1932*f1 - 7200*f2 + 7296*f3)

    f4 = f(t3, x3)
    t4 = t + h
    x4 = x + h*(439*f1/216 - 8*f2 + 3680*f3/513 - 845*f4/4104)

    f5 = f(t4, x4)
    t5 = t + h/2
    x5 = x + h*(-8*f1/27 + 2*f2 - 3544*f3/2565 + 1859*f4/4104 - 11*f5/40)

    f6 = f(t5, x5)

    # 以上より,1ステップ進んだ関数値が求まる.(5次の解)
    x += h*(16*f1/135 + 6656*f3/12825 + 28561*f4/56430 - 9*f5/50 + 2*f6/55)
    t += h

    # 誤差計算用に4次の精度を持つ解の近似値を求める.
    x_4 = x + h*(25*f1/216 + 1408*f3/2565 + 2197*f4/4104 - f5/5)

    # 誤差条件を満たさなくなったとき,新しい刻み幅を決める.
    k = 0.9  # 安全係数
    beta_e = abs(x_4 - x)
    if beta_e > alfa_e:
        h = k*h * (alfa_e / beta_e)**(1/4)
        print("調整")

    print("t:{0}, h:{1}, x:{2}".format(t, h, x))

どれもまあ良くできたもんだなと思いますが、刻み幅を勝手に調整してくれるフェールベルグ法なんて特に凄いですよね。初めて知ったときは感動しました。

精度比較


因みに、今回使った微分方程式では以下の式で真値が求まります。

以上3つの解法によって求めた数値と真値を比較すると、以下のようになります。

刻み幅:0.125 誤差条件:0.0625

色の割り当ては、

  • オイラー法:青
  • ルンゲ・クッタ法:赤
  • フェールベルグ法:黄
  • 真値:緑

としました。

オイラー法は t=0.75 付近から誤差が増え始め、t=1.50以降では爆発的に増大していることがわかります。

ルンゲ・クッタ法とフェールベルグ法に関しては、精度が高いので真値と重なって見えなくなっています。試しに少しずらして表示してみると以下のようになり、確かにプロットされていることが確認できます。

おわりに


フェールベルグ法は確かに精度が高くなりますが、刻み幅を調節すれば実用上はルンゲ・クッタ法で十分なように思います。

参考文献


  • 長沢工,桧山澄子:「パソコンで見る天体の動き」,株式会社 地人書館(1992年9月20日)