Automated Chicken Coop Door

Analysis: The assumption here is that the sunrise/set timetable is one sinus wave, the rest is scaling and translating a bit

__sunrise = int (350 + ( 90*cos( ((((month-1)*30.5)+dayOfMonth)+8) /58.1) )); __

The part: (month-1)*30.5 + dayOfMonth + 8 This is a formula for dayoftheyear with a small offset 8 days.

If you fill in the days and months of the year, you will get approx. 23 march = 90; 23 june = 180; 23 sept = 270 and 23 dec = 360 (=0) . These are the solstice and equinoxes.
Note the +8 is the offset between 1 jan and 23 dec (shortest day in NH = Northern Hemisphere)

so now we can bring back the formula to: __sunrise = 350 + 90*cos( dayofyear/58.1) ; __

As the cos() needs a value between 0..2PI the dayof year must be divided by a value so that 0 is mapped on 0 and 365 is mapped upon 2PI. simple math: 365/2PI = 58.0915542... which is rounded to 58.1. This is a very small error but one better uses 58.091554 (the approx limit of Arduino float) to keep error to a minimum

This brings the formula to: __sunrise = 350 + 90 * cos(); __ where cos() varies between from [-1, 1];

90 is the half of the difference between the sunrise on 23 dec and 23 june.
350 is the middle between the two sunrises, approx the sunrise @23 march/sept

OK, now take some time to reread the analysis above.


Back to the question : Where did this come from, and how do I know if it will work for my location (Hopkinsville, KY)
We now know where it comes from - see above - and we have the means to adapt the formulas.

OK, to change this formula to the lattitude of Hopkinsville, KY

step 1: Google EARTH => 36.51 north 87.29 E
step 2: NOAA Improved Sunrise/Sunset Calculation

-- update -- the numbers below are to be checked, this are just how its done

Sunrise @23 june = 4:32 = 60 * 4 + 32 = 272
Sunrise @23 dec = 7:21 = 60 * 7 + 21 = 441
delta = 441- 272 = 169 => divide by 2 makes 85
average = (441+272)/2 = 356

So the sunrise formula for Hopkinsville, KY will be: __sunrise = 356 + 85 * cos( ((month-1)*30.5+dayOfMonth+8) /58.1); __ // removed some unneeded ()

The sunset formula can be done in same way, left as an exercise for the reader.


Some programming/optimizing hints:

As sin() and cos() are quite equal I would change the formulas a bit so it only uses cos().

as : sin(x) = -cos(x+90);

one could convert the formulas to :

void getRiseSet()
{
int doy = (month-1)*30.5+dayOfMonth;

sunrise = 350 + 90cos(( doy + 8 )/58.1);
sunset = 1075 - 90
cos(( doy + 8 )/58.1); // OK, I smuggled 1 day :slight_smile: (83+8 = 91 not 90 but as there are more rounding errors allready...
}

or max optimized to

void getRiseSet()
{
float common = 90 * cos( ((month-1)*30.5+dayOfMonth + 8 ) / 58.091554) ;
sunrise = 350 + common;
sunset = 1075 - common;
}

update 2012-10-27 :
void getRiseSet()
{
float common = 90 * cos( ((month-1)*30.5+dayOfMonth + 8 ) * 0.017214206) ; // replace division with faster multiplication
sunrise = 350 + common;
sunset = 1075 - common;
}
90 * 0.017214206 can be precalculated too but they have a different semantic meaning and the compiler might optimize it anyway.


Some interesting link I found during this exercise: - Departement Natuurkunde - Universiteit Utrecht -
and of course wikipedia - Sunrise equation - Wikipedia -

Note 1: beware that this formulas are approximations (quite good ones I think)

Note 2: these formulas don't take DST into account.

fun!!!