This project is more of a cosmological calculator than something that specifically targets the control of appliances using light levels, but it will, in conjuction with the X10 Project and a Perl script, provide all the tools you need to build this.
I must admit that my first idea was to use some sort of digital I/O to capture the output of a LDR (light dependent resistor) and use that single bit to determine when it was day or night. The problem is that you must set a balance point in this type of circuit where it indicates darkness or light, and the hysteresis of a schmidt trigger means there is a band where nothing happens in the transition. I then thought - hey - I can calculate the exact light level and use that figure. Hence this project.
The only issues with this project are that local mountain ranges and cloud cover will mean the actual light levels may vary from what the code calculates.
Here is a live run of this application (press refresh to run again)
Hardware
- Just your Linux system.
Software
- Please refer to the source code provided below.
- You can see the original code here.
- Check out details of Solar Radiation Basics here
- The gcc compiler.
- Ideally you should have your clock synchronised with an accurate time source.
Ideas
- Extend this to make a special version of crontab that works based on cosmological conditions rather than time. I am working on this and will include details soon.
- Use this to turn on your sprinklers 1hr before sunset to minimise evaporation and avoid resetting the timer through the year.
- Tell me what you have done with it.
Visualisation
If you are interested in the visualisation portion of this project, the following provides a summary of how this was done. The image at the top of this page shows green vectors from a sample location (Canberra) to the sun at various sunrise, sunset and midday positions. It illustrates the meaning of the calculated times. Clicking on the image displays a 2.2MB fly-by animation.
- A Povray scene description file was created.
- It also requires an Include file to set camera coordinates in space.
- This was done by a Perl script to handle the repetitive portions and some of the 3D spacial calculations. The key parts of this script include:
- A central sphere represents the earth.
- A smaller sphere represents the moon.
- Many longitude and latitude lines are added using thin torus objects.
- A flatten image of the Earth was mapped onto the central sphere.
- A flatten image of the Moon was mapped onto the central sphere.
- The path taken by the sun is plotted using a gold torus. Of course, the path of the sun is shown on an exagerated scale to fit onto image.
- Radial vectors are draw from the observation point on earth to small spheres representing the sun at various key times of day. The angle of these vectors is accurate
- The space between the equator of the Earth and the path of the sun is a translucent disk to help show the angle of the sun on the earth.
- 3D text is added to lable each of the key features.
- I experimented with adding a star field but it didnt look realistic and increase the image disk size.
- The Perl script also calculates a camera trajectory through space.
- The animation was created by rendering the image with Povray every 2 deg whilst moving the camera along the elliptical trajectory. Overall rendering time for 800x600 images was about 10 min on a 1.3GHz system with 512MB RAM.
- The Linux Convert utility was used to merge all of the output png frames into a single Movie file.
Code
+ Make FileThe makefile: # Compiler options are: # -g = produce GDB compatible code # -Wall = show all warnings # -o = state output executable name new: cc -g -Wall -lm -L/usr/lib -o lighttab lighttab.c
+ C++ Header File
The 'lighttab.h' header file: /* A macro to compute the number of days elapsed since 2000 Jan 0.0 */ /* (which is equal to 1999 Dec 31, 0h UT) */ #define days_since_2000_Jan_0(y,m,d) \ (367L*(y)-((7*((y)+(((m)+9)/12)))/4)+((275*(m))/9)+(d)-730530L) /* Some conversion factors between radians and degrees */ #ifndef PI #define PI 3.1415926535897932384 #endif #define RADEG ( 180.0 / PI ) #define DEGRAD ( PI / 180.0 ) /* The trigonometric functions in degrees */ #define sind(x) sin((x)*DEGRAD) #define cosd(x) cos((x)*DEGRAD) #define tand(x) tan((x)*DEGRAD) #define atand(x) (RADEG*atan(x)) #define asind(x) (RADEG*asin(x)) #define acosd(x) (RADEG*acos(x)) #define atan2d(y,x) (RADEG*atan2(y,x)) /* Following are some macros around the "workhorse" function __daylen__ */ /* They mainly fill in the desired values for the reference altitude */ /* below the horizon, and also selects whether this altitude should */ /* refer to the Sun's center or its upper limb. */ /* This macro computes the length of the day, from sunrise to sunset. */ /* Sunrise/set is considered to occur when the Sun's upper limb is */ /* 35 arc minutes below the horizon (this accounts for the refraction */ /* of the Earth's atmosphere). */ #define day_length(year,month,day,lon,lat) \ __daylen__( year, month, day, lon, lat, -35.0/60.0, 1 ) /* This macro computes the length of the day, including civil twilight. */ /* Civil twilight starts/ends when the Sun's center is 6 degrees below */ /* the horizon. */ #define day_civil_twilight_length(year,month,day,lon,lat) \ __daylen__( year, month, day, lon, lat, -6.0, 0 ) /* This macro computes the length of the day, incl. nautical twilight. */ /* Nautical twilight starts/ends when the Sun's center is 12 degrees */ /* below the horizon. */ #define day_nautical_twilight_length(year,month,day,lon,lat) \ __daylen__( year, month, day, lon, lat, -12.0, 0 ) /* This macro computes the length of the day, incl. astronomical twilight. * */ /* Astronomical twilight starts/ends when the Sun's center is 18 degrees * */ /* below the horizon. * */ #define day_astronomical_twilight_length(year,month,day,lon,lat) \ __daylen__( year, month, day, lon, lat, -18.0, 0 ) /* This macro computes times for sunrise/sunset. */ /* Sunrise/set is considered to occur when the Sun's upper limb is */ /* 35 arc minutes below the horizon (this accounts for the refraction */ /* of the Earth's atmosphere). */ #define sun_rise_set(year,month,day,lon,lat,rise,set) \ __sunriset__( year, month, day, lon, lat, -35.0/60.0, 1, rise, set ) /* This macro computes the start and end times of civil twilight. */ /* Civil twilight starts/ends when the Sun's center is 6 degrees below */ /* the horizon. */ #define civil_twilight(year,month,day,lon,lat,start,end) \ __sunriset__( year, month, day, lon, lat, -6.0, 0, start, end ) /* This macro computes the start and end times of nautical twilight. */ /* Nautical twilight starts/ends when the Sun's center is 12 degrees */ /* below the horizon. */ #define nautical_twilight(year,month,day,lon,lat,start,end) \ __sunriset__( year, month, day, lon, lat, -12.0, 0, start, end ) /* This macro computes the start and end times of astronomical twilight. * */ /* Astronomical twilight starts/ends when the Sun's center is 18 degrees * */ /* below the horizon. * */ #define astronomical_twilight(year,month,day,lon,lat,start,end) \ __sunriset__( year, month, day, lon, lat, -18.0, 0, start, end ) /* Function prototypes */ double __daylen__( int year, int month, int day, double lon, double lat, double altit, int upper_limb ); int __sunriset__( int year, int month, int day, double lon, double lat, double altit, int upper_limb, double *rise, double *set); void sunpos( double d, double *lon, double *r ); void sun_RA_dec( double d, double *RA, double *dec, double *r ); double revolution( double x ); double rev180( double x ); double GMST0( double d ); #define INV360 ( 1.0 / 360.0 )
+ Configuration File
The '.lighttab' parameter file: #-------------------------------------------------------------- # Set the configuration parameters to your current location # on the surface of the earth. # The example here is for Canberra, Australia. # # G.Collett - Written - 3 Feb 2003 # #-------------------------------------------------------------- #-------------------------------------------------------------- # Define your location on the earth. # # Longitude is the angle (+)east or (-)west of Grenwich # Latitude is the angle (+)north or (-)south of Grenwich # TimeZone is the hours (+)ahead or (-)behind Grenwich #-------------------------------------------------------------- [location] Latitude=-35.400489 Longitude=148.983089 TimeZone=10.0
+ C++ Source File
The 'lighttab.c' application source code:
/*
*--------------------------------------------------------------------------------------------
*
* lighttab.c - computes Sun rise/set times, start/end of twilight, and
* the length of the day at any date and latitude
*
* Written as DAYLEN.C, 1989-08-16
*
* Modified to SUNRISET.C, 1992-12-01
*
* (c) Paul Schlyter, 1989, 1992
*
* Released to the public domain by Paul Schlyter, December 1992
*
* Portions Modified to SUNDOWN.NLM by Cliff Haas 98-05-22
*
* Adapted by Geoff Collett to lighttab on 24 Jan 2003
* Note that you must add the time zone offset time to the UT
* times provided by this program to get the local time.
* i.e. Sun rises -4.77h UT, sets 9.31h UT
* means: Sun rises -4.77h+10 = 5.23, sets 9.31h+10 = 19.31
* Canberra:
* Latitude = -35.400489 deg
* Longitude = 148.983089 deg
* Time Zone = +10hrs
* For this code, see: http://www.adventist.org/sun/help/
* For solar radiation see: http://solardat.uoregon.edu/SolarRadiationBasics.html
* For solar data see: http://solstice.crest.org/renewables/solrad/
* For explanantions: http://vortex.plymouth.edu/sun/sun1.html
* More explanations of calcs: http://www.xylem.f2s.com/kepler/sun.html
*
* Config file is .lighttab
*--------------------------------------------------------------------------------------------
*/
//-------------------------------------------------------
// Include files
//-------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include "lighttab.h"
//-------------------------------------------------------
// Function declarations
//-------------------------------------------------------
int getIniSettingDouble(char * filename, char * section, char * parameter, double * value);
int getIniSettingString(char * filename, char * section, char * parameter, char * value);
int getIniSettingInt(char * filename, char * section, char * parameter, int * value);
int getDate(int * year, int * month, int * day, int * hour, int * minute, int * sec);
void ShowHelpMessage();
//-------------------------------------------------------
// Global variable declarations
//-------------------------------------------------------
char param_file[400] = "";
int ShowExact = 0;
int ShowCivilian = 0;
int ShowNautical = 0;
int ShowAstronomical = 0;
int ShowDebug = 0;
int ShowSpacial = 0;
int ShowParams = 0;
//-------------------------------------------------------
// Main program loop
//-------------------------------------------------------
int
main(int argc, char ** argv)
{
int year,month,day;
double lon, lat;
double daylen, civlen, nautlen, astrlen;
double rise, set, civ_start, civ_end, naut_start, naut_end,
astr_start, astr_end;
int rs, civ, naut, astr;
double TZ = 10.0L;
int hour, minute, sec;
int i;
//-------------------------------------------------------
// Parse command line variables
//-------------------------------------------------------
if(argc == 1)
{
ShowHelpMessage();
return(0);
}
for(i = 1; i < argc; i++)
{
if(!strcmp(argv[i], "-i"))
{
i++;
sscanf(argv[i], "%s", param_file);
if(param_file[0] == '\0')
{
printf("Error: the -i parameter must be followed by the name of a file like .lighttab");
return(-1);
}
}
else if(!strcmp(argv[i], "-A"))
{
ShowExact = 1;
ShowCivilian = 1;
ShowNautical = 1;
ShowAstronomical = 1;
ShowSpacial = 1;
}
else if(!strcmp(argv[i], "-e"))
{
ShowExact = 1;
}
else if(!strcmp(argv[i], "-c"))
{
ShowCivilian = 1;
}
else if(!strcmp(argv[i], "-n"))
{
ShowNautical = 1;
}
else if(!strcmp(argv[i], "-a"))
{
ShowAstronomical = 1;
}
else if(!strcmp(argv[i], "-s"))
{
ShowSpacial = 1;
}
else if(!strcmp(argv[i], "-p"))
{
ShowParams = 1;
}
else if(!strcmp(argv[i], "-d"))
{
ShowDebug = 1;
}
else
{
ShowHelpMessage();
return(0);
}
}
//-------------------------------------------------------
// Default the ini file to .lighttab if not supplied
//-------------------------------------------------------
if(strlen(param_file) <= 0)
{
sprintf(param_file, ".lighttab");
}
//-------------------------------------------------------
// Read the ini file
//-------------------------------------------------------
getIniSettingDouble(param_file, "location", "TimeZone", &TZ);
getIniSettingDouble(param_file, "location", "Latitude", &lat);
getIniSettingDouble(param_file, "location", "Longitude", &lon);
//-------------------------------------------------------
// Read the date and time from the PC clock
//-------------------------------------------------------
getDate(&year, &month, &day, &hour, &minute, &sec);
//-------------------------------------------------------
// Show settings being used if debug is on
//-------------------------------------------------------
if(ShowDebug == 1 || ShowParams == 1)
{
printf("
Settings:
Param file = %s
ShowExact = %i
ShowCivilian = %i
ShowNautical = %i
ShowAstronomical = %i
ShowSpacial = %i
TimeZone = %f
Latitude = %f deg (+ is north)
Longitude = %f deg (+ is east)
Greenwich Time = %04i_%02i_%02i %02i:%02i:%02i (y_m_d h:m:s)\n",
param_file, ShowExact, ShowCivilian, ShowNautical, ShowAstronomical, ShowSpacial,
TZ, lat, lon,
year, month, day, hour, minute, sec);
}
//-------------------------------------------------------
// Perform daylight calculations
//-------------------------------------------------------
daylen = day_length(year,month,day,lon,lat);
civlen = day_civil_twilight_length(year,month,day,lon,lat);
nautlen = day_nautical_twilight_length(year,month,day,lon,lat);
astrlen = day_astronomical_twilight_length(year,month,day, lon,lat);
rs = sun_rise_set ( year, month, day, lon, lat, &rise, &set );
civ = civil_twilight ( year, month, day, lon, lat, &civ_start, &civ_end );
naut = nautical_twilight ( year, month, day, lon, lat, &naut_start, &naut_end );
astr = astronomical_twilight( year, month, day, lon, lat, &astr_start, &astr_end );
//-------------------------------------------------------
// Report requested results
//-------------------------------------------------------
printf("Sunrise and Sunset details:\n");
printf( "\tTime at Midday %5.2fh UT (%5.2f hrs)\n", (rise+set)/2.0, (rise+set)/2.0 + TZ );
if(ShowExact == 1)
{
printf( "\tDay length: %5.2f hours\n", daylen );
switch( rs )
{
case 0:
printf("\tSun rises %5.2fh UT (%5.2f hrs)\n", rise, rise+TZ);
printf("\tSun sets %5.2fh UT (%5.2f hrs)\n", set,set+TZ );
break;
case +1:
printf("\tSun above horizon (no night)\n" );
break;
case -1:
printf("\tSun below horizon (no daytime)\n" );
break;
}
}
if(ShowCivilian == 1)
{
printf( "\tLength of twilight: civil %5.2f hours\n", (civlen-daylen)/2.0);
printf( "\tDay length with civil twilight %5.2f hours\n", civlen );
switch( civ )
{
case 0:
printf("\tCivil twilight starts %5.2fh UT (%5.2f hrs)\n", civ_start,civ_start+TZ);
printf("\tCivil twilight ends %5.2fh UT (%5.2f hrs)\n", civ_end,civ_end+TZ );
break;
case +1:
printf("\tNever darker than civil twilight (no night)\n" );
break;
case -1:
printf("\tNever as bright as civil twilight (no daytime)\n" );
break;
}
}
if(ShowNautical == 1)
{
printf( "\tLength of twilight: nautical %5.2f hours\n", (nautlen-daylen)/2.0);
printf( "\tDay length with nautical twilight %5.2f hours\n", nautlen );
switch( naut )
{
case 0:
printf("\tNautical twilight starts %5.2fh UT (%5.2f hrs)\n", naut_start, naut_start+TZ);
printf("\tNautical twilight ends %5.2fh UT (%5.2f hrs)\n", naut_end, naut_end+TZ );
break;
case +1:
printf("\tNever darker than nautical twilight (no night)\n" );
break;
case -1:
printf("\tNever as bright as nautical twilight (no daytime)\n" );
break;
}
}
if(ShowAstronomical == 1)
{
printf( "\tLength of twilight: astronomical %5.2f hours\n", (astrlen-daylen)/2.0);
printf( "\tDay length with astronomical twilight %5.2f hours\n", astrlen );
switch( astr )
{
case 0:
printf("\tAstronomical twilight starts %5.2fh UT (%5.2f hrs)\n", astr_start, astr_start+TZ);
printf("\tAstronomical twilight ends %5.2fh UT (%5.2f hrs)\n", astr_end,astr_end+TZ );
break;
case +1:
printf("\tNever darker than astronomical twilight (no night)\n" );
break;
case -1:
printf("\tNever as bright as astronomical twilight (no daytime)\n" );
break;
}
}
return(0);
}
/***************************************************************************/
// Display the usage message in the case of errors of if -h(elp) is selected.
/***************************************************************************/
void
ShowHelpMessage()
{
printf("
. . . . . . . . . .
. . . . . . . . .
. **** . .. . . .
************ . lighttab
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This a program that calculates sunrise, sunset and other
details based on latitude, longitude and date/time.
Usage: lighttab [options]
where options are:
-i [filename] Specifies the initialisation file containing lat, lon, TZ etc.
-A Display ALL output
-e Exact time standard ( 0 deg below horizon)
-c Civil time standard ( 6 deg below horizon)
-n Nautical time standard (12 deg below horizon)
-a Astronomical time standard (18 deg below horizon)
-s Display spacial details
-p Display input parameters
-h Help
-d Debug
Send comments/suggestions to:
Geoff.Collett@AcaciaLT.com.au
http://www.AcaciaLT.com.au
\n");
}
/***************************************************************************/
/* The "workhorse" function for sun rise/set times */
/* Note: year,month,date = calendar date, 1801-2099 only. */
/* Eastern longitude positive, Western longitude negative */
/* Northern latitude positive, Southern latitude negative */
/* The longitude value IS critical in this function! */
/* altit = the altitude which the Sun should cross */
/* Set to -35/60 degrees for rise/set, -6 degrees */
/* for civil, -12 degrees for nautical and -18 */
/* degrees for astronomical twilight. */
/* upper_limb: non-zero -> upper limb, zero -> center */
/* Set to non-zero (e.g. 1) when computing rise/set */
/* times, and to zero when computing start/end of */
/* twilight. */
/* *rise = where to store the rise time */
/* *set = where to store the set time */
/* Both times are relative to the specified altitude, */
/* and thus this function can be used to comupte */
/* various twilight times, as well as rise/set times */
/* Return value: 0 = sun rises/sets this day, times stored at */
/* *trise and *tset. */
/* +1 = sun above the specified "horizon" 24 hours. */
/* *trise set to time when the sun is at south, */
/* minus 12 hours while *tset is set to the south */
/* time plus 12 hours. "Day" length = 24 hours */
/* -1 = sun is below the specified "horizon" 24 hours */
/* "Day" length = 0 hours, *trise and *tset are */
/* both set to the time when the sun is at south. */
/* */
/**********************************************************************/
int
__sunriset__( int year, int month, int day, double lon, double lat,
double altit, int upper_limb, double *trise, double *tset)
{
double d, /* Days since 2000 Jan 0.0 (negative before) */
ang,
sr, /* Solar distance, astronomical units */
sRA, /* Sun's Right Ascension */
sdec, /* Sun's declination */
sradius, /* Sun's apparent radius */
t, /* Diurnal arc */
tsouth, /* Time when Sun is at south */
sidtime; /* Local sidereal time */
int rc = 0; /* Return cde from function - usually 0 */
/* Compute d of 12h local mean solar time */
d = days_since_2000_Jan_0(year, month, day);
//printf("Days: %lf\n\n", d);
d = days_since_2000_Jan_0(year,month,day) + 0.5 - lon/360.0;
/* Compute local sideral time of this moment */
sidtime = revolution( GMST0(d) + 180.0 + lon );
/* Compute Sun's RA + Decl at this moment */
sun_RA_dec( d, &sRA, &sdec, &sr );
// printf("Right ascension = [%lf], Declination = [%lf]\n", sRA, sdec);
ang = 90.0 - sdec + lat;
// printf("Estimated angle of midday sun above horizon = [%lf] deg\n", ang);
// printf("Relative brightness at [%lf] deg is [%lf] \n", ang, sind(ang));
/*
*/
/* Compute time when Sun is at south - in hours UT */
tsouth = 12.0 - rev180(sidtime - sRA)/15.0;
/* Compute the Sun's apparent radius, degrees */
sradius = 0.2666 / sr;
/* Do correction to upper limb, if necessary */
if ( upper_limb )
altit -= sradius;
/* Compute the diurnal arc that the Sun traverses to reach */
/* the specified altitide altit: */
{
double cost;
cost = ( sind(altit) - sind(lat) * sind(sdec) ) / ( cosd(lat) * cosd(sdec) );
if ( cost >= 1.0 )
rc = -1, t = 0.0; /* Sun always below altit */
else if ( cost <= -1.0 )
rc = +1, t = 12.0; /* Sun always above altit */
else
t = acosd(cost)/15.0; /* The diurnal arc, hours Note that 15 deg = 1 hr */
// printf ("Time from midday to %5.2f deg below horizon t = %5.2f hrs\n", altit, t);
//printf ("cost = %5.2f\n", cost);
}
/* Store rise and set times - in hours UT */
*trise = tsouth - t;
*tset = tsouth + t;
return rc;
} /* __sunriset__ */
/**********************************************************************/
/* The "workhorse" function */
/* Note: year,month,date = calendar date, 1801-2099 only. */
/* Eastern longitude positive, Western longitude negative */
/* Northern latitude positive, Southern latitude negative */
/* The longitude value is not critical. Set it to the correct */
/* longitude if you're picky, otherwise set to to, say, 0.0 */
/* The latitude however IS critical - be sure to get it correct */
/* altit = the altitude which the Sun should cross */
/* Set to -35/60 degrees for rise/set, -6 degrees */
/* for civil, -12 degrees for nautical and -18 */
/* degrees for astronomical twilight. */
/* upper_limb: non-zero -> upper limb, zero -> center */
/* Set to non-zero (e.g. 1) when computing day length */
/* and to zero when computing day+twilight length. */
/**********************************************************************/
double
__daylen__( int year, int month, int day, double lon, double lat, double altit, int upper_limb )
{
double d, /* Days since 2000 Jan 0.0 (negative before) */
obl_ecl, /* Obliquity (inclination) of Earth's axis */
sr, /* Solar distance, astronomical units */
slon, /* True solar longitude */
sin_sdecl, /* Sine of Sun's declination */
cos_sdecl, /* Cosine of Sun's declination */
sradius, /* Sun's apparent radius */
t; /* Diurnal arc */
/* Compute d of 12h local mean solar time */
d = days_since_2000_Jan_0(year,month,day) + 0.5 - lon/360.0;
/* Compute obliquity of ecliptic (inclination of Earth's axis) */
obl_ecl = 23.4393 - 3.563E-7 * d;
/* Compute Sun's position */
sunpos( d, &slon, &sr );
/* Compute sine and cosine of Sun's declination */
sin_sdecl = sind(obl_ecl) * sind(slon);
cos_sdecl = sqrt( 1.0 - sin_sdecl * sin_sdecl );
/* Compute the Sun's apparent radius, degrees */
sradius = 0.2666 / sr;
/* Do correction to upper limb, if necessary */
if ( upper_limb )
{
altit -= sradius;
}
/* Compute the diurnal arc that the Sun traverses to reach */
/* the specified altitide altit: */
{
double cost;
cost = ( sind(altit) - sind(lat) * sin_sdecl ) / ( cosd(lat) * cos_sdecl );
//printf("\n\nCost: %f", cost);
if ( cost >= 1.0 )
t = 0.0; /* Sun always below altit */
else if ( cost <= -1.0 )
t = 24.0; /* Sun always above altit */
else t = (2.0/15.0) * acosd(cost); /* The diurnal arc, hours */
}
if(ShowSpacial == 1)
{
printf("Spacial details:
Inclination of the earths axis = [%5.5f] deg
Solar longitude slon = [%lf] deg
Distance to sun sr = [%lf] AU
Days since 1/1/2000 d = [%lf]
Suns declination sin = [%lf]
Suns declination cos = [%lf]
Height at noon = [%lf]
Suns apparent radius sradius = [%lf]
Diurnal arc t = [%lf] (varies with civilian etc)
Length of day for %5.2f deg below horizon t = %5.2f hrs\n",
obl_ecl,slon,sr,d, sin_sdecl, cos_sdecl, sin_sdecl * sr, sradius,t, altit, t);
ShowSpacial = 0;
}
return t;
} /* __daylen__ */
/* This function computes the Sun's position at any instant */
void
sunpos( double d, double *lon, double *r )
/******************************************************/
/* Computes the Sun's ecliptic longitude and distance */
/* at an instant given in d, number of days since */
/* 2000 Jan 0.0. The Sun's ecliptic latitude is not */
/* computed, since it's always very near 0. */
/******************************************************/
{
double M, /* Mean anomaly of the Sun */
w, /* Mean longitude of perihelion */
/* Note: Sun's mean longitude = M + w */
e, /* Eccentricity of Earth's orbit */
E, /* Eccentric anomaly */
x, y, /* x, y coordinates in orbit */
v; /* True anomaly */
/* Compute mean elements */
M = revolution( 356.0470 + 0.9856002585 * d );
w = 282.9404 + 4.70935E-5 * d;
e = 0.016709 - 1.151E-9 * d;
/* Compute true longitude and radius vector */
E = M + e * RADEG * sind(M) * ( 1.0 + e * cosd(M) );
x = cosd(E) - e;
y = sqrt( 1.0 - e*e ) * sind(E);
*r = sqrt( x*x + y*y ); /* Solar distance */
v = atan2d( y, x ); /* True anomaly */
*lon = v + w; /* True solar longitude */
if ( *lon >= 360.0 )
*lon -= 360.0; /* Make it 0..360 degrees */
}
void
sun_RA_dec( double d, double *RA, double *dec, double *r )
{
double lon, obl_ecl, x, y, z;
/* Compute Sun's ecliptical coordinates */
sunpos( d, &lon, r );
/* Compute ecliptic rectangular coordinates (z=0) */
x = *r * cosd(lon);
y = *r * sind(lon);
/* Compute obliquity of ecliptic (inclination of Earth's axis) */
obl_ecl = 23.4393 - 3.563E-7 * d;
/* Convert to equatorial rectangular coordinates - x is uchanged */
z = y * sind(obl_ecl);
y = y * cosd(obl_ecl);
/* Convert to spherical coordinates */
*RA = atan2d( y, x );
*dec = atan2d( z, sqrt(x*x + y*y) );
} /* sun_RA_dec */
/******************************************************************/
/* This function reduces any angle to within the first revolution */
/* by subtracting or adding even multiples of 360.0 until the */
/* result is >= 0.0 and < 360.0 */
/******************************************************************/
#define INV360 ( 1.0 / 360.0 )
/*****************************************/
/* Reduce angle to within 0..360 degrees */
/*****************************************/
double
revolution( double x )
{
return( x - 360.0 * floor( x * INV360 ) );
} /* revolution */
/*********************************************/
/* Reduce angle to within +180..+180 degrees */
/*********************************************/
double
rev180( double x )
{
return( x - 360.0 * floor( x * INV360 + 0.5 ) );
} /* revolution */
/*******************************************************************/
/* This function computes GMST0, the Greenwhich Mean Sidereal Time */
/* at 0h UT (i.e. the sidereal time at the Greenwhich meridian at */
/* 0h UT). GMST is then the sidereal time at Greenwich at any */
/* time of the day. I've generelized GMST0 as well, and define it */
/* as: GMST0 = GMST - UT -- this allows GMST0 to be computed at */
/* other times than 0h UT as well. While this sounds somewhat */
/* contradictory, it is very practical: instead of computing */
/* GMST like: */
/* */
/* GMST = (GMST0) + UT * (366.2422/365.2422) */
/* */
/* where (GMST0) is the GMST last time UT was 0 hours, one simply */
/* computes: */
/* */
/* GMST = GMST0 + UT */
/* */
/* where GMST0 is the GMST "at 0h UT" but at the current moment! */
/* Defined in this way, GMST0 will increase with about 4 min a */
/* day. It also happens that GMST0 (in degrees, 1 hr = 15 degr) */
/* is equal to the Sun's mean longitude plus/minus 180 degrees! */
/* (if we neglect aberration, which amounts to 20 seconds of arc */
/* or 1.33 seconds of time) */
/* */
/*******************************************************************/
double
GMST0( double d )
{
double sidtim0;
/* Sidtime at 0h UT = L (Sun's mean longitude) + 180.0 degr */
/* L = M + w, as defined in sunpos(). Since I'm too lazy to */
/* add these numbers, I'll let the C compiler do it for me. */
/* Any decent C compiler will add the constants at compile */
/* time, imposing no runtime or code overhead. */
sidtim0 = revolution( ( 180.0 + 356.0470 + 282.9404 ) +
( 0.9856002585 + 4.70935E-5 ) * d );
return sidtim0;
} /* GMST0 */
int
getIniSettingInt(char * filename, char * section, char * parameter, int * value)
{
FILE * fp;
char buff[2000];
char parm[2000];
char * equals;
double val;
//---------------------------------------------------
// Open the file
//---------------------------------------------------
fp = fopen(filename, "r");
if(fp == NULL)
{
printf("Error: unable to open initialisation file [%s]\n", filename);
fclose(fp);
*value = 0.0L;
return(-1);
}
//---------------------------------------------------
// Loop, looking for the section and reading whole lines
//---------------------------------------------------
//printf("Looking for [%s]%s\n", section, parameter);
while(fscanf(fp, "%s", buff) != EOF)
{
//---------------------------------------------------
// Skip comments and blanks
//---------------------------------------------------
if(buff[0] == '#' || buff[0] == '\0' || buff[0] == '\n')
continue;
//---------------------------------------------------
// Sections start with [
//---------------------------------------------------
if(buff[0] == '[')
{
//---------------------------------------------------
// See if the section name matches
//---------------------------------------------------
if(strncmp(&buff[0], section, strlen(section)))
{
//---------------------------------------------------
// Loop, looking for the parmeter=value line
//---------------------------------------------------
while(fscanf(fp, "%s", buff) != EOF)
{
//---------------------------------------------------
// Skip comments and blanks
//---------------------------------------------------
if(buff[0] == '#' || buff[0] == '\0' || buff[0] == '\n')
continue;
//---------------------------------------------------
// Sections start with [ so give up
//---------------------------------------------------
if(buff[0] == '[')
{
printf("Error: unable to find parameter [%s]\n", parameter);
*value = 0.0L;
fclose(fp);
return(-1);
}
//---------------------------------------------------
// See if we have a match
//---------------------------------------------------
equals = strstr(&buff[0], "=");
if(equals != NULL)
{
equals[0] = '\0';
sscanf(&buff[0], "%s", parm);
sscanf(&equals[1], "%lf\n", &val);
}
if(strncmp(parm, parameter, strlen(parameter)) == 0)
{
// printf("\tFound param [%s]=[%lf]\n", parm, val);
*value = val;
fclose(fp);
return(0);
}
}
}
}
}
printf("Error: EOF encountered and unable to find parameter [%s]\n", parameter);
*value = 0.0L;
fclose(fp);
return(0);
}
int
getIniSettingDouble(char * filename, char * section, char * parameter, double * value)
{
FILE * fp;
char buff[2000];
char parm[2000];
char * equals;
double val;
//---------------------------------------------------
// Open the file
//---------------------------------------------------
fp = fopen(filename, "r");
if(fp == NULL)
{
printf("Error: unable to open initialisation file [%s]\n", filename);
fclose(fp);
*value = 0.0L;
return(-1);
}
//---------------------------------------------------
// Loop, looking for the section and reading whole lines
//---------------------------------------------------
//printf("Looking for [%s]%s\n", section, parameter);
while(fscanf(fp, "%s", buff) != EOF)
{
//---------------------------------------------------
// Skip comments and blanks
//---------------------------------------------------
if(buff[0] == '#' || buff[0] == '\0' || buff[0] == '\n')
continue;
//---------------------------------------------------
// Sections start with [
//---------------------------------------------------
if(buff[0] == '[')
{
//---------------------------------------------------
// See if the section name matches
//---------------------------------------------------
if(strncmp(&buff[0], section, strlen(section)))
{
//---------------------------------------------------
// Loop, looking for the parmeter=value line
//---------------------------------------------------
while(fscanf(fp, "%s", buff) != EOF)
{
//---------------------------------------------------
// Skip comments and blanks
//---------------------------------------------------
if(buff[0] == '#' || buff[0] == '\0' || buff[0] == '\n')
continue;
//---------------------------------------------------
// Sections start with [ so give up
//---------------------------------------------------
if(buff[0] == '[')
{
printf("Error: unable to find parameter [%s]\n", parameter);
*value = 0.0L;
fclose(fp);
return(-1);
}
//---------------------------------------------------
// See if we have a match
//---------------------------------------------------
equals = strstr(&buff[0], "=");
if(equals != NULL)
{
equals[0] = '\0';
sscanf(&buff[0], "%s", parm);
sscanf(&equals[1], "%lf\n", &val);
}
if(strncmp(parm, parameter, strlen(parameter)) == 0)
{
// printf("\tFound param [%s]=[%lf]\n", parm, val);
*value = val;
fclose(fp);
return(0);
}
}
}
}
}
printf("Error: EOF encountered and unable to find parameter [%s]\n", parameter);
*value = 0.0L;
fclose(fp);
return(0);
}
int
getIniSettingString(char * filename, char * section, char * parameter, char * value)
{
FILE * fp;
char buff[2000];
char parm[2000];
char * equals;
char val[2000];
//---------------------------------------------------
// Open the file
//---------------------------------------------------
fp = fopen(filename, "r");
if(fp == NULL)
{
printf("Error: unable to open initialisation file [%s]\n", filename);
fclose(fp);
//*value = "\0";
return(-1);
}
//---------------------------------------------------
// Loop, looking for the section and reading whole lines
//---------------------------------------------------
//printf("Looking for [%s]%s\n", section, parameter);
while(fscanf(fp, "%s", buff) != EOF)
{
//---------------------------------------------------
// Skip comments and blanks
//---------------------------------------------------
if(buff[0] == '#' || buff[0] == '\0' || buff[0] == '\n')
continue;
//---------------------------------------------------
// Sections start with [
//---------------------------------------------------
if(buff[0] == '[')
{
//---------------------------------------------------
// See if the section name matches
//---------------------------------------------------
if(strncmp(&buff[0], section, strlen(section)))
{
//---------------------------------------------------
// Loop, looking for the parmeter=value line
//---------------------------------------------------
while(fscanf(fp, "%s", buff) != EOF)
{
//---------------------------------------------------
// Skip comments and blanks
//---------------------------------------------------
if(buff[0] == '#' || buff[0] == '\0' || buff[0] == '\n')
continue;
//---------------------------------------------------
// Sections start with [ so give up
//---------------------------------------------------
if(buff[0] == '[')
{
printf("Error: unable to find parameter [%s]\n", parameter);
//*value = NULL;
fclose(fp);
return(-1);
}
//---------------------------------------------------
// See if we have a match
//---------------------------------------------------
equals = strstr(&buff[0], "=");
equals[0] = '\0';
sscanf(&buff[0], "%s", parm);
sscanf(&equals[1], "%s\n", val);
if(strncmp(parm, parameter, strlen(parameter)) == 0)
{
// printf("\tFound param [%s]=[%s]\n", parm, val);
strcpy(value, val);
fclose(fp);
return(0);
}
}
}
}
}
printf("Error: EOF encountered and unable to find parameter [%s]\n", parameter);
//*value = NULL;
fclose(fp);
return(0);
}
int
getDate(int * year, int * month, int * day, int * hour, int * minute, int * sec)
{
time_t now;
struct tm * dt;
// Get the current time
time(&now);
dt = gmtime(&now);
*year = dt->tm_year + 1900;
*month = dt->tm_mon + 1;
*day = dt->tm_mday;
*hour = dt->tm_hour;
*minute = dt->tm_min;
*sec = dt->tm_sec;
//printf("It is now %02i:%02i:%02i %02i/%02i/%04i\n", *hour, *minute, *sec, *day, *month, *year);
return(0);
}
Click here to check out the list of other projects.
You may also like to click here to check out the list of Artificial Intelligence projects.
If you would like to get any further information on this or any of the other projects shown on this web site, please send an email to Acacia Lateral Technologies. or place a comment in our Guest Book
You might also like to submit your idea to our Free Ideas page for the benefit of other like-minded soles.