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 java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.Comparator;
  21. import java.util.HashMap;
  22. import java.util.List;
  23. import java.util.Map;

  24. import org.hipparchus.filtering.kalman.ProcessEstimate;
  25. import org.hipparchus.filtering.kalman.unscented.UnscentedEvolution;
  26. import org.hipparchus.filtering.kalman.unscented.UnscentedProcess;
  27. import org.hipparchus.linear.ArrayRealVector;
  28. import org.hipparchus.linear.MatrixUtils;
  29. import org.hipparchus.linear.RealMatrix;
  30. import org.hipparchus.linear.RealVector;
  31. import org.orekit.estimation.measurements.EstimatedMeasurement;
  32. import org.orekit.estimation.measurements.ObservedMeasurement;
  33. import org.orekit.orbits.Orbit;
  34. import org.orekit.orbits.OrbitType;
  35. import org.orekit.orbits.PositionAngleType;
  36. import org.orekit.propagation.Propagator;
  37. import org.orekit.propagation.PropagatorsParallelizer;
  38. import org.orekit.propagation.SpacecraftState;
  39. import org.orekit.propagation.conversion.PropagatorBuilder;
  40. import org.orekit.time.AbsoluteDate;
  41. import org.orekit.utils.ParameterDriver;
  42. import org.orekit.utils.ParameterDriversList;
  43. import org.orekit.utils.ParameterDriversList.DelegatingDriver;

  44. /** Class defining the process model dynamics to use with a {@link UnscentedKalmanEstimator}.
  45.  * @author GaĆ«tan Pierre
  46.  * @author Bryan Cazabonne
  47.  * @since 11.3
  48.  */
  49. public class UnscentedKalmanModel implements KalmanEstimation, UnscentedProcess<MeasurementDecorator> {

  50.     /** Builders for propagators. */
  51.     private final List<PropagatorBuilder> builders;

  52.     /** Estimated orbital parameters. */
  53.     private final ParameterDriversList allEstimatedOrbitalParameters;

  54.     /** Estimated propagation drivers. */
  55.     private final ParameterDriversList allEstimatedPropagationParameters;

  56.     /** Per-builder estimated orbital parameters. */
  57.     private final ParameterDriversList[] estimatedOrbitalParameters;

  58.     /** Per-builder estimated propagation parameters. */
  59.     private final ParameterDriversList[] estimatedPropagationParameters;

  60.     /** Estimated measurements parameters. */
  61.     private final ParameterDriversList estimatedMeasurementsParameters;

  62.     /** Start columns for each estimated orbit. */
  63.     private final int[] orbitsStartColumns;

  64.     /** End columns for each estimated orbit. */
  65.     private final int[] orbitsEndColumns;

  66.     /** Map for propagation parameters columns. */
  67.     private final Map<String, Integer> propagationParameterColumns;

  68.     /** Map for measurements parameters columns. */
  69.     private final Map<String, Integer> measurementParameterColumns;

  70.     /** Provider for covariance matrice. */
  71.     private final List<CovarianceMatrixProvider> covarianceMatrixProviders;

  72.     /** Process noise matrix provider for measurement parameters. */
  73.     private final CovarianceMatrixProvider measurementProcessNoiseMatrix;

  74.     /** Indirection arrays to extract the noise components for estimated parameters. */
  75.     private final int[][] covarianceIndirection;

  76.     /** Position angle types used during orbit determination. */
  77.     private final PositionAngleType[] angleTypes;

  78.     /** Orbit types used during orbit determination. */
  79.     private final OrbitType[] orbitTypes;

  80.     /** Current number of measurement. */
  81.     private int currentMeasurementNumber;

  82.     /** Current corrected estimate. */
  83.     private ProcessEstimate correctedEstimate;

  84.     /** Current date. */
  85.     private AbsoluteDate currentDate;

  86.     /** Previous date. */
  87.     private AbsoluteDate previousDate;

  88.     /** Predicted spacecraft states. */
  89.     private SpacecraftState[] predictedSpacecraftStates;

  90.     /** Corrected spacecraft states. */
  91.     private SpacecraftState[] correctedSpacecraftStates;

  92.     /** Predicted measurement. */
  93.     private EstimatedMeasurement<?> predictedMeasurement;

  94.     /** Corrected measurement. */
  95.     private EstimatedMeasurement<?> correctedMeasurement;

  96.     /** Unscented Kalman process model constructor (package private).
  97.      * @param propagatorBuilders propagators builders used to evaluate the orbits.
  98.      * @param covarianceMatrixProviders provider for covariance matrix
  99.      * @param estimatedMeasurementParameters measurement parameters to estimate
  100.      * @param measurementProcessNoiseMatrix provider for measurement process noise matrix
  101.      */
  102.     protected UnscentedKalmanModel(final List<PropagatorBuilder> propagatorBuilders,
  103.                                    final List<CovarianceMatrixProvider> covarianceMatrixProviders,
  104.                                    final ParameterDriversList estimatedMeasurementParameters,
  105.                                    final CovarianceMatrixProvider measurementProcessNoiseMatrix) {

  106.         this.builders                        = propagatorBuilders;
  107.         this.estimatedMeasurementsParameters = estimatedMeasurementParameters;
  108.         this.measurementParameterColumns     = new HashMap<>(estimatedMeasurementsParameters.getDrivers().size());
  109.         this.currentMeasurementNumber        = 0;
  110.         this.currentDate                     = propagatorBuilders.get(0).getInitialOrbitDate();
  111.         this.previousDate                    = currentDate;
  112.         this.covarianceMatrixProviders       = covarianceMatrixProviders;
  113.         this.measurementProcessNoiseMatrix   = measurementProcessNoiseMatrix;

  114.         final Map<String, Integer> orbitalParameterColumns = new HashMap<>(6 * builders.size());
  115.         orbitsStartColumns      = new int[builders.size()];
  116.         orbitsEndColumns        = new int[builders.size()];
  117.         int columns = 0;
  118.         allEstimatedOrbitalParameters = new ParameterDriversList();
  119.         estimatedOrbitalParameters    = new ParameterDriversList[builders.size()];
  120.         // Set estimated orbital parameters
  121.         for (int k = 0; k < builders.size(); ++k) {
  122.             estimatedOrbitalParameters[k] = new ParameterDriversList();
  123.             orbitsStartColumns[k] = columns;
  124.             final String suffix = propagatorBuilders.size() > 1 ? "[" + k + "]" : null;
  125.             for (final ParameterDriver driver : builders.get(k).getOrbitalParametersDrivers().getDrivers()) {
  126.                 if (driver.getReferenceDate() == null) {
  127.                     driver.setReferenceDate(currentDate);
  128.                 }
  129.                 if (suffix != null && !driver.getName().endsWith(suffix)) {
  130.                     // we add suffix only conditionally because the method may already have been called
  131.                     // and suffixes may have already been appended
  132.                     driver.setName(driver.getName() + suffix);
  133.                 }
  134.                 if (driver.isSelected()) {
  135.                     allEstimatedOrbitalParameters.add(driver);
  136.                     estimatedOrbitalParameters[k].add(driver);
  137.                     orbitalParameterColumns.put(driver.getName(), columns++);
  138.                 }
  139.             }
  140.             orbitsEndColumns[k] = columns;
  141.         }

  142.         // Set estimated propagation parameters
  143.         allEstimatedPropagationParameters = new ParameterDriversList();
  144.         estimatedPropagationParameters    = new ParameterDriversList[builders.size()];
  145.         final List<String> estimatedPropagationParametersNames = new ArrayList<>();
  146.         for (int k = 0; k < builders.size(); ++k) {
  147.             estimatedPropagationParameters[k] = new ParameterDriversList();
  148.             for (final ParameterDriver driver : builders.get(k).getPropagationParametersDrivers().getDrivers()) {
  149.                 if (driver.getReferenceDate() == null) {
  150.                     driver.setReferenceDate(currentDate);
  151.                 }
  152.                 if (driver.isSelected()) {
  153.                     allEstimatedPropagationParameters.add(driver);
  154.                     estimatedPropagationParameters[k].add(driver);
  155.                     final String driverName = driver.getName();
  156.                     // Add the driver name if it has not been added yet
  157.                     if (!estimatedPropagationParametersNames.contains(driverName)) {
  158.                         estimatedPropagationParametersNames.add(driverName);
  159.                     }
  160.                 }
  161.             }
  162.         }
  163.         estimatedPropagationParametersNames.sort(Comparator.naturalOrder());

  164.         // Populate the map of propagation drivers' columns and update the total number of columns
  165.         propagationParameterColumns = new HashMap<>(estimatedPropagationParametersNames.size());
  166.         for (final String driverName : estimatedPropagationParametersNames) {
  167.             propagationParameterColumns.put(driverName, columns++);
  168.         }

  169.         // Populate the map of measurement drivers' columns and update the total number of columns
  170.         for (final ParameterDriver parameter : estimatedMeasurementsParameters.getDrivers()) {
  171.             // Verify if the driver reference date has been set
  172.             if (parameter.getReferenceDate() == null) {
  173.                 parameter.setReferenceDate(currentDate);
  174.             }
  175.             measurementParameterColumns.put(parameter.getName(), columns);
  176.             columns++;
  177.         }

  178.         // set angle and orbit types
  179.         angleTypes = new PositionAngleType[builders.size()];
  180.         orbitTypes = new OrbitType[builders.size()];
  181.         for (int k = 0; k < builders.size(); k++) {
  182.             angleTypes[k] = builders.get(k).getPositionAngleType();
  183.             orbitTypes[k] = builders.get(k).getOrbitType();
  184.         }

  185.         // set covariance indirection
  186.         this.covarianceIndirection = new int[covarianceMatrixProviders.size()][columns];

  187.         for (int k = 0; k < covarianceIndirection.length; ++k) {
  188.             final ParameterDriversList orbitDrivers      = builders.get(k).getOrbitalParametersDrivers();
  189.             final ParameterDriversList parametersDrivers = builders.get(k).getPropagationParametersDrivers();
  190.             Arrays.fill(covarianceIndirection[k], -1);
  191.             int i = 0;
  192.             for (final ParameterDriver driver : orbitDrivers.getDrivers()) {
  193.                 final Integer c = orbitalParameterColumns.get(driver.getName());
  194.                 covarianceIndirection[k][i++] = (c == null) ? -1 : c.intValue();
  195.             }
  196.             for (final ParameterDriver driver : parametersDrivers.getDrivers()) {
  197.                 final Integer c = propagationParameterColumns.get(driver.getName());
  198.                 if (c != null) {
  199.                     covarianceIndirection[k][i++] = c.intValue();
  200.                 }
  201.             }
  202.             for (final ParameterDriver driver : estimatedMeasurementParameters.getDrivers()) {
  203.                 final Integer c = measurementParameterColumns.get(driver.getName());
  204.                 if (c != null) {
  205.                     covarianceIndirection[k][i++] = c.intValue();
  206.                 }
  207.             }
  208.         }

  209.         // Initialize the estimated state and fill its values
  210.         final RealVector correctedState = MatrixUtils.createRealVector(columns);

  211.         int p = 0;
  212.         for (final ParameterDriver driver : allEstimatedOrbitalParameters.getDrivers()) {
  213.             correctedState.setEntry(p++, driver.getValue());
  214.         }
  215.         for (final ParameterDriver driver : allEstimatedPropagationParameters.getDrivers()) {
  216.             correctedState.setEntry(p++, driver.getValue());
  217.         }
  218.         for (final ParameterDriver driver : estimatedMeasurementsParameters.getDrivers()) {
  219.             correctedState.setEntry(p++, driver.getValue());
  220.         }

  221.         this.predictedSpacecraftStates = new SpacecraftState[propagatorBuilders.size()];
  222.         for (int i = 0; i < propagatorBuilders.size(); i++) {
  223.             predictedSpacecraftStates[i] = propagatorBuilders.get(i).buildPropagator(propagatorBuilders.get(i).getSelectedNormalizedParameters()).getInitialState();
  224.         }
  225.         this.correctedSpacecraftStates = predictedSpacecraftStates.clone();

  226.         // Number of estimated measurement parameters
  227.         final int nbMeas = estimatedMeasurementParameters.getNbParams();

  228.         final RealMatrix correctedCovariance = MatrixUtils.createRealMatrix(columns, columns);
  229.         for (int k = 0; k < covarianceMatrixProviders.size(); k++) {
  230.             // Number of estimated dynamic parameters (orbital + propagation)
  231.             final int nbDyn  = orbitsEndColumns[k] - orbitsStartColumns[k] +
  232.                                estimatedPropagationParameters[k].getNbParams();
  233.             // Covariance matrix
  234.             final RealMatrix noiseK = MatrixUtils.createRealMatrix(nbDyn + nbMeas, nbDyn + nbMeas);
  235.             final RealMatrix noiseP = covarianceMatrixProviders.get(k).
  236.                                       getInitialCovarianceMatrix(correctedSpacecraftStates[k]);
  237.             noiseK.setSubMatrix(noiseP.getData(), 0, 0);
  238.             if (measurementProcessNoiseMatrix != null) {
  239.                 final RealMatrix noiseM = measurementProcessNoiseMatrix.
  240.                                           getInitialCovarianceMatrix(correctedSpacecraftStates[k]);
  241.                 noiseK.setSubMatrix(noiseM.getData(), nbDyn, nbDyn);
  242.             }

  243.             KalmanEstimatorUtil.checkDimension(noiseK.getRowDimension(),
  244.                                                builders.get(k).getOrbitalParametersDrivers(),
  245.                                                builders.get(k).getPropagationParametersDrivers(),
  246.                                                estimatedMeasurementsParameters);

  247.             final int[] indK = covarianceIndirection[k];
  248.             for (int i = 0; i < indK.length; ++i) {
  249.                 if (indK[i] >= 0) {
  250.                     for (int j = 0; j < indK.length; ++j) {
  251.                         if (indK[j] >= 0) {
  252.                             correctedCovariance.setEntry(indK[i], indK[j], noiseK.getEntry(i, j));
  253.                         }
  254.                     }
  255.                 }
  256.             }
  257.         }

  258.         // Initialize corrected estimate
  259.         this.correctedEstimate = new ProcessEstimate(0.0, correctedState, correctedCovariance);

  260.     }

  261.     /** {@inheritDoc} */
  262.     @Override
  263.     public UnscentedEvolution getEvolution(final double previousTime, final RealVector[] sigmaPoints,
  264.                                            final MeasurementDecorator measurement) {

  265.         // Set a reference date for all measurements parameters that lack one (including the not estimated ones)
  266.         final ObservedMeasurement<?> observedMeasurement = measurement.getObservedMeasurement();
  267.         for (final ParameterDriver driver : observedMeasurement.getParametersDrivers()) {
  268.             if (driver.getReferenceDate() == null) {
  269.                 driver.setReferenceDate(builders.get(0).getInitialOrbitDate());
  270.             }
  271.         }

  272.         // Increment measurement number
  273.         ++currentMeasurementNumber;

  274.         // Update the current date
  275.         currentDate = measurement.getObservedMeasurement().getDate();

  276.         // Initialize arrays of predicted states and measurements
  277.         final RealVector[] predictedStates       = new RealVector[sigmaPoints.length];

  278.         // Loop on builders
  279.         for (int k = 0; k < builders.size(); k++ ) {

  280.             // Sigma points for the current builder
  281.             final RealVector[] currentSigmaPoints = new ArrayRealVector[sigmaPoints.length];
  282.             for (int i = 0; i < sigmaPoints.length; i++) {
  283.                 currentSigmaPoints[i] = sigmaPoints[i].getSubVector(orbitsStartColumns[k], orbitsEndColumns[k] - orbitsStartColumns[k]);
  284.             }

  285.             // Predict states
  286.             final List<SpacecraftState> states = predictStates(currentSigmaPoints, k);

  287.             // Loop on states
  288.             for (int i = 0; i < states.size(); ++i) {
  289.                 if (k == 0) {
  290.                     predictedStates[i] = new ArrayRealVector(sigmaPoints[i].getDimension());
  291.                 }
  292.                 // Current predicted state
  293.                 final SpacecraftState predicted = states.get(i);
  294.                 // First, convert the predicted state to an array
  295.                 final double[] predictedArray = new double[currentSigmaPoints[i].getDimension()];
  296.                 orbitTypes[k].mapOrbitToArray(predicted.getOrbit(), angleTypes[k], predictedArray, null);
  297.                 predictedStates[i].setSubVector(orbitsStartColumns[k], new ArrayRealVector(predictedArray));
  298.             }

  299.         }

  300.         // compute process noise matrix
  301.         final RealMatrix processNoise = MatrixUtils.createRealMatrix(sigmaPoints[0].getDimension(), sigmaPoints[0].getDimension());

  302.         for (int k = 0; k < covarianceMatrixProviders.size(); ++k) {

  303.             // Number of estimated measurement parameters
  304.             final int nbMeas = estimatedMeasurementsParameters.getNbParams();

  305.             // Number of estimated dynamic parameters (orbital + propagation)
  306.             final int nbDyn  = orbitsEndColumns[k] - orbitsStartColumns[k] +
  307.                                estimatedPropagationParameters[k].getNbParams();

  308.             // Covariance matrix
  309.             final RealMatrix noiseK = MatrixUtils.createRealMatrix(nbDyn + nbMeas, nbDyn + nbMeas);
  310.             final RealMatrix noiseP = covarianceMatrixProviders.get(k).
  311.                                       getProcessNoiseMatrix(correctedSpacecraftStates[k],
  312.                                                             predictedSpacecraftStates[k]);
  313.             noiseK.setSubMatrix(noiseP.getData(), 0, 0);
  314.             if (measurementProcessNoiseMatrix != null) {
  315.                 final RealMatrix noiseM = measurementProcessNoiseMatrix.
  316.                                           getProcessNoiseMatrix(correctedSpacecraftStates[k],
  317.                                                                 predictedSpacecraftStates[k]);
  318.                 noiseK.setSubMatrix(noiseM.getData(), nbDyn, nbDyn);
  319.             }

  320.             KalmanEstimatorUtil.checkDimension(noiseK.getRowDimension(),
  321.                                                builders.get(k).getOrbitalParametersDrivers(),
  322.                                                builders.get(k).getPropagationParametersDrivers(),
  323.                                                estimatedMeasurementsParameters);

  324.             final int[] indK = covarianceIndirection[k];
  325.             for (int i = 0; i < indK.length; ++i) {
  326.                 if (indK[i] >= 0) {
  327.                     for (int j = 0; j < indK.length; ++j) {
  328.                         if (indK[j] >= 0) {
  329.                             processNoise.setEntry(indK[i], indK[j], noiseK.getEntry(i, j));
  330.                         }
  331.                     }
  332.                 }
  333.             }

  334.         }

  335.         // Update epoch
  336.         previousDate = currentDate;

  337.         // Return
  338.         return new UnscentedEvolution(measurement.getTime(), predictedStates, processNoise);
  339.     }

  340.     /** {@inheritDoc} */
  341.     @Override
  342.     public RealVector[] getPredictedMeasurements(final RealVector[] predictedSigmaPoints, final MeasurementDecorator measurement) {

  343.         // Observed measurement
  344.         final ObservedMeasurement<?> observedMeasurement = measurement.getObservedMeasurement();

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

  347.         // Initialize the relevant states used for measurement estimation
  348.         final SpacecraftState[][] statesForMeasurementEstimation = new SpacecraftState[predictedSigmaPoints.length][builders.size()];

  349.         // Convert sigma points to spacecraft states
  350.         for (int k = 0; k < builders.size(); k++ ) {

  351.             // Loop on sigma points
  352.             for (int i = 0; i < predictedSigmaPoints.length; i++) {
  353.                 final SpacecraftState state = new SpacecraftState(orbitTypes[k].mapArrayToOrbit(predictedSigmaPoints[i].toArray(), null,
  354.                                                                                                 angleTypes[k], currentDate, builders.get(k).getMu(),
  355.                                                                                                 builders.get(k).getFrame()));
  356.                 statesForMeasurementEstimation[i][k] = state;
  357.             }

  358.         }

  359.         // Loop on sigma points to predict measurements
  360.         for (int i = 0; i < predictedSigmaPoints.length; i++) {
  361.             final EstimatedMeasurement<?> estimated = observedMeasurement.estimate(currentMeasurementNumber, currentMeasurementNumber,
  362.                                                                                    KalmanEstimatorUtil.filterRelevant(observedMeasurement,
  363.                                                                                                                       statesForMeasurementEstimation[i]));
  364.             predictedMeasurements[i] = new ArrayRealVector(estimated.getEstimatedValue());
  365.         }

  366.         // Return the predicted measurements
  367.         return predictedMeasurements;

  368.     }

  369.     /** {@inheritDoc} */
  370.     @Override
  371.     public RealVector getInnovation(final MeasurementDecorator measurement, final RealVector predictedMeas,
  372.                                     final RealVector predictedState, final RealMatrix innovationCovarianceMatrix) {

  373.         // Loop on builders
  374.         for (int k = 0; k < builders.size(); k++) {

  375.             // Update predicted states
  376.             final double[] predictedStateArray = predictedState.getSubVector(orbitsStartColumns[k], orbitsEndColumns[k] - orbitsStartColumns[k]).toArray();
  377.             final Orbit predictedOrbit = orbitTypes[k].mapArrayToOrbit(predictedStateArray, null, angleTypes[k],
  378.                                                                        currentDate, builders.get(k).getMu(), builders.get(k).getFrame());
  379.             predictedSpacecraftStates[k] = new SpacecraftState(predictedOrbit);

  380.             // Update the builder with the predicted orbit
  381.             builders.get(k).resetOrbit(predictedOrbit);

  382.         }

  383.         // Predicted measurement
  384.         predictedMeasurement = measurement.getObservedMeasurement().estimate(currentMeasurementNumber, currentMeasurementNumber,
  385.                                                                              KalmanEstimatorUtil.filterRelevant(measurement.getObservedMeasurement(),
  386.                                                                                                                 predictedSpacecraftStates));
  387.         predictedMeasurement.setEstimatedValue(predictedMeas.toArray());

  388.         // set estimated value to the predicted value by the filter
  389.         KalmanEstimatorUtil.applyDynamicOutlierFilter(predictedMeasurement, innovationCovarianceMatrix);

  390.         // Compute the innovation vector (not normalized for unscented Kalman filter)
  391.         return KalmanEstimatorUtil.computeInnovationVector(predictedMeasurement);

  392.     }

  393.     /**
  394.      * Predict the predicted states for the given sigma points.
  395.      * @param sigmaPoints current sigma points
  396.      * @param index the index corresponding to the satellite one is dealing with
  397.      * @return predicted state for the given sigma point
  398.      */
  399.     private List<SpacecraftState> predictStates(final RealVector[] sigmaPoints, final int index) {

  400.         // Loop on sigma points to create the propagator parallelizer
  401.         final List<Propagator> propagators = new ArrayList<>(sigmaPoints.length);
  402.         for (int k = 0; k < sigmaPoints.length; ++k) {
  403.             // Current sigma point
  404.             final double[] currentPoint = sigmaPoints[k].copy().toArray();
  405.             // Create the corresponding orbit propagator
  406.             final Propagator currentPropagator = createPropagator(currentPoint, index);
  407.             // Add it to the list of propagators
  408.             propagators.add(currentPropagator);
  409.         }

  410.         // Create the propagator parallelizer and predict states
  411.         // (the shift is done to start a little bit before the previous measurement epoch)
  412.         final PropagatorsParallelizer parallelizer = new PropagatorsParallelizer(propagators, interpolators -> { });
  413.         final List<SpacecraftState>   states       = parallelizer.propagate(previousDate.shiftedBy(-1.0e-3), currentDate);

  414.         // Return
  415.         return states;

  416.     }

  417.     /**
  418.      * Create a propagator for the given sigma point.
  419.      * @param point input sigma point
  420.      * @param index the index corresponding to the satellite one is dealing with
  421.      * @return the corresponding orbit propagator
  422.      */
  423.     private Propagator createPropagator(final double[] point, final int index) {
  424.         // Create a new instance of the current propagator builder
  425.         final PropagatorBuilder copy = builders.get(index).copy();
  426.         // Convert the given sigma point to an orbit
  427.         final Orbit orbit = orbitTypes[index].mapArrayToOrbit(point, null, angleTypes[index], copy.getInitialOrbitDate(),
  428.                                                       copy.getMu(), copy.getFrame());
  429.         copy.resetOrbit(orbit);
  430.         // Create the propagator
  431.         final Propagator propagator = copy.buildPropagator(copy.getSelectedNormalizedParameters());
  432.         return propagator;
  433.     }

  434.     /** Finalize estimation.
  435.      * @param observedMeasurement measurement that has just been processed
  436.      * @param estimate corrected estimate
  437.      */
  438.     public void finalizeEstimation(final ObservedMeasurement<?> observedMeasurement,
  439.                                    final ProcessEstimate estimate) {

  440.         correctedEstimate = estimate;

  441.         // Loop on builders
  442.         for (int k = 0; k < builders.size(); k++ ) {

  443.             // Update corrected state
  444.             final double[] correctedStateArray = estimate.getState().getSubVector(orbitsStartColumns[k], orbitsEndColumns[k] - orbitsStartColumns[k]).toArray();
  445.             final Orbit correctedOrbit = orbitTypes[k].mapArrayToOrbit(correctedStateArray, null, angleTypes[k],
  446.                                                                    currentDate, builders.get(k).getMu(), builders.get(k).getFrame());
  447.             correctedSpacecraftStates[k] = new SpacecraftState(correctedOrbit);

  448.             // Update the builder
  449.             builders.get(k).resetOrbit(correctedOrbit);

  450.         }

  451.         // Corrected measurement
  452.         correctedMeasurement = observedMeasurement.estimate(currentMeasurementNumber,
  453.                                                             currentMeasurementNumber,
  454.                                                             KalmanEstimatorUtil.filterRelevant(observedMeasurement,
  455.                                                                                                getCorrectedSpacecraftStates()));
  456.     }

  457.     /** Get the propagators estimated with the values set in the propagators builders.
  458.      * @return propagators based on the current values in the builder
  459.      */
  460.     public Propagator[] getEstimatedPropagators() {
  461.         // Return propagators built with current instantiation of the propagator builders
  462.         final Propagator[] propagators = new Propagator[builders.size()];
  463.         for (int k = 0; k < builders.size(); ++k) {
  464.             propagators[k] = builders.get(k).buildPropagator(builders.get(k).getSelectedNormalizedParameters());
  465.         }
  466.         return propagators;
  467.     }

  468.     /** Get the current corrected estimate.
  469.      * @return current corrected estimate
  470.      */
  471.     public ProcessEstimate getEstimate() {
  472.         return correctedEstimate;
  473.     }

  474.     /** {@inheritDoc} */
  475.     @Override
  476.     public ParameterDriversList getEstimatedOrbitalParameters() {
  477.         return allEstimatedOrbitalParameters;
  478.     }

  479.     /** {@inheritDoc} */
  480.     @Override
  481.     public ParameterDriversList getEstimatedPropagationParameters() {
  482.         return allEstimatedPropagationParameters;
  483.     }

  484.     /** {@inheritDoc} */
  485.     @Override
  486.     public ParameterDriversList getEstimatedMeasurementsParameters() {
  487.         return estimatedMeasurementsParameters;
  488.     }

  489.     /** {@inheritDoc} */
  490.     @Override
  491.     public SpacecraftState[] getPredictedSpacecraftStates() {
  492.         return predictedSpacecraftStates.clone();
  493.     }

  494.     /** {@inheritDoc} */
  495.     @Override
  496.     public SpacecraftState[] getCorrectedSpacecraftStates() {
  497.         return correctedSpacecraftStates.clone();
  498.     }

  499.     /** {@inheritDoc} */
  500.     @Override
  501.     public RealVector getPhysicalEstimatedState() {
  502.         // Method {@link ParameterDriver#getValue()} is used to get
  503.         // the physical values of the state.
  504.         // The scales'array is used to get the size of the state vector
  505.         final RealVector physicalEstimatedState = new ArrayRealVector(getEstimate().getState().getDimension());
  506.         int i = 0;
  507.         for (final DelegatingDriver driver : getEstimatedOrbitalParameters().getDrivers()) {
  508.             physicalEstimatedState.setEntry(i++, driver.getValue());
  509.         }
  510.         for (final DelegatingDriver driver : getEstimatedPropagationParameters().getDrivers()) {
  511.             physicalEstimatedState.setEntry(i++, driver.getValue());
  512.         }
  513.         for (final DelegatingDriver driver : getEstimatedMeasurementsParameters().getDrivers()) {
  514.             physicalEstimatedState.setEntry(i++, driver.getValue());
  515.         }

  516.         return physicalEstimatedState;
  517.     }

  518.     /** {@inheritDoc} */
  519.     @Override
  520.     public RealMatrix getPhysicalEstimatedCovarianceMatrix() {
  521.         return correctedEstimate.getCovariance();
  522.     }


  523.     /** {@inheritDoc} */
  524.     @Override
  525.     public RealMatrix getPhysicalStateTransitionMatrix() {
  526.         return null;
  527.     }

  528.     /** {@inheritDoc} */
  529.     @Override
  530.     public RealMatrix getPhysicalMeasurementJacobian() {
  531.         return null;
  532.     }

  533.     /** {@inheritDoc} */
  534.     @Override
  535.     public RealMatrix getPhysicalInnovationCovarianceMatrix() {
  536.         return correctedEstimate.getInnovationCovariance();
  537.     }

  538.     /** {@inheritDoc} */
  539.     @Override
  540.     public RealMatrix getPhysicalKalmanGain() {
  541.         return correctedEstimate.getKalmanGain();
  542.     }

  543.     /** {@inheritDoc} */
  544.     @Override
  545.     public int getCurrentMeasurementNumber() {
  546.         return currentMeasurementNumber;
  547.     }

  548.     /** {@inheritDoc} */
  549.     @Override
  550.     public AbsoluteDate getCurrentDate() {
  551.         return currentDate;
  552.     }

  553.     /** {@inheritDoc} */
  554.     @Override
  555.     public EstimatedMeasurement<?> getPredictedMeasurement() {
  556.         return predictedMeasurement;
  557.     }

  558.     /** {@inheritDoc} */
  559.     @Override
  560.     public EstimatedMeasurement<?> getCorrectedMeasurement() {
  561.         return correctedMeasurement;
  562.     }

  563. }