KalmanEstimator.java

  1. /* Copyright 2002-2020 CS GROUP
  2.  * Licensed to CS GROUP (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.estimation.sequential;

  18. import java.util.List;

  19. import org.hipparchus.exception.MathRuntimeException;
  20. import org.hipparchus.filtering.kalman.ProcessEstimate;
  21. import org.hipparchus.filtering.kalman.extended.ExtendedKalmanFilter;
  22. import org.hipparchus.linear.MatrixDecomposer;
  23. import org.hipparchus.linear.MatrixUtils;
  24. import org.hipparchus.linear.RealMatrix;
  25. import org.hipparchus.linear.RealVector;
  26. import org.orekit.errors.OrekitException;
  27. import org.orekit.estimation.measurements.ObservedMeasurement;
  28. import org.orekit.estimation.measurements.PV;
  29. import org.orekit.estimation.measurements.Position;
  30. import org.orekit.propagation.conversion.IntegratedPropagatorBuilder;
  31. import org.orekit.propagation.conversion.PropagatorBuilder;
  32. import org.orekit.propagation.integration.AbstractIntegratedPropagator;
  33. import org.orekit.propagation.numerical.NumericalPropagator;
  34. import org.orekit.propagation.semianalytical.dsst.DSSTPropagator;
  35. import org.orekit.time.AbsoluteDate;
  36. import org.orekit.utils.ParameterDriver;
  37. import org.orekit.utils.ParameterDriversList;
  38. import org.orekit.utils.ParameterDriversList.DelegatingDriver;


  39. /**
  40.  * Implementation of a Kalman filter to perform orbit determination.
  41.  * <p>
  42.  * The filter uses a {@link IntegratedPropagatorBuilder} to initialize its reference trajectory {@link NumericalPropagator}
  43.  * or {@link DSSTPropagator} .
  44.  * </p>
  45.  * <p>
  46.  * The estimated parameters are driven by {@link ParameterDriver} objects. They are of 3 different types:<ol>
  47.  *   <li><b>Orbital parameters</b>:The position and velocity of the spacecraft, or, more generally, its orbit.<br>
  48.  *       These parameters are retrieved from the reference trajectory propagator builder when the filter is initialized.</li>
  49.  *   <li><b>Propagation parameters</b>: Some parameters modelling physical processes (SRP or drag coefficients etc...).<br>
  50.  *       They are also retrieved from the propagator builder during the initialization phase.</li>
  51.  *   <li><b>Measurements parameters</b>: Parameters related to measurements (station biases, positions etc...).<br>
  52.  *       They are passed down to the filter in its constructor.</li>
  53.  * </ol>
  54.  * <p>
  55.  * The total number of estimated parameters is m, the size of the state vector.
  56.  * </p>
  57.  * <p>
  58.  * The Kalman filter implementation used is provided by the underlying mathematical library Hipparchus.
  59.  * All the variables seen by Hipparchus (states, covariances, measurement matrices...) are normalized
  60.  * using a specific scale for each estimated parameters or standard deviation noise for each measurement components.
  61.  * </p>
  62.  *
  63.  * <p>A {@link KalmanEstimator} object is built using the {@link KalmanEstimatorBuilder#build() build}
  64.  * method of a {@link KalmanEstimatorBuilder}.</p>
  65.  *
  66.  * @author Romain Gerbaud
  67.  * @author Maxime Journot
  68.  * @author Luc Maisonobe
  69.  * @since 9.2
  70.  */
  71. public class KalmanEstimator {

  72.     /** Builders for orbit propagators. */
  73.     private List<IntegratedPropagatorBuilder> propagatorBuilders;

  74.     /** Reference date. */
  75.     private final AbsoluteDate referenceDate;

  76.     /** Kalman filter process model. */
  77.     private final KalmanODModel processModel;

  78.     /** Filter. */
  79.     private final ExtendedKalmanFilter<MeasurementDecorator> filter;

  80.     /** Observer to retrieve current estimation info. */
  81.     private KalmanObserver observer;

  82.     /** Kalman filter estimator constructor (package private).
  83.      * @param decomposer decomposer to use for the correction phase
  84.      * @param propagatorBuilders propagators builders used to evaluate the orbit.
  85.      * @param processNoiseMatricesProviders providers for process noise matrices
  86.      * @param estimatedMeasurementParameters measurement parameters to estimate
  87.      * @deprecated since 10.3, replaced by
  88.      * {@link #KalmanEstimator(MatrixDecomposer, List, List, ParameterDriversList, CovarianceMatrixProvider)}
  89.      */
  90.     @Deprecated
  91.     KalmanEstimator(final MatrixDecomposer decomposer,
  92.                     final List<IntegratedPropagatorBuilder> propagatorBuilders,
  93.                     final List<CovarianceMatrixProvider> processNoiseMatricesProviders,
  94.                     final ParameterDriversList estimatedMeasurementParameters) {
  95.         this(decomposer, propagatorBuilders, processNoiseMatricesProviders,
  96.              estimatedMeasurementParameters, null);
  97.     }

  98.     /** Kalman filter estimator constructor (package private).
  99.      * @param decomposer decomposer to use for the correction phase
  100.      * @param propagatorBuilders propagators builders used to evaluate the orbit.
  101.      * @param processNoiseMatricesProviders providers for process noise matrices
  102.      * @param estimatedMeasurementParameters measurement parameters to estimate
  103.      * @param measurementProcessNoiseMatrix provider for measurement process noise matrix
  104.      * @since 10.3
  105.      */
  106.     KalmanEstimator(final MatrixDecomposer decomposer,
  107.                     final List<IntegratedPropagatorBuilder> propagatorBuilders,
  108.                     final List<CovarianceMatrixProvider> processNoiseMatricesProviders,
  109.                     final ParameterDriversList estimatedMeasurementParameters,
  110.                     final CovarianceMatrixProvider measurementProcessNoiseMatrix) {

  111.         this.propagatorBuilders = propagatorBuilders;
  112.         this.referenceDate      = propagatorBuilders.get(0).getInitialOrbitDate();
  113.         this.observer           = null;

  114.         // Build the process model and measurement model
  115.         this.processModel = propagatorBuilders.get(0).buildKalmanModel(propagatorBuilders,
  116.                                                                    processNoiseMatricesProviders,
  117.                                                                    estimatedMeasurementParameters,
  118.                                                                    measurementProcessNoiseMatrix);

  119.         this.filter = new ExtendedKalmanFilter<>(decomposer, processModel, processModel.getEstimate());

  120.     }

  121.     /** Set the observer.
  122.      * @param observer the observer
  123.      */
  124.     public void setObserver(final KalmanObserver observer) {
  125.         this.observer = observer;
  126.     }

  127.     /** Get the current measurement number.
  128.      * @return current measurement number
  129.      */
  130.     public int getCurrentMeasurementNumber() {
  131.         return processModel.getCurrentMeasurementNumber();
  132.     }

  133.     /** Get the current date.
  134.      * @return current date
  135.      */
  136.     public AbsoluteDate getCurrentDate() {
  137.         return processModel.getCurrentDate();
  138.     }

  139.     /** Get the "physical" estimated state (i.e. not normalized)
  140.      * @return the "physical" estimated state
  141.      */
  142.     public RealVector getPhysicalEstimatedState() {
  143.         return processModel.getPhysicalEstimatedState();
  144.     }

  145.     /** Get the "physical" estimated covariance matrix (i.e. not normalized)
  146.      * @return the "physical" estimated covariance matrix
  147.      */
  148.     public RealMatrix getPhysicalEstimatedCovarianceMatrix() {
  149.         return processModel.getPhysicalEstimatedCovarianceMatrix();
  150.     }

  151.     /** Get the orbital parameters supported by this estimator.
  152.      * <p>
  153.      * If there are more than one propagator builder, then the names
  154.      * of the drivers have an index marker in square brackets appended
  155.      * to them in order to distinguish the various orbits. So for example
  156.      * with one builder generating Keplerian orbits the names would be
  157.      * simply "a", "e", "i"... but if there are several builders the
  158.      * names would be "a[0]", "e[0]", "i[0]"..."a[1]", "e[1]", "i[1]"...
  159.      * </p>
  160.      * @param estimatedOnly if true, only estimated parameters are returned
  161.      * @return orbital parameters supported by this estimator
  162.      */
  163.     public ParameterDriversList getOrbitalParametersDrivers(final boolean estimatedOnly) {

  164.         final ParameterDriversList estimated = new ParameterDriversList();
  165.         for (int i = 0; i < propagatorBuilders.size(); ++i) {
  166.             final String suffix = propagatorBuilders.size() > 1 ? "[" + i + "]" : null;
  167.             for (final ParameterDriver driver : propagatorBuilders.get(i).getOrbitalParametersDrivers().getDrivers()) {
  168.                 if (driver.isSelected() || !estimatedOnly) {
  169.                     if (suffix != null && !driver.getName().endsWith(suffix)) {
  170.                         // we add suffix only conditionally because the method may already have been called
  171.                         // and suffixes may have already been appended
  172.                         driver.setName(driver.getName() + suffix);
  173.                     }
  174.                     estimated.add(driver);
  175.                 }
  176.             }
  177.         }
  178.         return estimated;
  179.     }

  180.     /** Get the propagator parameters supported by this estimator.
  181.      * @param estimatedOnly if true, only estimated parameters are returned
  182.      * @return propagator parameters supported by this estimator
  183.      */
  184.     public ParameterDriversList getPropagationParametersDrivers(final boolean estimatedOnly) {

  185.         final ParameterDriversList estimated = new ParameterDriversList();
  186.         for (PropagatorBuilder builder : propagatorBuilders) {
  187.             for (final DelegatingDriver delegating : builder.getPropagationParametersDrivers().getDrivers()) {
  188.                 if (delegating.isSelected() || !estimatedOnly) {
  189.                     for (final ParameterDriver driver : delegating.getRawDrivers()) {
  190.                         estimated.add(driver);
  191.                     }
  192.                 }
  193.             }
  194.         }
  195.         return estimated;
  196.     }

  197.     /** Get the list of estimated measurements parameters.
  198.      * @return the list of estimated measurements parameters
  199.      */
  200.     public ParameterDriversList getEstimatedMeasurementsParameters() {
  201.         return processModel.getEstimatedMeasurementsParameters();
  202.     }

  203.     /** Process a single measurement.
  204.      * <p>
  205.      * Update the filter with the new measurement by calling the estimate method.
  206.      * </p>
  207.      * @param observedMeasurement the measurement to process
  208.      * @return estimated propagators
  209.      */
  210.     public AbstractIntegratedPropagator[] estimationStep(final ObservedMeasurement<?> observedMeasurement) {
  211.         try {
  212.             final ProcessEstimate estimate = filter.estimationStep(decorate(observedMeasurement));
  213.             processModel.finalizeEstimation(observedMeasurement, estimate);
  214.             if (observer != null) {
  215.                 observer.evaluationPerformed(processModel);
  216.             }
  217.             return processModel.getEstimatedPropagators();
  218.         } catch (MathRuntimeException mrte) {
  219.             throw new OrekitException(mrte);
  220.         }
  221.     }

  222.     /** Process several measurements.
  223.      * @param observedMeasurements the measurements to process in <em>chronologically sorted</em> order
  224.      * @return estimated propagators
  225.      */
  226.     public AbstractIntegratedPropagator[] processMeasurements(final Iterable<ObservedMeasurement<?>> observedMeasurements) {
  227.         AbstractIntegratedPropagator[] propagators = null;
  228.         for (ObservedMeasurement<?> observedMeasurement : observedMeasurements) {
  229.             propagators = estimationStep(observedMeasurement);
  230.         }
  231.         return propagators;
  232.     }

  233.     /** Decorate an observed measurement.
  234.      * <p>
  235.      * The "physical" measurement noise matrix is the covariance matrix of the measurement.
  236.      * Normalizing it consists in applying the following equation: Rn[i,j] =  R[i,j]/σ[i]/σ[j]
  237.      * Thus the normalized measurement noise matrix is the matrix of the correlation coefficients
  238.      * between the different components of the measurement.
  239.      * </p>
  240.      * @param observedMeasurement the measurement
  241.      * @return decorated measurement
  242.      */
  243.     private MeasurementDecorator decorate(final ObservedMeasurement<?> observedMeasurement) {

  244.         // Normalized measurement noise matrix contains 1 on its diagonal and correlation coefficients
  245.         // of the measurement on its non-diagonal elements.
  246.         // Indeed, the "physical" measurement noise matrix is the covariance matrix of the measurement
  247.         // Normalizing it leaves us with the matrix of the correlation coefficients
  248.         final RealMatrix covariance;
  249.         if (observedMeasurement instanceof PV) {
  250.             // For PV measurements we do have a covariance matrix and thus a correlation coefficients matrix
  251.             final PV pv = (PV) observedMeasurement;
  252.             covariance = MatrixUtils.createRealMatrix(pv.getCorrelationCoefficientsMatrix());
  253.         } else if (observedMeasurement instanceof Position) {
  254.             // For Position measurements we do have a covariance matrix and thus a correlation coefficients matrix
  255.             final Position position = (Position) observedMeasurement;
  256.             covariance = MatrixUtils.createRealMatrix(position.getCorrelationCoefficientsMatrix());
  257.         } else {
  258.             // For other measurements we do not have a covariance matrix.
  259.             // Thus the correlation coefficients matrix is an identity matrix.
  260.             covariance = MatrixUtils.createRealIdentityMatrix(observedMeasurement.getDimension());
  261.         }

  262.         return new MeasurementDecorator(observedMeasurement, covariance, referenceDate);

  263.     }

  264. }