海上保安庁海洋情報部-天体の位置計算式をコード化してみた
海上保安庁海洋情報部のサイトには、天文・暦情報のページに天測・天測略歴の付録に掲載されているコンピュータによる天体の位置計算式が紹介されています。解説には計算方法と計算例、PDFおよびTXTには計算に使用する係数が掲載されています。これらは毎年発行されており、天体の位置計算をするならばその年に発行された係数を使用しなければなりません。
計算対象となる天体は、太陽、月、金星、火星、木星、土星、41個の明るい恒星となります。天体は限定的ですが、もともとは天測のためのものですのでしかたがありません。ですが、天体はいずれも肉眼でも見えるものですし、いずれも天文現象で観測または観望のニュースになる天体です。
今回は、紹介されているコンピュータによる天体の位置計算式の解説に紹介されている計算方法を、Fortranでコード化してみました。ほかのプログラミング言語を使用している方は、コードを書き直してみるのもいいかもしれません。
なお、プログラム中で使用している係数は太陽のものを使用しています。ほかの天体の位置を計算する場合は係数のデータを置き換えてください。
▶ サブルーチン pcob_sub.f90
subroutine PlanetaryPosition(year, month, day, hour, minute, second, pos)
! 視赤経・視赤緯・地心距離および視半径の計算
! 海上保安庁 海洋情報部による略算式(2022版)
! https:!www1.kaiho.mlit.go.jp/KOHO/index.html
!
! 年度が替わる場合は、x()およびr()の値を変更する。
! 太陽以外の天体の位置を計算する場合は、x()およびSDの値を変更する。
!
! 引 数: 観測年月日+時分秒(日本標準時)
! year : 年
! month : 月
! day : 日
! hour : 時
! minute : 分
! second : 秒
! 戻り値: 視赤経・視赤緯・地心距離・視半径を返す
! pos(1): 視赤経
! pos(2): 視赤緯
! pos(3): 地心距離
! pos(4): 視半径
!
! 計算精度について:
! 略算式とはいえ、精度は国立天文台天文情報センター暦計算室の値と較べても
! 非常に高い一致をみる。ただ、使用にあたっては、係数の桁数の関係で視赤経
! および視赤緯、地心距離は小数点以下5-6桁までにとどめる。
implicit none
double precision, parameter :: PI = 3.141592653589793d0
double precision, parameter :: RAD = 180.0d0 / PI
double precision, parameter :: DELTAT = 70.0d0
double precision, parameter :: SD = 16.02d0 ! ベースとなる太陽の視半径
double precision, intent(in) :: year, month, day
double precision, intent(in) :: hour, minute, second
double precision, intent(out) :: pos(5)
double precision, dimension(0:29, 1:3) :: x
double precision, dimension(0:9) :: r
double precision :: f, tp, theta, rr
double precision :: ra ! 赤経
double precision :: dc ! 赤緯
double precision :: ds ! 地心距離
integer :: i, a, b, p, q, y, s, t
! 各種引数の計算
p = int(month) - 1
q = int((month + 7) / 10)
y = int((year / 4) - int(year / 4) + 0.77)
s = int(p * 0.55 - 0.33)
t = int(30 * p + q * (s - y) + p * (1 - q) + day)
f = (hour - 9.0d0) / 24.0d0 + minute / 1440.0d0 + second / 86400.0d0
tp = t + f + DELTAT / 86400.0d0
! 係数 - 太陽
if ((0 <= tp) .and. (tp <= 121)) then
! 1 / 0 - 5 / 1
a = 0
b = 121
x( 0, 1:3) = (/ 0.000000d0, 0.00000d0, 0.000000d0/)
x( 1, 1:3) = (/22.714111d0, -5.77971d0, 0.993148d0/)
x( 2, 1:3) = (/ 3.895588d0, 20.02854d0, 0.012659d0/)
x( 3, 1:3) = (/-0.102703d0, 1.72530d0, 0.002294d0/)
x( 4, 1:3) = (/ 0.034943d0, -0.98556d0, -0.000642d0/)
x( 5, 1:3) = (/ 0.006578d0, 0.01260d0, -0.000037d0/)
x( 6, 1:3) = (/-0.002269d0, 0.00796d0, 0.000013d0/)
x( 7, 1:3) = (/ 0.000090d0, -0.00351d0, 0.000009d0/)
x( 8, 1:3) = (/ 0.000090d0, 0.00081d0, 0.000005d0/)
x( 9, 1:3) = (/-0.000024d0, 0.00022d0, -0.000007d0/)
x(10, 1:3) = (/ 0.000024d0, 0.00010d0, 0.000002d0/)
x(11, 1:3) = (/ 0.000022d0, 0.00009d0, -0.000014d0/)
x(12, 1:3) = (/-0.000066d0, -0.00033d0, -0.000006d0/)
x(13, 1:3) = (/-0.000019d0, -0.00024d0, 0.000014d0/)
x(14, 1:3) = (/ 0.000040d0, 0.00022d0, 0.000004d0/)
x(15, 1:3) = (/ 0.000006d0, 0.00014d0, -0.000006d0/)
x(16, 1:3) = (/-0.000014d0, -0.00008d0, -0.000001d0/)
x(17, 1:3) = (/ 0.000004d0, -0.00003d0, 0.000002d0/)
x(18, 1:3) = (/ 0.000002d0, 0.00003d0, 0.000000d0/)
r(0) = 0.000000d0
r(1) = 0.618166d0
r(2) = 3.975436d0
r(3) = -0.000012d0
r(4) = 0.000005d0
r(5) = 0.000003d0
r(6) = 0.000000d0
r(7) = -0.000002d0
r(8) = 0.000000d0
else
if ((120 <= tp) .and. (tp <= 245)) then
! 4 / 30 - 9 / 1
a = 120
b = 244
x( 0, 1:3) = (/ 0.000000d0, 0.00000d0, 0.000000d0/)
x( 1, 1:3) = (/ 6.617773d0, 17.16569d0, 1.012365d0/)
x( 2, 1:3) = (/ 4.135644d0, -3.37392d0, 0.001158d0/)
x( 3, 1:3) = (/-0.041829d0, -5.79007d0, -0.004190d0/)
x( 4, 1:3) = (/-0.040668d0, 0.21379d0, -0.000055d0/)
x( 5, 1:3) = (/ 0.005360d0, 0.15980d0, 0.000107d0/)
x( 6, 1:3) = (/ 0.003267d0, -0.01083d0, -0.000003d0/)
x( 7, 1:3) = (/-0.000421d0, -0.00504d0, 0.000004d0/)
x( 8, 1:3) = (/-0.000120d0, 0.00078d0, -0.000006d0/)
x( 9, 1:3) = (/ 0.000017d0, 0.00005d0, -0.000010d0/)
x(10, 1:3) = (/ 0.000015d0, 0.00003d0, 0.000000d0/)
x(11, 1:3) = (/-0.000021d0, 0.00016d0, -0.000012d0/)
x(12, 1:3) = (/-0.000064d0, -0.00001d0, 0.000007d0/)
x(13, 1:3) = (/ 0.000028d0, 0.00011d0, 0.000016d0/)
x(14, 1:3) = (/ 0.000047d0, -0.00006d0, -0.000005d0/)
x(15, 1:3) = (/-0.000014d0, -0.00014d0, -0.000008d0/)
x(16, 1:3) = (/-0.000017d0, 0.00004d0, 0.000002d0/)
x(17, 1:3) = (/ 0.000005d0, 0.00004d0, 0.000002d0/)
x(18, 1:3) = (/ 0.000007d0, -0.00001d0, -0.000001d0/)
r(0) = 0.000000d0
r(1) = 18.601928d0
r(2) = 4.074040d0
r(3) = -0.000007d0
r(4) = -0.000004d0
r(5) = 0.000002d0
r(6) = 0.000000d0
r(7) = -0.000003d0
r(8) = 0.000001d0
else
if ((243 <= tp) .and. (tp <= 366)) then
! 8 / 31 - 12 / 32
a = 243
b = 366
x( 0, 1:3) = (/ 0.000000d0, 0.00000d0, 0.000000d0/)
x( 1, 1:3) = (/14.543576d0, -10.64695d0, 0.994687d0/)
x( 2, 1:3) = (/ 4.052451d0, -16.83097d0, -0.013825d0/)
x( 3, 1:3) = (/ 0.15169d0, 3.51949d0, 0.001824d0/)
x( 4, 1:3) = (/ 0.013092d0, 0.97356d0, 0.000717d0/)
x( 5, 1:3) = (/-0.013453d0, -0.02695d0, -0.000036d0/)
x( 6, 1:3) = (/-0.002111d0, -0.02322d0, -0.000021d0/)
x( 7, 1:3) = (/ 0.000314d0, -0.00527d0, 0.000001d0/)
x( 8, 1:3) = (/ 0.000181d0, 0.00005d0, -0.000014d0/)
x( 9, 1:3) = (/-0.000011d0, 0.00051d0, -0.000002d0/)
x(10, 1:3) = (/-0.000010d0, -0.00011d0, -0.000004d0/)
x(11, 1:3) = (/-0.000056d0, 0.00019d0, -0.000003d0/)
x(12, 1:3) = (/-0.000016d0, 0.00011d0, 0.000018d0/)
x(13, 1:3) = (/ 0.000057d0, -0.00036d0, 0.000003d0/)
x(14, 1:3) = (/ 0.000011d0, -0.00001d0, -0.000012d0/)
x(15, 1:3) = (/-0.000025d0, 0.00022d0, -0.000001d0/)
x(16, 1:3) = (/-0.000003d0, 0.00000d0, 0.000004d0/)
x(17, 1:3) = (/ 0.000011d0, -0.00009d0, 0.000001d0/)
x(18, 1:3) = (/ 0.000003d0, 0.00001d0, -0.000001d0/)
r(0) = 0.000000d0
r(1) = 2.651397d0
r(2) = 4.041161d0
r(3) = 0.000016d0
r(4) = 0.000003d0
r(5) = -0.000001d0
r(6) = 0.000002d0
r(7) = -0.000002d0
r(8) = 0.000002d0
end if
end if
end if
! 視赤経・視赤緯および地心距離の計算
theta = acos((2.0d0 * tp - (a + b)) / (b - a)) * RAD
ra = 0.0d0
dc = 0.0d0
ds = 0.0d0
do i = 0, 17
ra = ra + (x(i + 1, 1) * cos(mod((theta * i), 360.0d0) / RAD))
dc = dc + (x(i + 1, 2) * cos(mod((theta * i), 360.0d0) / RAD))
ds = ds + (x(i + 1, 3) * cos(mod((theta * i), 360.0d0) / RAD))
end do
if (ra >= 24) then
ra = ra - 24
else
if (ra < 0) then
ra = ra + 24
end if
end if
pos(1) = ra
pos(2) = dc
pos(3) = ds
pos(4) = SD / ds
! Rの計算
theta = acos((2.0d0 * (t + f) - (a + b)) / (b - a)) * RAD
rr = 0.0d0
do i = 0, 7
rr = rr + (r(i + 1) * cos(mod((theta * i), 360.0d0) / RAD))
end do
ra = rr - ra
pos(5) = ra
return
end subroutine PlanetaryPosition
▶ メインルーチン pcob_main.f90
テストのためのメインルーチンです。Rから求めた赤経は使用していません。
program pcob_main
! 天体の視位置を求める
implicit none
double precision, dimension(5) :: pos
double precision :: dy, dt
double precision :: year, month, day, hour, minute, second
double precision :: rs, ds, ss
integer :: rh, rm, dh, dm, sm
character(1) :: sign
character(255) :: sfmt
write(*,*)
write(*, fmt='(a)', advance='no') 'DATE AND TIME(JST) ? '
read(*,*) dy, dt
year = int(dy / 10000.0d0)
month = mod(int(dy / 100.0d0), 100)
day = mod(dy, 100.0d0)
hour = int(dt / 10000.0d0)
minute = mod(int(dt / 100.0d0), 100)
second = mod(dt, 100.0d0)
write(*, *)
sfmt = '(i5, "年 ", i2, "月 ", i2, "日 ", i2, "時 ", i2, "分 ", i2, "秒")'
write(*, sfmt) int(year), int(month), int(day), int(hour), int(minute), int(second)
call PlanetaryPosition(year, month, day, hour, minute, second, pos)
rh = int(pos(1))
rs = 60.0d0 * (pos(1) - rh)
rm = int(rs)
rs = 60.0d0 * (rs - rm)
sign = '+'
if (pos(2) < 0) then
sign = '-'
end if
dh = abs(int(pos(2)))
ds = 60.0d0 * (abs(pos(2)) - dh)
dm = int(ds)
ds = 60.0d0 * (ds - dm)
sm = int(pos(4))
ss = 60.0d0 * (pos(4) - sm)
write(*, *)
write(*, *) ' 赤経 赤緯 地心距離 視半径'
write(*, *) ' h m s 。 , AU , ,,'
write(*, '(" ", i2, " ", i2, " ", f6.3, " ", a1, i2, " ", i2, " ", f5.2, " ", f9.7, " ", i2, " ", f5.2)') &
rh, rm, rs, sign, dh, dm, ds, pos(3), sm, ss
write(*, *)
stop
end program pcob_main
コンパイル
gfortran pcob_main.f90 pcob_sub.f90
実行
./a.out
実行すると日付と時刻を入力するよう求められます。日付が2022年5月4日なら20220504、時刻が15時24分37秒なら152437とします。時刻は必ず秒まで入力してください。なお、日付と時刻はカンマ(,)で区切って入力してください(実行結果参照)。
実行結果
DATE AND TIME(JST) ? 20220504,152437 2022年 5月 4日 15時 24分 37秒 赤経 赤緯 地心距離 視半径 h m s 。 , AU , ,, 2 45 19.205 +15 58 34.87 1.0082528 15 53.33
国立天文台 天文情報センター暦計算室(暦年表ー太陽の地心座標)の値は以下のようになっています(時刻系の指定は+09時間(日本))。
h m s 。 , ,, AU , ,, 2 45 19.208 15 58 34.89 1.0082504 15 53.31