2
$\begingroup$

There are quite some sources for astronomical calculation formulas, e.g. Astronomy Answers: Position of the Sun, which is e.g. used by KDE's Night Color plugin to calculate the time of a sunset or sunrise (when the sun's elevation is equal to a given value).

I want to do such a calculation on an Arduino Uno board. The problem is that all those formulas depend on double precision calculations, because they take and return a Julian day with the time being the fraction part. The Arduino Uno only has float precision, so the interesting part, the fraction representing the time, is lost (the Julian day alone takes all the decimal places).

Apparently, it's possible to avoid this problem, e.g. Dr. David Brooks published code to do elevation and azimuth calculations using float precision only in Arduino Uno solar calculations. He splits the Julian day into an integer day part and a float time part.

However, those formulas only work for the current position of the sun at a given date, time and location, not vice versa. I'm interested in calculating the moment in time where the sun has e.g. a given elevation (a defined sunrise and sunset).

I thought that one approach to solve this could be to find the very first Julian day with the very same Earth-Sun constellation, where e.g. the sun had the same elevation at the same time. The day itself is not interesting, as I already know it – I only want to get the time. This way, the Julian day would be <= 365, leaving at least four digits to the time fraction. This would lead to a precision of about 10 s, which would be more than sufficient for my use-case.

So: Is it possible to find the first Julian day with the same Earth-Sun constellation as a given date? Like some modulo operation for a Julian day?

Thanks for all help!

$\endgroup$
3
  • $\begingroup$ Arduino float is IEEE-754 binary32, which has a 24 bit significand. $\endgroup$
    – PM 2Ring
    Commented Jun 5, 2022 at 19:32
  • $\begingroup$ Using float for T (Julian centuries since 2000.1.1) currently gives a granularity of ~90 seconds. That is, if $T=0.22$ then the smallest time step that makes a difference to $T$ is around 90 seconds. I'll put a live demo program (in Python) in the next comment. $\endgroup$
    – PM 2Ring
    Commented Jun 5, 2022 at 19:46
  • $\begingroup$ Granularity demo $\endgroup$
    – PM 2Ring
    Commented Jun 5, 2022 at 19:47

2 Answers 2

4
$\begingroup$

Most formulas accept a Julian Day as input, but internally usually use the number of days (or years, or centuries) since Jan 1, 2000 12:00pm. Take the function below, which accepts JD as input, but the first thing it does is compute n=jd-2451545.0, then uses n for the remainder of the calculations. So it's an easy modification to just have it accept n as the parameter, and not use Julian Days at all in the calling program.

    //Low precision sun position from Astronomical Almanac page C5 (2017 ed).
    //Accuracy 1deg from 1950-2050
    function sunPosition(jd)    {
        const torad=Math.PI/180.0;
        n=jd-2451545.0;
        L=(280.460+0.9856474*n)%360;
        g=((375.528+.9856003*n)%360)*torad;
        if(L<0){L+=360;}
        if(g<0){g+=Math.PI*2.0;}

        lamba=(L+1.915*Math.sin(g)+0.020*Math.sin(2*g))*torad;
        beta=0.0;
        eps=(23.439-0.0000004*n)*torad;
        ra=Math.atan2(Math.cos(eps)*Math.sin(lamba),Math.cos(lamba));
        dec=Math.asin(Math.sin(eps)*Math.sin(lamba));
        if(ra<0){ra+=Math.PI*2;}
        return [ra/torad/15.0,dec/torad];
    }

Here is an example that uses this is function to compute the sun rise and set for a given location.

The here is the Algorithm to solve for a give Altitude or Azimuth

$\endgroup$
4
  • $\begingroup$ Thanks! But the problem with this is that we still end up with e.g. for today 8189 as the Julian 2000 day. So with float precision on Arduino I think, we only have three digits left for the time fraction. This would result in a precision of almost 1,5 minutes … well, this is better than nothing. I'll try this out. $\endgroup$ Commented Jun 4, 2022 at 8:39
  • $\begingroup$ Arduino supports "double" types, just not on the Uno or Mega. So you might also look into a different board if you can. $\endgroup$ Commented Jun 4, 2022 at 15:14
  • 1
    $\begingroup$ Of course, you can simply use a board that CAN calculate doubles. But the challenge is to do it with floats only ;-) $\endgroup$ Commented Jun 5, 2022 at 17:40
  • $\begingroup$ You should mention the language that code is written in. I guess it's JavaScript, and so it's using 64 bit double arithmetic. $\endgroup$
    – PM 2Ring
    Commented Jun 5, 2022 at 19:53
1
$\begingroup$

First, a direct answer to your question (as I understand it), and then a different suggestion.

The modulus you are looking for here that brings the Sun and Earth back to the same relative position (in a way that’s relevant for sunrise/sunset calculations rather than positions of stars) is simply a year. More precisely, it is a tropical year. However, that definition doesn’t actually help you that much (at least if you want ~minute precision) because there are year-to-year variations of this of order 5 minutes or so due to the influence of the Moon and planets on Earth’s position.

That said, there is a pretty simple solution, using the code you already linked to. That code calculates the Sun’s elevation for a given date and time. To get the sunrise or sunset time, simply iterate over times in the day until you find the moment where the elevation is zero (though instead you probably want something -0.83 degrees, see explanation here).

Fewer than 12 iterations (0 to 12 hours) would get you the correct hour of sunrise, then <60 iterations each to narrow in on the minute and second. That might seem inefficient (and at some level it is) but it would happen in a tiny fraction of a second; you’re never going to notice the difference between that and some more efficient code you could spend a lot of time writing.

$\endgroup$
6
  • 1
    $\begingroup$ You don't have to iterate to find the 0 Alt point, it can be found directly: celestialprogramming.com/risesetalgorithm.html . Though some iteration will still be necessary, as you'll need to recompute the RA/Dec of the Sun at the rise/set times to get a more accurate result. $\endgroup$ Commented Jun 5, 2022 at 14:12
  • $\begingroup$ @GregMiller Agreed - it just depends on how much code the OP wants to rewrite to work around the float vs. double issue. My suggestion is intended to make it possible to find the sunrise/set with the adequate-precision code already available, without having to work around precision issues in other code. $\endgroup$ Commented Jun 5, 2022 at 14:16
  • $\begingroup$ Of course, I would like to find a way to calculate the moment in time for a given elevation using float precision only WITHOUT having to iterate around it … but this seems to be no trivial task … $\endgroup$ Commented Jun 5, 2022 at 17:39
  • $\begingroup$ @TobiasLeupold Using Greg's suggestion, you only need 2 or 3 iterations to get sunrise / sunset times, starting from the declination at (local) noon. That's using double arithmetic. Working with floats, you probably don't need to iterate at all, since your times have limited precision. $\endgroup$
    – PM 2Ring
    Commented Jun 5, 2022 at 20:00
  • 1
    $\begingroup$ @Eric The tropical year can certainly be used to get the time in the next year when the Sun's RA & declination are repeated. But the time of day of that event will be ~5h48m later, due to the fractional part of the tropical year. So it takes a little more work to do the alt-azimuth calculations. $\endgroup$
    – PM 2Ring
    Commented Jun 5, 2022 at 21:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .