マイコン宇宙講座-惑星探査機の軌道追跡

最近、小惑星リュウグウにサンプル・リターンして、持ち帰ったサンプルからアミノ酸を始めとする25種類のサンプルが発見されたことは有名なニュースです。その前は、小惑星イトカワにサンプル・リターンに挑戦し、満身創痍になりながらも地球へ帰還し、サンプルを持ち帰りました。映画になるほど有名になりましたね。

探査機の打ち上げは月に始まります。ソ連と米国の宇宙開発競争ですね。月に人類を到達させたのは米国でアポロ11号です。アポロ計画は1972年アポロ17号を最後に、それ以降は月へ人類を送っていません。さて、月以外はどうでしょう。金星、火星、木星、土星、天王星、海王星とさまざまな惑星へ探査機を送っています。このうち、地表へ到達できるのは金星と火星のみで、それ以外は軌道上からの撮影です。それでも、鮮明な写真により地球からわからないことがたくさん発見されました。

サブルーチン ecliptic_coordinates_xyz

※サブルーチンはlib.pyに記述してください。

# KOUDO ZAHYO from XYZ
def ecliptic_coordinates_xyz(x, p, K):
    xe = x[1][p]
    ye = x[2][p] * K[4] + x[3][p] * K[5]
    ze = -x[2][p] * K[5] + x[3][p] * K[4]

    ss = ye
    cc = xe
    tt = quadrant(ss, cc)
    lp = tt
    cc = ye / math.sin(lp)
    ss = ze
    bp = math.atan(ss / cc)
    r0 = math.sqrt(xe * xe + ye * ye + ze * ze)

    return lp, bp, r0

サブルーチン print_elements_display

※サブルーチンはlib.pyに記述してください。

def print_elements_display(td, pe, ec, nd, ic, no, q, K, T):
    jd = td
    yy, mm, dd = jdate(jd, T)
    a = q / (1.0 - ec)
    pd = pow(a, 1.5)
    print('     T    =  %4d  %2d  %6.3f ET' % (yy, mm, dd))
    print('     Peri.= %7.3f               e = %9.5f' % (pe * K[3], ec))
    print('     Node = %7.3f (1950)        a = %9.5f' % (nd * K[3], a))
    print('     Inc. = %7.3f               n =  %9.6f' % (ic * K[3], no * K[3]))
    print('        q =  %8.5f (AU)        P =   %4.2f 年' % (q, pd))

    return a

メインルーチン m49.py

このプログラムでは、探査機の軌道が楕円軌道を描いたときのみとされています(「マイコン宇宙講座」115頁)。ですので、計算できない探査機もあります。

# m49.py
# マイコン宇宙講座
# 4-9 惑星探査機の軌道追跡プログラム
from PIL import Image, ImageDraw, ImageFont
from tkinter.constants import SOLID
import tkinter as tk
import math
import lib


def drawing_frame(jd, from_planet, to_planet, frame_color, sun_color, fonts, draw):
    draw.rectangle((1, 1, 640, 400), outline=frame_color, width=1)

    draw.line((96, 1, 96, 400), fill=frame_color, width=1)
    draw.line((536, 1, 536, 400), fill=frame_color, width=1)
    draw.line((536, 96, 640, 96), fill=frame_color, width=1)
    draw.line((536, 224, 640, 224), fill=frame_color, width=1)
    draw.line((536, 304, 640, 304), fill=frame_color, width=1)

    draw.ellipse((316, 196, 324, 204), fill=sun_color)
    for ln in range(326, 520, 5):
        draw.line((ln, 200, ln + 2, 200))
    draw.line((520, 200, 515, 195))
    draw.line((520, 200, 515, 205))

    yy, mm, dd = lib.jdate(jd, lib.T)

    draw.text((544, 16), ' 打ち上げ日', font=fonts)
    draw.text((544, 48), '  %4d 年' % (yy), font=fonts)
    draw.text((544, 64), ' %02d 月 %02d日' % (mm, dd), font=fonts)
    draw.text((544, 128), 'From', font=fonts)
    draw.text((544, 144), '   ' + from_planet, font=fonts)
    draw.text((544, 176), 'To', font=fonts)
    draw.text((544, 192), '   ' + to_planet, font=fonts)
    draw.text((542, 240), '探査機の速度', font=fonts)
    draw.text((540, 272), ' %4.1f Km/Sec' % (vo1), font=fonts)
    draw.text((544, 320), '  飛行速度', font=fonts)
    draw.text((4, 16), '   到着日', font=fonts)


# メイン
x = [[0 for i in range(10)] for j in range(4)]
f = [0, 0, 0, 0]
q = [0, 0, 0, 0]
ww = [0, 0, 0]
jd = [0, 0, 0]
pln = [0, 0, 0]
lp = [0, 0, 0]
bp = [0, 0, 0]
r = [0, 0, 0]
r0 = [0, 40, 40, 40, 25, 8, 4]

