SolarRadiationPressure.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: SolarRadiationPressure.cpp 2457 2010-08-18 14:20:12Z coandrei $"
00002 
00010 //============================================================================
00011 //
00012 //  This file is part of GPSTk, the GPS Toolkit.
00013 //
00014 //  The GPSTk is free software; you can redistribute it and/or modify
00015 //  it under the terms of the GNU Lesser General Public License as published
00016 //  by the Free Software Foundation; either version 2.1 of the License, or
00017 //  any later version.
00018 //
00019 //  The GPSTk is distributed in the hope that it will be useful,
00020 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00021 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022 //  GNU Lesser General Public License for more details.
00023 //
00024 //  You should have received a copy of the GNU Lesser General Public
00025 //  License along with GPSTk; if not, write to the Free Software Foundation,
00026 //  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00027 //
00028 //  Wei Yan - Chinese Academy of Sciences . 2009, 2010
00029 //
00030 //============================================================================
00031 
00032 #include "SolarRadiationPressure.hpp"
00033 #include "ASConstant.hpp"
00034 #include "ReferenceFrames.hpp"
00035 
00036 namespace gpstk
00037 {
00038 
00039       /* Determines if the satellite is in sunlight or shadow.
00040        * Taken from Montenbruck and Gill p. 80-83
00041        * @param r ECI position vector of spacecraft [m].
00042        * @param r_Sun Sun position vector (geocentric) [m].
00043        * @param r_Moon Moon position vector (geocentric) [m].
00044        * @return 0.0 if in shadow, 1.0 if in sunlight, 0 to 1.0 if in partial shadow
00045        */
00046    double SolarRadiationPressure::getShadowFunction(Vector<double> r, 
00047                                                     Vector<double> r_Sun,
00048                                                     Vector<double> r_Moon,
00049                                                     SolarRadiationPressure::ShadowModel sm)
00050    {
00051       // shadow function
00052       double v = 0.0;
00053       
00054       // Mean Radious of Sun, Moon and Earth
00055       const double R_sun = ASConstant::R_Sun;
00056       const double R_moon = ASConstant::R_Moon;
00057       const double R_earth = ASConstant::R_Earth;
00058 
00059       Vector<double> e_Sun = r_Sun/norm(r_Sun);   // Sun direction unit vector
00060 
00061       double r_dot_sun = dot(r,e_Sun);
00062       
00063       if(r_dot_sun>0)
00064       {
00065          // Sunny side of central body is always fully lit and return
00066          v= 1.0;
00067          return v;
00068       }
00069       
00070       if(sm == SM_CYLINDRICAL)      
00071       {
00072          // Taken fram Jisheng Li P111, and checked with GMAT and Bernese5 SHADOW.f
00073          v = ((r_dot_sun>0 || norm(r-r_dot_sun*e_Sun)>R_earth) ? 1.0 : 0.0);
00074          return v;
00075       }
00076       else if(sm == SM_CONICAL)
00077       {
00078          /*
00079          // Taken from Montenbruck and Gill p. 80-83
00080          double s0, s2;
00081          
00082          // Montenbruck and Gill, eq. 3.79
00083          s0 = -dot(r,e_Sun); //-state[0]*unitsun[0] - state[1]*unitsun[1] - state[2]*unitsun[2];
00084          s2 = dot(r,r);      //state[0]*state[0] + state[1]*state[1] + state[2]*state[2];
00085 
00086          // Montenbruck and Gill, eq. 3.80
00087          double lsc = sqrt(s2 - s0*s0);
00088 
00089          // Montenbruck and Gill, eq. 3.81
00090          double sinf1 = (R_sun + R_earth) / norm(r_Sun);
00091          double sinf2 = (R_earth - R_earth) / norm(r_Sun);
00092          
00093          // Appropriate l1 and l2 temporarily
00094          double t1 = sinf1 * sinf1;
00095          double t2 = sinf2 * sinf2;
00096          double tanf1 = sqrt(t1 / (1.0 - t1));
00097          double tanf2 = sqrt(t2 / (1.0 - t2));
00098          
00099          // Montenbruck and Gill, eq. 3.82
00100          double c1 = s0 + R_earth / sinf1;
00101          double c2 = R_earth / sinf2 - s0;       // Different sign from M&G
00102 
00103          // Montenbruck and Gill, eq. 3.83
00104          double l1 = c1 * tanf1;
00105          double l2 = c2 * tanf2;
00106 
00107          if (lsc > l1)   // Outside of the penumbral cone
00108          {
00109             v = 1.0;
00110             return v;
00111          }
00112          else 
00113          {
00114             //lit = false;
00115             if (lsc < fabs(l2)) 
00116             {
00117                // Inside umbral cone
00118                if (c2 >= 0.0) 
00119                { 
00120                   // no annular ring
00121                   percentSun = 0.0;
00122                   dark = true;
00123                }
00124                else 
00125                {
00126                   // annular eclipse
00127                   pcbrad = asin(R_earth / sqrt(s2));
00128                   percentSun = (psunrad*psunrad - pcbrad*pcbrad) / 
00129                      (psunrad*psunrad);
00130                   dark = false;
00131                }
00132 
00133                return;
00134             }
00135             // In penumbra
00136             pcbrad = asin(R_earth / sqrt(s2));
00137             percentSun = ShadowFunction(state);
00138             lit = false;
00139             dark = false;
00140          }*/
00141 
00143 
00144          double r_sun_mag = norm(r_Sun);
00145          double r_mag = norm(r);
00146          
00147          Vector<double> d = r_Sun-r;            // vector from sc to sun
00148          double dmag = norm(d);               
00149 
00150          double a = std::asin(R_sun/dmag);               // eq. 3.85
00151          double b = std::asin(R_earth/r_mag);               // eq. 3.86
00152          double c = std::acos(-1.0*dot(r,d)/(r_mag*dmag));   // eq. 3.87
00153 
00154          if((a+b)<=c)         // in Sun light
00155          {
00156             v = 1.0;
00157          }
00158          else if(c < (b-a))      // in Umbra
00159          {
00160             v =  0.0;
00161          }
00162          else               // in Penumbra 
00163          {
00164             double x = (c*c+a*a-b*b)/(2*c);                     // eq. 3.93
00165             double y = std::sqrt(a*a-x*x);
00166             double A = a*a*std::acos(x/a)+b*b*std::acos((c-x)/b)-c*y;         // eq. 3.92
00167             v = 1.0 - A/(ASConstant::PI*a*a);                  // eq. 3.94
00168          }
00169 
00170          return v;
00171       }
00172       else
00173       {
00174          // unexpected value
00175          Exception e("Unexpect ShadowModel in getShadowFunction()");
00176          GPSTK_THROW(e);
00177       }
00178 
00179       return v;
00180 
00181    }  // End of method 'SolarRadiationPressure::getShadowFunction()'
00182 
00183 
00184 
00185       /* Compute the acceleration due to a solar radiation pressure.
00186        * @param r ECI position vector [m].
00187        * @param r_Sun ECI position vector of Sun in m.
00188        * @return Acceleration due to solar radiation pressure in m/s^2.
00189        */
00190    Vector<double> SolarRadiationPressure::accelSRP(Vector<double> r, Vector<double> r_Sun) 
00191    {
00192       // Relative position vector of spacecraft w.r.t. Sun (from the sun to s/c)
00193       Vector<double> d = r-r_Sun;
00194       double dmag = norm(d);
00195       double dcubed = dmag * dmag * dmag;
00196       double au2 = ASConstant::AU * ASConstant::AU;
00197       
00198       double P_STK = 4.5344321837439e-06; //4.560E-6
00199       
00200       //double factor = CR * (area/mass) * P_STK * au2 / dcubed;
00201       
00202       double Ls = 3.823e26; //* STK [W]
00203       double factor = reflectCoeff * (crossArea/dryMass) * Ls 
00204                     / (4.0*ASConstant::PI*ASConstant::SPEED_OF_LIGHT*dcubed); // STK HPOP method
00205       
00206       Vector<double> out = d * factor;
00207       
00208       return  out;
00209 
00210    }  // End of method 'SolarRadiationPressure::accelSRP()'
00211 
00212 
00213       /* Determines if the satellite is in sunlight or shadow based on simple cylindrical shadow model.
00214        * Taken from Montenbruck and Gill p. 80-83
00215        * @param r ECI position vector of spacecraft [m].
00216        * @param r_Sun Sun position vector (geocentric) [m].
00217        * @return 0.0 if in shadow, 1.0 if in sunlight, 0 to 1.0 if in partial shadow
00218        */
00219    double SolarRadiationPressure::partial_illumination(Vector<double> r, Vector<double> r_Sun )
00220    {
00221       double r_sun_mag = norm(r_Sun);
00222       double r_mag = norm(r);
00223 
00224       double R_sun = ASConstant::R_Sun;
00225       double R_earth = ASConstant::R_Earth;
00226       Vector<double> d = r_Sun-r;
00227       double dmag = norm(d);
00228       double sd = -1.0 * dot(r,d);
00229       double a = std::asin(R_sun/dmag);
00230       double b = std::asin(R_earth/r_mag);
00231       double c = std::acos(sd/(r_mag*dmag));
00232       
00233       if((a+b)<=c) 
00234       {
00235          return 1.0;
00236       }
00237       else if(c < (b-a))
00238       {
00239          return 0.0;
00240       }
00241       else 
00242       {
00243          double x = (c*c+a*a-b*b)/(2*c);
00244          double y = std::sqrt(a*a-x*x);
00245          double A = a*a*std::acos(x/a)+b*b*std::acos((c-x)/b)-c*y;
00246          double nu = 1 - A/(ASConstant::PI*a*a);
00247          return nu;
00248       }
00249 
00250    }  // End of method 'SolarRadiationPressure::partial_illumination()'
00251 
00252 
00253    void SolarRadiationPressure::doCompute(UTCTime utc, EarthBody& rb, Spacecraft& sc)
00254    {
00255       crossArea = sc.getDragArea();
00256       dryMass = sc.getDryMass();
00257       reflectCoeff = sc.getReflectCoeff();
00258 
00259       Vector<double> r_sun = ReferenceFrames::getJ2kPosition(utc.asTDB(),SolarSystem::Sun);
00260       Vector<double> r_moon = ReferenceFrames::getJ2kPosition(utc.asTDB(),SolarSystem::Moon);
00261       
00262       // from km to m
00263       r_sun = r_sun*1000.0;
00264       r_moon = r_moon*1000.0;
00265 
00266       // a
00267       a = accelSRP(sc.R(),r_sun)*getShadowFunction(sc.R(),r_sun,r_moon,SM_CONICAL);
00268 
00269       // da_dr   reference to Montenbruck P248
00270       // and it's in the same way as the gravitational attraction of the sun
00271       da_dr.resize(3,3,0.0);
00272 
00273       double au2 = ASConstant::AU * ASConstant::AU;
00274       double factor = -1.0*reflectCoeff * (crossArea/dryMass) * ASConstant::P_Sol*au2;
00275 
00276       Vector<double> d = sc.R() - r_sun;
00277       double dmag = norm(d);
00278       double dcubed = dmag * dmag *dmag;
00279 
00280       Vector<double> temp1 = d / dcubed;         //  detRJ/detRJ^3
00281 
00282       double smag = norm(r_sun);
00283       double scubed = smag * smag * smag;
00284 
00285       double muod3 = factor / dcubed;
00286       double jk = 3.0 * muod3/dmag/dmag; 
00287 
00288       double xx = d(0);
00289       double yy = d(1);
00290       double zz = d(2);
00291 
00292       da_dr(0,0) = jk * xx * xx - muod3;
00293       da_dr(0,1) = jk * xx * yy;
00294       da_dr(0,2) = jk * xx * zz;
00295 
00296       da_dr(1,0) = da_dr(0,1);
00297       da_dr(1,1) = jk * yy * yy - muod3;
00298       da_dr(1,2) = jk * yy * zz;
00299 
00300       da_dr(2,0) = da_dr(0,2);
00301       da_dr(2,1) = da_dr(1,2);
00302       da_dr(2,2) = jk * zz * zz - muod3;
00303 
00304       // da_dv
00305       da_dv.resize(3,3,0.0);
00306 
00307       // da_dp
00308       dadcr.resize(3,0.0);
00309       dadcr = a /reflectCoeff;
00310 
00311       da_dcr(0,0) = dadcr(0);
00312       da_dcr(1,0) = dadcr(1);
00313       da_dcr(2,0) = dadcr(2);
00314 
00315    }  // End of method 'SolarRadiationPressure::doCompute()'
00316 
00317 }  // End of namespace 'gpstk'
00318 

Generated on Tue May 22 03:31:01 2012 for GPS ToolKit Software Library by  doxygen 1.3.9.1