Go Down

### Topic: Automated Chicken Coop Door (Read 14989 times)previous topic - next topic

#### SouthernAtHeart

##### Jul 13, 2011, 05:56 pm
I see most of my coding has been done before, saving me a lot of time!

http://arduino.cc/forum/index.php/topic,8705.0.html

There are the lines:
Code: [Select]
`sunrise = int(350 + (90*cos(((((month-1)*30.5)+dayOfMonth)+8)/58.1)));  sunset = int(1075 + (90*sin(((((month-1)*30.5)+dayOfMonth)-83)/58.1)));`
Where did this come from, and how do I know if it will work for my location (Hopkinsville, KY)

#### bilbo

#1
##### Jul 13, 2011, 07:30 pm
Any equation to find sunrise sunset is based on location. In order to rewrite it for your location, take a look at this: take a look at this: http://williams.best.vwh.net/sunrise_sunset_algorithm.htm . One question: why not use a light sensor to figure out sunrise/sunset instead of an expensive RTC and lots of math? IMHO, that makes a lot more sense.

#### robtillaart

#2
##### Jul 13, 2011, 08:32 pmLast Edit: Aug 08, 2015, 01:23 pm by robtillaart
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: http://www.srrb.noaa.gov/highlights/sunrise/sunrise.html

-- 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 + 90*cos(( doy + 8 )/58.1);
sunset = 1075 - 90*cos(( doy + 8 )/58.1);    // OK,  I smuggled 1 day     (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: - http://www.astro.uu.nl/~strous/AA/en/antwoorden/zonpositie.html -
and of course wikipedia - http://en.wikipedia.org/wiki/Sunrise_equation -

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

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

fun!!!
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

#### retrolefty

#3
##### Jul 13, 2011, 08:34 pmLast Edit: Jul 13, 2011, 08:36 pm by retrolefty Reason: 1
Quote
One question: why not use a light sensor to figure out sunrise/sunset instead of an expensive RTC and lots of math? IMHO, that makes a lot more sense.

Overcast days, fogged in mornings or evenings, full moon Vs new moon, stormy weather? I would think ambient light level would be a very unreliable indications of exact sunrise and sunset times?

Lefty

#### robtillaart

#4
##### Jul 13, 2011, 09:05 pm

BTW an automated chicken door could also be based upon a microphone checking the morning call of the rooster
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

#5

#### SouthernAtHeart

#6
##### Jul 13, 2011, 11:05 pm
IT'LL TAKE ME 2 WEEKS TO GET OVER THE ANSWER TO THIS QUESTION!

#### robtillaart

#7
##### Jul 13, 2011, 11:48 pm

OK,

- exact numbers  for Hopkinsville, KY  based upon - http://www.srrb.noaa.gov/highlights/sunrise/sunrise.html

Sunrise @23 jun = 4:32= 60 * 4 + 32= 272
Sunrise @23 dec = 7:00 = 60 * 7 + 00 = 420
delta = 420- 272 = 148 => divide by 2 makes 74
average = (420+272)/2 = 346

Sunset @23 jun = 19:13 = 60 * 19 + 23= 1163
Sunset @23 dec = 16:38 = 60 * 16 + 38= 998
delta = 1163 - 998 = 165 => divide by 2 makes 82
average = (1163 + 998)/2 = 1080

So the formulas for Hopkinsville, KY will be:
Code: [Select]
`void getRiseSet(){  float common = cos( ((month-1)*30.5+dayOfMonth + 8 ) / 58.091554) ;    sunrise = 346 + 74 * common;  sunset =  1080 - 82 * common;    }`

I hope I saved you two weeks, but please spent an hour or so to understand the story, maybe I have bugged up somewhere and you should be able to fix it

@ SouthernAtHeart,  don't read below this line

What amazed me is that the sunset has a bigger spread (delta is 8 minutes larger) than the sunrise. can't explain this yet ...?

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

#### SouthernAtHeart