print('\n')
pln[1] = input('打ち上げ惑星の番号 ? ')
pln[1] = int(pln[1])
std = input('打ち上げ日と時刻 ? ')
dy, dt = std.split(',')
dy = float(dy)
dt = float(dt)
jde, yy, mm, dd, hh, ms, ss = lib.mjd(dy, dt)
jd[1] = jde

pln[2] = input('目的惑星の番号 ? ')
pln[2] = int(pln[2])
std = input('到着日と時刻 ? ')
dy, dt = std.split(',')
dy = float(dy)
dt = float(dt)
jde, yy, mm, dd, hh, ms, ss = lib.mjd(dy, dt)
jd[2] = jde

print('\n')

# 打ち上げ惑星
t1 = jd[1] - 33281.92334
t1 = t1 * (2.737909288e-5 + 1.260132857e-17 * t1)
t2 = t1 * t1

e, m, p, n, i, a, rd = lib.mean_elements(pln[1], t1, t2)

pe = p
nd = n
ic = i
ax1 = a

f, q = lib.eph_const(pe, nd, ic, lib.K)

ec = e
mo = m / (2.0 * math.pi)
mo = 2.0 * math.pi * (mo - int(mo))

ss, cc, ff = lib.kepler(mo, ec)

b = a * math.sqrt(1.0 - e * e)
for n in range(1, 4):
    f[n] = a * f[n]
    q[n] = b * q[n]

for n in range(1, 4):
    x[n][pln[1]] = ff * f[n] + ss * q[n]

lp[1], bp[1], r[1] = lib.ecliptic_coordinates_xyz(x, pln[1], lib.K)

# 目的惑星
t1 = jd[2] - 33281.92334
t1 = t1 * (2.737909288e-5 + 1.260132857e-17 * t1)
t2 = t1 * t1

e, m, p, n, i, a, rd = lib.mean_elements(pln[2], t1, t2)

pe = p
nd = n
ic = i
ax2 = a

f, q = lib.eph_const(pe, nd, ic, lib.K)

ec = e
mo = m / (2.0 * math.pi)
mo = 2.0 * math.pi * (mo - int(mo))

ss, cc, ff = lib.kepler(mo, ec)

b = a * math.sqrt(1.0 - e * e)
for n in range(1, 4):
    f[n] = a * f[n]
    q[n] = b * q[n]

for n in range(1, 4):
    x[n][pln[2]] = ff * f[n] + ss * q[n]

lp[2], bp[2], r[2] = lib.ecliptic_coordinates_xyz(x, pln[2], lib.K)

if lp[2] < lp[1]:
    lp[2] = lp[2] + 2.0 * math.pi

cc = math.cos(bp[2]) * math.sin(lp[2] - lp[1])
ss = math.cos(bp[1]) * math.sin(bp[2]) - math.sin(bp[1]) * math.cos(bp[2]) * math.cos(lp[2] - lp[1])
ic = math.atan(ss / cc)
ss = ss / math.sin(ic)
cc = math.sin(bp[1]) * math.sin(bp[2]) + math.cos(bp[1]) * math.cos(bp[2]) * math.cos(lp[2] - lp[1])

tt = lib.quadrant(ss, cc)

u2 = tt
if ic < 0:
    nd = lp[1] - math.pi
    if nd < 0:
        nd = nd + 2.0 * math.pi
if ic > 0:
    nd = lp[1]

bb = 0.1
i = 1
ps = 0.1
ps1 = ps

# goto 555
while True:
    ps = ps
    q1 = ps / r[1] - 1.0
    q2 = ps / r[2] - 1.0
    cc = q1
    ss = (q1 * math.cos(u2) - q2) / math.sin(u2)

    tt = lib.quadrant(ss, cc)

    v1 = tt
    v2 = v1 + u2
    ec = math.sqrt(ss * ss + cc * cc)

    if ec > 0.99:
        ps = ps + 0.05
        ps1 = ps
        continue
    a = ps / (1.0 - ec * ec)
    no = lib.K[1] / pow(a, 1.5)
    e1 = 2.0 * math.atan(math.sqrt((1.0 - ec) / (1.0 + ec)) * math.tan(v1 / 2.0))
    e2 = 2.0 * math.atan(math.sqrt((1.0 - ec) / (1.0 + ec)) * math.tan(v2 / 2.0))
    m1 = e1 - ec * math.sin(e1)
    m2 = e2 - ec * math.sin(e2)

    if m1 > m2:
        m2 = m2 + 2.0 * math.pi
    tc = (m2 - m1) / no
    ww[i] = tc - (jd[2] - jd[1])
    print('  PS=%8.5f  BB=%9.5f  WW=%10.2f  e=%7.4f' % (ps, bb, ww[i], ec))

    if abs(ww[i]) < 0.5:
        break

    if i != 2:
        i = 2
        ps1 = ps
        ps = ps + bb
        continue

    if ww[1] * ww[2] >= 0:
        i = 2
        ps1 = ps
        ps = ps + bb
        ww[1] = ww[2]
        continue
    print('-----------------------------------------------------')
    ps = ps1
    i = 1
    bb = bb / 10.0
    print('NEW PS=%9.5f\n' % (ps))

