SolarPosition.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: SolarPosition.cpp 2293 2010-02-12 18:14:16Z btolman $"
00002 
00007 // ======================================================================
00008 // This software was developed by Applied Research Laboratories, The
00009 // University of Texas at Austin under contract to an agency or agencies
00010 // within the U.S. Department of Defense. The U.S. Government retains all
00011 // rights to use, duplicate, distribute, disclose, or release this
00012 // software.
00013 // 
00014 // Copyright 2008 The University of Texas at Austin
00015 // ======================================================================
00016 
00017 //------------------------------------------------------------------------------------
00018 // includes
00019 // system
00020 // GPSTk
00021 #include "DayTime.hpp"
00022 #include "Position.hpp"
00023 #include "icd_200_constants.hpp"       // TWO_PI
00024 #include "geometry.hpp"                // DEG_TO_RAD
00025 
00026 #include "SolarPosition.hpp"
00027 
00028 using namespace std;
00029 
00030 //------------------------------------------------------------------------------------
00031 // Compute Greenwich Mean Sidereal Time in degrees
00032 static double GMST(gpstk::DayTime t)
00033 {
00034    static const long JulianEpoch=2451545;
00035    // days since epoch
00036    double days = t.JD() - JulianEpoch;                         // days
00037    if(days <= 0.0) days -= 1.0;
00038    double Tp = days/36525.0;                                   // dim-less
00039 
00040       // Compute GMST in radians
00041    double G;
00042    // seconds (24060s = 6h 41min)
00043    //G = 24110.54841 + (8640184.812866 + (0.093104 - 6.2e-6*Tp)*Tp)*Tp;   // sec
00044    //G /= 86400.0; // instead, divide the numbers above manually
00045    G = 0.279057273264 + 100.0021390378009*Tp        // seconds/86400 = days
00046                       + (0.093104 - 6.2e-6*Tp)*Tp*Tp/86400.0;
00047    G += t.secOfDay()/86400.0;                      // days
00048 
00049    // put answer between 0 and 360 deg
00050    G = fmod(G,1.0);
00051    while(G < 0.0) G += 1.0;
00052    G *= 360.0;                                                 // degrees
00053 
00054    return G;
00055 }
00056 
00057 namespace gpstk {
00058 
00059 //------------------------------------------------------------------------------------
00060 // accuracy is about 1 arcminute, when t is within 2 centuries of 2000.
00061 // Ref. Astronomical Almanac pg C24, as presented on USNO web site.
00062 // input
00063 //    t             epoch of interest
00064 // output
00065 //    lat,lon,R     latitude, longitude and distance (deg,deg,m in ECEF) of sun at t.
00066 //    AR            apparent angular radius of sun as seen at Earth (deg) at t.
00067 Position SolarPosition(DayTime t, double& AR) throw()
00068 {
00069    //const double mPerAU = 149598.0e6;
00070    double D;     // days since J2000
00071    double g,q;   // q is mean longitude of sun, corrected for aberration
00072    double L;     // sun's geocentric apparent ecliptic longitude (deg)
00073    //double b=0; // sun's geocentric apparent ecliptic latitude (deg)
00074    double e;     // mean obliquity of the ecliptic (deg)
00075    //double R;   // sun's distance from Earth (m)
00076    double RA;    // sun's right ascension (deg)
00077    double DEC;   // sun's declination (deg)
00078    //double AR;  // sun's apparent angular radius as seen at Earth (deg)
00079 
00080    D = t.JD() - 2451545.0;
00081    g = (357.529 + 0.98560028 * D) * DEG_TO_RAD;
00082    // AA 1990 has g = (357.528 + 0.9856003 * D) * DEG_TO_RAD;
00083    q = 280.459 + 0.98564736 * D;
00084    // AA 1990 has q = 280.460 + 0.9856474 * D;
00085    L = (q + 1.915 * sin(g) + 0.020 * sin(2*g)) * DEG_TO_RAD;
00086 
00087    e = (23.439 - 0.00000036 * D) * DEG_TO_RAD;
00088    // AA 1990 has e = (23.439 - 0.0000004 * D) * DEG_TO_RAD;
00089    RA = atan2(cos(e)*sin(L),cos(L)) * RAD_TO_DEG;
00090    DEC = asin(sin(e)*sin(L)) * RAD_TO_DEG;
00091 
00092    // equation of time = apparent solar time minus mean solar time
00093    // = [q-RA (deg)]/(15deg/hr)
00094 
00095    // compute the hour angle of the vernal equinox = GMST and convert RA to lon
00096    double lon = fmod(RA-GMST(t),360.0);
00097    if(lon < -180.0) lon += 360.0;
00098    if(lon >  180.0) lon -= 360.0;
00099 
00100    double lat = DEC;
00101 
00102    // ECEF unit vector in direction Earth to sun
00103    double xhat = cos(lat*DEG_TO_RAD)*cos(lon*DEG_TO_RAD);
00104    double yhat = cos(lat*DEG_TO_RAD)*sin(lon*DEG_TO_RAD);
00105    double zhat = sin(lat*DEG_TO_RAD);
00106 
00107    // R in AU
00108    double R = 1.00014 - 0.01671 * cos(g) - 0.00014 * cos(2*g);
00109    // apparent angular radius in degrees
00110    AR = 0.2666/R;
00111    // convert to meters
00112    R *= 149598.0e6;
00113 
00114    Position ES;
00115    ES.setECEF(R*xhat,R*yhat,R*zhat);
00116    return ES;
00117 }
00118 
00119 //------------------------------------------------------------------------------------
00120 // Compute the position (latitude and longitude, in degrees) of the sun
00121 // given the day of year and the hour of the day.
00122 // Adapted from sunpos by D. Coco 12/15/94
00123 void CrudeSolarPosition(DayTime t, double& lat, double& lon) throw()
00124 {
00125    int doy = t.DOY();
00126    int hod = int(t.secOfDay()/3600.0 + 0.5);
00127    lat = sin(23.5*DEG_TO_RAD)*sin(TWO_PI*double(doy-83)/365.25);
00128    lat = lat / sqrt(1.0-lat*lat);
00129    lat = RAD_TO_DEG*atan(lat);
00130    lon = 180.0 - hod*15.0;
00131 }
00132 
00133 //------------------------------------------------------------------------------------
00134 // Consider the sun and the earth as seen from the satellite. Let the sun be a circle
00135 // of angular radius r, center in direction s, and the earth be a (larger) circle
00136 // of angular radius R, center in direction e. The circles overlap if |e-s| < R+r;
00137 // complete overlap if |e-s| < R. Let L == |e-s|.
00138 //    What is the area of overlap if R-r < L < R+r ?
00139 // Call the two points where the circles intersect p1 and p2. Draw a line from e to s;
00140 // call the points where this line intersects the two circles r1 and R1, respectively.
00141 // Draw lines from e to s, e to p1, e to p2, s to p1 and s to p2. Call the angle
00142 // between e-s and e-p1 alpha, and that between s-e and s-p1, beta.
00143 // Draw a rectangle with top and bottom parallel to e-s passing through p1 and p2,
00144 // and with sides passing through s and r1. Similarly for e and R1. Note that the
00145 // area of intersection lies within the intersection of these two rectangles.
00146 // Call the area of the rectangle outside the circles A and B. The height H of the
00147 // rectangles is
00148 // H = 2Rsin(alpha) = 2rsin(beta)
00149 // also L = rcos(beta)+Rcos(alpha)
00150 // The area A will be the area of the rectangle
00151 //              minus the area of the wedge formed by the angle 2*alpha
00152 //              minus the area of the two triangles which meet at s :
00153 // A = RH - (2alpha/2pi)*pi*R*R - 2*(1/2)*(H/2)Rcos(alpha)
00154 // Similarly
00155 // B = rH - (2beta/2pi)*pi*r*r  - 2*(1/2)*(H/2)rcos(beta)
00156 // The area of intersection will be the area of the rectangular intersection
00157 //                            minus the area A
00158 //                            minus the area B
00159 // Intersection = H(R+r-L) - A - B
00160 //              = HR+Hr-HL -HR+alpha*R*R+(H/2)Rcos(alpha) -Hr+beta*r*r+(H/2)rcos(beta)
00161 // Cancel terms, and substitute for L using above equation L = ..
00162 //              = -(H/2)rcos(beta)-(H/2)Rcos(alpha)+alpha*R*R+beta*r*r
00163 // substitute for H/2
00164 //              = -R*R*sin(alpha)cos(alpha)-r*r*sin(beta)cos(beta)+alpha*R*R+beta*r*r
00165 // Intersection = R*R*[alpha-sin(alpha)cos(alpha)]+r*r*[beta-sin(beta)cos(beta)]
00166 // Solve for alpha and beta in terms of R, r and L using the H and L relations above
00167 // (r/R)cos(beta)=(L/R)-cos(alpha)
00168 // (r/R)sin(beta)=sin(alpha)
00169 // so
00170 // (r/R)^2 = (L/R)^2 - (2L/R)cos(alpha) + 1
00171 // cos(alpha) = (R/2L)(1+(L/R)^2-(r/R)^2)
00172 // cos(beta) = (L/r) - (R/r)cos(alpha)
00173 // and 0 <= alpha or beta <= pi
00174 //
00175 // Rearth    angular radius of the earth as seen at the satellite
00176 // Rsun      angular radius of the sun as seen at the satellite
00177 // dES       angular distance of the sun from the earth
00178 // return    fraction (0 <= f <= 1) of area of sun covered by earth
00179 // units only need be consistent
00180 double shadowFactor(double Rearth, double Rsun, double dES) throw()
00181 {
00182    if(dES >= Rearth+Rsun) return 0.0;
00183    if(dES <= fabs(Rearth-Rsun)) return 1.0;
00184    double r=Rsun, R=Rearth, L=dES;
00185    if(Rsun > Rearth) { r=Rearth; R=Rsun; }
00186    double cosalpha = (R/L)*(1.0+(L/R)*(L/R)-(r/R)*(r/R))/2.0;
00187    double cosbeta = (L/r) - (R/r)*cosalpha;
00188    double sinalpha = ::sqrt(1-cosalpha*cosalpha);
00189    double sinbeta = ::sqrt(1-cosbeta*cosbeta);
00190    double alpha = ::asin(sinalpha);
00191    double beta = ::asin(sinbeta);
00192    double shadow = r*r*(beta-sinbeta*cosbeta)+R*R*(alpha-sinalpha*cosalpha);
00193    shadow /= ::acos(-1.0)*Rsun*Rsun;
00194    return shadow;
00195 }
00196 
00197 //------------------------------------------------------------------------------------
00198 // From AA 1990 D46
00199 Position LunarPosition(DayTime t, double& AR) throw()
00200 {
00201    // days since J2000
00202    double N = t.JD()-2451545.0;
00203    // centuries since J2000
00204    double T = N/36525.0;
00205    // ecliptic longitude
00206    double lam = DEG_TO_RAD*(218.32 + 481267.883*T
00207               + 6.29 * ::sin(DEG_TO_RAD*(134.9+477198.85*T))
00208               - 1.27 * ::sin(DEG_TO_RAD*(259.2-413335.38*T))
00209               + 0.66 * ::sin(DEG_TO_RAD*(235.7+890534.23*T))
00210               + 0.21 * ::sin(DEG_TO_RAD*(269.9+954397.70*T))
00211               - 0.19 * ::sin(DEG_TO_RAD*(357.5+ 35999.05*T))
00212               - 0.11 * ::sin(DEG_TO_RAD*(259.2+966404.05*T)));
00213    // ecliptic latitude
00214    double bet = DEG_TO_RAD*(5.13 * ::sin(DEG_TO_RAD*( 93.3+483202.03*T))
00215                           + 0.28 * ::sin(DEG_TO_RAD*(228.2+960400.87*T))
00216                           - 0.28 * ::sin(DEG_TO_RAD*(318.3+  6003.18*T))
00217                           - 0.17 * ::sin(DEG_TO_RAD*(217.6-407332.20*T)));
00218    // horizontal parallax
00219    double par = DEG_TO_RAD*(0.9508
00220               + 0.0518 * ::cos(DEG_TO_RAD*(134.9+477198.85*T))
00221               + 0.0095 * ::cos(DEG_TO_RAD*(259.2-413335.38*T))
00222               + 0.0078 * ::cos(DEG_TO_RAD*(235.7+890534.23*T))
00223               + 0.0028 * ::cos(DEG_TO_RAD*(269.9+954397.70*T)));
00224 
00225    // obliquity of the ecliptic
00226    double eps = (23.439 - 0.00000036 * N) * DEG_TO_RAD;
00227 
00228    // convert ecliptic lon,lat to geocentric lon,lat
00229    double l = ::cos(bet)*::cos(lam);
00230    double m = ::cos(eps)*::cos(bet)*::sin(lam) - ::sin(eps)*::sin(bet);
00231    double n = ::sin(eps)*::cos(bet)*::sin(lam) + ::cos(eps)*::sin(bet);
00232 
00233    // convert to right ascension and declination,
00234    // (referred to mean equator and equinox of date)
00235    double RA = atan2(m,l) * RAD_TO_DEG;
00236    double DEC = asin(n) * RAD_TO_DEG;
00237 
00238    // compute the hour angle of the vernal equinox = GMST and convert RA to lon
00239    double lon = fmod(RA-GMST(t),360.0);
00240    if(lon < -180.0) lon += 360.0;
00241    if(lon >  180.0) lon -= 360.0;
00242 
00243    double lat = DEC;
00244 
00245    // apparent semidiameter of moon (in radians)
00246    AR = 0.2725 * par;
00247    // moon distance in meters
00248    double R = 1.0 / ::sin(par);
00249    R *= 6378137.0;
00250 
00251    // ECEF vector in direction Earth to moon
00252    double x = R*cos(lat*DEG_TO_RAD)*cos(lon*DEG_TO_RAD);
00253    double y = R*cos(lat*DEG_TO_RAD)*sin(lon*DEG_TO_RAD);
00254    double z = R*sin(lat*DEG_TO_RAD);
00255 
00256    Position EM;
00257    EM.setECEF(x,y,z);
00258 
00259    return EM;
00260 }
00261 
00262 //------------------------------------------------------------------------------------
00263 } // end namespace gpstk

Generated on Wed Sep 8 03:30:56 2010 for GPS ToolKit Software Library by  doxygen 1.3.9.1