PRSolution.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: PRSolution.cpp 3140 2012-06-18 15:03:02Z susancummins $"
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
00026 //  
00027 //  Copyright 2004, The University of Texas at Austin
00028 //
00029 //============================================================================
00030 
00031 #include "MathBase.hpp"
00032 #include "PRSolution.hpp"
00033 #include "GPSEllipsoid.hpp"
00034 #include "Combinations.hpp"
00035 #include "TimeString.hpp"
00036 #include "stl_helpers.hpp"
00037 #include "logstream.hpp"
00038 
00039 using namespace std;
00040 using namespace gpstk;
00041 
00042 namespace gpstk
00043 {
00044    const string PRSolution::calfmt = string("%04Y/%02m/%02d %02H:%02M:%02S");
00045    const string PRSolution::gpsfmt = string("%4F %10.3g");
00046    const string PRSolution::timfmt = gpsfmt + string(" ") + calfmt;
00047 
00048    ostream& operator<<(ostream& os, const WtdAveStats& was)
00049       { was.dump(os,was.getMessage()); return os;}
00050  
00051    // -------------------------------------------------------------------------
00052    // Prepare for the autonomous solution by computing direction cosines,
00053    // corrected pseudoranges and satellite system.
00054    int PRSolution::PreparePRSolution(const CommonTime& Tr,
00055                                      vector<SatID>& Sats,
00056                                      vector<SatID::SatelliteSystem>& Syss,
00057                                      const vector<double>& Pseudorange,
00058                                      const XvtStore<SatID> *pEph,
00059                                      Matrix<double>& SVP) const
00060       throw()
00061    {
00062       int i,j,noeph(0),N,NSVS;
00063       CommonTime tx;
00064       Xvt PVT;
00065 
00066       // if necessary, define the SystemIDs vector (but NOT the member data one)
00067       if(Syss.size() == 0) {
00068          for(i=0; i<Sats.size(); i++) {
00069             SatID::SatelliteSystem sys=Sats[i].system;
00070             if(vectorindex(Syss, sys) == -1)     // not found
00071                Syss.push_back(sys);              // add it
00072          }
00073       }
00074 
00075       // must ignore and mark satellites if system is not found in Syss
00076       for(N=0,i=0; i<Sats.size(); i++) {
00077          if(Sats[i].id <= 0) continue;                // already marked
00078          if(vectorindex(Syss, Sats[i].system) == -1) {
00079             LOG(DEBUG) << " PRSolution ignores satellite (system) "
00080                << RinexSatID(Sats[i]) << " at time " << printTime(Tr,timfmt);
00081             Sats[i].id = -Sats[i].id;                 // don't have system - mark it
00082             continue;
00083          }
00084          ++N;                                         // count good sat
00085       }
00086 
00087       SVP = Matrix<double>(Sats.size(),4,0.0);        // define the matrix to return
00088       if(N <= 0) return 0;                            // nothing to do
00089       NSVS = 0;                                       // count good sats w/ ephem
00090 
00091       // loop over all satellites
00092       for(i=0; i<Sats.size(); i++) {
00093 
00094          // skip marked satellites
00095          if(Sats[i].id <= 0) {
00096             LOG(DEBUG) << " PRSolution ignores marked satellite "
00097                << RinexSatID(Sats[i]) << " at time " << printTime(Tr,timfmt);
00098             continue;
00099          }
00100 
00101          // first estimate of transmit time
00102          tx = Tr;
00103          tx -= Pseudorange[i]/C_MPS;
00104          try {
00105             PVT = pEph->getXvt(Sats[i], tx);          // get ephemeris range, etc
00106          }
00107          catch(InvalidRequest& e) {
00108             LOG(DEBUG) << "Warning - PRSolution ignores satellite (no ephemeris) "
00109                << RinexSatID(Sats[i]) << " at time " << printTime(tx,timfmt)
00110                << " [" << e.getText() << "]";
00111             Sats[i].id = -::abs(Sats[i].id);
00112             ++noeph;
00113             continue;
00114          }
00115 
00116          // update transmit time and get ephemeris range again
00117          tx -= PVT.clkbias + PVT.relcorr;
00118          try {
00119             PVT = pEph->getXvt(Sats[i], tx);
00120          }
00121          catch(InvalidRequest& e) {                   // unnecessary....you'd think!
00122             LOG(DEBUG) << "Warning - PRSolution ignores satellite (no ephemeris 2) "
00123                << RinexSatID(Sats[i]) << " at time " << printTime(tx,timfmt)
00124                << " [" << e.getText() << "]";
00125             Sats[i].id = -::abs(Sats[i].id);
00126             ++noeph;
00127             continue;
00128          }
00129 
00130          // SVP = {SV position at transmit time}, raw range + clk + rel
00131          for(j=0; j<3; j++) SVP(i,j) = PVT.x[j];
00132          SVP(i,3) = Pseudorange[i] + C_MPS * (PVT.clkbias + PVT.relcorr);
00133 
00134          LOG(DEBUG) << "SVP: Sat " << RinexSatID(Sats[i])
00135             << " PR " << fixed << setprecision(3) << Pseudorange[i]
00136             << " clkbias " << C_MPS*PVT.clkbias
00137             << " relcorr " << C_MPS*PVT.relcorr;
00138 
00139          // count the good satellites
00140          NSVS++;
00141       }
00142 
00143       if(noeph == N) return -4;                       // no ephemeris for any good sat
00144 
00145       return NSVS;
00146   
00147    } // end PreparePRPRSolution
00148 
00149 
00150    // -------------------------------------------------------------------------
00151    // Compute a straightforward solution using all the unmarked data.
00152    // Call PreparePRSolution first.
00153    int PRSolution::SimplePRSolution(const CommonTime& T,
00154                                     const vector<SatID>& Sats,
00155                                     const Matrix<double>& SVP,
00156                                     const Matrix<double>& invMC,
00157                                     TropModel *pTropModel,
00158                                     const int& niterLimit,
00159                                     const double& convLimit,
00160                                     const vector<SatID::SatelliteSystem>& Syss,
00161                                     const Vector<double>& APSol,
00162                                     Vector<double>& Resids,
00163                                     Vector<double>& Slopes)
00164       throw(Exception)
00165    {
00166       if(!pTropModel) {
00167          Exception e("Undefined tropospheric model");
00168          GPSTK_THROW(e);
00169       }
00170       if(Sats.size() != SVP.rows() ||
00171          (invMC.rows() > 0 && invMC.rows() != Sats.size())) {
00172          LOG(ERROR) << "Sats has length " << Sats.size();
00173          LOG(ERROR) << "SVP has dimension " << SVP.rows() << "x" << SVP.cols();
00174          LOG(ERROR) << "invMC has dimension " << invMC.rows() << "x" << invMC.cols();
00175          Exception e("Invalid dimensions");
00176          GPSTK_THROW(e);
00177       }
00178       if(Syss.size() == 0) {
00179          Exception e("Allowed satellite systems input (Syss) is empty!");
00180          GPSTK_THROW(e);
00181       }
00182 
00183       int iret(0),i,j,k,n;
00184       double rho,wt,svxyz[3];
00185       GPSEllipsoid ellip;
00186 
00187       Valid = false;
00188 
00189       try {
00190          // -----------------------------------------------------------
00191          // counts, systems and dimensions
00192          vector<SatID::SatelliteSystem> mySyss;
00193          {
00194             // define the Syss (system IDs) vector, and count good satellites
00195             vector<SatID::SatelliteSystem> tempSyss;
00196             for(Nsvs=0,i=0; i<Sats.size(); i++) {
00197                if(Sats[i].id <= 0)                          // reject marked sats
00198                   continue;
00199 
00200                SatID::SatelliteSystem sys(Sats[i].system);  // get this system
00201                if(vectorindex(Syss, sys) == -1)             // reject disallowed sys
00202                   continue;
00203 
00204                Nsvs++;                                      // count it
00205                if(vectorindex(tempSyss, sys) == -1)         // add unique system
00206                   tempSyss.push_back(sys);
00207             }
00208 
00209             // must sort as in Syss
00210             for(i=0; i<Syss.size(); i++)
00211                if(vectorindex(tempSyss, Syss[i]) != -1)
00212                   mySyss.push_back(Syss[i]);
00213          }
00214 
00215          // dimension of the solution vector (3 pos + 1 clk/sys)
00216          const int dim(3 + mySyss.size());
00217 
00218          // require number of good satellites to be >= number unknowns (no RAIM here)
00219          if(Nsvs < dim) return -3;
00220 
00221          // -----------------------------------------------------------
00222          // build the measurement covariance matrix
00223          Matrix<double> iMC;
00224          if(invMC.rows() > 0) {
00225             LOG(DEBUG) << "Build inverse MCov";
00226             iMC = Matrix<double>(Nsvs,Nsvs,0.0);
00227             for(n=0,i=0; i<Sats.size(); i++) {
00228                if(Sats[i].id <= 0) continue;
00229                for(k=0,j=0; j<Sats.size(); j++) {
00230                   if(Sats[j].id <= 0) continue;
00231                   iMC(n,k) = invMC(i,j);
00232                   ++k;
00233                }
00234                ++n;
00235             }
00236             LOG(DEBUG) << "inv MCov matrix is\n" << fixed << setprecision(4) << iMC;
00237          }
00238 
00239          // -----------------------------------------------------------
00240          // define for computation
00241          Vector<double> CRange(Nsvs),dX(dim);
00242          Matrix<double> P(Nsvs,dim,0.0),PT,G(dim,Nsvs),PG(Nsvs,Nsvs),Rotation;
00243          Triple dirCos;
00244          Xvt SV,RX;
00245 
00246          Solution.resize(dim);
00247          Covariance.resize(dim,dim);
00248          Resids.resize(Nsvs);
00249          Slopes.resize(Nsvs);
00250          LOG(DEBUG) << " Solution dimension is " << dim << " and Nsvs is " << Nsvs;
00251 
00252          // prepare for iteration loop
00253          // iterate at least twice so that trop model gets evaluated
00254          int n_iterate(0), niter_limit(niterLimit < 2 ? 2 : niterLimit);
00255          double converge(0.0);
00256 
00257          // start with apriori
00258          if(APSol.size() == 0) Solution = Vector<double>(dim,0.0);
00259          else {
00260             // TD what if size is wrong?
00261             Solution = APSol;
00262 
00263             LOG(DEBUG) << " apriori solution (" << Solution.size() << ") is [ "
00264                << fixed << setprecision(3) << Solution << " ]";
00265          }
00266 
00267          // -----------------------------------------------------------
00268          // iteration loop
00269          do {
00270             TropFlag = false;       // true means the trop corr was NOT applied
00271 
00272             // current estimate of position solution
00273             RX.x = Triple(Solution(0),Solution(1),Solution(2));
00274 
00275             // loop over satellites, computing partials matrix
00276             for(n=0,i=0; i<Sats.size(); i++) {
00277                // ignore marked satellites
00278                if(Sats[i].id <= 0) continue;
00279 
00280                // ------------ ephemeris
00281                // rho is time of flight (sec)
00282                if(n_iterate == 0)
00283                   rho = 0.070;             // initial guess: 70ms
00284                else
00285                   rho = RSS(SVP(i,0)-Solution(0),
00286                            SVP(i,1)-Solution(1), SVP(i,2)-Solution(2))/ellip.c();
00287 
00288                // correct for earth rotation
00289                wt = ellip.angVelocity()*rho;             // radians
00290                svxyz[0] =  ::cos(wt)*SVP(i,0) + ::sin(wt)*SVP(i,1);
00291                svxyz[1] = -::sin(wt)*SVP(i,0) + ::cos(wt)*SVP(i,1);
00292                svxyz[2] = SVP(i,2);
00293 
00294                // rho is now geometric range
00295                rho = RSS(svxyz[0]-Solution(0),
00296                          svxyz[1]-Solution(1),
00297                          svxyz[2]-Solution(2));
00298 
00299                // direction cosines
00300                dirCos[0] = (Solution(0)-svxyz[0])/rho;
00301                dirCos[1] = (Solution(1)-svxyz[1])/rho;
00302                dirCos[2] = (Solution(2)-svxyz[2])/rho;
00303 
00304                // ------------ data
00305                // corrected pseudorange (m) minus geometric range
00306                CRange(n) = SVP(i,3) - rho;
00307 
00308                // correct for troposphere and PCOs (but not on the first iteration)
00309                if(n_iterate > 0) {
00310                   SV.x = Triple(svxyz[0],svxyz[1],svxyz[2]);
00311                   Position R,S;
00312                   R.setECEF(RX.x[0],RX.x[1],RX.x[2]);
00313                   S.setECEF(SV.x[0],SV.x[1],SV.x[2]);
00314 
00315                   // trop
00316                   double tc(R.getHeight());  // tc is a dummy here
00317                   // must test R for reasonableness to avoid corrupting TropModel
00318                   if(R.elevation(S) < 0.0 || tc > 100000.0 || tc < -1000.0) {
00319                      tc = 0.0;
00320                      TropFlag = true;        // true means failed to apply trop corr
00321                   }
00322                   else
00323                      tc = pTropModel->correction(R,S,T);    // pTropModel not const
00324 
00325                   CRange(n) -= tc;
00326                   LOG(DEBUG) << "Trop " << i << " " << Sats[i] << " "
00327                      << fixed << setprecision(3) << tc;
00328 
00329                }  // end if n_iterate > 0
00330 
00331                // get the index, for this clock, in the solution vector
00332                j = 3 + vectorindex(mySyss, Sats[i].system); // Solution ~ X,Y,Z,clks
00333 
00334                // find the clock for the sat's system
00335                const double clk(Solution(j));
00336                LOG(DEBUG) << "Clock is (" << j << ") " << clk;
00337 
00338                // data vector: corrected range residual
00339                Resids(n) = CRange(n) - clk;
00340 
00341                // ------------ least squares
00342                // partials matrix
00343                P(n,0) = dirCos[0];           // x direction cosine
00344                P(n,1) = dirCos[1];           // y direction cosine
00345                P(n,2) = dirCos[2];           // z direction cosine
00346                P(n,j) = 1.0;                 // clock
00347 
00348                // ------------ increment index
00349                // n is index and number of good satellites - also used for Slope
00350                n++;
00351 
00352             }  // end loop over satellites
00353 
00354             if(n != Nsvs) {
00355                Exception e("Counting error after satellite loop");
00356                GPSTK_THROW(e);
00357             }
00358 
00359             LOG(DEBUG) << "Partials (" << P.rows() << "x" << P.cols() << ")\n"
00360                << fixed << setprecision(4) << P;
00361             LOG(DEBUG) << "Resids (" << Resids.size() << ") "
00362                << fixed << setprecision(3) << Resids;
00363 
00364             // ------------------------------------------------------
00365             // compute information matrix (inverse covariance) and generalized inverse
00366             PT = transpose(P);
00367 
00368             // weight matrix = measurement covariance inverse
00369             if(invMC.rows() > 0) Covariance = PT * iMC * P;
00370             else                 Covariance = PT * P;
00371             LOG(DEBUG) << "Computed inverse cov";
00372 
00373             // invert using SVD
00374             try {
00375                Covariance = inverseSVD(Covariance);
00376             }
00377             catch(SingularMatrixException& sme) { return -2; }
00378 
00379             // generalized inverse
00380             if(invMC.rows() > 0) G = Covariance * PT * iMC;
00381             else                 G = Covariance * PT;
00382 
00383             // PG is used for Slope computation
00384             PG = P * G;
00385             LOG(DEBUG) << "Computed PG";
00386 
00387             n_iterate++;                        // increment number iterations
00388 
00389             // ------------------------------------------------------
00390             // compute solution
00391             dX = G * Resids;
00392             LOG(DEBUG) << "Computed dX(" << dX.size() << ")";
00393             Solution += dX;
00394 
00395             // ------------------------------------------------------
00396             // test for convergence
00397             converge = norm(dX);
00398             if(n_iterate > 1 && converge < convLimit) {              // success: quit
00399                iret = 0;
00400                break;
00401             }
00402             if(n_iterate >= niterLimit || converge > 1.e10) {        // failure: quit
00403                iret = -1;
00404                break;
00405             }
00406 
00407          } while(1);    // end iteration loop
00408          LOG(DEBUG) << "Out of iteration loop";
00409 
00410          if(TropFlag) LOG(DEBUG) << "Trop correction not applied at time "
00411                                  << printTime(T,timfmt);
00412 
00413          // compute slopes
00414          MaxSlope = 0.0;
00415          Slopes = 0.0;
00416          if(iret == 0) for(j=0,i=0; i<Sats.size(); i++) {
00417             if(Sats[i].id <= 0) continue;
00418 
00419             for(int k=0; k<dim; k++) Slopes(j) += G(k,j)*G(k,j);  // TD why k<4? dim?
00420             Slopes(j) = SQRT(Slopes(j)*double(n-dim)/(1.0-PG(j,j)));
00421 
00422             if(Slopes(j) > MaxSlope) MaxSlope = Slopes(j);
00423 
00424             j++;
00425          }
00426 
00427          // compute pre-fit residuals
00428          if(APSol.size() != 0)
00429             PreFitResidual = P*(Solution-APSol) - Resids;
00430 
00431          // Compute RMS residual (member)
00432          RMSResidual = RMS(Resids);
00433 
00434          // Find the maximum slope (member)
00435          MaxSlope = 0.0;
00436          for(i=0; i<Slopes.size(); i++)
00437             if(Slopes(i) > MaxSlope)
00438                MaxSlope = Slopes[i];
00439 
00440          // save to member data
00441          currTime = T;
00442          SatelliteIDs = Sats;
00443          SystemIDs = mySyss;
00444          invMeasCov = iMC;
00445          Partials = P;
00446          NIterations = n_iterate;
00447          Convergence = converge;
00448          Valid = true;
00449 
00450          return iret;
00451       
00452       } catch(Exception& e) { GPSTK_RETHROW(e); }
00453 
00454    } // end PRSolution::SimplePRSolution
00455 
00456 
00457    // -------------------------------------------------------------------------
00458    // Compute a solution using RAIM.
00459    int PRSolution::RAIMCompute(const CommonTime& Tr,
00460                                vector<SatID>& Sats,
00461                                vector<SatID::SatelliteSystem>& Syss,
00462                                const vector<double>& Pseudorange,
00463                                const Matrix<double>& invMC,
00464                                const XvtStore<SatID> *pEph,
00465                                TropModel *pTropModel)
00466       throw(Exception)
00467    {
00468       try {
00469          int iret,i,j,N;
00470          vector<int> GoodIndexes;
00471          // use these to save the 'best' solution within the loop.
00472          // BestRMS marks the 'Best' set as unused.
00473          bool BestTropFlag(false);
00474          int BestNIter(0),BestIret(-5);
00475          double BestRMS(-1.0),BestSL(0.0),BestConv(0.0);
00476          Vector<double> BestSol(3,0.0),BestPFR;
00477          vector<SatID> BestSats,SaveSats;
00478          Matrix<double> SVP,BestCov,BestInvMCov,BestPartials;
00479          vector<SatID::SatelliteSystem> BestSyss;
00480 
00481          // initialize
00482          Valid = false;
00483          currTime = Tr;
00484          TropFlag = SlopeFlag = RMSFlag = false;
00485 
00486          // ----------------------------------------------------------------
00487          // fill the SVP matrix, and use it for every solution
00488          // NB this routine will: define Syss if it is empty,
00489          //    reject sat systems not found in Syss, and
00490          //    reject sats without ephemeris.
00491          N = PreparePRSolution(Tr, Sats, Syss, Pseudorange, pEph, SVP);
00492 
00493          if(LOGlevel >= ConfigureLOG::Level("DEBUG")) {
00494             ostringstream oss;
00495             oss << "RAIMCompute: after PrepareAS(): Satellites:";
00496             for(i=0; i<Sats.size(); i++) {
00497                RinexSatID rs(::abs(Sats[i].id), Sats[i].system);
00498                oss << " " << (Sats[i].id < 0 ? "-" : "") << rs;
00499             }
00500             oss << endl;
00501 
00502             oss << " SVP matrix("
00503                << SVP.rows() << "," << SVP.cols() << ")" << endl;
00504             oss << fixed << setw(16) << setprecision(5) << SVP;
00505 
00506             LOG(DEBUG) << oss.str();
00507          }
00508 
00509          // return is >=0(number of good sats) or -4(no ephemeris)
00510          if(N <= 0) return -4;
00511 
00512          // ----------------------------------------------------------------
00513          // Build GoodIndexes based on Sats; save Sats as SaveSats.
00514          // Sats is used to mark good sats (id > 0) and those to ignore (id <= 0).
00515          // SaveSats saves the original so it can be reused for each RAIM solution.
00516          // Let GoodIndexes be all the indexes of Sats that are good:
00517          // Sats[GoodIndexes[.]].id > 0 by definition.
00518          SaveSats = Sats;
00519          for(i=0; i<Sats.size(); i++)
00520             if(Sats[i].id > 0)
00521                GoodIndexes.push_back(i);
00522 
00523          // dump good satellites for debug
00524          if(LOGlevel >= ConfigureLOG::Level("DEBUG")) {
00525             ostringstream oss;
00526             oss << " Good satellites (" << N << ") are:";
00527             for(i=0; i<GoodIndexes.size(); i++)
00528                oss << " " << RinexSatID(Sats[GoodIndexes[i]]);
00529             LOG(DEBUG) << oss.str();
00530          }
00531 
00532          // ----------------------------------------------------------------
00533          // now compute the solution, first with all the data. If this fails,
00534          // RAIM: reject 1 satellite at a time and try again, then 2, etc.
00535 
00536          // Slopes for each satellite are computed (cf. the RAIM algorithm)
00537          Vector<double> Slopes;
00538          // Resids stores the post-fit data residuals.
00539          Vector<double> Resids;
00540 
00541          // stage is the number of satellites to reject.
00542          int stage(0);
00543 
00544          do {
00545             // compute all the combinations of N satellites taken stage at a time
00546             Combinations Combo(N,stage);
00547 
00548             // compute a solution for each combination of marked satellites
00549             do {
00550                // Mark the satellites for this combination
00551                Sats = SaveSats;
00552                for(i=0; i<GoodIndexes.size(); i++)
00553                   if(Combo.isSelected(i))
00554                      Sats[GoodIndexes[i]].id = -::abs(Sats[GoodIndexes[i]].id);
00555 
00556                if(LOGlevel >= ConfigureLOG::Level("DEBUG")) {
00557                   ostringstream oss;
00558                   oss << " RAIM: Try the combo ";
00559                   for(i=0; i<Sats.size(); i++) {
00560                      RinexSatID rs(::abs(Sats[i].id), Sats[i].system);
00561                      oss << " " << (Sats[i].id < 0 ? "-" : " ") << rs;
00562                   }
00563                   LOG(DEBUG) << oss.str();
00564                }
00565 
00566                // define apriroi solution    // TD clocks??
00567                Vector<double> APSol(4,0.0);
00568                if(hasMemory) APSol = memory.APSolution;
00569 
00570                // ----------------------------------------------------------------
00571                // Compute a solution given the data; ignore ranges for marked
00572                // satellites. Fill Vector 'Slopes' with slopes for each unmarked
00573                // satellite.
00574                // Return 0  ok
00575                //       -1  failed to converge
00576                //       -2  singular problem
00577                //       -3  not enough good data
00578                //       -4  no ephemeris
00579                iret = SimplePRSolution(Tr, Sats, SVP, invMC, pTropModel,
00580                        MaxNIterations, ConvergenceLimit, Syss, APSol, Resids, Slopes);
00581 
00582                LOG(DEBUG) << " RAIM: SimplePRS returns " << iret;
00583                if(iret <= 0 && iret > BestIret) BestIret = iret;
00584 
00585                // ----------------------------------------------------------------
00586                // if error, either quit or continue with next combo (SPS sets Valid F)
00587                if(iret < 0) {
00588                   if(iret == -1) {
00589                      LOG(DEBUG) << " SPS: Failed to converge - go on";
00590                      continue;
00591                   }
00592                   else if(iret == -2) {
00593                      LOG(DEBUG) << " SPS: singular - go on";
00594                      continue;
00595                   }
00596                   else if(iret == -3) {
00597                      LOG(DEBUG) <<" SPS: not enough satellites: quit";
00598                      break;
00599                   }
00600                   else if(iret == -4) {
00601                      LOG(DEBUG) <<" SPS: no ephemeris: quit";
00602                      break;
00603                   }
00604                }
00605 
00606                // ----------------------------------------------------------------
00607                // print solution with diagnostic information
00608                LOG(DEBUG) << outputString(string("RPS"),iret);
00609 
00610                // do again for residuals
00611                // if memory exists, output residuals
00612                //if(hasMemory) LOG(DEBUG) << outputString(string("RAP"), -99,
00613                      //(Solution-memory.APSolution));
00614 
00615                // deal with the results of SimplePRSolution()
00616                // save 'best' solution for later
00617                if(BestRMS < 0.0 || RMSResidual < BestRMS) {
00618                   BestRMS = RMSResidual;
00619                   BestSol = Solution;
00620                   BestSats = SatelliteIDs;
00621                   BestSyss = SystemIDs;
00622                   BestSL = MaxSlope;
00623                   BestConv = Convergence;
00624                   BestNIter = NIterations;
00625                   BestCov = Covariance;
00626                   BestInvMCov = invMeasCov;
00627                   BestPartials = Partials;
00628                   BestPFR = PreFitResidual;
00629                   BestTropFlag = TropFlag;
00630                   BestIret = iret;
00631                }
00632 
00633                if(stage==0 && RMSResidual < RMSLimit)
00634                   break;
00635 
00636             } while(Combo.Next() != -1);  // get the next combinations and repeat
00637 
00638             // end of the stage
00639             if(BestRMS > 0.0 && BestRMS < RMSLimit) {          // success
00640                LOG(DEBUG) << " RAIM: Success in the RAIM loop";
00641                iret = 0;
00642                break;
00643             }
00644 
00645             // go to next stage
00646             stage++;
00647 
00648             // but not if too many are being rejected
00649             if(NSatsReject > -1 && stage > NSatsReject) {
00650                LOG(DEBUG) << " RAIM: break before stage " << stage
00651                   << " due to NSatsReject " << NSatsReject;
00652                break;
00653             }
00654 
00655             // already broke out of the combo loop...
00656             if(iret == -3 || iret == -4) {
00657                LOG(DEBUG) << " RAIM: break before stage " << stage
00658                   << "; " << (iret==-3 ? "too few sats" : "no ephemeris");
00659                break;
00660             }
00661 
00662             LOG(DEBUG) << " RAIM: go to stage " << stage;
00663 
00664          } while(1);    // end loop over stages
00665 
00666          // ----------------------------------------------------------------
00667          // copy out the best solution and return
00668          if(iret >= 0) {
00669             Sats = SatelliteIDs = BestSats;
00670             SystemIDs = BestSyss;
00671             Solution = BestSol;
00672             Covariance = BestCov;
00673             invMeasCov = BestInvMCov;
00674             Partials = BestPartials;
00675             PreFitResidual = BestPFR;
00676             Convergence = BestConv;
00677             NIterations = BestNIter;
00678             RMSResidual = BestRMS;
00679             MaxSlope = BestSL;
00680             TropFlag = BestTropFlag;
00681             iret = BestIret;
00682 
00683             // must add zeros to state, covariance and partials if these don't match
00684             if(Syss.size() != BestSyss.size()) {
00685                N = 3+Syss.size();
00686                Solution = Vector<double>(N,0.0);
00687                Covariance = Matrix<double>(N,N,0.0);
00688                Partials = Matrix<double>(BestPartials.rows(),N,0.0);
00689 
00690                // build a little map of indexes; note systems are sorted alike
00691                vector<int> indexes;
00692                for(j=0,i=0; i<Syss.size(); i++)
00693                   indexes.push_back(Syss[i] == BestSyss[j] ? j++ : -1);
00694 
00695                // copy over position part
00696                for(i=0; i<3; i++) {
00697                   Solution(i) = BestSol(i);
00698                   for(j=0; j<Partials.rows(); j++) Partials(i,j) = BestPartials(i,j);
00699                   for(j=0; j<3; j++) Covariance(i,j) = BestCov(i,j);
00700                   for(j=0; j<indexes.size(); j++) {
00701                      Covariance(i,3+j)=(indexes[j]==-1 ? 0.:BestCov(i,3+indexes[j]));
00702                      Covariance(3+j,i)=(indexes[j]==-1 ? 0.:BestCov(3+indexes[j],i));
00703                   }
00704                }
00705 
00706                // copy the clock part, inserting zeros where needed
00707                for(j=0; j<indexes.size(); j++) {
00708                   int n(indexes[j]);
00709                   bool ok(n != -1);
00710                   Solution(3+j) = (ok ? BestSol(3+n) : 0.0);
00711                   for(i=0; i<Partials.rows(); i++)
00712                      Partials(i,3+j) = (ok ? BestPartials(i,3+n) : 0.0);
00713                   for(i=0; i<indexes.size(); i++) {
00714                      Covariance(3+i,3+j) = (ok ? BestCov(3+i,3+n) : 0.0);
00715                      Covariance(3+j,3+i) = (ok ? BestCov(3+n,3+i) : 0.0);
00716                   }
00717                }
00718             }
00719 
00720             // compute number of satellites actually used
00721             for(Nsvs=0,i=0; i<SatelliteIDs.size(); i++)
00722                if(SatelliteIDs[i].id > 0)
00723                   Nsvs++;
00724          }
00725 
00726          if(iret==0) {
00727             if(BestSL > SlopeLimit) { iret = 1; SlopeFlag = true; }
00728             if(BestSL > SlopeLimit/2.0 && Nsvs == 5) { iret = 1; SlopeFlag = true; }
00729             if(BestRMS >= RMSLimit) { iret = 1; RMSFlag = true; }
00730             if(TropFlag) iret = 1;
00731             Valid = true;
00732 
00733             // compute DOPs
00734             DOPCompute();
00735 
00736             // update memory
00737             if(hasMemory)
00738                memory.add(Solution, Covariance, PreFitResidual, Partials, invMeasCov);
00739          }
00740 
00741          LOG(DEBUG) << " RAIM exit with ret value " << iret
00742                      << " and Valid " << (Valid ? "T":"F");
00743 
00744          return iret;
00745       }
00746       catch(Exception& e) {
00747          GPSTK_RETHROW(e);
00748       }
00749    }  // end PRSolution::RAIMCompute()
00750 
00751 
00752    // -------------------------------------------------------------------------
00753    int PRSolution::DOPCompute(void) throw(Exception)
00754    {
00755       try {
00756          Matrix<double> PTP(transpose(Partials)*Partials);
00757          Matrix<double> Cov(inverseLUD(PTP));
00758 
00759          PDOP = SQRT(Cov(0,0)+Cov(1,1)+Cov(2,2));
00760 
00761          TDOP = 0.0;
00762          for(int i=3; i<Cov.rows(); i++) TDOP += Cov(i,i);
00763          TDOP = SQRT(TDOP);
00764 
00765          GDOP = RSS(PDOP,TDOP);
00766 
00767          return 0;
00768       }
00769       catch(Exception& e) { GPSTK_RETHROW(e); }
00770    }
00771 
00772    // -------------------------------------------------------------------------
00773    // conveniences for printing the solutions
00774    string PRSolution::outputValidString(int iret) throw()
00775    {
00776       ostringstream oss;
00777       if(iret != -99) {
00778          oss << " (" << iret << " " << errorCodeString(iret);
00779          if(iret==1) {
00780             oss << " due to";
00781             if(RMSFlag) oss << " large RMS residual";
00782             if(SlopeFlag) oss << " large slope";
00783             if(TropFlag) oss << " missed trop. corr.";
00784          }
00785          oss << ") " << (Valid ? "" : "N") << "V";
00786       }
00787       return oss.str();
00788    }  // end PRSolution::outputValidString
00789 
00790    string PRSolution::outputNAVString(string tag, int iret, const Vector<double>& Vec)
00791       throw()
00792    {
00793       ostringstream oss;
00794 
00795       // tag NAV timetag X Y Z clks endtag
00796       oss << tag << " NAV " << printTime(currTime,gpsfmt)
00797          << fixed << setprecision(6)
00798          << " " << setw(16) << (&Vec==&PRSNullVector ? Solution(0) : Vec(0))
00799          << " " << setw(16) << (&Vec==&PRSNullVector ? Solution(1) : Vec(1))
00800          << " " << setw(16) << (&Vec==&PRSNullVector ? Solution(2) : Vec(2))
00801          << fixed << setprecision(3);
00802       for(int i=0; i<SystemIDs.size(); i++) {
00803          RinexSatID sat(1,SystemIDs[i]);
00804          oss << " " << sat.systemString3() << " " << setw(11) << Solution(3+i);
00805       }
00806       oss << outputValidString(iret);
00807 
00808       return oss.str();
00809    }  // end PRSolution::outputNAVString
00810 
00811    string PRSolution::outputPOSString(string tag, int iret, const Vector<double>& Vec)
00812       throw()
00813    {
00814       ostringstream oss;
00815 
00816       // tag POS timetag X Y Z endtag
00817       oss << tag << " POS " << printTime(currTime,gpsfmt)
00818          << fixed << setprecision(6)
00819          << " " << setw(16) << (&Vec==&PRSNullVector ? Solution(0) : Vec(0))
00820          << " " << setw(16) << (&Vec==&PRSNullVector ? Solution(1) : Vec(1))
00821          << " " << setw(16) << (&Vec==&PRSNullVector ? Solution(2) : Vec(2))
00822          << outputValidString(iret);
00823 
00824       return oss.str();
00825    }  // end PRSolution::outputPOSString
00826 
00827    string PRSolution::outputCLKString(string tag, int iret) throw()
00828    {
00829       ostringstream oss;
00830 
00831       // tag CLK timetag SYS clk [SYS clk SYS clk ...] endtag
00832       oss << tag << " CLK " << printTime(currTime,gpsfmt)
00833          << fixed << setprecision(3);
00834       for(int i=0; i<SystemIDs.size(); i++) {
00835          RinexSatID sat(1,SystemIDs[i]);
00836          oss << " " << sat.systemString3() << " " << setw(11) << Solution(3+i);
00837       }
00838       oss << outputValidString(iret);
00839 
00840       return oss.str();
00841    }  // end PRSolution::outputCLKString
00842 
00843    // NB must call DOPCompute() if SimplePRSol() only was called.
00844    string PRSolution::outputRMSString(string tag, int iret) throw()
00845    {
00846       ostringstream oss;
00847 
00848       // tag RMS timetag NSVdrop Nsv RMS Slope niter conv
00849       oss << tag << " RMS " << printTime(currTime,gpsfmt)
00850          << " " << setw(2) << SatelliteIDs.size()-Nsvs
00851          << " " << setw(2) << Nsvs
00852          << fixed << setprecision(3)
00853          << " " << setw(8) << RMSResidual
00854          << setprecision(2)
00855          << " " << setw(7) << TDOP
00856          << " " << setw(7) << PDOP
00857          << " " << setw(7) << GDOP
00858          << setprecision(1)
00859          << " " << setw(5) << MaxSlope
00860          << " " << setw(2) << NIterations
00861          << scientific << setprecision(2)
00862          << " " << setw(8) << Convergence;
00863       for(int i=0; i<SatelliteIDs.size(); i++) {
00864          RinexSatID rs(::abs(SatelliteIDs[i].id), SatelliteIDs[i].system);
00865          oss << " " << (SatelliteIDs[i].id < 0 ? "-" : " ") << rs;
00866       }
00867       oss << outputValidString(iret);
00868 
00869       return oss.str();
00870    }  // end PRSolution::outputRMSString
00871 
00872    string PRSolution::outputString(string tag, int iret, const Vector<double>& Vec)
00873       throw()
00874    {
00875       ostringstream oss;
00876       oss << outputNAVString(tag,iret,Vec) << endl;
00877       oss << outputRMSString(tag,iret);
00878 
00879       return oss.str();
00880    }  // end PRSolution::outputString
00881 
00882    string PRSolution::errorCodeString(int iret) throw()
00883    {
00884       string str("unknown");
00885       if(iret == 1) str = string("ok but perhaps degraded");
00886       else if(iret== 0) str = string("ok");
00887       else if(iret==-1) str = string("failed to converge");
00888       else if(iret==-2) str = string("singular solution");
00889       else if(iret==-3) str = string("not enough satellites");
00890       else if(iret==-4) str = string("not any ephemeris");
00891       return str;
00892    }
00893 
00894    string PRSolution::configString(string tag) throw()
00895    {
00896       ostringstream oss;
00897       oss << tag << " " << printTime(currTime,timfmt)
00898          << (Valid ? "":" not") << " valid,"
00899          << (Mixed ? "":" not") << " mixed"
00900          << "\n   iterations " << MaxNIterations
00901          << "\n   convergence " << scientific << setprecision(2) << ConvergenceLimit
00902          << "\n   RMS residual limit " << fixed << RMSLimit
00903          << "\n   RAIM slope limit " << fixed << SlopeLimit << " meters"
00904          << "\n   Maximum number of satellites to reject is " << NSatsReject
00905          << "\n   Memory information IS " << (hasMemory ? "":"NOT ") << "stored"
00906          ;
00907 
00908       // TD output memory information
00909       //if(APrioriSol.size() >= 4) oss
00910       //   << "\n   APriori is " << fixed << setprecision(3) << APrioriSol(0)
00911       //      << " " << APrioriSol(1) << " " << APrioriSol(2) << " " << APrioriSol(3);
00912       //else oss << "\n   APriori is undefined";
00913 
00914       return oss.str();
00915    }
00916 
00917    const Vector<double> PRSolution::PRSNullVector;
00918 
00919 } // namespace gpstk
00920 

Generated on Fri May 24 03:31:10 2013 for GPS ToolKit Software Library by  doxygen 1.3.9.1