08 January 2026, Thursday

ephem Python packageを用いた、標高による日出没時刻のズレに関する考察【その2】

伏角の計算

2025年12月に書いた『ephem Python packageを用いた、標高による日出没時刻のズレに関する考察』において、観測者の標高により水平線がどれくらい沈んで見えるかの伏角(θとθ')の計算を行った。今回、実際の日出・日没の時刻算出を行う実効伏角(θref)を決める式を導き、検証を行った。

(1)光学伏角 θ (真空中の場合の幾何学的解法)

20260108-dip-vacuum.png

※ 地球の平均半径 R = 6371000, 観測者の標高 h

(2)見かけの空気屈折伏角 θ'

20260108-dip-refsimple.png

※ 空気屈折率 κ = 2β = 0.13 〜 0.16

※ κの出典: κ=0.13(国土地理院 公共測量), 1/7 = 0.143(アメリカ国家地理空間情報局 航海術), 0.14(土木測量 0.10〜0.16), 等温大気で0.16, 逆転層があると0.16以上の大きめの値となる

(3)空気屈折伏角(実効値) θref

実効伏角は「標高に対する気温の変化(気温勾配)」「気圧」「気温」によって表されるとされるが、解法が非常にややこしく証明を断念した。なお、空気屈折率を一定とした場合の幾何学的解法を試みたが、こちらはこの記事の後半にあるように数式が解けなかった...

次の式は、国立天文台の「こよみの計算」で計算した時刻および、Ephemの大気屈折の自動計算の時刻に合わせ込むために「係数」を決めたものだ。

20260108-dip-ref2.png

これより、光学伏角との関係は θref = 1.4902 × θ となる。

計算結果の検算

国立天文台の「こよみの計算」で計算した時刻を用いて、次の2つの計算結果を検算する。

(1)光学伏角 θ (真空中の場合の幾何学的解法) + Ephemの空気屈折補正機能
20260108-dip-vacuum.png


(3)空気屈折伏角(実効値) θref
20260108-dip-ref2.png


国立天文台の「こよみの計算」で計算した時刻

国立天文台の「こよみの計算」で手動入力して計算した結果を、コピペした一覧表

年月日,緯度,経度
標高,日の出時刻,日の入り時刻
標高,日の出時刻,日の入り時刻
...


大阪

2025/1/1, 34.67, 135.5
0,07:05,16:58
500,07:01,17:02
1000,06:59,17:04
1500,06:58,17:06
2000,06:56,17:07
2500,06:55,17:08
3000,06:54,17:09
3500,06:54,17:10

2025/7/1, 34.67, 135.5
0,04:48,19:15
500,04:44,19:20
1000,04:42,19:21
1500,04:41,19:23
2000,04:40,19:24
2500,04:39,19:25
3000,04:38,19:26
3500,04:37,19:27


東京

2025/1/1,35.66,139.74
0,06:51,16:39
500,06:46,16:43
1000,06:44,16:45
1500,06:43,16:46
2000,06:42,16:47
2500,06:41,16:48
3000,06:40,16:49
3500,06:39,16:50

2025/7/1,35.66,139.74
0,04:29,19:01
500,04:24,19:05
1000,04:22,19:07
1500,04:21,19:09
2000,04:20,19:10
2500,04:19,19:11
3000,04:18,19:12
3500,04:17,19:13


札幌

2025/1/1,43.07,141.35
0,07:06,16:10
500,07:01,16:15
1000,06:59,16:17
1500,06:57,16:19
2000,06:56,16:20
2500,06:55,16:22
3000,06:54,16:23
3500,06:53,16:24

検証用のPythonスクリプト

日の出・日の入時刻を計算するPythonスクリプト
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""指定された緯度・経度・標高に基づき日出・日没時刻を検証するスクリプト。

スクリプト単純実装のテスト用

"""
from datetime import datetime, timedelta
import math
import ephem

target_ymd = "2025/1/1"
R = 6371000.0           # 地球半径 [m]
lat_deg = 34.67         # 緯度
lon_deg = 135.50        # 経度
height_m = 3000         # 標高
refraction_factor = 1.4902      # dip_ref = refraction_factor * dip_geom


def calc_dipgeom_ephemrefraction() -> None:

    pressure_0m = 1013.25   # 標高 0mの気圧 [hPa]
    pressure = pressure_0m * (1 - 2.25577e-5 * height_m) ** 5.2559
    temperature_0m = 15.0   # 標高 0mの気温 [℃]
    temperature = temperature_0m - 0.6 * height_m / 100

    jst_offset = timedelta(hours=9)     # JST → UTC

    # 光学伏角(真空中)
    dip_geom = math.sqrt(2 * height_m / R) * 180.0 / math.pi

    obs = ephem.Observer()
    obs.date = datetime.strptime(target_ymd, "%Y/%m/%d") - jst_offset
    obs.lat = str(lat_deg)
    obs.lon = str(lon_deg)
    obs.elevation = float(height_m)
    obs.pressure = pressure
    obs.temperature = temperature
    obs.horizon = f"-{dip_geom}"

    sun = ephem.Sun()  # type: ignore[reportAttributeAccessIssue]

    # 日の出・日の入り(UTC → JST)
    sunrise = obs.next_rising(sun).datetime() + jst_offset
    sunset = obs.next_setting(sun).datetime() + jst_offset

    print(f"日の出 : {sunrise.strftime('%H:%M:%S')}\n"
          f"日の入 : {sunset.strftime('%H:%M:%S')}\n"
          f"標高 : {height_m} m\n"
          f"補正気圧 : {pressure:5.1f} hPa\n"
          f"補正気温 : {temperature:3.1f} 度\n"
          f"伏角 : {dip_geom:4.3f} °")


def calc_dipref() -> None:

    pressure = 0.0          # Ephemでの空気屈折計算を無効化
    # temperature = 11.0      # Ephemのデフォルト値

    jst_offset = timedelta(hours=9)     # JST → UTC

    # 光学伏角(真空中)
    dip_geom = math.sqrt(2 * height_m / R) * 180.0 / math.pi
    # 実効伏角
    dip_ref = refraction_factor * dip_geom

    obs = ephem.Observer()
    obs.date = datetime.strptime(target_ymd, "%Y/%m/%d") - jst_offset
    obs.lat = str(lat_deg)
    obs.lon = str(lon_deg)
    obs.elevation = float(height_m)
    obs.pressure = pressure
    obs.horizon = f"-{dip_ref}"

    sun = ephem.Sun()  # type: ignore[reportAttributeAccessIssue]

    # 日の出・日の入り(UTC → JST)
    sunrise = obs.next_rising(sun).datetime() + jst_offset
    sunset = obs.next_setting(sun).datetime() + jst_offset

    print(f"日の出 : {sunrise.strftime('%H:%M:%S')}\n"
          f"日の入 : {sunset.strftime('%H:%M:%S')}\n"
          f"標高 : {height_m} m\n"
          f"補正気圧 : {obs.pressure:5.1f} hPa\n"
          f"補正気温 : {obs.temperature:3.1f} 度\n"
          f"伏角 : {dip_ref:4.3f} °")


print("=== 光学伏角 + Ephem空気屈折補正 ===")
calc_dipgeom_ephemrefraction()
print("=== 空気屈折伏角 ===")
calc_dipref()

実行結果で検証

大阪 2025/01/01 標高3000m
=== 光学伏角 + Ephem空気屈折補正 ===
日の出 : 06:53:21
日の入 : 17:09:45
標高 : 3000 m
補正気圧 : 701.1 hPa
補正気温 : -3.0 度
伏角 : 1.758 °
=== 空気屈折伏角 ===
日の出 : 06:53:54
日の入 : 17:09:12
標高 : 3000 m
補正気圧 :   0.0 hPa
補正気温 : 15.0 度
伏角 : 2.620 °

グラフで検証

作成したスクリプトはこのページに掲載するには大きすぎるため、別ファイルとして保存しているPythonスクリプトをダウンロード できる。

赤線が(1)光学伏角 θ (真空中の場合の幾何学的解法) + Ephemの空気屈折補正機能
青線が(3)空気屈折伏角(実効値) θref
黒点が 国立天文台 「こよみの計算」

20260108-compare-osaka-0101.jpg
大阪 2025/01/01

20260108-compare-osaka-0701.jpg
大阪 2025/07/01

20260108-compare-tokyo-0101.jpg
東京 2025/01/01

20260108-compare-tokyo-0701.jpg
東京 2025/07/01

20260108-compare-sapporo-0101.jpg
札幌 2025/01/01

空気屈折率を一定とした場合の実効伏角θrefの幾何学的解法

空気中での光の経路が屈折することにより、見かけ上の水平線より下に実効的な水平線を想定することで得られる伏角を求める。

20260108-dip-ref.png

黒の円周 : 地球のジオイド面で半径はR
赤の円周 : 観測者の場所 O を通り空気屈折し水平線 A まで達するの光の経路を両側に延長した仮想円
C : 地球の中心
Ce : 仮想円の中心
B : 観測者の場所をジオイド面に落とした点
O : 観測者の場所で、ジオイド面から 高さ h の点
A : 観測者が見る水平線上の地点(地球のジオイド面:黒 と仮想円:赤 が接する点)
OT : 観測者 O から見た見かけ上の水平線(オレンジ点線)
θ' : 観測者 O から見た見かけ上の水平線の伏角
ATH : 空気屈折を考慮した水平線地点での黒・赤円の接線 Lref(オレンジ実線)
OA' : 観測者 O から見た真空時の水平線(緑の実線)
θ : 観測者 O から見た真空時の伏角

観測者から見かけ上の水平線までの距離 : AOの長さ

地球中心と観測者・水平線を結んだ三角形CAOについて余弦定理を用いて関係を表す

20260108-dipref-eq-01.png

20260108-dipref-eq-02.png

θrefが極めて小さい場合

20260108-dipref-eq-03.png

と近似できるため

20260108-dipref-eq-04.png

20260108-dipref-eq-05.png

20260108-dipref-eq-06.png

H << R を考慮すると

20260108-dipref-eq-07.png

∠OAT ( = Φ ) を伏角 θref で表す

地球中心と観測者・水平線を結んだ三角形CAOについて正弦定理を用いて関係を表す

20260108-dipref-eq-10.png

20260108-dipref-eq-11.png

20260108-dipref-eq-12.png

θrefが極めて小さい場合、また R >> h の場合、次の近似ができる。

20260108-dipref-eq-13.png

20260108-dipref-eq-14.png

Φが小さい場合は 次のように近似できるため

20260108-dipref-eq-15.png

20260108-dipref-eq-16.png

(11)と(12)を合わせると

20260108-dipref-eq-17.png

20260108-dipref-eq-18.png

20260108-dipref-eq-21.png

20260108-dipref-eq-22.png

分母に対してRθrefをそれぞれ外に出すと

20260108-dipref-eq-23.png

ここで、次行に示すテイラー展開の公式の第2項までを用いることにする

20260108-dipref-eq-19.png

20260108-dipref-eq-20.png のようにすれば

20260108-dipref-eq-24.png

ここで 20260108-dipref-eq-25.png と置いて

20260108-dipref-eq-26.png

分数部分の一部は次のように表記できる

20260108-dipref-eq-27.png

ここで再びテイラー展開の公式(第2項まで) 20260108-dipref-eq-28.png において次行のように置けば

20260108-dipref-eq-29.png

次のように表記できる

20260108-dipref-eq-30.png

20260108-dipref-eq-31.png

xの1次までにまるめて(x^2 以上は切り捨てして)

20260108-dipref-eq-32.png

ここからもとの式に戻していく

20260108-dipref-eq-33.png

20260108-dipref-eq-36.png

20260108-dipref-eq-37.png

ここでテイラー展開 20260108-dipref-eq-28.png で第2項までの近似を用いてルートを外すと

20260108-dipref-eq-38.png

20260108-dipref-eq-39.png

ここで、20260108-dipref-eq-40.png を用いて、Φを消すと

20260108-dipref-eq-41.png

θref^3を掛けて、すべての項を左辺側に移すと

20260108-dipref-eq-42.png

ここでθref^2 = x と置き、κ/2 = b, h/R = a と置くと

20260108-dipref-eq-43.png

さらに b = A, -a = B, 3/8 a^3 = C と置くと、

20260108-dipref-eq-44.png

二次方程式の解の公式により

20260108-dipref-eq-45.png

x, a, b に戻すと

20260108-dipref-eq-46.png

20260108-dipref-eq-47.png

ここで、a = h/R がかなり小さな値であることを考慮すると 20260108-dipref-eq-48.png のように近似できるため

20260108-dipref-eq-49.png

20260108-dipref-eq-50.png

20260108-dipref-eq-51.png

解の次元(光学伏角はhの1/2乗で、空気屈折伏角がhの1/4乗)というのはおかしく、さらにいえば屈折率が上がれば伏角が(1/κの1/4乗に比例して)小さくなるは理屈に合わない。つまり、ちゃんと問題が解けていないのだ。

私の実力では、解は得られなかった...