Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

KalmanFilter.cpp

Go to the documentation of this file.
00001 // $Id: KalmanFilter.cpp,v 1.3 2005/05/25 09:29:22 hernando Exp $
00002 //
00003 //  Implementation of the KalmanFilter tool
00004 //
00005 //  Original Author: Rutger van der Eijk
00006 //  Created: 07-04-1999
00007 //  Adapted: 21-03-2002  Olivier Callot
00008 //  Adapted: 15-04-2005  Jose A. Hernando
00009 
00010 //gaudi
00011 #include "GaudiKernel/ToolFactory.h"
00012 
00013 // TrEvent
00014 #include "KalmanFilter.h"
00015 
00016 // CLHEP
00017 #include "CLHEP/Matrix/DiagMatrix.h"
00018 #include "CLHEP/Matrix/Matrix.h"
00019 #include "CLHEP/Units/PhysicalConstants.h"
00020 
00021 static const ToolFactory<KalmanFilter>  s_factory;
00022 const IToolFactory& KalmanFilterFactory = s_factory;
00023 
00024 KalmanFilter::KalmanFilter( const std::string& type,
00025                             const std::string& name,
00026                             const IInterface* parent) :
00027   GaudiTool( type, name, parent)
00028 {
00029   declareInterface<ITrackFitter>( this );
00030 
00031   declareProperty("Extrapolator",m_extrapolatorName = "MasterExtrapolator");
00032 
00033   declareProperty("Projector",m_projectorName = "MasterProjector");
00034 
00035   m_state = NULL;
00036   m_nodes.clear();
00037   m_K = HepVector(5,0);
00038 }
00039 
00040 KalmanFilter::~KalmanFilter() {
00041 }
00042 
00043 StatusCode KalmanFilter::initialize() 
00044 {
00045   m_extrapolator = get<ITrackExtrapolator>(m_extrapolatorName);
00046 
00047   m_projector = get<ITrackProjector>(m_projectorName);
00048 
00049   return StatusCode::SUCCESS;
00050 }
00051 
00052 StatusCode KalmanFilter::failure(const std::string& comment){
00053   info() << " Kalman Filter failure: " << comment << endreq;
00054   return StatusCode::FAILURE;
00055 }
00056 
00057 //
00058 // perform filter /smoothing
00059 //
00060 
00061 StatusCode KalmanFilter::fit(Track& track, const State& state)
00062 {
00063   StatusCode sc = filter(track,state);
00064   if (sc.isFailure()) return failure(" No able to filter the track");
00065   
00066   return sc = smoother(track);
00067   if (sc.isFailure()) return failure(" No able to smooth the track");
00068   
00069   return sc;
00070 }
00071 
00072 StatusCode KalmanFilter::iniKalman(Track & track) 
00073 {
00074   // destroy the previous state if not null
00075   if (m_state != NULL) delete m_state;
00076   // Kalman has private copy of the nodes to acelerate the computations
00077   // remember that the track owns the Nodes, so it is responsability of the
00078   // Track destructor to delete them!
00079   m_nodes.clear();
00080   std::vector<Measurement*>& measures = track.measurements();
00081   std::vector<Node*>& nodes = track.nodes();
00082   if (nodes.size() > 0) 
00083     for (std::vector<Node*>::iterator it = nodes.begin(); it != nodes.end();
00084          it++) delete *it;  
00085   nodes.clear();
00086   for (std::vector<Measurement*>::iterator it = measures.begin(); 
00087        it != measures.end(); it++) {
00088     Measurement& meas = *(*it);
00089     FitNode* node = new FitNode(meas);
00090     m_nodes.push_back(node);
00091     track.addToNodes(node);
00092   }
00093 
00094   if (msgLevel(MSG::DEBUG)) {
00095     debug() << " seed state vector \t" << m_state->stateVector() << endreq;
00096     debug() << " seed state cov \t" << m_state->covariance() << endreq;
00097     debug() << " track nodes size \t" << m_nodes.size() << endreq;
00098   }
00099   
00100   return StatusCode::SUCCESS;
00101 }
00102 
00103 StatusCode KalmanFilter::filter(Track& track, const State& state)
00104 {
00105   StatusCode sc = StatusCode::SUCCESS;
00106   sc = iniKalman(track);
00107   if (sc.isFailure()) return failure(" Not able to create Nodes");
00108 
00109   m_state = state.clone();
00110 
00111   std::vector<FitNode*>::iterator iNode = m_nodes.begin();
00112   double z = (*iNode)->measurement().z();
00113   // sc = m_extrapolator->propagate(*m_state,z,m_particleID);
00114   sc = m_extrapolator->propagate(*m_state,z);
00115   if (sc.isFailure()) 
00116     return failure(" Not able to extrapolate to 1st measurement");
00117 
00118   // TODO: handle different iterations
00119   for (iNode = m_nodes.begin(); iNode != m_nodes.end(); ++iNode) {
00120     FitNode& node = *(*iNode);
00121     sc = predict(node,*m_state);
00122     if (sc.isFailure()) return failure(" not able to predict at node");
00123     sc = filter(node);
00124     if (sc.isFailure()) return failure(" not able to filter node ");
00125   }  
00126 
00127   computeChiSq(track);
00128   return sc;
00129 }
00130 
00131 StatusCode KalmanFilter::smoother(Track& track) 
00132 {
00133   StatusCode sc = StatusCode::SUCCESS;
00134   // smoother loop - runs in opposite direction to filter
00135   std::vector<FitNode*>::reverse_iterator riNode = m_nodes.rbegin();
00136   FitNode* oldNode = *riNode;
00137   ++riNode;
00138   
00139   while (riNode != m_nodes.rend()) {
00140     sc = smooth( *(*riNode), *oldNode );
00141     if (sc.isFailure()) return failure(" not able to smooth node");      
00142     oldNode = *riNode;
00143     ++riNode;
00144   }
00145 
00146   computeChiSq(track);
00147 
00148   return StatusCode::SUCCESS;
00149 }
00150 
00151 void KalmanFilter::computeChiSq(Track& track) 
00152 {
00153   double chi2 = 0.;
00154   for (std::vector<FitNode*>::iterator it = m_nodes.begin();
00155        it != m_nodes.end(); it++) 
00156     chi2 += (*it)->chi2();
00157   int ndof = -(m_state->nParameters());
00158   ndof += m_nodes.size();
00159   double chi2Norma = 0.;
00160   if (ndof != 0) chi2Norma = chi2 /((float) (ndof));
00161   track.setChi2PerDoF(chi2Norma);
00162   track.setNDoF(ndof);
00163 
00164   if (msgLevel(MSG::DEBUG)) {
00165     debug() << " track ndof \t" << track.chi2() << endreq;
00166     debug() << " track chi2, chi2/ndof \t " << track.chi2()  << ", "
00167             << track.chi2PerDoF() << endreq;
00168   }
00169   
00170 }
00171 
00172 //
00173 // perform Kalman filter step on a node ie predict-update
00174 //
00175 StatusCode KalmanFilter::predict(FitNode& aNode, State& aState) {
00176 
00177   Measurement& thisMeasure = aNode.measurement();
00178 
00179   // only use extrapolator in first iteration; else use stored parameters
00180   HepVector prevStateVec = aState.stateVector();
00181   HepSymMatrix prevStateCov = aState.covariance();
00182   double z = thisMeasure.z();
00183   // StatusCode sc = m_extrapolator->propagate(state,z,m_particleID);
00184   StatusCode sc = m_extrapolator->propagate(aState,z);
00185   if (sc.isFailure()) 
00186     return failure(" No able to predit state at next measurement");
00187 
00188   const HepMatrix& F = m_extrapolator->transportMatrix();
00189   aNode.setTransportMatrix( F );
00190   aNode.setTransportVector( aState.stateVector() - F * prevStateVec );
00191   aNode.setNoiseMatrix( aState.covariance() - prevStateCov.similarity(F) );
00192 
00193   // save predicted state
00194   aNode.setPredictedState(aState);
00195 
00196   if (msgLevel(MSG::DEBUG)) {
00197     debug() << " predicted  state at z \t" << z << endreq;
00198     debug() << " predicted  state vector  \t" << aState.stateVector() << endreq;
00199     debug() << " predicted  state cov \t" << aState.covariance() << endreq;
00200     debug() << " transport matrix \t" << aNode.transportMatrix() << endreq;
00201     debug() << " transport vector \t" << aNode.transportVector() << endreq;
00202     debug() << " noise matrix \t" << aNode.noiseMatrix() << endreq;
00203   } 
00204 
00205   return StatusCode::SUCCESS;  
00206 }
00207 
00208 StatusCode KalmanFilter::filter(FitNode& node) 
00209 {
00210   
00211   Measurement& meas = node.measurement();
00212   State& state = node.state();
00213 
00214   StatusCode sc = filter(state, meas);
00215   if (sc.isFailure()) return failure("Not able to filter the node!");
00216 
00217   double tMeasureError = meas.errMeasure();
00218   double res = m_projector->residual();  
00219   const HepVector& H = m_projector->projectionMatrix();
00220 
00221   double HK = dot ( H, m_K);
00222   res     *= (1 - HK);
00223   double errorRes = (1 - HK) * pow(tMeasureError, 2.0);
00224   
00225   node.setResidual(res);
00226   node.setErrResidual(sqrt(errorRes));
00227   
00228   // save predicted state
00229   node.setFilteredState(state);
00230 
00231   if (msgLevel(MSG::DEBUG)) {
00232     debug() << " filtered residual and error \t" << node.residual() << ", "
00233             <<node.errResidual() << endreq;;
00234   } 
00235  
00236   return StatusCode::SUCCESS;
00237 }
00238 
00239 //-----------------------------------------------------------------
00240 // Update the current track 'state' with the TrMeasurement 'measure'.
00241 // (i.e. filter the measurement into the state)
00242 //  the  measurement ch-sq is updated
00243 //-----------------------------------------------------------------
00244 StatusCode KalmanFilter::filter(State& state, Measurement& meas)  {
00245   
00246   // check z position
00247   if ( fabs(meas.z() - state.z()) > 1e-6) {
00248     warning() << "z position of TrState (=" << state.z() 
00249               << ") and TrStateMeasurement (= " << meas.z() 
00250               << ") are not equal." << endreq;
00251   }
00252 
00253   // get reference to the state vector and cov
00254   HepVector&    tX = state.stateVector();
00255   HepSymMatrix& tC = state.covariance();
00256 
00257   // project the state into the measurement 
00258   StatusCode sc = m_projector->project(state,meas);
00259   if (sc.isFailure()) 
00260     return failure(" Not able to project a state into a measurement");
00261   
00262   // calculate predicted residuals
00263   double errorMeas = meas.errMeasure();
00264   double res = m_projector->residual();
00265   double errorRes = m_projector->errResidual();
00266   double errorRes2 = (errorRes*errorRes);
00267   const HepVector& H = m_projector->projectionMatrix();
00268 
00269   // calculate gain matrix K
00270   m_K = (tC * H)/errorRes2;
00271 
00272   // update state vector 
00273   tX += m_K * res;
00274 
00275   HepMatrix B  = HepDiagMatrix(tC.num_row(), 1) - ( m_K * H.T());
00276   tC.assign( B * tC * B.T() + ( m_K * pow(errorMeas, 2.0) * m_K.T()));
00277 
00278  if (msgLevel(MSG::DEBUG)) {
00279     debug() << " measure and error \t" << meas.measure() << ", " 
00280             << errorMeas << endreq;
00281     debug() << " residual and error \t" << res << ", " 
00282             << errorRes << endreq;
00283     debug() << " projection matrix \t" << H << endreq;
00284     debug() << " gain matrix \t" << m_K << endreq;
00285     debug() << " filter state vector \t" << tX << endreq;
00286     debug() << " filter state covariance \t"<< tC << endreq;
00287   }
00288   
00289   return sc;
00290 }
00291 
00292 //----------------------------------------------------------------
00293 // smooth a node on a track
00294 // Input: node to be smoothed (k) + last node (k+1)
00295 // remember we are now running in the opposite direction to the filter !!
00296 // M. Needham 9/11/99
00297 //----------------------------------------------------------------
00298 StatusCode KalmanFilter::smooth(FitNode& thisNode, FitNode& prevNode){
00299 
00300   // preliminaries, first we need to invert the _predicted_ covariance
00301   // matrix at k+1
00302   HepVector&    prevNodeX = prevNode.predictedState().stateVector();
00303   HepSymMatrix& prevNodeC = prevNode.predictedState().covariance();
00304 
00305   // check that the elements are not too large else dsinv will crash
00306   StatusCode sc = checkInvertMatrix(prevNodeC);; 
00307   if ( sc.isFailure() ) return failure(" not valid matrix in smoother"); 
00308 
00309   //invert the covariance matrix
00310   HepSymMatrix  invPrevNodeC = prevNodeC;
00311   sc = invertMatrix(invPrevNodeC);
00312   if ( sc.isFailure() ) return failure(" inverting matrix in smoother");
00313 
00314   //references to _predicted_ state + cov of this node from the first step
00315   HepVector&    thisNodeX = thisNode.state().stateVector();
00316   HepSymMatrix& thisNodeC = thisNode.state().covariance();
00317 
00318   //transport
00319   const HepMatrix& F = prevNode.transportMatrix();
00320 
00321   //calculate gain matrix A
00322   HepMatrix A = thisNodeC * F.T() * invPrevNodeC;
00323 
00324   // best = smoothed state at prev Node
00325   HepVector&    prevNodeSmoothedX = prevNode.state().stateVector();
00326   HepSymMatrix& prevNodeSmoothedC = prevNode.state().covariance();
00327 
00328   //smooth state
00329   thisNodeX += A * (prevNodeSmoothedX - prevNodeX);
00330 
00331   // smooth covariance  matrix
00332   HepSymMatrix covDiff = prevNodeSmoothedC- prevNodeC;
00333   HepSymMatrix covUpDate = covDiff.similarity(A);
00334   thisNodeC += covUpDate;
00335 
00336   // check that the cov matrix is possitive
00337   sc = checkPositiveMatrix(thisNodeC);
00338   if (sc.isFailure()) return Warning(" not postive Matrix in smoother");
00339 
00340   // update = smooth the residuals
00341   const HepVector& H = thisNode.projectionMatrix();
00342   sc = m_projector->project(thisNode.state(),thisNode.measurement());
00343   if (sc.isFailure()) Warning(" unable to project the smooth node");
00344   double res = m_projector->residual();
00345   thisNode.setResidual(res);
00346   double errRes = thisNode.errResidual();
00347   double errRes2 = errRes*errRes -  covUpDate.similarity(H);
00348   if (errRes2 >0.) errRes = sqrt(errRes2);
00349   else return Warning(" negative error residuals in smoother");
00350   thisNode.setErrResidual(sqrt(errRes));
00351 
00352   if (msgLevel(MSG::DEBUG)) {
00353     debug() << " A matrix \t" << A << endreq;;
00354     debug() << " smooth state vector \t" << thisNodeX << endreq;
00355     debug() << " smooth state covariance \t"<< thisNodeC << endreq;
00356     debug() << " smooth residual, error and chi2 \t" << res << ", "
00357             << errRes << ", " << thisNode.chi2() << endreq;      
00358   }
00359 
00360   return StatusCode::SUCCESS;
00361 }
00362 
00363 StatusCode KalmanFilter::checkInvertMatrix(HepSymMatrix& mat) 
00364 {
00365   int nParam = (int) mat.num_row();
00366   for (int i=0; i<nParam; ++i){
00367     for (int j=0; j<nParam; ++j){
00368       if (mat[i][j] > 1e20)
00369         return Warning("covariance errors too big to invert");
00370     } // j
00371   }   // i
00372   return StatusCode::SUCCESS;
00373 }
00374 
00375 StatusCode KalmanFilter::checkPositiveMatrix(HepSymMatrix& mat) 
00376 {
00377   int nParam = (int) mat.num_row();
00378   for (int i=0; i<nParam; ++i){
00379     if (mat[i][i] <= 0.)
00380       return Warning("covariance errors too big to convert");
00381   } 
00382  
00383 
00384  return StatusCode::SUCCESS;
00385 }
00386 
00387 //=========================================================================
00388 // Invert prev node covariance matrix
00389 // What follows may seem strange - trust me it works - you
00390 // are strongly recommended NOT to change it. It turns out that
00391 // the choice of MeV, mm as units is BAD - the inversion simply fails
00392 // for numerical reasons. Therefore it is necessary to change back to G3
00393 // units, invert then go back to G4 units
00394 // M. Needham 13/6/2000
00395 // J.A. Hernando (we trust you) 15/05/05
00396 //=========================================================================
00397 StatusCode KalmanFilter::invertMatrix(HepSymMatrix& invPrevNodeC){
00398 
00399   StatusCode sc = StatusCode::SUCCESS; 
00400 
00401   // G3 units
00402   cToG3(invPrevNodeC);
00403 
00404   HepSymMatrix tempMatrix = invPrevNodeC;
00405 
00406   int ifail;
00407   invPrevNodeC.invert(ifail);
00408 
00409   //G4 units
00410   cToG4(invPrevNodeC);
00411 
00412   if (ifail !=0){
00413     warning()
00414        <<"failed to invert covariance matrix, failure code " <<ifail<<endreq;
00415     sc = StatusCode::FAILURE;
00416   }
00417   return sc;
00418 }
00419 
00420 //=========================================================================
00421 //  Change some units for better matrix invertability
00422 //=========================================================================
00423 StatusCode KalmanFilter::cToG3(HepSymMatrix& C){
00424 
00425   // cov matrix
00426   C[0][0] /= cm2;
00427   C[0][1] /= cm2;
00428   C[0][2] /= cm;
00429   C[0][3] /= cm;
00430   C[0][4]  = C[0][4]*GeV/cm;
00431 
00432   C[1][1] /= cm2;
00433   C[1][2] /= cm;
00434   C[1][3] /= cm;
00435   C[1][4]  = C[1][4]*GeV/cm;
00436 
00437   C[2][4]  = C[2][4]*GeV;
00438 
00439   C[3][4]  = C[3][4]*GeV;
00440 
00441   C[4][4]  = C[4][4]*GeV*GeV;
00442 
00443   return StatusCode::SUCCESS;
00444 
00445 }
00446 
00447 //=========================================================================
00448 //  Restore units after inversion. same as cToG3 !
00449 //=========================================================================
00450 StatusCode KalmanFilter::cToG4(HepSymMatrix& invC){
00451 
00452   // cov matrix
00453   invC[0][0] /= cm2;
00454   invC[0][1] /= cm2;
00455   invC[0][2] /= cm;
00456   invC[0][3] /= cm;
00457   invC[0][4]  = invC[0][4]*GeV/cm;
00458 
00459   invC[1][1] /= cm2;
00460   invC[1][2] /= cm;
00461   invC[1][3] /= cm;
00462   invC[1][4]  = invC[1][4]*GeV/cm;
00463 
00464   invC[2][4]  = invC[2][4]*GeV;
00465 
00466   invC[3][4]  = invC[3][4]*GeV;
00467 
00468   invC[4][4]  = invC[4][4]*GeV*GeV;
00469 
00470   return StatusCode::SUCCESS;
00471 }
00472 
00473 
00474 
00475 
00476 
00477 
00478 
00479 
00480 
00481 
00482 
00483 

Generated on Fri May 27 13:59:37 2005 for New Track Event Model by doxygen 1.4.1