feat(Q5): NOAA sunset calculator (stdlib only)
This commit is contained in:
parent
a5dd15d0a1
commit
e75a9a9d71
18
tests/unit/test_solar.py
Normal file
18
tests/unit/test_solar.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import datetime
|
||||||
|
from vigilar.detection.solar import get_sunset
|
||||||
|
|
||||||
|
|
||||||
|
def test_sunset_returns_time():
|
||||||
|
result = get_sunset(45.0, -85.0, datetime.date(2026, 6, 21))
|
||||||
|
assert isinstance(result, datetime.time)
|
||||||
|
|
||||||
|
|
||||||
|
def test_sunset_equator():
|
||||||
|
result = get_sunset(0.0, 0.0, datetime.date(2026, 3, 20))
|
||||||
|
assert 17 <= result.hour <= 19
|
||||||
|
|
||||||
|
|
||||||
|
def test_sunset_different_dates_vary():
|
||||||
|
d1 = get_sunset(45.0, -85.0, datetime.date(2026, 3, 1))
|
||||||
|
d2 = get_sunset(45.0, -85.0, datetime.date(2026, 9, 1))
|
||||||
|
assert d1 != d2
|
||||||
31
vigilar/detection/solar.py
Normal file
31
vigilar/detection/solar.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
"""Sunset calculation using NOAA solar equations. Stdlib only."""
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import math
|
||||||
|
|
||||||
|
|
||||||
|
def get_sunset(latitude: float, longitude: float, date: datetime.date) -> datetime.time:
|
||||||
|
n = date.timetuple().tm_yday
|
||||||
|
gamma = 2 * math.pi / 365 * (n - 1)
|
||||||
|
eqtime = 229.18 * (
|
||||||
|
0.000075 + 0.001868 * math.cos(gamma) - 0.032077 * math.sin(gamma)
|
||||||
|
- 0.014615 * math.cos(2 * gamma) - 0.040849 * math.sin(2 * gamma)
|
||||||
|
)
|
||||||
|
decl = (
|
||||||
|
0.006918 - 0.399912 * math.cos(gamma) + 0.070257 * math.sin(gamma)
|
||||||
|
- 0.006758 * math.cos(2 * gamma) + 0.000907 * math.sin(2 * gamma)
|
||||||
|
- 0.002697 * math.cos(3 * gamma) + 0.00148 * math.sin(3 * gamma)
|
||||||
|
)
|
||||||
|
lat_rad = math.radians(latitude)
|
||||||
|
zenith = math.radians(90.833)
|
||||||
|
cos_ha = (
|
||||||
|
math.cos(zenith) / (math.cos(lat_rad) * math.cos(decl))
|
||||||
|
- math.tan(lat_rad) * math.tan(decl)
|
||||||
|
)
|
||||||
|
cos_ha = max(-1.0, min(1.0, cos_ha))
|
||||||
|
ha = math.degrees(math.acos(cos_ha))
|
||||||
|
sunset_minutes = 720 - 4 * (longitude - ha) - eqtime
|
||||||
|
sunset_minutes = sunset_minutes % 1440
|
||||||
|
hours = int(sunset_minutes // 60)
|
||||||
|
minutes = int(sunset_minutes % 60)
|
||||||
|
return datetime.time(hour=hours, minute=minutes)
|
||||||
Loading…
Reference in New Issue
Block a user