CodeKalmanSolver.cpp

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

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