muwerk mupplet Core Library
muwerk applets; mupplets: functional units that support specific hardware or reusable applications
Loading...
Searching...
No Matches
mup_astro.h
1#pragma once
2
3#include <math.h>
4
5namespace ustd {
6
7const double C_PI = 3.1415926535897932384626433;
8const double C_D2R = C_PI / 180.0;
9const double C_R2D = 180.0 / C_PI;
10const double C_AU = 149597870700.0;
11const double C_C = 299792458.0;
12const double C_CAUD = C_C * 60 * 60 * 24 / C_AU;
13const double C_MJD = 2400000.5;
14
19class Astro {
20 public:
21 double lat, lon, utcOffset;
22
23#ifdef USTD_FEATURE_FILESYSTEM
24 Astro() {
26 }
27#endif
28 Astro(double lat, double lon, double utcOffset)
29 : lat(lat), lon(lon), utcOffset(utcOffset) {
36 }
37
38 static long julianDayNumber(int year, uint8_t month, uint8_t day) {
58 long JDN = (1461L * ((long)year + 4800L + ((long)month - 14L) / 12L)) / 4L +
59 (367L * ((long)month - 2L - 12L * (((long)month - 14L) / 12L))) / 12L -
60 (3L * (((long)year + 4900L + ((long)month - 14L) / 12L) / 100L)) / 4L +
61 (long)day - 32075L;
62 return JDN;
63 }
64
65 static double fracDay(uint8_t hour, uint8_t min, double sec) {
72 double dayFrac = ((double)hour + (double)min / 60.0 + (double)sec / 3600.0) / 24.0;
73 return dayFrac;
74 }
75
76 static double julianDate(int year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min,
77 double sec) {
95 long JDN = julianDayNumber(year, month, day);
96 double dfrac = fracDay(hour, min, sec) - 0.5;
97 double JD = (double)JDN + dfrac;
98 return JD;
99 }
100
101 static double modifiedJulianDate(int year, uint8_t month, uint8_t day, uint8_t hour,
102 uint8_t min, double sec) {
126 long JDN = julianDayNumber(year, month, day);
127 double dfrac = fracDay(hour, min, sec) - 0.5;
128 double JD = (double)(JDN - C_MJD) + dfrac;
129 return JD;
130 }
131
132 static bool calculateSunRiseSet(int year, int month, int day, double lat, double lon,
133 int localOffset, int daylightSavings, bool bRising,
134 double *pSunTime) {
143 // 1. first calculate the day of the year
144 const double ZENITH = 90.0 + 50.0 / 60.0;
145 double N1 = floor(275.0 * month / 9.0);
146 double N2 = floor((month + 9.0) / 12.0);
147 double N3 = (1.0 + floor((year - 4 * floor(year / 4.0) + 2.0) / 3.0));
148 double N = N1 - (N2 * N3) + day - 30.0;
149
150 // 2. convert the longitude to hour value and calculate an approximate time
151 double lonHour = lon / 15.0;
152 double t;
153 if (bRising)
154 t = N + ((6 - lonHour) / 24); // if rising time is desired:
155 else
156 t = N + ((18 - lonHour) / 24); // if setting time is desired:
157
158 // 3. calculate the Sun's mean anomaly
159 double M = (0.9856 * t) - 3.289;
160
161 // 4. calculate the Sun's true longitude
162 double L =
163 fmod(M + (1.916 * sin(C_D2R * M)) + (0.020 * sin(2 * C_D2R * M)) + 282.634, 360.0);
164
165 // 5a. calculate the Sun's right ascension
166 double RA = fmod(C_R2D * atan(0.91764 * tan(C_D2R * L)), 360.0);
167
168 // 5b. right ascension value needs to be in the same quadrant as L
169 double Lquadrant = floor(L / 90.0) * 90.0;
170 double RAquadrant = floor(RA / 90.0) * 90.0;
171 RA = RA + (Lquadrant - RAquadrant);
172
173 // 5c. right ascension value needs to be converted into hours
174 RA = RA / 15.0;
175
176 // 6. calculate the Sun's declination
177 double sinDec = 0.39782 * sin(C_D2R * L);
178 double cosDec = cos(asin(sinDec));
179
180 // 7a. calculate the Sun's local hour angle
181 // double cosH = (sin(C_D2R * ZENITH) - (sinDec * sin(C_D2R * lat))) /
182 // (cosDec * cos(C_D2R * lat));
183 double cosH =
184 (cos(C_D2R * ZENITH) - (sinDec * sin(lat * C_D2R))) / (cosDec * cos(C_D2R * lat));
185
186 if (bRising) {
187 if (cosH > 1.0) { // the sun never rises on this location (on the specified date)
188 *pSunTime = -1.0;
189 return false;
190 }
191 } else {
192 if (cosH < -1.0) { // the sun never sets on this location (on the specified date)
193 *pSunTime = -1.0;
194 return false;
195 }
196 }
197
198 // 7b. finish calculating H and convert into hours
199 double H;
200 if (bRising)
201 H = 360.0 - C_R2D * acos(cosH); // if if rising time is desired:
202 else
203 H = C_R2D * acos(cosH); // if setting time is desired:
204 H = H / 15.0;
205
206 // 8. calculate local mean time of rising/setting
207 double T = H + RA - (0.06571 * t) - 6.622;
208
209 // 9. adjust back to UTC
210 double UT = fmod(T - lonHour, 24.0);
211
212 // 10. convert UT value to local time zone of latitude/longitude
213 *pSunTime = UT + localOffset + daylightSavings;
214 return true;
215 }
216
217 static int cmpHourMinuteTime(uint8_t h1, uint8_t m1, uint8_t h2, uint8_t m2) {
225 if (h2 > h1)
226 return 1;
227 if (h2 < h1)
228 return -1;
229 if (m2 > m1)
230 return 1;
231 if (m2 < m1)
232 return -1;
233 return 0;
234 }
235
236 static int deltaHourMinuteTime(uint8_t h1, uint8_t m1, uint8_t h2, uint8_t m2) {
244 if (m2 < m1) {
245 m2 += 60;
246 if (h2 > 0)
247 --h2;
248 else
249 h2 = 23;
250 }
251 if (h2 < h1)
252 h2 += 24;
253 return (h2 - h1) * 60 + m2 - m1;
254 }
255
256 static bool inHourMinuteInterval(uint8_t test_hour, uint8_t test_minute, uint8_t start_hour,
257 uint8_t start_minute, uint8_t end_hour, uint8_t end_minute) {
262 if (cmpHourMinuteTime(start_hour, start_minute, end_hour, end_minute) > 0) {
263 if (cmpHourMinuteTime(test_hour, test_minute, start_hour, start_minute) <= 0 &&
264 cmpHourMinuteTime(test_hour, test_minute, end_hour, end_minute) >= 0)
265 return true;
266 else
267 return false;
268 } else {
269 if (cmpHourMinuteTime(test_hour, test_minute, start_hour, start_minute) > 0 &&
270 cmpHourMinuteTime(test_hour, test_minute, end_hour, end_minute) < 0)
271 return false;
272 else
273 return true;
274 }
275 return false;
276 }
277
278 static bool parseHourMinuteString(String hourMinute, int *hour, int *minute) {
279 int ind = hourMinute.indexOf(':');
280 if (ind == -1)
281 return false;
282 int hr = hourMinute.substring(0, ind).toInt();
283 int mn = hourMinute.substring(ind + 1).toInt();
284 if (hr < 0 || hr > 23)
285 return false;
286 if (mn < 0 || mn > 59)
287 return false;
288 *hour = hr;
289 *minute = mn;
290 return true;
291 }
292};
293
294} // namespace ustd
mupplet helper for some astronomical calculations: sunrise and sunset
Definition: mup_astro.h:19
static double modifiedJulianDate(int year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, double sec)
Definition: mup_astro.h:101
static double fracDay(uint8_t hour, uint8_t min, double sec)
Definition: mup_astro.h:65
static int cmpHourMinuteTime(uint8_t h1, uint8_t m1, uint8_t h2, uint8_t m2)
Definition: mup_astro.h:217
static long julianDayNumber(int year, uint8_t month, uint8_t day)
Definition: mup_astro.h:38
static bool inHourMinuteInterval(uint8_t test_hour, uint8_t test_minute, uint8_t start_hour, uint8_t start_minute, uint8_t end_hour, uint8_t end_minute)
Definition: mup_astro.h:256
static double julianDate(int year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, double sec)
Definition: mup_astro.h:76
static bool calculateSunRiseSet(int year, int month, int day, double lat, double lon, int localOffset, int daylightSavings, bool bRising, double *pSunTime)
Definition: mup_astro.h:132
static int deltaHourMinuteTime(uint8_t h1, uint8_t m1, uint8_t h2, uint8_t m2)
Definition: mup_astro.h:236
Astro(double lat, double lon, double utcOffset)
Definition: mup_astro.h:28
The muwerk namespace.
Definition: home_assistant.h:10
const double C_MJD
MJD = JD - C_MJD.
Definition: mup_astro.h:13
const double C_C
speed of light, m/s
Definition: mup_astro.h:11
const double C_D2R
degree -> radians conversion
Definition: mup_astro.h:8
const double C_CAUD
AUs per day, approx 173.
Definition: mup_astro.h:12
const double C_AU
astronomical unit, meter
Definition: mup_astro.h:10
const double C_PI
PI.
Definition: mup_astro.h:7
const double C_R2D
radians -> degrees
Definition: mup_astro.h:9