#8
##### Jul 14, 2011, 12:30 am
In the original code (what I posted in #1)
Code: [Select]
`sunrise = int(350 + (90*cos(((((month-1)*30.5)+dayOfMonth)+8)/58.1)));  sunset = int(1075 + (90*sin(((((month-1)*30.5)+dayOfMonth)-83)/58.1)));`
it has 350 + ....
and 1075 + ....

but yours has

346 + ...
1080 - ....
should that be 1080 + ...

I haven't spent an hour on it, but 20 minutes or so.  I understand the jist of it, but doubt I could troubleshoot your formula. If you made a mistake, you're going to here from my chickens! (if they can get out of the pen)

#### robtillaart

#9
##### Jul 14, 2011, 12:46 am
Quote
but yours has

346 + ...
1080 - ....
should that be 1080 + ...

The change of sign is introduced as I rewrote the sin(x) with a  -cos(x + 90) ;   (and yes I smuggled 1 day )

If I apply the above rewriteing on the original formula the sign will change.

Code: [Select]
`sunrise = int(350 + (90*cos(((((month-1)*30.5)+dayOfMonth)+8)/58.1)));  sunset = int(1075 - (90*cos(((((month-1)*30.5)+dayOfMonth)+8)/58.1)));`

To explain it otherwise, first note that the whole long part (90*....)  is the same now due to the rewrite

If it becomes summer that long part will go to -1
sunrise = 350 + 90 * -1  => sinrise is earlier
sunset = 1075 - 90 * -1  => sunset is later
days are becoming longer.

If it becomes winter that long part will go to 1
sunrise = 350 + 90 * 1  => sunrise is later and later
sunset = 1075 - 90 * -1  => sunset is earlier and earlier
days are becoming shorter

The formula is in essence :   sunrise = average sunrise +  Func(dayOfTheYear);    // idem for sunset

more clear now?

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

#### SouthernAtHeart

#10
##### Jul 14, 2011, 01:03 am
It's VERY clear that you understand it!  I follow the jist of it, but it's a little gray yet.
I'll move on now to something simpler like watching the little 1-wire temperature sensor, and turning an AC relay on if it gets too hot or too cold (for a fan, or a drinking water heater)
I'll be back when I run into trouble!

#### robtillaart

#11
##### Jul 14, 2011, 01:12 am

write a small sketch that uses the formula and let it generate a list of sunrises and sunsets. You see that it will be reasonable correct (+_ 5 minutes)

Quote
I'll be back when I run into trouble!

If you have problems with this one, PM me.  Add a link to this discussion.

Quote
I'll move on now to something simpler like watching the little 1-wire temperature sensor, and turning an AC relay on if it gets too hot or too cold

Also a fun project, familiar with - http://www.milesburton.com/Dallas_Temperature_Control_Library - ??
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

#### SouthernAtHeart

#12
##### Jul 26, 2011, 04:17 am
Thanks, robtillaart, I've gone thru this code a few more times, and have understood it enough to redo it for another GPS location!  It's not too complicated once you understand it,  and I DO much prefer to understand the code I use, rather than use it and not know how it does what it does...

My next question:
This one has me stumped.   I'm using an RTC to get my date info.  Each time I get the date, I want to check to see if it is:
1) after the second Sunday in March, &
2) before the first Sunday in November

I thought I use a boolean function that returns TRUE if it is DST, or FALSE if it's not DST

Code: [Select]
`boolean CheckDST(){/*Starts: Second Sunday in MarchEnds: First Sunday in November*/    if (month >= 3 && dayOfWeek <= 11) {    //It's a DST month         ...not sure here...                }month, dayOfWeek, dayOfMonth, etc are all global variables that are updated to the current date`

#### gerg

#13
##### Jul 26, 2011, 02:39 pm

I see most of my coding has been done before, saving me a lot of time!

Having previously written a sunrise/sunset algorithm (+-1 minute, based on current GPS location) before, whereby it took an embarrassingly long time to write/debug, I tip my hat to you for a dramatically simplified approximation. Nicely done.

If anyone cares, my implementation was used to automatically brighten and dim the display of an android device while providing considerable power savings over that of the common auto adjust logic. If you have an android device and struggle with battery life, turning off auto brightness typically saves a fair amount.
http://maniacalbits.blogspot.com

#### wildbill

#14
##### Jul 26, 2011, 07:45 pm
Just curious - why does it matter whether it's DST? I'd assumed that you're opening the coop at astronomical sunrise - are there other functions that are affected by what time people think it is?

Go Up