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