How to locate the sun

Referring to the Wikipedia articles Solar Zenith Angle and Solar Azimuth Angle, we have two equations. 'A' comes before 'Z', so lets attack azimuth first. Put into code, we have...

Azimuth = atan ( sin(HourAngle) / (cos(HourAngle) * sin(Latitude) - tan(Declination) * cos(Latitude)))

We need 3 inputs to this equation. The first input we need is HourAngle, and... what the heck is that? HourAngle can be defined as the current angle of rotation of the Earth, with respect to a solar day. It ranges from -180 to +180 degrees, with 0 degrees being solar noon. Luckily, AVR-Libc provides the solar_noon() function, from which we can derive the HourAngle for a point in time...
HourAngle
	#include <math.h>
	#include <time.h>
	time_t * point_in_time;
	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 r = tday - noon;                              // offset from noon, -43200 to + 43200 seconds
	double HourAngle = r / 86400.0;                    // hour angle as percentage of full day
	HourAngle = HourAngle * 2.0 * M_PI;                // hour angle in radians


The second thing we need is Declination, which is the current angle of the Sun above Earths equatorial plane. Again, AVR-Libc provides a function for that...
Declination
   double Declination = solar_declination(point_in_time);


Finally, we need the Latitude. AVR-Libc has a global long, __latitude, which we need to convert from seconds of arc into radians...
Latitude
  extern long __latitude;
  #define RAD_TO_DEGREE 57.29577951308233
  double Latitude = __latitude / ( ONE_DEGREE * RAD_TO_DEGREE); // latitude in radians


Lets write a function to compute the azimuth...

Solar Azimuth
#include <math.h>
#include <time.h>
#define RAD_TO_DEGREE 57.29577951308233
double SolarAzimuth(time_t * point_in_time){

  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 r = tday - noon;                                   // offset from noon, -43200 to + 43200 seconds
  double HourAngle = r / 86400.0;                         // hour angle as percentage of full day
  HourAngle = HourAngle * 2.0 * M_PI;                     // hour angle in radians

  double Declination = solar_declination(point_in_time);  // declination in radians

  extern long  __latitude;
  double Latitude =  __latitude / ( ONE_DEGREE * RAD_TO_DEGREE);          // latitude in radians

  double Azimuth = atan ( sin(HourAngle) / (cos(HourAngle) * sin(Latitude) - tan(Declination) * cos(Latitude)));

  return Azimuth; // return azimuth in radians
}


For altitude, the equation is...

Altitude = asin( cos(HourAngle) * cos(Declination) * cos(Latitude) + sin(Declination) * sin(Latitude));

We can write the function...

Solar Altitude
double SolarAltitude(time_t * point_in_time){

  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 r = tday - noon;                                   // offset from noon, -43200 to + 43200 seconds
  double HourAngle = r / 86400.0;                         // hour angle as percentage of full day
  HourAngle = HourAngle * 2.0 * M_PI;                     // hour angle in radians

  double Declination = solar_declination(point_in_time);  // declination in radians

  extern long  __latitude;
  Latitude =  __latitude / ( ONE_DEGREE * RAD_TO_DEGREE);          // latitude in radians

  Altitude = asin( cos(HourAngle) * cos(Declination) * cos(Latitude) + sin(Declination) * sin(Latitude));

  return Altitude; // altitude in radians

}


Now, generally whenever we need the altitude, we also need the azimuth, & vice versa. There is a lot of common code between the two functions, so we could merge them...

Solar Position
#include <math.h>
#include <time.h>
#define RAD_TO_DEGREE 57.29577951308233
void SolarPosition(time_t * point_in_time, double * Azimuth, double * Altitude){


  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 r = tday - noon;                                   // offset from noon, -43200 to + 43200 seconds
  double HourAngle = r / 86400.0;                         // hour angle as percentage of full day
  HourAngle = HourAngle * 2.0 * M_PI;                     // hour angle in radians

  double Declination = solar_declination(point_in_time);  // declination in radians

  extern long  __latitude;
  double Latitude =  __latitude / ( ONE_DEGREE * RAD_TO_DEGREE);          // latitude in radians

  *Azimuth = atan ( sin(HourAngle) / (cos(HourAngle) * sin(Latitude) - tan(Declination) * cos(Latitude)));
  *Altitude = asin( cos(HourAngle) * cos(Declination) * cos(Latitude) + sin(Declination) * sin(Latitude));
}


Now we only have to compute HourAngle, Declination, and Latitude once. Next, lets look at all those trig functions. We compute many of these twice. Lets re-arrange to compute everything just once...

Solar Position (optimized)
#include <math.h>
#include <time.h>
#define RAD_TO_DEGREE 57.29577951308233
void SolarPosition(time_t * point_in_time, double * Azimuth, double * Altitude){


  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 r = tday - noon;                                   // offset from noon, -43200 to + 43200 seconds
  double HourAngle = r / 86400.0;                         // hour angle as percentage of full day
  HourAngle = HourAngle * 2.0 * M_PI;                     // hour angle in radians

  double Declination = solar_declination(point_in_time);  // declination in radians

  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 );
}



As noted in the Wiki articles, these algorithms are approximations. However, they do come quite close, the error being less than 1 degree over most of the Earth, at most times.

Error generally increases with latitude. In particular, where Latitude == 90 degrees - Declination, an attempted division by zero will produce wildly inaccurate results. We could test for this condition and correct for it, but we leave that as an exercise for the reader.

This algorithm also does not take into account atmospheric refraction. Causing light to bend around the horizon, the sun can appear above the horizion, when geometrically it is actually below.

The azimuth computed by this function uses the 'traditional' definition, where the azimuth is negative in the morning after sunrise, zero at solar noon, and positive in the afternoon... in other words the azimuth approximates the HourAngle.
Questions and comments can be sent to