CodeKalmanSolver.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: CodeKalmanSolver.cpp 3140 2012-06-18 15:03:02Z susancummins $"
00002 
00008 //============================================================================
00009 //
00010 //  This file is part of GPSTk, the GPS Toolkit.
00011 //
00012 //  The GPSTk is free software; you can redistribute it and/or modify
00013 //  it under the terms of the GNU Lesser General Public License as published
00014 //  by the Free Software Foundation; either version 2.1 of the License, or
00015 //  any later version.
00016 //
00017 //  The GPSTk is distributed in the hope that it will be useful,
00018 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 //  GNU Lesser General Public License for more details.
00021 //
00022 //  You should have received a copy of the GNU Lesser General Public
00023 //  License along with GPSTk; if not, write to the Free Software Foundation,
00024 //  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
00025 //
00026 //  Dagoberto Salazar - gAGE ( http://www.gage.es ). 2008, 2009, 2011
00027 //
00028 //============================================================================
00029 
00030 
00031 #include "CodeKalmanSolver.hpp"
00032 #include "MatrixFunctors.hpp"
00033 
00034 
00035 namespace gpstk
00036 {
00037 
00038       // Returns a string identifying this object.
00039    std::string CodeKalmanSolver::getClassName() const
00040    { return "CodeKalmanSolver"; }
00041 
00042 
00043       // Default constructor.
00044    CodeKalmanSolver::CodeKalmanSolver()
00045    {
00046 
00047          // First, let's define a set with the typical code-based unknowns
00048       TypeIDSet tempSet;
00049       tempSet.insert(TypeID::dx);
00050       tempSet.insert(TypeID::dy);
00051       tempSet.insert(TypeID::dz);
00052       tempSet.insert(TypeID::cdt);
00053 
00054          // Now, we build the default definition for a common GNSS 
00055          // code-based equation
00056       defaultEqDef.header = TypeID::prefitC;
00057       defaultEqDef.body = tempSet;
00058 
00059          // Call the initializing method
00060       Init();
00061 
00062    }  // End of 'CodeKalmanSolver::CodeKalmanSolver()'
00063 
00064 
00065 
00066       // Initializing method.
00067    void CodeKalmanSolver::Init()
00068    {
00069 
00070       numUnknowns = defaultEqDef.body.size();
00071 
00072       Vector<double> initialState(numUnknowns, 0.0);
00073       Matrix<double> initialErrorCovariance(numUnknowns, numUnknowns, 0.0);
00074          // Fill the initialErrorCovariance matrix
00075          // First, the coordinates
00076       for (int i=0; i<3; i++)
00077       {
00078          initialErrorCovariance(i,i) = 100.0;
00079       }
00080          // Now, the receiver clock
00081       initialErrorCovariance(3,3) = 9.0e10;
00082 
00083       kFilter.Reset( initialState, initialErrorCovariance );
00084 
00085          // Set default coordinates stochastic model (constant)
00086       setCoordinatesModel(&constantModel);
00087 
00088 
00089          // Pointer to default receiver clock stochastic model (white noise)
00090       pClockStoModel = &whitenoiseModel;
00091 
00092 
00093       solution.resize(numUnknowns);
00094 
00095    }  // End of method 'CodeKalmanSolver::Init()'
00096 
00097 
00098 
00099       /* Explicit constructor. Sets the default equation definition
00100        * to be used when fed with GNSS data structures.
00101        *
00102        * @param eqDef     gnssEquationDefinition to be used
00103        */
00104    CodeKalmanSolver::CodeKalmanSolver(const gnssEquationDefinition& eqDef)
00105    {
00106 
00107       setDefaultEqDefinition(eqDef);
00108 
00109       Init();
00110 
00111    }  // End of 'CodeKalmanSolver::CodeKalmanSolver()'
00112 
00113 
00114 
00115       /* Compute the code-based Kalman solution of the given equations set.
00116        *
00117        * @param prefitResiduals   Vector of prefit residuals
00118        * @param designMatrix      Design matrix for the equation system
00119        * @param weightVector      Vector of weights assigned to each
00120        *                          satellite.
00121        *
00122        * \warning A typical Kalman filter works with the measurements noise
00123        * covariance matrix, instead of the vector of weights. Beware of this
00124        * detail, because this method uses the later.
00125        *
00126        * \warning If you use this method, be sure you previously set
00127        * phiMatrix and qMatrix using the appropriate methods.
00128        *
00129        * @return
00130        *  0 if OK
00131        *  -1 if problems arose
00132        */
00133    int CodeKalmanSolver::Compute( const Vector<double>& prefitResiduals,
00134                                   const Matrix<double>& designMatrix,
00135                                   const Vector<double>& weightVector )
00136       throw(InvalidSolver)
00137    {
00138 
00139          // By default, results are invalid
00140       valid = false;
00141 
00142          // Check that everyting has a proper size
00143       int wSize = static_cast<int>(weightVector.size());
00144       int pSize = static_cast<int>(prefitResiduals.size());
00145       if (!(wSize==pSize))
00146       {
00147          InvalidSolver e("prefitResiduals size does not match dimension \
00148 of weightVector");
00149 
00150          GPSTK_THROW(e);
00151       }
00152 
00153       Matrix<double> wMatrix(wSize,wSize,0.0);  // Declare a weight matrix
00154 
00155          // Fill the weight matrix diagonal with the content of 
00156          // the weight vector
00157       for (int i=0; i<wSize; i++)
00158       {
00159          wMatrix(i,i) = weightVector(i);
00160       }
00161 
00162          // Call the more general CodeKalmanSolver::Compute() method
00163       return CodeKalmanSolver::Compute( prefitResiduals,
00164                                         designMatrix,
00165                                         wMatrix );
00166 
00167    }  // End of method 'CodeKalmanSolver::Compute()'
00168 
00169 
00170 
00171       // Compute the code-based Kalman solution of the given equations set.
00172       //
00173       // @param prefitResiduals   Vector of prefit residuals
00174       // @param designMatrix      Design matrix for equation system
00175       // @param weightMatrix      Matrix of weights
00176       //
00177       // \warning A typical Kalman filter works with the measurements noise
00178       // covariance matrix, instead of the matrix of weights. Beware of this
00179       // detail, because this method uses the later.
00180       //
00181       // \warning If you use this method, be sure you previously set
00182       // phiMatrix and qMatrix using the appropriate methods.
00183       //
00184       // @return
00185       //  0 if OK
00186       //  -1 if problems arose
00187       //
00188    int CodeKalmanSolver::Compute( const Vector<double>& prefitResiduals,
00189                                   const Matrix<double>& designMatrix,
00190                                   const Matrix<double>& weightMatrix )
00191       throw(InvalidSolver)
00192    {
00193 
00194          // By default, results are invalid
00195       valid = false;
00196 
00197       if (!(weightMatrix.isSquare()))
00198       {
00199          InvalidSolver e("Weight matrix is not square");
00200          GPSTK_THROW(e);
00201       }
00202 
00203       int wRow = static_cast<int>(weightMatrix.rows());
00204       int pRow = static_cast<int>(prefitResiduals.size());
00205       if (!(wRow==pRow))
00206       {
00207          InvalidSolver e("prefitResiduals size does not match dimension of \
00208 weightMatrix");
00209 
00210          GPSTK_THROW(e);
00211       }
00212 
00213       int gRow = static_cast<int>(designMatrix.rows());
00214       if (!(gRow==pRow))
00215       {
00216          InvalidSolver e("prefitResiduals size does not match dimension \
00217 of designMatrix");
00218 
00219          GPSTK_THROW(e);
00220       }
00221 
00222       if (!(phiMatrix.isSquare()))
00223       {
00224          InvalidSolver e("phiMatrix is not square");
00225 
00226          GPSTK_THROW(e);
00227       }
00228 
00229       int phiRow = static_cast<int>(phiMatrix.rows());
00230       if (!(phiRow==numUnknowns))
00231       {
00232          InvalidSolver e("prefitResiduals size does not match dimension \
00233 of phiMatrix");
00234 
00235          GPSTK_THROW(e);
00236       }
00237 
00238       if (!(qMatrix.isSquare()))
00239       {
00240          InvalidSolver e("qMatrix is not square");
00241 
00242          GPSTK_THROW(e);
00243       }
00244 
00245       int qRow = static_cast<int>(qMatrix.rows());
00246       if (!(qRow==numUnknowns))
00247       {
00248          InvalidSolver e("prefitResiduals size does not match dimension \
00249 of qMatrix");
00250 
00251          GPSTK_THROW(e);
00252       }
00253 
00254          // After checking sizes, let's invert the matrix of weights in order
00255          // to get the measurements noise covariance matrix, which is what we
00256          // use in the "SimpleKalmanFilter" class
00257       Matrix<double> measNoiseMatrix;
00258 
00259       try
00260       {
00261          measNoiseMatrix = inverseChol(weightMatrix);
00262       }
00263       catch(...)
00264       {
00265          InvalidSolver e("Correct(): Unable to compute measurements noise \
00266 covariance matrix.");
00267 
00268          GPSTK_THROW(e);
00269       }
00270 
00271       try
00272       {
00273             // Call the Kalman filter object.
00274          kFilter.Compute( phiMatrix,
00275                           qMatrix,
00276                           prefitResiduals,
00277                           designMatrix,
00278                           measNoiseMatrix );
00279       }
00280       catch(InvalidSolver& e)
00281       {
00282          GPSTK_RETHROW(e);
00283       }
00284 
00285          // Store the solution
00286       solution = kFilter.xhat;
00287 
00288          // Store the covariance matrix of the solution
00289       covMatrix = kFilter.P;
00290 
00291          // Compute the postfit residuals Vector
00292       postfitResiduals = prefitResiduals - designMatrix * solution;
00293 
00294          // If everything is fine so far, then the results should be valid
00295       valid = true;
00296 
00297       return 0;
00298 
00299    }  // End of method 'CodeKalmanSolver::Compute()'
00300 
00301 
00302 
00303       /* Returns a reference to a gnnsSatTypeValue object after
00304        * solving the previously defined equation system.
00305        *
00306        * @param gData    Data object holding the data.
00307        */
00308    gnssSatTypeValue& CodeKalmanSolver::Process(gnssSatTypeValue& gData)
00309       throw(ProcessingException)
00310    {
00311 
00312       try
00313       {
00314 
00315             // Build a gnssRinex object and fill it with data
00316          gnssRinex g1;
00317          g1.header = gData.header;
00318          g1.body = gData.body;
00319 
00320             // Call the Process() method with the appropriate input object
00321          Process(g1);
00322 
00323             // Update the original gnssSatTypeValue object with the results
00324          gData.body = g1.body;
00325 
00326          return gData;
00327 
00328       }
00329       catch(Exception& u)
00330       {
00331             // Throw an exception if something unexpected happens
00332          ProcessingException e( getClassName() + ":"
00333                                 + u.what() );
00334 
00335          GPSTK_THROW(e);
00336 
00337       }
00338 
00339    }  // End of method 'CodeKalmanSolver::Process()'
00340 
00341 
00342 
00343       /* Returns a reference to a gnnsRinex object after solving
00344        * the previously defined equation system.
00345        *
00346        * @param gData     Data object holding the data.
00347        */
00348    gnssRinex& CodeKalmanSolver::Process(gnssRinex& gData)
00349       throw(ProcessingException)
00350    {
00351 
00352       try
00353       {
00354 
00355             // Number of measurements equals the number of visible satellites
00356          numMeas = gData.numSats();
00357 
00358             // State Transition Matrix (PhiMatrix)
00359          phiMatrix.resize(numUnknowns, numUnknowns, 0.0);
00360 
00361             // Noise covariance matrix (QMatrix)
00362          qMatrix.resize(numUnknowns, numUnknowns, 0.0);
00363 
00364             // Geometry matrix
00365          hMatrix.resize(numMeas, numUnknowns, 0.0);
00366 
00367             // Weights matrix
00368          rMatrix.resize(numMeas, numMeas, 0.0);
00369 
00370             // Measurements vector (Prefit-residuals)
00371          measVector.resize(numMeas, 0.0);
00372 
00373             // Build the vector of measurements
00374          measVector = gData.getVectorOfTypeID(defaultEqDef.header);
00375 
00376 
00377             // Generate the appropriate weights matrix
00378             // Try to extract weights from GDS
00379          satTypeValueMap dummy(gData.body.extractTypeID(TypeID::weight));
00380 
00381             // Count the number of satellites with weights
00382          int nW(dummy.numSats());
00383          for (int i=0; i<numMeas; i++)
00384          {
00385             if (nW == numMeas)   // Check if weights match
00386             {
00387                Vector<double>
00388                   weightsVector(gData.getVectorOfTypeID(TypeID::weight));
00389 
00390                rMatrix(i,i) = weightsVector(i);
00391             }
00392             else
00393             {
00394 
00395                  // If weights don't match, assign generic weights
00396                rMatrix(i,i) = 1.0;
00397 
00398             }
00399          }
00400 
00401 
00402             // Generate the corresponding geometry/design matrix
00403          hMatrix = gData.body.getMatrixOfTypes((*this).defaultEqDef.body);
00404 
00405          SatID  dummySat;
00406 
00407             // Now, let's fill the Phi and Q matrices
00408             // First, the coordinates
00409          pCoordXStoModel->Prepare(dummySat, gData);
00410          phiMatrix(0,0) = pCoordXStoModel->getPhi();
00411          qMatrix(0,0)   = pCoordXStoModel->getQ();
00412 
00413          pCoordYStoModel->Prepare(dummySat, gData);
00414          phiMatrix(1,1) = pCoordYStoModel->getPhi();
00415          qMatrix(1,1)   = pCoordYStoModel->getQ();
00416 
00417          pCoordZStoModel->Prepare(dummySat, gData);
00418          phiMatrix(2,2) = pCoordZStoModel->getPhi();
00419          qMatrix(2,2)   = pCoordZStoModel->getQ();
00420 
00421 
00422             // Now, the receiver clock
00423          pClockStoModel->Prepare(dummySat, gData);
00424          phiMatrix(3,3) = pClockStoModel->getPhi();
00425          qMatrix(3,3)   = pClockStoModel->getQ();
00426 
00427              // Call the Compute() method with the defined equation model.
00428              // This equation model MUST HAS BEEN previously set, usually
00429              // when creating the CodeKalmanSolver object with the
00430              // appropriate constructor.
00431          Compute(measVector, hMatrix, rMatrix);
00432 
00433 
00434             // Now we have to add the new values to the data structure
00435          if ( defaultEqDef.header == TypeID::prefitC )
00436          {
00437             gData.insertTypeIDVector(TypeID::postfitC, postfitResiduals);
00438          }
00439 
00440          return gData;
00441 
00442       }
00443       catch(Exception& u)
00444       {
00445             // Throw an exception if something unexpected happens
00446          ProcessingException e( getClassName() + ":"
00447                                 + u.what() );
00448 
00449          GPSTK_THROW(e);
00450 
00451       }
00452 
00453    }  // End of method 'CodeKalmanSolver::Process()'
00454 
00455 
00456 
00457       /* Set a single coordinates stochastic model to ALL coordinates.
00458        *
00459        * @param pModel      Pointer to StochasticModel associated with
00460        *                    coordinates.
00461        *
00462        * @warning Do NOT use this method to set the SAME state-aware
00463        * stochastic model (like RandomWalkModel, for instance) to ALL
00464        * coordinates, because the results will certainly be erroneous. Use
00465        * this method only with non-state-aware stochastic models like
00466        * 'StochasticModel' (constant coordinates) or 'WhiteNoiseModel'.
00467        */
00468    CodeKalmanSolver& CodeKalmanSolver::setCoordinatesModel(
00469                                                    StochasticModel* pModel)
00470    {
00471 
00472          // All coordinates will have the same model
00473       pCoordXStoModel = pModel;
00474       pCoordYStoModel = pModel;
00475       pCoordZStoModel = pModel;
00476 
00477       return (*this);
00478 
00479    }  // End of method 'CodeKalmanSolver::setCoordinatesModel()'
00480 
00481 
00482 }  // End of namespace gpstk

Generated on Sun May 19 03:31:05 2013 for GPS ToolKit Software Library by  doxygen 1.3.9.1