# 近似パス 軌道要素の計算
pe = -v1
if ic < 0:
    pe = math.pi - v1

if pe < 0:
    pe = pe + 2.0 * math.pi
if pe > 2.0 * math.pi:
    pe = pe - 2.0 * math.pi

ic = abs(ic)
q = a * (1 - ec)
td = jd[1] - m1 / no

print('\n\n     惑星探査機の軌道\n')
print('     from ' + lib.PL[pln[1]] + ' to ' + lib.PL[pln[2]] + '\n')
a = lib.print_elements_display(td, pe, ec, nd, ic, no, q, lib.K, lib.T)

vo1 = 29.785 * math.sqrt(2.0 / r[1] - 1 / a)
vo2 = 29.785 * math.sqrt(2.0 / r[1] - 1 / ax1)
print('\n          打ち上げ速度 = %8.3f Km/Sec' % (vo1 - vo2))
print('          探査機の速度 = %8.3f Km/Sec' % (vo1))
print('          地球の速度  = %8.3f Km/Sec' % (vo2))
print('\n')

# std = input('PRESS ANY KEY ')

root = tk.Tk()
root.resizable(False, False)
root.geometry('644x440')
root.title('マイコン宇宙講座 - 惑星探査機の軌道追跡プログラム')

img = Image.new('RGB', (642, 402), (0, 0, 0))
draw = ImageDraw.Draw(img)

canvas = tk.Canvas(root, width=642, height=402, bg='black')
canvas.pack(anchor=tk.NW)

# フォント名は実行環境に合わせて変更すること
fonts = ImageFont.truetype('ipag.ttf', 15)

# カラーパレット
frame_color = (255, 255, 255)
sun_color = (255, 0, 0)
orbit_color = (0, 20, 175)

# フレーム描画
from_planet = lib.PL[pln[1]]
to_planet = lib.PL[pln[2]]
drawing_frame(jd[1], from_planet, to_planet, frame_color, sun_color, fonts, draw)

ro = r0[pln[2]]
i1 = int(jd[2] - jd[1])
i2 = i1 / 15
iv = int(i2)
jde = jd[1]

