Example: Computing Position from RINEX Observations

In this example, RINEX observations are used to compute the user position. The class that computes the position can use RAIM concepts in order to reduce the impact of satellite failures on the position computation.

    19 using namespace std;
    20 using namespace gpstk;

Lines 19 and 20 allow the use of standard objects (such as cout) and the use of GPSTk classes without having to specify the namespace.

    21 main(int argc, char *argv[])
    22 {
    23    BCEphemerisStore bcestore;
    24    RAIMSolution raimSolver;
    25    ZeroTropModel noTropModel;
    26    GGTropModel ggTropModel;
    27    TropModel *tropModelPtr=&noTropModel;

The object created in line 23 is used to store broadcast ephemerides from a RINEX navigation message file.

The RAIMSolution object instantiated in line 24 handles the complexity of robustly solving for the receiver position.

Lines 25 through 27 defines objects to compute the troposphere correction.

    36    try
    37    {  
    39       RinexNavStream rnffs(argv[2]);
    40       RinexNavData rne;
    41       RinexNavHeader hdr;
    42       
    43       rnffs >> hdr;

    44       while (rnffs >> rne) bcestore.addEphemeris(rne);
    45       bcestore.SearchNear();
    46

In lines 39 through 46, the contents of a specified RINEX navigation file are parsed and stored for later use.

    48       list<RinexMetData> rml;
    49       if (argc==4)
    50       {
    51          RinexMetStream rms(argv[3]);
    52          RinexMetHeader rmh;
    53          rms >> rmh;
    54          
    55          RinexMetData rmd;
    56          tropModelPtr=&ggTropModel;
    57          while (rms >> rmd) rml.push_back(rmd);
    58       }

In lines 48 through 58, the contents of the specified RINEX meteorological file are parsed and stored for later use.

    61       RinexObsStream roffs(argv[1]);
    62       roffs.exceptions(ios::failbit);
       
    63       RinexObsHeader roh;
    64       RinexObsData rod;
       
    65       roffs >> roh;
       
    66       list::iterator mi=rml.begin();
       
    67       while (roffs >> rod)
    68       {
    69          double T, P, H;
    70          
    71          // Find a weather point.
    72          while ( (argc==4) &&
    73                  (!rml.empty()) &&
    74                  (mi!=rml.end()) &&
    75                  ((*mi).time < rod.time) )
    76          {
    77             mi++;
    78             ggTropModel.setWeather(
                        (*mi).data[RinexMetHeader::TD],
    79                 (*mi).data[RinexMetHeader::PR],
    80                 (*mi).data[RinexMetHeader::HR]);
    81          }
    82

In the above code section, the RINEX observation file is accessed. Line 67 sets up the loop that controls the epoch-by-epoch parsing of the observation file.

In lines 72 through 81, if the user specifies a RINEX meteorological file, then the list of weather data is access to update the tropospheric model.

    83          // Apply editing criteria 
    84          if  (rod.epochFlag == 0 || rod.epochFlag == 1)
    85   {
    86      vector prnVec;
    87             vector rangeVec;
       
    88      RinexObsData::RinexPrnMap::const_iterator it;
    89             for (it = rod.obs.begin(); it!= rod.obs.end(); 
                         it++)
    90      {
    91         RinexObsData::RinexObsTypeMap otmap;
    92         RinexObsData::RinexObsTypeMap::const_iterator 
                          itP1, itP2; 
    93                RinexObsData::RinexDatum meas;
    94                otmap = (*it).second;
    95                itP1 = otmap.find(RinexObsHeader::P1);
    96      
    97                if (itP1!=otmap.end())
    98         {
    99                   double ionocorr = 0;
   100                   itP2 = otmap.find(RinexObsHeader::P2);
   101                   if (itP2!=otmap.end()) 
   102                      ionocorr = 1./(1.-gamma)*
                                         ((*itP1).second.data 
                                          -(*itP2).second.data);
   103                   prnVec.push_back((*it).first);
   104                   rangeVec.push_back((*itP1).second.data
                                             - ionocorr);
   105         }           
       
   106             }
       
   107             raimSolver.RMSLimit = 3e6;
   108      raimSolver.Compute(rod.time,prnVec,rangeVec, 
                                       bcestore, tropModelPtr);

In the above code segment, the data structures that contain the range observations for the current observation, are used to compute the position of the receiver. Many of these access techniques to the map structures within RinexObsData are discussed in example 3.

In lines 97 through 105, a dual frequency ionosphere correction is calculated. If the calculation is made, then a vector of range observations, and a vector of satellite ranges, are created for later input into the position solution call in line 108.

   110            if (raimSolver.isValid())
   111     {
   112               cout << setprecision(12) << raimSolver.Solution[0] << " " ;
   113               cout << raimSolver.Solution[1] << " " ;
   114               cout << raimSolver.Solution[2];
   115               cout << endl ;
   116            }
   117             
   118  
   119    } // End usable data
       
   120       } // End loop through each epoch
   121    }
   132 }

The above code merely writes the position calculation to standard output.

 
WEBLOGOALT