Sunrise/Sunset near London 2024

Anyone worked with calculations of sunrise/sunset? The libraries I've browsed look darned complicated (and require several inputs other than latitude, longitude and day of year. (Alitude, zenith angle, refraction...). Or they need 32-bit MCUs. In contrast I'm looking for a function that would take
float myLat = 51.1287, myLon = -0.0145; // East Grinstead
and doy2024 (derived from my exsting RTClib, adafruit version)
and return four ints: sunRiseHour, sunRiseMins, sunsetHour and sunsetMins.

EDIT: Sorry, forgot this para:
I'll be trying to merge it with a project that's already at 72%/62% so I assume that an array of 366 entries would be hungrier and probably not fit in my Nano.

Whatever spherical trig I ever knew is long forgotten so I don't expect to necessarily understand the formula used!

An Uno can do 32 bit calculations, although somewhat slower. I guess you only need to do the calculation once per day, so that does not seem an issue.

You might be referring to this library GitHub - buelowp/sunset: Calculate Sunrise and Sunset and the phase of the moon accurately based on date and geographic position which claims

I have used this library on the following systems successfully, and test it on a Raspberry PI. It really does require a 32 bit system at a minimum, and due to the math needs, a 32 bit processor that has native floating point support is best. This does mean that the original Arudino and other similar 8 bit micros cannot use this library correctly.

which on the face of it sounds like total nonsense. I am looking into what the basis for this claim is.

Thanks, my mistake. And true of my Nano too (see edit).

Yes. Specifically:
Supported targets
This should work on any platform that supports C++ 14 and later. There is a hard requirement on 32 bit systems at a minimum due to needing full 32 bit integers for some of the work.

So I didn't pursue its Examples further. But briefly looking just now, I don't see a formula/function in the simple form I hope to use?

So just for fun I ported the library to AVR with a few modifications. I was about to create a fork on github, but I realised there is already an AVR version at GitHub - negre/sunset: Calculate Sunrise and Sunset and the phase of the moon accurately based on date and geographic position.

For a simplified example I used the following :

#include "sunset.h"

#if 0
/* I'm in the midwest, so this is what I use for my home */
#define LATITUDE        41.12345
#define LONGITUDE       -87.98765
#define DST_OFFSET      -5
#endif

// London, UK
#define LATITUDE        51.509865
#define LONGITUDE       -0.118092
#define DST_OFFSET      0


SunSet sun;

void setup() 
{
  Serial.begin (115200);

    /* Set our position and a default timezone value */
    sun.setPosition(LATITUDE, LONGITUDE, DST_OFFSET);
    sun.setTZOffset(DST_OFFSET);

    int year = 2024;
    int month = 2;
    int day = 9;
    
    sun.setCurrentDate(year, month, day);

    int sunrise = static_cast<int>(sun.calcSunrise());
    int sunset = static_cast<int>(sun.calcSunset());

    Serial.print("Sunrise at ");
    Serial.print(sunrise / 60);
    Serial.print(":");
    Serial.print(sunrise % 60);
    Serial.print("am, Sunset at ");
    Serial.print(sunset / 60);
    Serial.print(":");
    Serial.print(sunset % 60);
    Serial.println("pm");
}

void loop() {
  // put your main code here, to run repeatedly:

}

I tested with
a) Uno clone
b) Visual Studio 2022

and verified against a random website, and they all give the same answer.

Now I understand that the author may not want to support certain platforms, and that is his prerogative, but the claims he makes are clearly false.

Obviously the code will run slower, but I cannot see how that would be an issue.

I think if you need it for one defined place, the correct way is to calculate this data on a PC and then put it in the code in the form of a table. If you are worried about space -keep in mind that the function to calculate this data will take more than a pre-computed table for all 366 days. To store a sunrise-sunset time pair, three bytes are enough, and taking into account the fact that the time changes smoothly from day to day - you can write into the table, say, only the time for the Sundays, and for the next days store only the difference - for each day it will be enough a single byte.
As a result, the entire year table will take 366 + 52 * 2 = 470 bytes in program memory

