皆既月食で,皆既中の写真を2地点から撮影して,周りの星との位置のずれから視差を測定し,月までの距離を求めるための計算とpyhtonによるプログラム。

2地点の緯度・経度から,距離を求める式は,長谷川一郎著「天文計算入門」(恒星社)30pに出ている公式(式9-1,p26)を使いました。

  • 2地点の基線長とその方位角の計算
    地球の半径=6371kmとしました。
    地球の半径をr,地点Aの(経度x1, 緯度y1)、地点Bの(経度x2, 緯度y2)とすると  
    SDs = cos(y2)sin(x2 – x1)   SDc = cos(y1)sin(y2) – sin(y1)cos(y2)cos(x2 – x1)
    # 方位角(Azimuth)は     Az = tan-1(SDs/SDc)    (方位角は北:0°、東:90°、南:180°、西270°)
    CD = sin(y1)sin(y2) + cos(y1)cos(y2)cos(x2 – x1)
    # 検算  K = SDs2 + SDc2 + CD2  で K = 1  になります。
    # 2地点の弧の中心角 DDは  DD = cos-1(CD)
    # 基線長(弦の長さ)は  Dist = 2 r × sin(DD/2)

2地点からの視差が観測されたとしても普通,基線となる2地点の方向は,月の視線方向とは直交していませんので,月からみた2地点を投影した基線長にするか,視差を視線方向に直交する値に補正するかしなければなりません。ここでは後者の方法を考えました(下図参照)。2地点を直径とする球面上で考えます。月と2地点を通る大円上で地平線から月までの角(X)を,2地点の方位角と月の方位角のなす角(D)と月の地平高度(h)から,直角球面三角形の公式で求め,基線と直交する方向(90°)からの差の角度(Z)の(cosZ)で,観測された視差を割れば,補正した視差になると考えました。あるいはこの図では分かりずらいと思うのですが,月のから基線の長さをみると,AB間の距離が,cosZ倍に短くなると考えるのと同じ計算(逆数で割るので)になります。

  • 視線方向への視差の補正計算
    月の地平高度:h  月の方位角※: Am  基線の方位角:Az  とする。
    D = |Am – Az|   #絶対値
    X = cos(D) × cos(h)  (直角球面三角形の公式)
    Z = 90 – cos-1(X)
    # 補正視差Pxは 観測された視差Poに対して  Px = Po / cos(Z)
視差補正の説明図

2地点の緯度経度と月の高度方位角,観測された視差から,月までの距離を求めるプログラムを組んでみました。pythonをインストールしてお使い頂くか,実行ファイル(exe形式)も作りましたので,こちらからダウンロードもできます。

こちらのコードをドラッグしてコピーできます(行番号はコピーされません)。

'''
2地点の観測による視差から月までの距離を求めるプログラム(Python3)
'''

import sys
import tkinter as tk  # graphical user interface module
import math # 数学関数の標準モジュール

def baseline(lon_a, lat_a, lon_b, lat_b): # 基線長をもとめる関数
    ra = 6371.0  # earth radius (km)
    lat_a = math.radians(lat_a)  # to radian unit
    lon_a = math.radians(lon_a)
    lat_b = math.radians(lat_b)
    lon_b = math.radians(lon_b)
    # 2地点,緯度経度から方位角Az,中心角DDを求める(公式)
    SDs = math.cos(lat_b) * math.sin(lon_b - lon_a)
    SDc = math.cos(lat_a) * math.sin(lat_b) - math.sin(lat_a) * math.cos(lat_b) * math.cos(lon_b - lon_a)
    Az = math.atan(SDs/SDc)  # 方位角(Azimuth)# を求める
    Az = math.degrees(Az)
    if SDc < 0:
        Az = Az + 180
    if Az < 0:
        Az = Az + 360
    CD = math.sin(lat_a) * math.sin(lat_b) + math.cos(lat_a) * math.cos(lat_b) * math.cos(lon_b - lon_a)
    # K = SDs * SDs + SDc * SDc + CD * CD
    # print(K)   # 検算 = 1
    DD = math.acos(CD) # 2地点の弧の中心角 DD
    # print(math.degrees(DD))
    Dist = 2 * ra * math.sin(DD/2)  # 弦の長さ=基線長
    return [Dist, Az]


def hoseikaku(h, Am, Az): # 月の方位角と高度,基線の方位から補正角をもとめる関数
    if Az > 180:
        Az = Az - 180
    a = abs(Am - Az)
    a = math.radians(a)
    b = math.radians(h)
    c = math.cos(a) * math.cos(b) # 直角球面三角形の公式
    c = math.acos(c)
    c = math.degrees(c)
    return c

def main(lon_a, lat_a, lon_b, lat_b, horizon, Am, P_obs):

    Dist,Az = baseline(lon_a, lat_a, lon_b, lat_b) # 関数にわたす
    print("")
    print(" 基線長 Dist = ", format(Dist,'5g'),"km")  # 基線長(Dist)とaからbへの方位角(Az)
    print(" 基線方位角 Az = ", format(Az,'f'),"°")
    C = hoseikaku(horizon, Am, Az)
    Z = 90 - C
    Z = math.radians(Z)

    Px = P_obs / math.cos(Z)   # 補正
    print(" 観測された視差 Observed P= ", P_obs," 秒")
    print(" 視線方向に補正した視差 Px= ",format(Px,'f')," 秒")
    MD = 206264.8 * Dist / Px    # 視差から距離をもとめる(1秒のラジアン単位の逆数倍)
    print(" 月の距離 Moon_Distance = ",format(MD,'.8g')," km")
    return MD


"""        =========  GUI  ==========       """

class Application(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        master.title("Calculating Distance of the Moon from Parallax")
        master.geometry("640x380")
        self.pack()
        self.lat_a = tk.DoubleVar(value=35.0)
        self.lon_a = tk.DoubleVar(value=138.0)
        self.lat_b = tk.DoubleVar(value=36.0)
        self.lon_b = tk.DoubleVar(value=139.0)
        self.horizon = tk.DoubleVar(value=30.0)
        self.Am = tk.DoubleVar(value=130.0)
        self.P_obs = tk.DoubleVar(value=77.0)
        self.Distance = tk.DoubleVar(value=0.0)
        self.create_widgets()

    def create_widgets(self):
        self.lb1 = tk.Label(self, text='\n月の視差から距離を測定するプログラム\n ',
                            width=300, font=('MSゴシック', 11), anchor='c')
        self.lb1.pack()
        self.lb2 = tk.Label(self,
                            text='\n\n     観測点A,Bの緯度と経度を(°単位)小数表示で入力してください。\n   ',
                            font=('MSゴシック', 10), width=300, anchor='w')
        self.lb2.pack()
        self.lb01 = tk.Label(text='Aの緯度',width=15)
        self.lb01.place(x=20, y=100)
        self.Entry1 = tk.Entry(textvariable=self.lat_a, width=15)
        self.Entry1.place(x=30, y=120)
        self.lb02 = tk.Label(text='Aの経度', width=15)
        self.lb02.place(x=150, y=100)
        self.Entry2 = tk.Entry(textvariable=self.lon_a, width=15)
        self.Entry2.place(x=160, y=120)
        self.lb03 = tk.Label(text='Bの緯度', width=15)
        self.lb03.place(x=280, y=100)
        self.Entry3 = tk.Entry(textvariable=self.lat_b, width=15)
        self.Entry3.place(x=290, y=120)
        self.lb04 = tk.Label(text='Bの経度', width=15)
        self.lb04.place(x=400, y=100)
        self.Entry4 = tk.Entry(textvariable=self.lon_b, width=15)
        self.Entry4.place(x=410, y=120)
        self.lb3 = tk.Label(self,text='\n\n\n\n\n     月の地平高度(°)と方位角(°),観測された視差(秒)を入力してください。\n',
                            font=('MSゴシック',10),width=300,anchor='w')
        self.lb3.pack()
        self.lb05 = tk.Label(text='地平高度(°)', width=15)
        self.lb05.place(x=20, y=200)
        self.Entry5 = tk.Entry(textvariable=self.horizon,width=15)
        self.Entry5.place(x=30, y=220)
        self.lb06 = tk.Label(text='方位角(°)', width=15)
        self.lb06.place(x=150, y=200)
        self.Entry6 = tk.Entry(textvariable=self.Am,width=15)
        self.Entry6.place(x=160, y=220)
        self.lb07 = tk.Label(text='視差(”)', width=15)
        self.lb07.place(x=310, y=200)
        self.Entry7 = tk.Entry(textvariable=self.P_obs,width=15)
        self.Entry7.place(x=310, y=220)

        self.bt3 = tk.Button(text='計算実行', width=15, command=self.excute)
        self.bt3.place(x=430, y=280)
        self.lb08 = tk.Label(text='方位角は,北を基準に時計回り360°の値です。')
        self.lb08.place(x=100, y=250)
        self.bt4 = tk.Button(text='終了(EXIT)', width=15, command=self.end)
        self.bt4.place(x=470, y=50)
        self.lb09 = tk.Label(text='月までの距離(km)',width=15,font=('MSゴシック',11))
        self.lb09.place(x=50, y=300)
        self.Entry8 = tk.Entry(textvariable=self.Distance,font=('MSゴシック',11),width=20)
        self.Entry8.place(x=180, y=300)

    def excute(self): # 計算ボタンで実行する
        lta = self.lat_a.get()
        loa = self.lon_a.get()
        ltb = self.lat_b.get()
        lob = self.lon_b.get()
        h = self.horizon.get()
        A = self.Am.get()
        P = self.P_obs.get()
        self.Distance = main(loa,lta,lob,ltb,h,A,P)
        self.Entry8.delete(0,tk.END)
        self.Entry8.insert(0,str(format(self.Distance,'.7g')))

    def end(self): # 終了ボタンで終了
        root.destroy()
        sys.exit()

if __name__ == '__main__':
    root = tk.Tk()
    app = Application(master = root)
    app.mainloop()