00001 00004 #include <math.h> 00005 00006 #define HR_PER_RADIAN (12.0 / PI) 00007 #define PI_OVER_180 (PI / 180) 00008 #define raddeg (PI / 180) 00009 #define degrad (180 / PI) 00010 #define COS85DEG 0.08715574274765817355806427083747 00011 00012 static short days_thru_month[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; // Ignores leap years... 00013 00014 //Solpos 00015 // cumulative number of days prior to beginning of month - SOLPOS constants 00016 static int month_days[2][13] = { { 0, 0, 31, 59, 90, 120, 151, 00017 181, 212, 243, 273, 304, 334 }, 00018 { 0, 0, 31, 60, 91, 121, 152, 00019 182, 213, 244, 274, 305, 335 } }; 00020 00021 //Perez tilt model coefficients - extracted from Perez et al., 1990. 00022 static double perez_tilt_coeff_F1[3][8] = {{-0.008, 0.130, 0.330, 0.568, 0.873, 1.132, 1.060, 0.678}, 00023 {0.588, 0.683, 0.487, 0.187, -0.392, -1.237, -1.600, -0.327}, 00024 {-0.062, -0.151, -0.221, -0.295, -0.362, -0.412, -0.359, -0.250}}; 00025 00026 static double perez_tilt_coeff_F2[3][8] = {{-0.060, -0.019, 0.055, 0.109, 0.226, 0.288, 0.264, 0.156}, 00027 {0.072, 0.066, -0.064, -0.152, -0.462, -0.823, -1.127, -1.377}, 00028 {-0.022, -0.029, -0.026, -0.014, 0.001, 0.056, 0.131, 0.251}}; 00029 00030 //Boundaries for Perez model "discrete sky clearness" categories - from Perez et al., 1990 00031 static double perez_clearness_limits[8] = {1.0, 1.065, 1.230, 1.500, 1.950, 2.800, 4.500, 6.200}; 00032 00033 class SolarAngles { 00034 private: 00035 // No instance data (for now). Someday it may be useful to 00036 // keep latitude, longitude, and standard meridian as member 00037 // data, but that would complicate using the class for multiple 00038 // locations sequentially... 00039 00040 public: 00041 00042 // The order of the arguments across methods is not always 00043 // consistent. They're that way to match the S-PLUS and C 00044 // implementations, which are that way for no particular reason... 00045 00046 SolarAngles(void); 00047 ~SolarAngles(void); 00048 00049 double eq_time(short day_of_yr); // hours 00050 double solar_time(double std_time, short day_of_yr, double std_meridian, double longitude); // decimal hours 00051 double local_time(double std_time, short day_of_yr, double std_meridian, double longitude); // decimal hours 00052 double declination(short day_of_yr); // radians 00053 double cos_incident(double latitude, double slope, double az, double sol_time, short day_of_yr); // unitless 00054 double incident(double latitude, double slope, double az, double sol_time, short day_of_yr); // radians 00055 double zenith(short day_of_yr, double latitude, double sol_time); // radians 00056 double altitude(short day_of_yr, double latitude, double sol_time); // radians 00057 double hr_sunrise(short day_of_yr, double latitude); // decimal hours 00058 double day_len(short day_of_yr, double latitude); // decimal hours 00059 short day_of_yr(short month, short day); // julian days 00060 //sjin: add solar elevation and azimuth funcions 00061 double elevation(short day_of_yr, double latitude, double sol_time); 00062 double azimuth(short day_of_yr, double latitude, double sol_time); 00063 00064 //Most additions below here are from the NREL Solar Position algorithm 2.0 00065 //http://rredc.nrel.gov/solar/codesandalgorithms/solpos/aboutsolpos.html 00066 //Perez model function at the end (perez_tilt) extracted from referenced paper 00067 typedef struct SOLPOS_TRIGDATA //used to pass calculated values locally 00068 { 00069 double cd; // cosine of the declination 00070 double ch; // cosine of the hour angle 00071 double cl; // cosine of the latitude 00072 double sd; // sine of the declination 00073 double sl; // sine of the latitude 00074 }; 00075 00076 typedef struct SOLPOS_POSDATA 00077 { 00078 /***** ALPHABETICAL LIST OF COMMON VARIABLES *****/ 00079 /* Each comment begins with a 1-column letter code: 00080 I: INPUT variable 00081 O: OUTPUT variable 00082 T: TRANSITIONAL variable used in the algorithm, 00083 of interest only to the solar radiation 00084 modelers, and available to you because you 00085 may be one of them. 00086 00087 The FUNCTION column indicates which sub-function 00088 within solpos must be switched on using the 00089 "function" parameter to calculate the desired 00090 output variable. All function codes are 00091 defined in the solpos.h file. The default 00092 S_ALL switch calculates all output variables. 00093 Multiple functions may be or'd to create a 00094 composite function switch. For example, 00095 (S_TST | S_SBCF). Specifying only the functions 00096 for required output variables may allow solpos 00097 to execute more quickly. 00098 00099 The S_DOY mask works as a toggle between the 00100 input date represented as a day number (daynum) 00101 or as month and day. To set the switch (to 00102 use daynum input), the function is or'd; to 00103 clear the switch (to use month and day input), 00104 the function is inverted and and'd. 00105 00106 For example: 00107 pdat->function |= S_DOY (sets daynum input) 00108 pdat->function &= ~S_DOY (sets month and day input) 00109 00110 Whichever date form is used, S_solpos will 00111 calculate and return the variables(s) of the 00112 other form. See the soltest.c program for 00113 other examples. */ 00114 00115 /* VARIABLE I/O Function Description */ 00116 /* ------------- ---- ---------- ---------------------------------------*/ 00117 00118 int day; /* I/O: S_DOY Day of month (May 27 = 27, etc.) 00119 solpos will CALCULATE this by default, 00120 or will optionally require it as input 00121 depending on the setting of the S_DOY 00122 function switch. */ 00123 int daynum; /* I/O: S_DOY Day number (day of year; Feb 1 = 32 ) 00124 solpos REQUIRES this by default, but 00125 will optionally calculate it from 00126 month and day depending on the setting 00127 of the S_DOY function switch. */ 00128 int function; /* I: Switch to choose functions for desired 00129 output. */ 00130 int hour; /* I: Hour of day, 0 - 23, DEFAULT = 12 */ 00131 int interval; /* I: Interval of a measurement period in 00132 seconds. Forces solpos to use the 00133 time and date from the interval 00134 midpoint. The INPUT time (hour, 00135 minute, and second) is assumed to 00136 be the END of the measurement 00137 interval. */ 00138 int minute; /* I: Minute of hour, 0 - 59, DEFAULT = 0 */ 00139 int month; /* I/O: S_DOY Month number (Jan = 1, Feb = 2, etc.) 00140 solpos will CALCULATE this by default, 00141 or will optionally require it as input 00142 depending on the setting of the S_DOY 00143 function switch. */ 00144 int second; /* I: Second of minute, 0 - 59, DEFAULT = 0 */ 00145 int year; /* I: 4-digit year (2-digit year is NOT 00146 allowed */ 00147 00148 /***** doubleS *****/ 00149 00150 double amass; /* O: S_AMASS Relative optical airmass */ 00151 double ampress; /* O: S_AMASS Pressure-corrected airmass */ 00152 double aspect; /* I: Azimuth of panel surface (direction it 00153 faces) N=0, E=90, S=180, W=270, 00154 DEFAULT = 180 */ 00155 double azim; /* O: S_SOLAZM Solar azimuth angle: N=0, E=90, S=180, 00156 W=270 */ 00157 double cosinc; /* O: S_TILT Cosine of solar incidence angle on 00158 panel */ 00159 double coszen; /* O: S_REFRAC Cosine of refraction corrected solar 00160 zenith angle */ 00161 double dayang; /* T: S_GEOM Day angle (daynum*360/year-length) 00162 degrees */ 00163 double declin; /* T: S_GEOM Declination--zenith angle of solar noon 00164 at equator, degrees NORTH */ 00165 double eclong; /* T: S_GEOM Ecliptic longitude, degrees */ 00166 double ecobli; /* T: S_GEOM Obliquity of ecliptic */ 00167 double ectime; /* T: S_GEOM Time of ecliptic calculations */ 00168 double elevetr; /* O: S_ZENETR Solar elevation, no atmospheric 00169 correction (= ETR) */ 00170 double elevref; /* O: S_REFRAC Solar elevation angle, 00171 deg. from horizon, refracted */ 00172 double eqntim; /* T: S_TST Equation of time (TST - LMT), minutes */ 00173 double erv; /* T: S_GEOM Earth radius vector 00174 (multiplied to solar constant) */ 00175 double etr; /* O: S_ETR Extraterrestrial (top-of-atmosphere) 00176 W/sq m global horizontal solar 00177 irradiance */ 00178 double etrn; /* O: S_ETR Extraterrestrial (top-of-atmosphere) 00179 W/sq m direct normal solar 00180 irradiance */ 00181 double etrtilt; /* O: S_TILT Extraterrestrial (top-of-atmosphere) 00182 W/sq m global irradiance on a tilted 00183 surface */ 00184 double gmst; /* T: S_GEOM Greenwich mean sidereal time, hours */ 00185 double hrang; /* T: S_GEOM Hour angle--hour of sun from solar noon, 00186 degrees WEST */ 00187 double julday; /* T: S_GEOM Julian Day of 1 JAN 2000 minus 00188 2,400,000 days (in order to regain 00189 single precision) */ 00190 double latitude; /* I: Latitude, degrees north (south negative) */ 00191 double longitude; /* I: Longitude, degrees east (west negative) */ 00192 double lmst; /* T: S_GEOM Local mean sidereal time, degrees */ 00193 double mnanom; /* T: S_GEOM Mean anomaly, degrees */ 00194 double mnlong; /* T: S_GEOM Mean longitude, degrees */ 00195 double rascen; /* T: S_GEOM Right ascension, degrees */ 00196 double press; /* I: Surface pressure, millibars, used for 00197 refraction correction and ampress */ 00198 double prime; /* O: S_PRIME Factor that normalizes Kt, Kn, etc. */ 00199 double sbcf; /* O: S_SBCF Shadow-band correction factor */ 00200 double sbwid; /* I: Shadow-band width (cm) */ 00201 double sbrad; /* I: Shadow-band radius (cm) */ 00202 double sbsky; /* I: Shadow-band sky factor */ 00203 double solcon; /* I: Solar constant (NREL uses 1367 W/sq m) */ 00204 double ssha; /* T: S_SRHA Sunset(/rise) hour angle, degrees */ 00205 double sretr; /* O: S_SRSS Sunrise time, minutes from midnight, 00206 local, WITHOUT refraction */ 00207 double ssetr; /* O: S_SRSS Sunset time, minutes from midnight, 00208 local, WITHOUT refraction */ 00209 double temp; /* I: Ambient dry-bulb temperature, degrees C, 00210 used for refraction correction */ 00211 double tilt; /* I: Degrees tilt from horizontal of panel */ 00212 double timezone; /* I: Time zone, east (west negative). 00213 USA: Mountain = -7, Central = -6, etc. */ 00214 double tst; /* T: S_TST True solar time, minutes from midnight */ 00215 double tstfix; /* T: S_TST True solar time - local standard time */ 00216 double unprime; /* O: S_PRIME Factor that denormalizes Kt', Kn', etc. */ 00217 double utime; /* T: S_GEOM Universal (Greenwich) standard time */ 00218 double zenetr; /* T: S_ZENETR Solar zenith angle, no atmospheric 00219 correction (= ETR) */ 00220 double zenref; /* O: S_REFRAC Solar zenith angle, deg. from zenith, 00221 refracted */ 00222 //Added variables - Perez model 00223 double diff_horz; //Diffuse horizontal radiation for Perez tilt model calculations 00224 double dir_norm; //Direct normal radiation for Perez tilt model calculations 00225 double extra_irrad; //Extraterrestrial direct normal irradiance 00226 double perez_horz; //Horizontal scalar from Perez diffuse model 00227 int perez_skyclear_idx; //Sky clearness index from Perez tilt model 00228 double perez_skyclear; //Sky clearness epsilon value from Perez tilt model 00229 double perez_brightness; //Sky brightness value from Perez tilt model 00230 double perez_F1; //F1 coefficient calculation from Perez tilt model 00231 double perez_F2; //F2 coefficient calculation from Perez tilt model 00232 }; 00233 00234 SOLPOS_POSDATA solpos_vals; //Working variable for all solpos calculations 00235 00236 int S_solpos(SOLPOS_POSDATA *pdat); 00237 void S_init(SOLPOS_POSDATA *pdat); 00238 00239 void doy2dom( SOLPOS_POSDATA *pdat ); 00240 void geometry( SOLPOS_POSDATA *pdat ); 00241 void zen_no_ref ( SOLPOS_POSDATA *pdat, SOLPOS_TRIGDATA *tdat ); 00242 void ssha( SOLPOS_POSDATA *pdat, SOLPOS_TRIGDATA *tdat ); 00243 void sbcf( SOLPOS_POSDATA *pdat, SOLPOS_TRIGDATA *tdat ); 00244 void tst( SOLPOS_POSDATA *pdat ); 00245 void srss( SOLPOS_POSDATA *pdat ); 00246 void sazm( SOLPOS_POSDATA *pdat, SOLPOS_TRIGDATA *tdat ); 00247 void refrac( SOLPOS_POSDATA *pdat ); 00248 void amass( SOLPOS_POSDATA *pdat ); 00249 void prime( SOLPOS_POSDATA *pdat ); 00250 void etr( SOLPOS_POSDATA *pdat ); 00251 void tilt( SOLPOS_POSDATA *pdat ); 00252 void perez_tilt( SOLPOS_POSDATA *pdat ); 00253 00254 };