The code for calculating sunrise is quite complex, probably uses float math and trigonometry, and cannot be kept short. I'm sure that adding a function for analytical calculation to your sketch will increase its size by much more than 470 bytes.

That would be particularly true if floating point is not used anywhere else in the code. Just adding a single floating point calculation causes the floating point library to be added to the sketch.

Yes it was a real pain. I have it running on a Nano (8 bit) and it does a nice job almost. It is buried in a very large program. I used one of the libraries (https://github.com/dmkishi/Dusk2Dawn), removed the math lib include and after a few twerks on location, time etc it appears to work.

Thanks, looks really promising and I’ll try it later this afternnoon on my Nano.

Just saved me some work, many thanks. To test my assumption, I was about to try writing an array based sketch. Although it means I’ll have to first read up again on multi-dimensional types. I’ll need those 4 values I mentioned for every one of however many days I settle on, and I’ve not done that before. I was also mere minutes ahead of you on the interpolation approach. I was thinking of populating it for say every 30th day (36 for the last set). I recall an average daily gap of 2 mins 7 secs mentioned BTW, but I expect that will vary over the year.

As for the actual data, I’m just downloading it from one of the several online tables. Will probably then play with it in Excel.
.

Thanks, interesting. That was one of the libraries I looked at. You clearly made more progress than me. I moved onto JC_Sunrise but gave up.

I suggest you research PROGMEM, and store a sunrise / sunset table in PROGMEM. This is important, because if you try storing it in RAM, it will gobble up too much RAM, so you need PROGMEM.

You could create your table using:

Also, I think you should be using bytes and not ints. Hours will be in the range 0 to 23 and can thus fit in a byte. Minutes will be in the range 0 to 59 and can thus fit in a byte as well.

Sunrise hours variation in London is only five hours from 4 to 8'clock, sunset is from 15 to 21'clock, so we can pack it both in a single byte.

By your comments, you misunderstood my idea. You don't need multidimensional arrays. The sunrise and sunset time values are stored by date in one one-dimensional array, packed into three bytes - the first byte is the sunrise and sunset hours in one byte, for example, the most significant 4 bits are sunrise and the least significant bits are sunset. The second byte is the minutes for sunrise, the third is the minutes for sunset.
And of course, this array should be in PROGMEM, and not in memory.

If you want to further reduce the size of the data, you can create two arrays, one as described above, each entry three bytes - for dates once a week, for example on Sundays. And a second array - for all other days, one byte per day, where there in upper 4bits will be the difference in sunrise time from the nearest Sunday is stored in minutes, and in lower 4bits for sunset as well.

Packing sunrise hours and sunset hours into one byte seems like premature optimization.
This is a hobby project, most likely a one-off hobby project. If the array fits in PROGMEM, it fits; there is no need to optimize for every last byte. Why make life harder than it has to be?

The author said that his project already occupies 72 percent of the program space in Nano, so optimization is unlikely to be superfluous.
Besides, I just don't like wasting a whole byte where the value only changes from 4 to 8 :slight_smile:

I'm just offering options.

1 Like

In that case, there is a trick I once used to save myself some typing when I was hand-coding a sunset table. The trick is this: only store the hours for one day of each month, and let the minutes climb past 60 as needed.

1 Like

The another option is only store the difference between days... as I suggested in #6 and 14

At the given coordinates

Sunrise ranges from 3:44 to 8:03 --> 4h 19m = 259 minutes
Sunset ranges from 15:52 to 20:19 --> 4h 27m = 267 minutes

so the range will just barely exceed a byte.

It seems like your idea will almost work. I think you would be able to make it work, if you just hand-code an if statement for the dates on which 256 minutes must be added.

Thanks both for those fresh suggestions. As I’m not a C/C++ programmer I find working with the bits of a byte hard going . But I was forced to do it once before . So I may refresh my memory and try it if simpler methods fail.
———-
.

If I’ve understood, you then use an if() on the minutes to adjust hh:mm if mm>60, yes? Also does this require any special measures in constructing the arrays.