Nutze Skyfield fuer praezisere Daemmerungsberechnung

This commit is contained in:
2026-07-13 19:35:39 +02:00
parent dc5292735f
commit 97357a88e0
1092 changed files with 370248 additions and 61 deletions
+134
View File
@@ -0,0 +1,134 @@
# -*- coding: utf-8 -*-
"""Search for eclipses."""
from __future__ import division
from numpy import arcsin, byte
from .constants import AU_KM, C_AUDAY, ERAD
from .functions import angle_between, length_of
from .searchlib import find_maxima
from .relativity import add_aberration
LUNAR_ECLIPSES = [
'Penumbral',
'Partial',
'Total',
]
def lunar_eclipses(start_time, end_time, eph):
"""Return the lunar eclipses between ``start_time`` and ``end_time``.
Returns a three-item tuple:
* A :class:`~skyfield.timelib.Time` giving the dates of each eclipse.
* An integer array of codes identifying how complete each eclipse is.
* A dictionary of further supplementary details about each eclipse.
This routine is adapted from the Explanatory Supplement to the
Astronomical Almanac 11.2.3. See `lunar-eclipses` for the details
of how to call this function.
"""
# Calls to the inner function `f()` from `find_maxima()` incur most
# of the expense of this routine, so we use raw ephemeris segments.
# This (a) avoids computing velocities we won't use (calls to `at()`
# always compute velocity), and (b) avoids computing any segments
# twice.
#
# Note that we neglect light-travel time between the Earth and Moon,
# and also light travel time from the Sun: the Sun moves so slowly
# that a few minutes of difference in its position does not
# meaningfully affect our eclipse predictions.
sdict = dict(((s.center, s.target), s.spk_segment) for s in eph.segments)
sun = sdict[0,10]
earth_barycenter = sdict[0,3]
earth = sdict[3,399]
moon = sdict[3,301]
def f(t):
jd, fr = t.whole, t.tdb_fraction
b, velocity = earth_barycenter.compute_and_differentiate(jd, fr)
e = earth.compute(jd, fr)
m = moon.compute(jd, fr)
s = sun.compute(jd, fr)
earth_to_sun = s - b - e
earth_to_moon = m - e
# The aberration routine requires specific units. (We can leave
# the `earth_to_moon` vector unconverted because we only need
# its direction.) We approximate the Earth’s velocity as being
# that of the Earth-Moon barycenter.
earth_to_sun /= AU_KM
velocity /= AU_KM
light_travel_time = length_of(earth_to_sun) / C_AUDAY
add_aberration(earth_to_sun, velocity, light_travel_time)
return angle_between(earth_to_sun, earth_to_moon)
f.step_days = 5.0
t, y = find_maxima(start_time, end_time, f, num=4)
jd, fr = t.whole, t.tdb_fraction
b = earth_barycenter.compute(jd, fr)
e = earth.compute(jd, fr)
m = moon.compute(jd, fr)
s = sun.compute(jd, fr)
earth_to_sun = s - b - e
moon_to_earth = e - m
solar_radius_km = 696340.0
moon_radius_km = 1737.1
# Strict geometry would demand that `arcsin()` be applied to these
# three values, but the angles are small enough that no eclipse
# prediction seems to be affected.
pi_m = ERAD / 1e3 / length_of(moon_to_earth)
pi_s = ERAD / 1e3 / length_of(earth_to_sun)
s_s = solar_radius_km / length_of(earth_to_sun)
closest_approach = angle_between(earth_to_sun, moon_to_earth)
moon_radius = arcsin(moon_radius_km / length_of(moon_to_earth))
# Use Danjon's method for calculating enlargement of Earth's shadow.
# See https://eclipse.gsfc.nasa.gov/LEcat5/shadow.html
pi_1 = 1.01 * pi_m
penumbra_radius = pi_1 + pi_s + s_s
umbra_radius = pi_1 + pi_s - s_s
penumbral = closest_approach < penumbra_radius + moon_radius
# We now know which conjunctions are eclipses! Before proceeding,
# narrow all of our arrays to only those incidents.
t = t[penumbral]
closest_approach = closest_approach[penumbral]
moon_radius = moon_radius[penumbral]
penumbra_radius = penumbra_radius[penumbral]
umbra_radius = umbra_radius[penumbral]
# Calculate fraction of the Moon's diameter covered by the Earth’s shadow.
twice_radius = 2 * moon_radius
umbral_magnitude = umbra_radius + moon_radius - closest_approach
umbral_magnitude /= twice_radius
penumbral_magnitude = penumbra_radius + moon_radius - closest_approach
penumbral_magnitude /= twice_radius
partial = closest_approach < umbra_radius + moon_radius
total = closest_approach < umbra_radius - moon_radius
code = partial.astype(byte)
code += total
details = {
'closest_approach_radians': closest_approach,
'moon_radius_radians': moon_radius,
'penumbra_radius_radians': penumbra_radius,
'umbra_radius_radians': umbra_radius,
'umbral_magnitude': umbral_magnitude,
'penumbral_magnitude': penumbral_magnitude,
}
return t, code, details