MOPSWeight.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: MOPSWeight.cpp 2479 2010-10-26 08:02:55Z architest $"
00002 
00009 //============================================================================
00010 //
00011 //  This file is part of GPSTk, the GPS Toolkit.
00012 //
00013 //  The GPSTk is free software; you can redistribute it and/or modify
00014 //  it under the terms of the GNU Lesser General Public License as published
00015 //  by the Free Software Foundation; either version 2.1 of the License, or
00016 //  any later version.
00017 //
00018 //  The GPSTk is distributed in the hope that it will be useful,
00019 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00020 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021 //  GNU Lesser General Public License for more details.
00022 //
00023 //  You should have received a copy of the GNU Lesser General Public
00024 //  License along with GPSTk; if not, write to the Free Software Foundation,
00025 //  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00026 //
00027 //  Dagoberto Salazar - gAGE. 2006, 2008
00028 //
00029 //============================================================================
00030 
00031 
00032 
00033 #include "MOPSWeight.hpp"
00034 
00035 
00036 using namespace std;
00037 
00038 namespace gpstk
00039 {
00040 
00041 
00042       /* Computes a vector with the weights for the given satellites.
00043        *
00044        * @param time               Epoch weights will be computed for.
00045        * @param Satellites         Vector of satellites.
00046        * @param bcEph              Satellite broadcast ephemeris.
00047        * @param ionoCorrections    Ionospheric corrections computed using
00048        *                           Klobuchar model.
00049        * @param elevationVector    Vector of elevations, in degrees.
00050        * @param azimuthVector      Vector of azimuths, in degrees.
00051        * @param rxPosition         Position of the receiver.
00052        * @param rxClass            Integer indicating receiver class
00053        *                           according MOPS-C. It is 2 by default
00054        *                           (conservative setting).
00055        *
00056        * @return Number of satellites with valid weights.
00057        *
00058        * \note
00059        * Method isValid() will return 'false' if some satellite does not have
00060        * a valid weight. Also, its PRN will be set to a negative value.
00061        *
00062        */
00063    int MOPSWeight::getWeights( DayTime& time,
00064                                Vector<SatID>& Satellites,
00065                                GPSEphemerisStore& bcEph,
00066                                Vector<double>& ionoCorrections,
00067                                Vector<double>& elevationVector,
00068                                Vector<double>& azimuthVector,
00069                                Position rxPosition,
00070                                int rxClass )
00071       throw(InvalidWeights)
00072    {
00073 
00074       int N( Satellites.size() );
00075       int Ne( elevationVector.size() );
00076       int Na( azimuthVector.size() );
00077 
00078          // We need at least one satellite
00079       if (N == 0)
00080       {
00081 
00082          InvalidWeights eWeight("At least one satellite is needed to \
00083 compute weights.");
00084 
00085          GPSTK_THROW(eWeight);
00086 
00087       }
00088 
00089 
00090       if ( (N != Ne) ||
00091            (N != Na) )
00092       {
00093          InvalidWeights eWeight("Size of input vectors do not match.");
00094 
00095          GPSTK_THROW(eWeight);
00096 
00097       }
00098 
00099 
00100       SimpleIURAWeight sIura;
00101 
00102          // Compute satellites' IURA weights
00103       int goodSV( sIura.getWeights(time, Satellites, bcEph) );
00104 
00105          // Let's compute sigma^2 and weight values
00106       Compute( goodSV,
00107                sIura,
00108                Satellites,
00109                ionoCorrections,
00110                elevationVector,
00111                azimuthVector,
00112                rxPosition,
00113                rxClass );
00114 
00115        return goodSV;
00116 
00117    }  // End of method 'MOPSWeight::getWeights()'
00118 
00119 
00120 
00121       /* Computes a vector with the weights for the given satellites.
00122        *
00123        * @param time               Epoch weights will be computed for.
00124        * @param Satellites         Vector of satellites.
00125        * @param preciseEph         Satellite precise ephemeris.
00126        * @param ionoCorrections    Ionospheric corrections computed using
00127        *                           Klobuchar model.
00128        * @param elevationVector    Vector of elevations, in degrees.
00129        * @param azimuthVector      Vector of azimuths, in degrees.
00130        * @param rxPosition         Position of the receiver.
00131        * @param rxClass            Integer indicating receiver class.
00132        *                           according MOPS-C. It is 2 by default
00133        *                           (conservative setting).
00134        *
00135        * @return Number of satellites with valid weights.
00136        *
00137        * \note
00138        * Method isValid() will return 'false' if some satellite does not have
00139        * a valid weight. Also, its PRN will be set to a negative value.
00140        *
00141        */
00142    int MOPSWeight::getWeights( DayTime& time,
00143                                Vector<SatID>& Satellites,
00144                                TabularEphemerisStore& preciseEph,
00145                                Vector<double>& ionoCorrections,
00146                                Vector<double>& elevationVector,
00147                                Vector<double>& azimuthVector,
00148                                Position rxPosition,
00149                                int rxClass )
00150       throw(InvalidWeights)
00151    {
00152 
00153       int N( Satellites.size() );
00154       int Ne( elevationVector.size() );
00155       int Na( azimuthVector.size() );
00156 
00157          // We need at least one satellite
00158       if (N == 0)
00159       {
00160 
00161          InvalidWeights eWeight("At least one satellite is needed to \
00162 compute weights.");
00163 
00164          GPSTK_THROW(eWeight);
00165 
00166       }
00167 
00168 
00169       if ( (N != Ne) ||
00170            (N != Na) )
00171       {
00172 
00173          InvalidWeights eWeight("Size of input vectors do not match.");
00174 
00175          GPSTK_THROW(eWeight);
00176 
00177       }
00178 
00179 
00180       SimpleIURAWeight sIura;
00181 
00182          // Compute satellites' IURA weights
00183       int goodSV( sIura.getWeights(time, Satellites, preciseEph) );
00184 
00185          // Let's compute sigma^2 and weight values
00186       Compute( goodSV,
00187                sIura,
00188                Satellites,
00189                ionoCorrections,
00190                elevationVector,
00191                azimuthVector,
00192                rxPosition,
00193                rxClass );
00194 
00195       return goodSV;
00196 
00197    }  // End of method 'MOPSWeight::getWeights()'
00198 
00199 
00200 
00201       // Compute satellites' weights
00202    void MOPSWeight::Compute( int goodSV,
00203                              SimpleIURAWeight& sIura,
00204                              Vector<SatID>& Satellites,
00205                              Vector<double>& ionoCorrections,
00206                              Vector<double>& elevationVector,
00207                              Vector<double>& azimuthVector,
00208                              Position rxPosition,
00209                              int rxClass )
00210       throw(InvalidWeights)
00211    {
00212 
00213       int N( Satellites.size() );
00214 
00215       double sigma2rx;    // Receiver noise sigma^2 in meters^2
00216 
00217       if (rxClass==1)
00218       {
00219          sigma2rx = 0.25;
00220       }
00221       else
00222       {
00223          sigma2rx = 0.36;
00224       }
00225 
00226       double sigma2ura, sigma2multipath, sigma2trop, sigma2uire;
00227 
00228          // Let's resize weightsVector
00229       weightsVector.resize(goodSV);
00230 
00231          // We need a MOPSTropModel object. Parameters must be valid but
00232          // they aren't important
00233       MOPSTropModel mopsTrop(0.0, 0.0, 1);
00234 
00235       if (N==goodSV)    // In this case, we don't have to worry much
00236       {                 // and things go faster
00237 
00238          for (int i=0; i<goodSV; i++)
00239          {
00240 
00241             sigma2ura = (1.0 / sIura.weightsVector(i));
00242             sigma2multipath = 0.13 + ( 0.53 *
00243                                        std::exp(-elevationVector(i)/10.0) );
00244                // The former expression in DO-229D document is for sigma,
00245                // not for sigma^2. Thanks to Everett Wang for the fix.
00246             sigma2multipath *= sigma2multipath;
00247             sigma2trop = mopsTrop.MOPSsigma2(elevationVector(i));
00248             sigma2uire = sigma2iono( ionoCorrections(i),
00249                                      elevationVector(i),
00250                                      azimuthVector(i),
00251                                      rxPosition );
00252             weightsVector(i) = 1.0 / ( sigma2rx + sigma2ura + sigma2multipath
00253                                      + sigma2trop + sigma2uire );
00254 
00255          }  // End of 'for (int i=0; i<goodSV; i++)...'
00256 
00257       }
00258       else    // More care must be taken in this case
00259       {
00260 
00261          int offset(0);
00262 
00263          for (int i=0; i<goodSV; i++)
00264          {
00265 
00266                // Lets make sure we are using the same satellites
00267             while ( (sIura.availableSV(i).id != Satellites(i+offset).id) &&
00268                     ((i+offset)<N) )
00269             {
00270                offset++;
00271             }
00272 
00273             if ( (i+offset) >= N )
00274             {
00275                break;
00276             }
00277 
00278             sigma2ura = (1.0 / sIura.weightsVector(i));
00279             sigma2multipath = 0.13 + ( 0.53 *
00280                                        std::exp(-elevationVector(i)/10.0) );
00281                // The former expression in DO-229D document is for sigma,
00282                // not for sigma^2. Thanks to Everett Wang for the fix.
00283             sigma2multipath *= sigma2multipath;                                      
00284             sigma2trop = mopsTrop.MOPSsigma2(elevationVector(i+offset));
00285             sigma2uire = sigma2iono( ionoCorrections(i+offset),
00286                                      elevationVector(i+offset),
00287                                      azimuthVector(i+offset),
00288                                      rxPosition );
00289             weightsVector(i) = 1.0 / ( sigma2rx + sigma2ura + sigma2multipath
00290                                      + sigma2trop + sigma2uire );
00291 
00292          }  // End of 'for (int i=0; i<goodSV; i++)...'
00293 
00294       }  // End of 'if (N==goodSV) ... else ...'
00295 
00296 
00297       valid = sIura.isValid();      // Valididy depends if sIura rejected
00298                                     // satellites or not
00299       availableSV = sIura.availableSV;
00300       rejectedSV = sIura.rejectedSV;
00301 
00302       return;
00303 
00304     } // End of method 'MOPSWeight::Compute()'
00305 
00306 
00307 
00308       // Compute ionospheric sigma^2 according to Appendix J.2.3 and
00309       // Appendix A.4.4.10.4 in MOPS-C
00310    double MOPSWeight::sigma2iono( double& ionoCorrection,
00311                                   double& elevation,
00312                                   double& azimuth,
00313                                   Position rxPosition )
00314       throw(InvalidWeights)
00315    {
00316 
00317          // First, let's found magnetic latitude according to ICD-GPS-200,
00318          // section 20.3.3.5.2.6
00319       double azRad( azimuth * DEG_TO_RAD );
00320       double elevRad( elevation * DEG_TO_RAD );
00321       double cosElev( std::cos(elevRad) );
00322       double svE( elevation / 180.0 );     // Semi-circles
00323 
00324       double phi_u( rxPosition.getGeodeticLatitude() / 180.0 ); // Semi-circles
00325       double lambda_u( rxPosition.getLongitude() / 180.0 );     // Semi-circles
00326 
00327       double psi( (0.0137 / (svE + 0.11)) - 0.022 );            // Semi-circles
00328 
00329       double phi_i( phi_u + psi * std::cos(azRad) );            // Semi-circles
00330 
00331       if (phi_i > 0.416)
00332       {
00333          phi_i = 0.416;
00334       }
00335 
00336       if (phi_i < -0.416)
00337       {
00338          phi_i = -0.416;
00339       }
00340 
00341          // In semi-circles
00342       double lambda_i( lambda_u + (psi*std::sin(azRad) / std::cos(phi_i*PI)) );
00343       double phi_m( phi_i + 0.064 * std::cos((lambda_i - 1.617)*PI) );
00344 
00345          // Convert magnetic latitude to degrees
00346       phi_m = std::abs(phi_m * 180.0);
00347 
00348          // Estimate vertical ionospheric delay according to MOPS-C
00349       double tau_vert;
00350 
00351       if ( (phi_m >= 0.0) &&
00352            (phi_m <= 20.0) )
00353       {
00354          tau_vert = 9.0;
00355       }
00356       else
00357       {
00358 
00359          if ( (phi_m > 20.0) &&
00360               (phi_m <= 55.0) )
00361          {
00362             tau_vert = 4.5;
00363          }
00364          else
00365          {
00366             tau_vert = 6.0;
00367          }
00368 
00369       }  // End of 'if ( (phi_m >= 0.0) && (phi_m <= 20.0) ) ... else ...'
00370 
00371 
00372          // Compute obliquity factor
00373       double fpp( 1.0 / (std::sqrt(1.0 - 0.898665418 * cosElev * cosElev)) );
00374 
00375       double sigma2uire( (ionoCorrection*ionoCorrection) / 25.0 );
00376 
00377       double fact( (fpp*tau_vert) * (fpp*tau_vert) );
00378 
00379       if (fact > sigma2uire)
00380       {
00381          sigma2uire = fact;
00382       }
00383 
00384       return sigma2uire;
00385 
00386    }  // End of method 'MOPSWeight::sigma2iono()'
00387 
00388 
00389 }  // End of namespace gpstk

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