1 |
greg |
1.1 |
#ifndef lint |
2 |
greg |
2.7 |
static const char RCSid[] = "$Id: sun.c,v 2.6 2013/08/09 16:51:15 greg Exp $"; |
3 |
greg |
1.1 |
#endif |
4 |
greg |
1.2 |
/* |
5 |
greg |
1.1 |
* SOLAR CALCULATIONS |
6 |
|
|
* |
7 |
|
|
* 3/31/87 |
8 |
|
|
* |
9 |
greg |
2.7 |
* Michalsky algorithm added October 2019: |
10 |
|
|
* "The Astronomical Almanac's Algorithm for Approximate |
11 |
|
|
* Solar Position (1950-2050)" by Joseph J. Michalsky, |
12 |
|
|
* published in 1988 in Solar Energy, Vol. 40, No. 3. |
13 |
|
|
* Also added correction to sdec() (365 was 368 originally) |
14 |
|
|
* |
15 |
greg |
1.1 |
*/ |
16 |
|
|
|
17 |
greg |
2.2 |
#include <math.h> |
18 |
greg |
2.6 |
#include "sun.h" |
19 |
greg |
2.2 |
|
20 |
greg |
2.5 |
#ifdef M_PI |
21 |
|
|
#define PI M_PI |
22 |
|
|
#else |
23 |
greg |
2.7 |
#define PI 3.14159265358979323846 |
24 |
greg |
2.5 |
#endif |
25 |
greg |
2.7 |
#undef DEG |
26 |
|
|
#define DEG (PI/180.) |
27 |
|
|
|
28 |
greg |
1.1 |
|
29 |
greg |
2.7 |
double s_latitude = 0.66; /* site latitude (radians north of equator) */ |
30 |
|
|
double s_longitude = 2.13; /* site longitude (radians west of Greenwich) */ |
31 |
|
|
double s_meridian = 120.*DEG; /* standard meridian (radians west) */ |
32 |
greg |
1.1 |
|
33 |
|
|
|
34 |
|
|
int |
35 |
schorsch |
2.4 |
jdate( /* Julian date (days into year) */ |
36 |
|
|
int month, |
37 |
|
|
int day |
38 |
|
|
) |
39 |
greg |
1.1 |
{ |
40 |
|
|
static short mo_da[12] = {0,31,59,90,120,151,181,212,243,273,304,334}; |
41 |
|
|
|
42 |
|
|
return(mo_da[month-1] + day); |
43 |
|
|
} |
44 |
|
|
|
45 |
|
|
|
46 |
|
|
double |
47 |
schorsch |
2.4 |
stadj( /* solar time adjustment from Julian date */ |
48 |
|
|
int jd |
49 |
|
|
) |
50 |
greg |
1.1 |
{ |
51 |
greg |
2.7 |
return( 0.170 * sin( (4.*PI/373.) * (jd - 80) ) - |
52 |
|
|
0.129 * sin( (2.*PI/355.) * (jd - 8) ) + |
53 |
|
|
(12./PI) * (s_meridian - s_longitude) ); |
54 |
greg |
1.1 |
} |
55 |
|
|
|
56 |
|
|
|
57 |
|
|
double |
58 |
schorsch |
2.4 |
sdec( /* solar declination angle from Julian date */ |
59 |
|
|
int jd |
60 |
|
|
) |
61 |
greg |
1.1 |
{ |
62 |
greg |
2.7 |
return( 0.4093 * sin( (2.*PI/365.) * (jd - 81) ) ); |
63 |
greg |
1.1 |
} |
64 |
|
|
|
65 |
|
|
|
66 |
|
|
double |
67 |
schorsch |
2.4 |
salt( /* solar altitude from solar declination and solar time */ |
68 |
|
|
double sd, |
69 |
|
|
double st |
70 |
|
|
) |
71 |
greg |
1.1 |
{ |
72 |
|
|
return( asin( sin(s_latitude) * sin(sd) - |
73 |
greg |
2.7 |
cos(s_latitude) * cos(sd) * cos(st*(PI/12.)) ) ); |
74 |
greg |
1.1 |
} |
75 |
|
|
|
76 |
|
|
|
77 |
|
|
double |
78 |
schorsch |
2.4 |
sazi( /* solar azimuth from solar declination and solar time */ |
79 |
|
|
double sd, |
80 |
|
|
double st |
81 |
|
|
) |
82 |
greg |
1.1 |
{ |
83 |
greg |
2.7 |
return( -atan2( cos(sd)*sin(st*(PI/12.)), |
84 |
greg |
1.1 |
-cos(s_latitude)*sin(sd) - |
85 |
greg |
2.7 |
sin(s_latitude)*cos(sd)*cos(st*(PI/12.)) ) ); |
86 |
|
|
} |
87 |
|
|
|
88 |
|
|
|
89 |
|
|
/****************** More accurate Michalsky algorithm ****************/ |
90 |
|
|
|
91 |
|
|
|
92 |
|
|
/* circle normalization */ |
93 |
|
|
static double |
94 |
|
|
norm_cir(double r, const double p) |
95 |
|
|
{ |
96 |
|
|
while (r < 0) r += p; |
97 |
|
|
while (r >= p) r -= p; |
98 |
|
|
return(r); |
99 |
|
|
} |
100 |
|
|
|
101 |
|
|
|
102 |
|
|
/* Almanac Julian date relative to noon UT on Jan 1, 2000 (fractional days) */ |
103 |
|
|
double |
104 |
|
|
mjdate(int year, int month, int day, double hour) |
105 |
|
|
{ |
106 |
|
|
int jd = jdate(month, day); |
107 |
|
|
jd += (month > 2) & !(year&3); |
108 |
|
|
jd += (year - 1949)*365 + (year - 1949)/4; |
109 |
|
|
hour += s_meridian*(12./PI); |
110 |
|
|
return(jd + hour*(1./24.) + (2432916.5-2451545.)); |
111 |
|
|
} |
112 |
|
|
|
113 |
|
|
|
114 |
|
|
/* Solar declination (and solar time) from Almanac Julian date (fractional) */ |
115 |
|
|
double |
116 |
|
|
msdec(double mjd, double *stp) |
117 |
|
|
{ /* Ecliptic coordinates (radians) */ |
118 |
|
|
double L = norm_cir(280.460*DEG + 0.9856474*DEG*mjd, 2.*PI); |
119 |
|
|
double g = norm_cir(357.528*DEG + 0.9856003*DEG*mjd, 2.*PI); |
120 |
|
|
double l = L + 1.915*DEG*sin(g) + 0.020*DEG*sin(2.*g); |
121 |
|
|
double ep = 23.439*DEG - 4e-7*DEG*mjd; |
122 |
|
|
double sin_l = sin(l); |
123 |
|
|
|
124 |
|
|
if (stp) { /* solar time requested, also? */ |
125 |
|
|
double ra = atan2(sin_l*cos(ep), cos(l)); |
126 |
|
|
double utime = 24.*(mjd - floor(mjd)) + 12.; |
127 |
|
|
double gmst = 6.697375 + 0.0657098242*mjd + utime; |
128 |
|
|
double lmst = gmst - s_longitude*(12./PI); |
129 |
|
|
|
130 |
|
|
*stp = norm_cir(lmst - ra*(12./PI) + 12., 24.); |
131 |
|
|
} |
132 |
|
|
return(asin(sin(ep)*sin_l)); /* return solar declination angle */ |
133 |
greg |
1.1 |
} |