while True:
    t1 = jde - 33281.92334
    t1 = t1 * (2.737909288e-5 + 1.260132857e-17 * t1)
    t2 = t1 * t1

    yy, mm, dd = lib.jdate(jde, lib.T)

    draw.rectangle((4, 16, 94, 96), fill=(0, 0, 0))
    draw.text((4, 16), '   到着日', font=fonts)
    draw.text((8, 48), '  %4d 年' % (yy), font=fonts)
    draw.text((8, 64), '%02d 月 %02d 日' % (mm, dd + 0.375), font=fonts)

    for cnt in range(1, 3):
        pn = pln[cnt]

        e, m, p, n, i, ap, rd = lib.mean_elements(pn, t1, t2)

        mo = m / (2.0 * math.pi)
        mo = 2.0 * math.pi * (mo - int(mo))

        ss, cc, ff = lib.kepler(mo, e)

        b = ap * math.sqrt(1.0 - e * e)
        ss = b * ss
        cc = ap * ff

        tt = lib.quadrant(ss, cc)

        v = tt
        pp = n + p
        vv = v + pp
        rr = ro * math.sqrt(ss * ss + cc * cc)

        x = rr * math.cos(vv)
        y = rr * math.sin(vv)
        y = -y
        x = int(x + 80)
        y = int(y + 50)
        if int(jde) != int(jd[1]):
            x = x * 4
            y = y * 4
            draw.rectangle((x - 1, y - 1, x + 1, y + 1), fill=(255, 255, 255))
            # continue
        if pln[2] <= 3:
            if x >= 80:
                x = (x + 6) * 4
                y = (y + 6) * 4
                draw.text((x, y), lib.PL[pln[cnt]], font=fonts)
            elif x < 80:
                x = (x - 6) * 4
                y = (y - 6) * 4
                draw.text((x, y), lib.PL[pln[cnt]], font=fonts)
        if pln[cnt] != 3:
            if x < 80:
                if y > 50:
                    x = (x - 7) * 4
                    y = (y - 10) * 4
                    draw.text((x, y), lib.PL[pln[cnt]], font=fonts)
                else:
                    x = (x + 8) * 4
                    y = y * 4
                    draw.text((x, y), lib.PL[pln[cnt]], font=fonts)
            else:
                if y > 50:
                    x = (x - 18) * 4
                    y = y * 4
                    draw.text((x, y), lib.PL[pln[cnt]], font=fonts)
                else:
                    x = x * 4
                    y = (y + 10) * 4
                    draw.text((x, y), lib.PL[pln[cnt]], font=fonts)
        elif x < 80:
            x = (x - 18) * 4
            y = y * 4
            draw.text((x, y), lib.PL[pln[cnt]], font=fonts)
        else:
            x = (x + 8) * 4
            y = y * 4
            draw.text((x, y), lib.PL[pln[cnt]], font=fonts)

        draw.rectangle((x - 1, y - 1, x + 1, y + 1), fill=(255, 255, 255))

    # 探査機のプロット
    mo = no * (jde - td)

    ss, cc, ff = lib.kepler(mo, ec)

    b = a * math.sqrt(1.0 - ec * ec)
    ss = b * ss
    cc = a * ff

    tt = lib.quadrant(ss, cc)

    v = tt
    rs = math.sqrt(ss * ss + cc * cc)
    pp = nd + pe
    vv = v + pp
    rr = ro * rs

    x = rr * math.cos(vv)
    y = rr * math.sin(vv)
    y = -y

    x = int(x + 80) * 4
    y = int(y + 50) * 4
    draw.rectangle((x - 1, y - 1, x + 1, y + 1))

    vo1 = 29.785 * math.sqrt(2.0 / rs - 1 / a)

    draw.rectangle((540, 352, 638, 370), fill=(0, 0, 0))
    draw.text((540, 352), ' %4.1f Km/Sec' % (vo1), font=fonts)
    if abs(jde - jd[2]) <= iv:
        draw.rectangle((30, 104, 64, 360), outline=frame_color, width=1)
        draw.text((40, 112), '惑', font=fonts)
        draw.text((40, 144), '星', font=fonts)
        draw.text((40, 176), '探', font=fonts)
        draw.text((40, 208), '査', font=fonts)
        draw.text((40, 240), '機', font=fonts)
        draw.text((40, 272), 'の', font=fonts)
        draw.text((40, 304), '軌', font=fonts)
        draw.text((40, 336), '道', font=fonts)
    if jde < jd[2] + iv:
        jde = jde + iv
        continue
    else:
        break
draw.text((4, 368), '    END', font=fonts)

# 描画した星座の画像を保存
img.save('./images/course.png')

# プロット結果の表示
photo = tk.PhotoImage(file='./images/course.png')
canvas.create_image(1, 1, image=photo, anchor=tk.NW)

button = tk.Button(root, text='閉じる', width=6, relief=SOLID, cursor='hand1', command=root.destroy)
button.place(x=558, y=407)

root.mainloop()

例題 マリーナ4号は、1964年11月28日に1965年7月14日から15日に火星へ接近しました。打ち上げから火星までの軌道を描いてみよう。なお、時刻は9時とします。

打ち上げ惑星の番号 ? 3
打ち上げ日と時刻 ? 19641128,090000
目的惑星の番号 ? 4
到着日と時刻 ? 19650715,090000


  PS= 1.05000  BB=  0.10000  WW=   2401.94  e= 0.8526
  PS= 1.15000  BB=  0.10000  WW=    133.10  e= 0.3703
  PS= 1.25000  BB=  0.10000  WW=    -44.90  e= 0.3266
-----------------------------------------------------
NEW PS=  1.15000

  PS= 1.15000  BB=  0.01000  WW=    133.10  e= 0.3703
  PS= 1.16000  BB=  0.01000  WW=    101.55  e= 0.3300
  PS= 1.17000  BB=  0.01000  WW=     74.91  e= 0.2938
  PS= 1.18000  BB=  0.01000  WW=     52.15  e= 0.2632
  PS= 1.19000  BB=  0.01000  WW=     32.51  e= 0.2405
  PS= 1.20000  BB=  0.01000  WW=     15.40  e= 0.2280
  PS= 1.21000  BB=  0.01000  WW=      0.37  e= 0.2275


     惑星探査機の軌道

     from EARTH to MARS

     T    =  1964  11  23.539 ET
     Peri.= 355.025               e =   0.22746
     Node =  65.593 (1950)        a =   1.27602
     Inc. =   0.158               n =   0.683783
        q =   0.98578 (AU)        P =   1.44 年

          打ち上げ速度 =    3.026 Km/Sec
          探査機の速度 =   33.217 Km/Sec
          地球の速度  =   30.191 Km/Sec
マリーナ4号火星への軌道
マリーナ4号火星への軌道