Some of those operations can be done away with by the use of interpolation tables. That works well, for a limited range of time. But tables grow quickly as the range increases.

Using either long form formulas or huge lookup tables, in the general avr context, is... lunacy.

However, if we can be satisfied with an approximation, and allow an error of a few degrees, we

At solar noon, on the day of the 'new moon', Earth, Moon, and Sun are lined up... the angle between moon and sun is zero. If we check again at noon the following day, we will notice that the angle between the Sun and Moon has increased , and a tiny portion of the Moons Eastern hemisphere is visible.

Continuing as the moon 'waxes', the angle has increased to 90 degrees at the time of the First Quarter, when the Moons entire Eastern Hemisphere is lit.

This angle is called the Elongation of the Moon. It's easy to see that the Phase and Elongation are related. AVR-Libc provides a function, moon_phase(), that returns the phase as a percentage. We can get the Elongation easily from moon_phase()...

- In Degrees : El = moon_phase() * 1.8
- In Radians : El = moon_phase() * M_PI / 100.0
- In Hours : El = moon_phase() * 12.0
- In Seconds : El = moon_phase() * 432

Given the elongation of the moon El in hours, we can say that the Moon reaches its highest point in the sky El hours before the Sun does. Indeed, for any lunar 'event', that event will occur El hours before the equivalent solar event... and that includes the rising and setting of the moon. Since AVR-Libc provides the functions sun_rise() and sun_set(), we can proceed to determine the time of the equivalent lunar events...

time_t MoonRise(time_t * point_in_time){ time_t sunrise = sun_rise(point_in_time); long elongation = moon_phase(&sunrise) * 432L; return sunrise + elongation; }

Wasn't that too easy?! Lets do MoonSet()...

time_t MoonSet(time_t * point_in_time){ time_t sunset = sun_set(point_in_time); long elongation = moon_phase(&sunset) * 432L; return sunset + elongation; }

A typical lunatic is satisfied with the moons phase and time of rising / setting. The most outrageously lunatic, however, want to keep track of where the moon is at all times. To obtain the altitude and azimuth of the moon, we must know the moons Hour Angle and its Declination.

The declination is easy. The Moon orbits the Earth almost on the same plane that the Earth orbits the Sun, the 'Ecliptic' plane, tilted by about 5 degrees. We can approximate the declination of the moon simply by substituting the declination of the sun. Since AVR-Libc provides the solar_declination() function, we have that part of it in the bag.

Now, about the Hour Angle of the Moon, HA

#include <math.h> #include <time.h> #define RAD_TO_DEGREE 57.29577951308233 double MoonHourAngle(time_t * point_in_time){ // compute hour angle of sun (in seconds) time_t noon = solar_noon(point_in_time) % ONE_DAY; // time of noon mod one day time_t tday = *point_in_time % ONE_DAY; // current time mod one day long HAsun = tday - noon; // offset from noon, -43200 to + 43200 seconds // compute elongation of moon in seconds long elongation = moon_phase(point_in_time) * 432L; // compute moon hour angle in seconds double HAmoon = HAsun - elongation; // convert to radians HAmoon *= M_PI; return HAmoon / 43200.0; }

Given the Moons Hour Angle and Declination, we are now in a position to obtain the altitude and azimuth. We will re-use the AltAz() function described in the previous article, and reproduced here...

void AltAz(double HourAngle, double Declination, double * Azimuth, double * Altitude){ extern long __latitude; double Latitude = __latitude / ( ONE_DEGREE * RAD_TO_DEGREE); // latitude in radians double CosHourAngle = cos(HourAngle); double SinLatitude = sin(Latitude); double CosLatitude = cos(Latitude); *Azimuth = atan ( sin(HourAngle) / ( CosHourAngle * SinLatitude - tan(Declination ) * CosLatitude ) ); *Altitude = asin( CosHourAngle * cos(Declination) * CosLatitude + sin(Declination) * SinLatitude ); }

So finally, to obtain the moons position...

void MoonPosition(time_t * point_in_time, double * Azimuth, double * Altitude){ double HAmoon = MoonHourAngle(point_in_time); double Declination = solar_declination(point_in_time); AltAz( HAmoon, Declination, Azimuth, Altitude ); }

Questions and comments can be sent to