UnscentedKalmanModel.java

  1. /* Copyright 2002-2024 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 org.hipparchus.filtering.kalman.ProcessEstimate;
  19. import org.hipparchus.filtering.kalman.unscented.UnscentedEvolution;
  20. import org.hipparchus.filtering.kalman.unscented.UnscentedProcess;
  21. import org.hipparchus.linear.ArrayRealVector;
  22. import org.hipparchus.linear.MatrixUtils;
  23. import org.hipparchus.linear.RealMatrix;
  24. import org.hipparchus.linear.RealVector;
  25. import org.orekit.estimation.measurements.EstimatedMeasurement;
  26. import org.orekit.estimation.measurements.EstimatedMeasurementBase;
  27. import org.orekit.estimation.measurements.ObservedMeasurement;
  28. import org.orekit.orbits.CartesianOrbit;
  29. import org.orekit.orbits.Orbit;
  30. import org.orekit.propagation.Propagator;
  31. import org.orekit.propagation.SpacecraftState;
  32. import org.orekit.propagation.conversion.PropagatorBuilder;
  33. import org.orekit.time.AbsoluteDate;
  34. import org.orekit.utils.ParameterDriver;
  35. import org.orekit.utils.ParameterDriversList;
  36. import org.orekit.utils.ParameterDriversList.DelegatingDriver;

  37. import java.util.List;

  38. /** Class defining the process model dynamics to use with a {@link UnscentedKalmanEstimator}.
  39.  * @author GaĆ«tan Pierre
  40.  * @author Bryan Cazabonne
  41.  * @since 11.3
  42.  */
  43. public class UnscentedKalmanModel extends KalmanEstimationCommon implements UnscentedProcess<MeasurementDecorator> {

  44.     /** Reference values. */
  45.     private final double[] referenceValues;

  46.     /** Unscented Kalman process model constructor (package private).
  47.      * @param propagatorBuilders propagators builders used to evaluate the orbits.
  48.      * @param covarianceMatricesProviders provider for covariance matrix
  49.      * @param estimatedMeasurementParameters measurement parameters to estimate
  50.      * @param measurementProcessNoiseMatrix provider for measurement process noise matrix
  51.      */
  52.     protected UnscentedKalmanModel(final List<PropagatorBuilder> propagatorBuilders,
  53.                                    final List<CovarianceMatrixProvider> covarianceMatricesProviders,
  54.                                    final ParameterDriversList estimatedMeasurementParameters,
  55.                                    final CovarianceMatrixProvider measurementProcessNoiseMatrix) {

  56.         super(propagatorBuilders, covarianceMatricesProviders, estimatedMeasurementParameters, measurementProcessNoiseMatrix);

  57.         // Record the initial reference values
  58.         int stateDimension = 0;
  59.         for (final ParameterDriver ignored : getEstimatedOrbitalParameters().getDrivers()) {
  60.             stateDimension += 1;
  61.         }
  62.         for (final ParameterDriver ignored : getEstimatedPropagationParameters().getDrivers()) {
  63.             stateDimension += 1;
  64.         }
  65.         for (final ParameterDriver ignored : getEstimatedMeasurementsParameters().getDrivers()) {
  66.             stateDimension += 1;
  67.         }

  68.         this.referenceValues = new double[stateDimension];
  69.         int index = 0;
  70.         for (final ParameterDriver driver : getEstimatedOrbitalParameters().getDrivers()) {
  71.             referenceValues[index++] = driver.getReferenceValue();
  72.         }
  73.         for (final ParameterDriver driver : getEstimatedPropagationParameters().getDrivers()) {
  74.             referenceValues[index++] = driver.getReferenceValue();
  75.         }
  76.         for (final ParameterDriver driver : getEstimatedMeasurementsParameters().getDrivers()) {
  77.             referenceValues[index++] = driver.getReferenceValue();
  78.         }
  79.     }

  80.     /** {@inheritDoc} */
  81.     @Override
  82.     public UnscentedEvolution getEvolution(final double previousTime, final RealVector[] sigmaPoints,
  83.                                            final MeasurementDecorator measurement) {

  84.         // Set a reference date for all measurements parameters that lack one (including the not estimated ones)
  85.         final ObservedMeasurement<?> observedMeasurement = measurement.getObservedMeasurement();
  86.         for (final ParameterDriver driver : observedMeasurement.getParametersDrivers()) {
  87.             if (driver.getReferenceDate() == null) {
  88.                 driver.setReferenceDate(getBuilders().get(0).getInitialOrbitDate());
  89.             }
  90.         }

  91.         // Increment measurement number
  92.         incrementCurrentMeasurementNumber();

  93.         // Update the current date
  94.         setCurrentDate(measurement.getObservedMeasurement().getDate());

  95.         // Initialize array of predicted sigma points
  96.         final RealVector[] predictedSigmaPoints = new RealVector[sigmaPoints.length];

  97.         // Propagate each sigma point
  98.         for (int i = 0; i < sigmaPoints.length; i++) {

  99.             // Set parameters for this sigma point
  100.             final RealVector sigmaPoint = sigmaPoints[i].copy();
  101.             updateParameters(sigmaPoint);

  102.             // Get propagators
  103.             final Propagator[] propagators = getEstimatedPropagators();

  104.             // Do prediction
  105.             predictedSigmaPoints[i] = predictState(observedMeasurement.getDate(), sigmaPoint, propagators);
  106.         }

  107.         // Reset the driver reference values based on the first sigma point
  108.         int d = 0;
  109.         for (final DelegatingDriver driver : getEstimatedOrbitalParameters().getDrivers()) {
  110.             driver.setReferenceValue(referenceValues[d]);
  111.             driver.setNormalizedValue(predictedSigmaPoints[0].getEntry(d));
  112.             referenceValues[d] = driver.getValue();

  113.             // Make remaining sigma points relative to the first
  114.             for (int i = 1; i < predictedSigmaPoints.length; ++i) {
  115.                 predictedSigmaPoints[i].setEntry(d, predictedSigmaPoints[i].getEntry(d) - predictedSigmaPoints[0].getEntry(d));
  116.             }
  117.             predictedSigmaPoints[0].setEntry(d, 0.0);

  118.             d += 1;
  119.         }

  120.         // compute process noise matrix
  121.         final RealMatrix normalizedProcessNoise = getNormalizedProcessNoise(sigmaPoints[0].getDimension());

  122.         // Return
  123.         return new UnscentedEvolution(measurement.getTime(), predictedSigmaPoints, normalizedProcessNoise);
  124.     }

  125.     /** {@inheritDoc} */
  126.     @Override
  127.     public RealVector[] getPredictedMeasurements(final RealVector[] predictedSigmaPoints, final MeasurementDecorator measurement) {

  128.         // Observed measurement
  129.         final ObservedMeasurement<?> observedMeasurement = measurement.getObservedMeasurement();

  130.         // Standard deviation as a vector
  131.         final RealVector theoreticalStandardDeviation =
  132.                 MatrixUtils.createRealVector(observedMeasurement.getTheoreticalStandardDeviation());

  133.         // Initialize arrays of predicted states and measurements
  134.         final RealVector[] predictedMeasurements = new RealVector[predictedSigmaPoints.length];

  135.         // Loop on sigma points to predict measurements
  136.         for (int i = 0; i < predictedSigmaPoints.length; i++) {
  137.             // Set parameters for this sigma point
  138.             final RealVector predictedSigmaPoint = predictedSigmaPoints[i].copy();
  139.             updateParameters(predictedSigmaPoint);

  140.             // Get propagators
  141.             Propagator[] propagators = getEstimatedPropagators();

  142.             // "updateParameters" sets the correct orbital and parameters info, but doesn't reset the time.
  143.             for (int k = 0; k < propagators.length; ++k) {
  144.                 final SpacecraftState predictedState = propagators[k].getInitialState();
  145.                 final Orbit predictedOrbit = getBuilders().get(k).getOrbitType().convertType(
  146.                         new CartesianOrbit(predictedState.getPVCoordinates(),
  147.                                 predictedState.getFrame(),
  148.                                 observedMeasurement.getDate(),
  149.                                 predictedState.getMu()
  150.                         )
  151.                 );
  152.                 getBuilders().get(k).resetOrbit(predictedOrbit);
  153.             }
  154.             propagators = getEstimatedPropagators();

  155.             // Predicted states
  156.             final SpacecraftState[] predictedStates = new SpacecraftState[propagators.length];
  157.             for (int k = 0; k < propagators.length; ++k) {
  158.                 predictedStates[k] = propagators[k].getInitialState();
  159.             }

  160.             // Calculated estimated measurement from predicted sigma point
  161.             final EstimatedMeasurement<?> estimated = estimateMeasurement(observedMeasurement, getCurrentMeasurementNumber(),
  162.                                                                                    KalmanEstimatorUtil.filterRelevant(observedMeasurement,
  163.                                                                                                                       predictedStates));
  164.             predictedMeasurements[i] = new ArrayRealVector(estimated.getEstimatedValue())
  165.                     .ebeDivide(theoreticalStandardDeviation);
  166.         }

  167.         // Return the predicted measurements
  168.         return predictedMeasurements;

  169.     }

  170.     /** {@inheritDoc} */
  171.     @Override
  172.     public RealVector getInnovation(final MeasurementDecorator measurement, final RealVector predictedMeas,
  173.                                     final RealVector predictedState, final RealMatrix innovationCovarianceMatrix) {
  174.         // Set parameters from predicted state
  175.         final RealVector predictedStateCopy = predictedState.copy();
  176.         updateParameters(predictedStateCopy);

  177.         // Standard deviation as a vector
  178.         final RealVector theoreticalStandardDeviation =
  179.                 MatrixUtils.createRealVector(measurement.getObservedMeasurement().getTheoreticalStandardDeviation());

  180.         // Get propagators
  181.         Propagator[] propagators = getEstimatedPropagators();

  182.         // "updateParameters" sets the correct orbital info, but doesn't reset the time.
  183.         for (int k = 0; k < propagators.length; ++k) {
  184.             final SpacecraftState predicted = propagators[k].getInitialState();
  185.             final Orbit predictedOrbit = getBuilders().get(k).getOrbitType().convertType(
  186.                     new CartesianOrbit(predicted.getPVCoordinates(),
  187.                             predicted.getFrame(),
  188.                             measurement.getObservedMeasurement().getDate(),
  189.                             predicted.getMu()
  190.                     )
  191.             );
  192.             getBuilders().get(k).resetOrbit(predictedOrbit);
  193.         }
  194.         propagators = getEstimatedPropagators();

  195.         // Predicted states
  196.         for (int k = 0; k < propagators.length; ++k) {
  197.             setPredictedSpacecraftState(propagators[k].getInitialState(), k);
  198.         }

  199.         // set estimated value to the predicted value from the filter
  200.         final EstimatedMeasurement<?> predictedMeasurement =
  201.             estimateMeasurement(measurement.getObservedMeasurement(), getCurrentMeasurementNumber(),
  202.                                 KalmanEstimatorUtil.filterRelevant(measurement.getObservedMeasurement(),
  203.                                 getPredictedSpacecraftStates()));
  204.         setPredictedMeasurement(predictedMeasurement);
  205.         predictedMeasurement.setEstimatedValue(predictedMeas.ebeMultiply(theoreticalStandardDeviation).toArray());

  206.         // Check for outliers
  207.         KalmanEstimatorUtil.applyDynamicOutlierFilter(predictedMeasurement, innovationCovarianceMatrix);

  208.         // Compute the innovation vector
  209.         return KalmanEstimatorUtil.computeInnovationVector(predictedMeasurement,
  210.                 predictedMeasurement.getObservedMeasurement().getTheoreticalStandardDeviation());
  211.     }


  212.     private RealVector predictState(final AbsoluteDate date,
  213.                                     final RealVector previousState,
  214.                                     final Propagator[] propagators) {

  215.         // Initialise predicted state
  216.         final RealVector predictedState = previousState.copy();

  217.         // Orbital parameters counter
  218.         int jOrb = 0;

  219.         // Loop over propagators
  220.         for (int k = 0; k < propagators.length; ++k) {

  221.             // Record original state
  222.             final SpacecraftState originalState = propagators[k].getInitialState();

  223.             // Propagate
  224.             final SpacecraftState predicted = propagators[k].propagate(date);

  225.             // Update the builder with the predicted orbit
  226.             // This updates the orbital drivers with the values of the predicted orbit
  227.             getBuilders().get(k).resetOrbit(predicted.getOrbit());

  228.             // The orbital parameters in the state vector are replaced with their predicted values
  229.             // The propagation & measurement parameters are not changed by the prediction (i.e. the propagation)
  230.             // As the propagator builder was previously updated with the predicted orbit,
  231.             // the selected orbital drivers are already up to date with the prediction
  232.             for (DelegatingDriver orbitalDriver : getBuilders().get(k).getOrbitalParametersDrivers().getDrivers()) {
  233.                 if (orbitalDriver.isSelected()) {
  234.                     orbitalDriver.setReferenceValue(referenceValues[jOrb]);
  235.                     predictedState.setEntry(jOrb, orbitalDriver.getNormalizedValue());

  236.                     jOrb += 1;
  237.                 }
  238.             }

  239.             // Set the builder back to the original time
  240.             getBuilders().get(k).resetOrbit(originalState.getOrbit());

  241.         }

  242.         return predictedState;
  243.     }


  244.     /** Finalize estimation.
  245.      * @param observedMeasurement measurement that has just been processed
  246.      * @param estimate corrected estimate
  247.      */
  248.     public void finalizeEstimation(final ObservedMeasurement<?> observedMeasurement,
  249.                                    final ProcessEstimate estimate) {
  250.         // Update the parameters with the estimated state
  251.         // The min/max values of the parameters are handled by the ParameterDriver implementation
  252.         setCorrectedEstimate(estimate);
  253.         updateParameters(estimate.getState());

  254.         // Get the estimated propagator (mirroring parameter update in the builder)
  255.         // and the estimated spacecraft state
  256.         final Propagator[] estimatedPropagators = getEstimatedPropagators();
  257.         for (int k = 0; k < estimatedPropagators.length; ++k) {
  258.             setCorrectedSpacecraftState(estimatedPropagators[k].getInitialState(), k);
  259.         }

  260.         // Corrected measurement
  261.         setCorrectedMeasurement(estimateMeasurement(observedMeasurement, getCurrentMeasurementNumber(),
  262.                                                     KalmanEstimatorUtil.filterRelevant(observedMeasurement,
  263.                                                     getCorrectedSpacecraftStates())));
  264.     }

  265.     /**
  266.      * Estimate measurement (without derivatives).
  267.      * @param <T> measurement type
  268.      * @param observedMeasurement observed measurement
  269.      * @param measurementNumber measurement number
  270.      * @param spacecraftStates states
  271.      * @return estimated measurement
  272.      * @since 12.1
  273.      */
  274.     private static <T extends ObservedMeasurement<T>> EstimatedMeasurement<T> estimateMeasurement(final ObservedMeasurement<T> observedMeasurement,
  275.                                                                                                   final int measurementNumber,
  276.                                                                                                   final SpacecraftState[] spacecraftStates) {
  277.         final EstimatedMeasurementBase<T> estimatedMeasurementBase = observedMeasurement.
  278.                 estimateWithoutDerivatives(measurementNumber, measurementNumber,
  279.                 KalmanEstimatorUtil.filterRelevant(observedMeasurement, spacecraftStates));
  280.         final EstimatedMeasurement<T> estimatedMeasurement = new EstimatedMeasurement<>(estimatedMeasurementBase.getObservedMeasurement(),
  281.                 estimatedMeasurementBase.getIteration(), estimatedMeasurementBase.getCount(),
  282.                 estimatedMeasurementBase.getStates(), estimatedMeasurementBase.getParticipants());
  283.         estimatedMeasurement.setEstimatedValue(estimatedMeasurementBase.getEstimatedValue());
  284.         return estimatedMeasurement;
  285.     }

  286.     /** Update parameter drivers with a normalised state, adjusting state according to the driver limits.
  287.      * @param normalizedState the input state
  288.      * The min/max allowed values are handled by the parameter themselves.
  289.      */
  290.     private void updateParameters(final RealVector normalizedState) {
  291.         int i = 0;
  292.         for (final DelegatingDriver driver : getEstimatedOrbitalParameters().getDrivers()) {
  293.             // let the parameter handle min/max clipping
  294.             driver.setReferenceValue(referenceValues[i]);
  295.             driver.setNormalizedValue(normalizedState.getEntry(i));
  296.             normalizedState.setEntry(i++, driver.getNormalizedValue());
  297.         }
  298.         for (final DelegatingDriver driver : getEstimatedPropagationParameters().getDrivers()) {
  299.             // let the parameter handle min/max clipping
  300.             driver.setNormalizedValue(normalizedState.getEntry(i));
  301.             normalizedState.setEntry(i++, driver.getNormalizedValue());
  302.         }
  303.         for (final DelegatingDriver driver : getEstimatedMeasurementsParameters().getDrivers()) {
  304.             // let the parameter handle min/max clipping
  305.             driver.setNormalizedValue(normalizedState.getEntry(i));
  306.             normalizedState.setEntry(i++, driver.getNormalizedValue());
  307.         }
  308.     }
  309. }