kopia lustrzana https://github.com/peterhinch/micropython-samples
astronomy: Apply algorithm improvements.
rodzic
d3790626c4
commit
9ef5dd7f96
|
@ -14,6 +14,13 @@ algorithms I am unlikely to be able to offer an opinion, still less a fix.
|
||||||
|
|
||||||
The code is currently under development: the API may change.
|
The code is currently under development: the API may change.
|
||||||
|
|
||||||
|
## Applications
|
||||||
|
|
||||||
|
There are two application areas. Firstly timing of events relative to sun or
|
||||||
|
moon rise and set times, discussed later in this doc. Secondly constructing
|
||||||
|
lunar clocks such as this one - the "lunartick":
|
||||||
|
![Image](./lunartick.jpg)
|
||||||
|
|
||||||
## Licensing and acknowledgements
|
## Licensing and acknowledgements
|
||||||
|
|
||||||
The code was ported from C/C++ as presented in "Astronomy on the Personal
|
The code was ported from C/C++ as presented in "Astronomy on the Personal
|
||||||
|
|
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 514 KiB |
|
@ -7,6 +7,8 @@
|
||||||
# ISBN 978-3-540-67221-0
|
# ISBN 978-3-540-67221-0
|
||||||
# Also contributions from Raul Kompaß and Marcus Mendenhall: see
|
# Also contributions from Raul Kompaß and Marcus Mendenhall: see
|
||||||
# https://github.com/orgs/micropython/discussions/13075
|
# https://github.com/orgs/micropython/discussions/13075
|
||||||
|
# Raul Kompaß perfomed major simplification of the maths for deriving rise and set_times.
|
||||||
|
|
||||||
|
|
||||||
import time
|
import time
|
||||||
from math import sin, cos, sqrt, fabs, atan, radians, floor, pi
|
from math import sin, cos, sqrt, fabs, atan, radians, floor, pi
|
||||||
|
@ -127,10 +129,10 @@ def minisun(t):
|
||||||
x = cos(l)
|
x = cos(l)
|
||||||
y = coseps * sl
|
y = coseps * sl
|
||||||
z = sineps * sl
|
z = sineps * sl
|
||||||
rho = sqrt(1 - z * z)
|
# rho = sqrt(1 - z * z)
|
||||||
# dec = (360.0 / 2 * pi) * atan(z / rho)
|
# dec = (360.0 / 2 * pi) * atan(z / rho)
|
||||||
ra = ((48.0 / (2 * pi)) * atan(y / (x + rho))) % 24
|
# ra = ((48.0 / (2 * pi)) * atan(y / (x + rho))) % 24
|
||||||
return z, rho, ra
|
return x, y, z
|
||||||
|
|
||||||
|
|
||||||
def minimoon(t):
|
def minimoon(t):
|
||||||
|
@ -185,10 +187,10 @@ def minimoon(t):
|
||||||
w = sin(b_moon)
|
w = sin(b_moon)
|
||||||
y = coseps * v - sineps * w
|
y = coseps * v - sineps * w
|
||||||
z = sineps * v + coseps * w
|
z = sineps * v + coseps * w
|
||||||
rho = sqrt(1.0 - z * z)
|
# rho = sqrt(1.0 - z * z)
|
||||||
# dec = (360.0 / 2 * pi) * atan(z / rho)
|
# dec = (360.0 / 2 * pi) * atan(z / rho)
|
||||||
ra = ((48.0 / (2 * pi)) * atan(y / (x + rho))) % 24
|
# ra = ((48.0 / (2 * pi)) * atan(y / (x + rho))) % 24
|
||||||
return z, rho, ra
|
return x, y, z
|
||||||
|
|
||||||
|
|
||||||
class RiSet:
|
class RiSet:
|
||||||
|
@ -205,6 +207,7 @@ class RiSet:
|
||||||
|
|
||||||
# ***** API start *****
|
# ***** API start *****
|
||||||
# Examine Julian dates either side of current one to cope with localtime.
|
# Examine Julian dates either side of current one to cope with localtime.
|
||||||
|
# 707μs on RP2040 at standard clock and with local time == UTC
|
||||||
def set_day(self, day: int = 0):
|
def set_day(self, day: int = 0):
|
||||||
mjd = get_mjd(day)
|
mjd = get_mjd(day)
|
||||||
if self.mjd is None or self.mjd != mjd:
|
if self.mjd is None or self.mjd != mjd:
|
||||||
|
@ -234,6 +237,11 @@ class RiSet:
|
||||||
def moonphase(self) -> float:
|
def moonphase(self) -> float:
|
||||||
return self._phase
|
return self._phase
|
||||||
|
|
||||||
|
# May need to temporarily adjust self.mjd
|
||||||
|
# def is_up(self, sun=True):
|
||||||
|
# t = ((time.time() % 86400) + self.lto) / 3600
|
||||||
|
# return sin_alt(t, sun) > 0
|
||||||
|
|
||||||
def set_lto(self, t): # Update the offset from UTC
|
def set_lto(self, t): # Update the offset from UTC
|
||||||
lto = round(t * 3600) # Localtime offset in secs
|
lto = round(t * 3600) # Localtime offset in secs
|
||||||
if self.lto != lto: # changed
|
if self.lto != lto: # changed
|
||||||
|
@ -251,18 +259,16 @@ class RiSet:
|
||||||
mr, ms = self.rise_set(False) # Moon
|
mr, ms = self.rise_set(False) # Moon
|
||||||
# Adjust for local time. Store in ._times if value is in 24-hour
|
# Adjust for local time. Store in ._times if value is in 24-hour
|
||||||
# local time window
|
# local time window
|
||||||
self.adjust(sr, day, 0)
|
self.adjust((sr, ss, mr, ms), day)
|
||||||
self.adjust(ss, day, 1)
|
|
||||||
self.adjust(mr, day, 2)
|
|
||||||
self.adjust(ms, day, 3)
|
|
||||||
self.mjd = mjd
|
self.mjd = mjd
|
||||||
|
|
||||||
def adjust(self, n, day, idx):
|
def adjust(self, times, day):
|
||||||
if n is not None:
|
for idx, n in enumerate(times):
|
||||||
n += self.lto + (day - 1) * 86400
|
if n is not None:
|
||||||
h = n // 3600
|
n += self.lto + (day - 1) * 86400
|
||||||
if 0 <= h < 24:
|
h = n // 3600
|
||||||
self._times[idx] = n
|
if 0 <= h < 24:
|
||||||
|
self._times[idx] = n
|
||||||
|
|
||||||
def _format(self, n, variant):
|
def _format(self, n, variant):
|
||||||
if variant == 0: # Default: secs since Midnight (local time)
|
if variant == 0: # Default: secs since Midnight (local time)
|
||||||
|
@ -278,9 +284,9 @@ class RiSet:
|
||||||
return f"{hr:02d}:{mi:02d}:{sec:02d}"
|
return f"{hr:02d}:{mi:02d}:{sec:02d}"
|
||||||
|
|
||||||
# See https://github.com/orgs/micropython/discussions/13075
|
# See https://github.com/orgs/micropython/discussions/13075
|
||||||
def lmst(self, t):
|
def lstt(self, t):
|
||||||
# Takes the mjd and the longitude (west negative) and then returns
|
# Takes the mjd and the longitude (west negative) and then returns
|
||||||
# the local sidereal time in hours. Im using Meeus formula 11.4
|
# the local sidereal time in degrees. Im using Meeus formula 11.4
|
||||||
# instead of messing about with UTo and so on
|
# instead of messing about with UTo and so on
|
||||||
# modified to use the pre-computed 't' value from sin_alt
|
# modified to use the pre-computed 't' value from sin_alt
|
||||||
d = t * 36525
|
d = t * 36525
|
||||||
|
@ -289,24 +295,23 @@ class RiSet:
|
||||||
c2 = 0.98564736629
|
c2 = 0.98564736629
|
||||||
dsum = c1 * df + c2 * d # no large integer * 360 here
|
dsum = c1 * df + c2 * d # no large integer * 360 here
|
||||||
lst = 280.46061837 + dsum + 0.000387933 * t * t - t * t * t / 38710000
|
lst = 280.46061837 + dsum + 0.000387933 * t * t - t * t * t / 38710000
|
||||||
return (lst % 360) / 15.0 + self.long / 15
|
return lst % 360
|
||||||
|
|
||||||
def sin_alt(self, hour, func):
|
def sin_alt(self, hour, sun):
|
||||||
# Returns the sine of the altitude of the object (moon or sun)
|
# Returns the sine of the altitude of the object (moon or sun)
|
||||||
# at an hour relative to the current date (mjd)
|
# at an hour relative to the current date (mjd)
|
||||||
mjd1 = (self.mjd - 51544.5) + hour / 24.0
|
func = minisun if sun else minimoon
|
||||||
# mjd1 = self.mjd + hour / 24.0
|
mjd = (self.mjd - 51544.5) + hour / 24.0
|
||||||
t1 = mjd1 / 36525.0
|
# mjd = self.mjd + hour / 24.0
|
||||||
sin_dec, cos_dec, ra = func(t1)
|
t = mjd / 36525.0
|
||||||
# hour angle of object: one hour = 15 degrees. Note lmst() uses longitude
|
x, y, z = func(t)
|
||||||
tau = 15.0 * (self.lmst(t1) - ra)
|
tl = self.lstt(t) + self.long # Local mean sidereal time adjusted for logitude
|
||||||
# sin(alt) of object using the conversion formulas
|
return self.sglat * z + self.cglat * (x * cos(radians(tl)) + y * sin(radians(tl)))
|
||||||
return self.sglat * sin_dec + self.cglat * cos_dec * cos(radians(tau))
|
|
||||||
|
|
||||||
# Modified to find sunrise and sunset only, not twilight events.
|
# Modified to find sunrise and sunset only, not twilight events.
|
||||||
|
# Calculate rise and set times of sun or moon for the current MJD. Times are
|
||||||
|
# relative to that 24 hour period.
|
||||||
def rise_set(self, sun):
|
def rise_set(self, sun):
|
||||||
# this is my attempt to encapsulate most of the program in a function
|
|
||||||
# then this function can be generalised to find all the Sun events.
|
|
||||||
t_rise = None # Rise and set times in secs from midnight
|
t_rise = None # Rise and set times in secs from midnight
|
||||||
t_set = None
|
t_set = None
|
||||||
sinho = sin(radians(-0.833)) if sun else sin(radians(8 / 60))
|
sinho = sin(radians(-0.833)) if sun else sin(radians(8 / 60))
|
||||||
|
@ -315,12 +320,11 @@ class RiSet:
|
||||||
# The loop finds the sin(alt) for sets of three consecutive
|
# The loop finds the sin(alt) for sets of three consecutive
|
||||||
# hours, and then tests for a single zero crossing in the interval
|
# hours, and then tests for a single zero crossing in the interval
|
||||||
# or for two zero crossings in an interval for for a grazing event
|
# or for two zero crossings in an interval for for a grazing event
|
||||||
func = minisun if sun else minimoon
|
yp = self.sin_alt(0, sun) - sinho
|
||||||
yp = self.sin_alt(0, func) - sinho
|
|
||||||
for hour in range(1, 24, 2):
|
for hour in range(1, 24, 2):
|
||||||
ym = yp
|
ym = yp
|
||||||
yz = self.sin_alt(hour, func) - sinho
|
yz = self.sin_alt(hour, sun) - sinho
|
||||||
yp = self.sin_alt(hour + 1, func) - sinho
|
yp = self.sin_alt(hour + 1, sun) - sinho
|
||||||
nz, z1, z2, ye = quad(ym, yz, yp) # Find horizon crossings
|
nz, z1, z2, ye = quad(ym, yz, yp) # Find horizon crossings
|
||||||
if nz == 1: # One crossing found
|
if nz == 1: # One crossing found
|
||||||
if ym < 0.0:
|
if ym < 0.0:
|
||||||
|
|
Ładowanie…
Reference in New Issue