Nutze Skyfield fuer praezisere Daemmerungsberechnung
This commit is contained in:
@@ -1,10 +1,20 @@
|
||||
#!/usr/bin/env python3
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from decimal import Decimal, InvalidOperation, ROUND_HALF_UP, localcontext
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import astronomy
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
VENDOR_DIR = os.path.join(SCRIPT_DIR, "vendor")
|
||||
VENDOR_DATA_DIR = os.path.join(SCRIPT_DIR, "vendor_data")
|
||||
SKYFIELD_EPHEMERIS_PATH = os.path.join(VENDOR_DATA_DIR, "de421.bsp")
|
||||
|
||||
if VENDOR_DIR not in sys.path:
|
||||
sys.path.insert(0, VENDOR_DIR)
|
||||
|
||||
try:
|
||||
from astropy.time import Time as AstropyTime
|
||||
ASTROPY_AVAILABLE = True
|
||||
@@ -12,6 +22,15 @@ except ImportError:
|
||||
AstropyTime = None
|
||||
ASTROPY_AVAILABLE = False
|
||||
|
||||
try:
|
||||
from skyfield.api import load as skyfield_load
|
||||
from skyfield.api import wgs84 as skyfield_wgs84
|
||||
SKYFIELD_AVAILABLE = True
|
||||
except ImportError:
|
||||
skyfield_load = None
|
||||
skyfield_wgs84 = None
|
||||
SKYFIELD_AVAILABLE = False
|
||||
|
||||
SPEED_OF_LIGHT_KM_S = 299792.458
|
||||
H0 = 70.0
|
||||
OMEGA_M = 0.3
|
||||
@@ -102,6 +121,9 @@ EQ_TO_GAL_MATRIX = (
|
||||
(-0.8676661490190047, -0.1980763734312015, 0.4559837761750669),
|
||||
)
|
||||
|
||||
_SKYFIELD_TIMESCALE = None
|
||||
_SKYFIELD_PLANETS = None
|
||||
|
||||
|
||||
def parse_decimal_input(value: str) -> Decimal | None:
|
||||
text = str(value or "").strip()
|
||||
@@ -177,6 +199,32 @@ def normalize_angle_degrees(value: float) -> float:
|
||||
return normalized
|
||||
|
||||
|
||||
def skyfield_context() -> tuple[object, object]:
|
||||
global _SKYFIELD_TIMESCALE, _SKYFIELD_PLANETS
|
||||
|
||||
if not SKYFIELD_AVAILABLE:
|
||||
raise RuntimeError("Skyfield ist lokal nicht verfuegbar.")
|
||||
|
||||
if not os.path.exists(SKYFIELD_EPHEMERIS_PATH):
|
||||
raise RuntimeError("Die lokale Skyfield-Ephemeride de421.bsp fehlt.")
|
||||
|
||||
if _SKYFIELD_TIMESCALE is None:
|
||||
_SKYFIELD_TIMESCALE = skyfield_load.timescale()
|
||||
|
||||
if _SKYFIELD_PLANETS is None:
|
||||
_SKYFIELD_PLANETS = skyfield_load(SKYFIELD_EPHEMERIS_PATH)
|
||||
|
||||
return _SKYFIELD_TIMESCALE, _SKYFIELD_PLANETS
|
||||
|
||||
|
||||
def calculate_solar_altaz_skyfield(dt_utc: datetime, latitude: float, longitude: float) -> tuple[float, float]:
|
||||
timescale, planets = skyfield_context()
|
||||
time_value = timescale.from_datetime(dt_utc.astimezone(timezone.utc))
|
||||
observer = planets["earth"] + skyfield_wgs84.latlon(latitude, longitude)
|
||||
altitude, azimuth, _distance = observer.at(time_value).observe(planets["sun"]).apparent().altaz()
|
||||
return float(altitude.degrees), float(azimuth.degrees)
|
||||
|
||||
|
||||
def transpose_matrix(matrix: tuple[tuple[float, float, float], ...]) -> tuple[tuple[float, float, float], ...]:
|
||||
return tuple(tuple(matrix[row][column] for row in range(3)) for column in range(3))
|
||||
|
||||
@@ -557,15 +605,21 @@ def convert_tools(payload: dict) -> dict:
|
||||
return {"valid": False, "fields": {key: "" for key in TOOLS_ORDER}}
|
||||
|
||||
dt_utc = local_dt.astimezone(timezone.utc)
|
||||
time_value = dt_to_time(dt_utc)
|
||||
observer = astronomy.Observer(latitude, longitude, 0.0)
|
||||
equator = astronomy.Equator(astronomy.Body.Sun, time_value, observer, True, True)
|
||||
horizon = astronomy.Horizon(time_value, observer, equator.ra, equator.dec, astronomy.Refraction.Normal)
|
||||
|
||||
try:
|
||||
altitude_deg, azimuth_deg = calculate_solar_altaz_skyfield(dt_utc, latitude, longitude)
|
||||
except Exception:
|
||||
time_value = dt_to_time(dt_utc)
|
||||
observer = astronomy.Observer(latitude, longitude, 0.0)
|
||||
equator = astronomy.Equator(astronomy.Body.Sun, time_value, observer, True, True)
|
||||
horizon = astronomy.Horizon(time_value, observer, equator.ra, equator.dec, astronomy.Refraction.Normal)
|
||||
altitude_deg = float(horizon.altitude)
|
||||
azimuth_deg = float(horizon.azimuth)
|
||||
|
||||
fields = {
|
||||
"utc": format_utc_datetime(dt_utc),
|
||||
"altitude": format_decimal_german(horizon.altitude, max_fraction_digits=4),
|
||||
"azimuth": format_decimal_german(normalize_angle_degrees(horizon.azimuth), max_fraction_digits=4),
|
||||
"altitude": format_decimal_german(altitude_deg, max_fraction_digits=4),
|
||||
"azimuth": format_decimal_german(normalize_angle_degrees(azimuth_deg), max_fraction_digits=4),
|
||||
}
|
||||
return {"valid": True, "fields": fields}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user