SemiAnalyticalUnscentedKalmanModel.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.UnscentedKalmanFilter;
  21. import org.hipparchus.filtering.kalman.unscented.UnscentedProcess;
  22. import org.hipparchus.linear.ArrayRealVector;
  23. import org.hipparchus.linear.MatrixUtils;
  24. import org.hipparchus.linear.RealMatrix;
  25. import org.hipparchus.linear.RealVector;
  26. import org.hipparchus.util.FastMath;
  27. import org.orekit.estimation.measurements.EstimatedMeasurement;
  28. import org.orekit.estimation.measurements.EstimatedMeasurementBase;
  29. import org.orekit.estimation.measurements.ObservedMeasurement;
  30. import org.orekit.orbits.Orbit;
  31. import org.orekit.orbits.OrbitType;
  32. import org.orekit.orbits.PositionAngleType;
  33. import org.orekit.propagation.PropagationType;
  34. import org.orekit.propagation.SpacecraftState;
  35. import org.orekit.propagation.conversion.DSSTPropagatorBuilder;
  36. import org.orekit.propagation.semianalytical.dsst.DSSTPropagator;
  37. import org.orekit.propagation.semianalytical.dsst.forces.DSSTForceModel;
  38. import org.orekit.propagation.semianalytical.dsst.forces.ShortPeriodTerms;
  39. import org.orekit.propagation.semianalytical.dsst.utilities.AuxiliaryElements;
  40. import org.orekit.time.AbsoluteDate;
  41. import org.orekit.time.ChronologicalComparator;
  42. import org.orekit.utils.ParameterDriver;
  43. import org.orekit.utils.ParameterDriversList;
  44. import org.orekit.utils.ParameterDriversList.DelegatingDriver;

  45. import java.util.ArrayList;
  46. import java.util.Comparator;
  47. import java.util.List;

  48. /** Class defining the process model dynamics to use with a {@link SemiAnalyticalUnscentedKalmanEstimator}.
  49.  * @author GaĆ«tan Pierre
  50.  * @author Bryan Cazabonne
  51.  * @since 11.3
  52.  */
  53. public class SemiAnalyticalUnscentedKalmanModel implements KalmanEstimation, UnscentedProcess<MeasurementDecorator>, SemiAnalyticalProcess {

  54.     /** Initial builder for propagator. */
  55.     private final DSSTPropagatorBuilder builder;

  56.     /** Estimated orbital parameters. */
  57.     private final ParameterDriversList estimatedOrbitalParameters;

  58.     /** Estimated propagation parameters. */
  59.     private final ParameterDriversList estimatedPropagationParameters;

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

  62.     /** Provider for covariance matrice. */
  63.     private final CovarianceMatrixProvider covarianceMatrixProvider;

  64.     /** Process noise matrix provider for measurement parameters. */
  65.     private final CovarianceMatrixProvider measurementProcessNoiseMatrix;

  66.     /** Position angle type used during orbit determination. */
  67.     private final PositionAngleType angleType;

  68.     /** Orbit type used during orbit determination. */
  69.     private final OrbitType orbitType;

  70.     /** Current corrected estimate. */
  71.     private ProcessEstimate correctedEstimate;

  72.     /** Observer to retrieve current estimation info. */
  73.     private KalmanObserver observer;

  74.     /** Current number of measurement. */
  75.     private int currentMeasurementNumber;

  76.     /** Current date. */
  77.     private AbsoluteDate currentDate;

  78.     /** Nominal mean spacecraft state. */
  79.     private SpacecraftState nominalMeanSpacecraftState;

  80.     /** Previous nominal mean spacecraft state. */
  81.     private SpacecraftState previousNominalMeanSpacecraftState;

  82.     /** Predicted osculating spacecraft state. */
  83.     private SpacecraftState predictedSpacecraftState;

  84.     /** Corrected mean spacecraft state. */
  85.     private SpacecraftState correctedSpacecraftState;

  86.     /** Predicted measurement. */
  87.     private EstimatedMeasurement<?> predictedMeasurement;

  88.     /** Corrected measurement. */
  89.     private EstimatedMeasurement<?> correctedMeasurement;

  90.     /** Predicted mean element filter correction. */
  91.     private RealVector predictedFilterCorrection;

  92.     /** Corrected mean element filter correction. */
  93.     private RealVector correctedFilterCorrection;

  94.     /** Propagators for the reference trajectories, up to current date. */
  95.     private DSSTPropagator dsstPropagator;

  96.     /** Short period terms for the nominal mean spacecraft state. */
  97.     private RealVector shortPeriodicTerms;

  98.     /** Unscented Kalman process model constructor (package private).
  99.      * @param propagatorBuilder propagators builders used to evaluate the orbits.
  100.      * @param covarianceMatrixProvider provider for covariance matrix
  101.      * @param estimatedMeasurementParameters measurement parameters to estimate
  102.      * @param measurementProcessNoiseMatrix provider for measurement process noise matrix
  103.      */
  104.     protected SemiAnalyticalUnscentedKalmanModel(final DSSTPropagatorBuilder propagatorBuilder,
  105.                                                  final CovarianceMatrixProvider covarianceMatrixProvider,
  106.                                                  final ParameterDriversList estimatedMeasurementParameters,
  107.                                                  final CovarianceMatrixProvider measurementProcessNoiseMatrix) {

  108.         this.builder                         = propagatorBuilder;
  109.         this.angleType                       = propagatorBuilder.getPositionAngleType();
  110.         this.orbitType                       = propagatorBuilder.getOrbitType();
  111.         this.estimatedMeasurementsParameters = estimatedMeasurementParameters;
  112.         this.currentMeasurementNumber        = 0;
  113.         this.currentDate                     = propagatorBuilder.getInitialOrbitDate();
  114.         this.covarianceMatrixProvider        = covarianceMatrixProvider;
  115.         this.measurementProcessNoiseMatrix   = measurementProcessNoiseMatrix;

  116.         // Number of estimated parameters
  117.         int columns = 0;

  118.         // Set estimated orbital parameters
  119.         this.estimatedOrbitalParameters = new ParameterDriversList();
  120.         for (final ParameterDriver driver : propagatorBuilder.getOrbitalParametersDrivers().getDrivers()) {

  121.             // Verify if the driver reference date has been set
  122.             if (driver.getReferenceDate() == null) {
  123.                 driver.setReferenceDate(currentDate);
  124.             }

  125.             // Verify if the driver is selected
  126.             if (driver.isSelected()) {
  127.                 estimatedOrbitalParameters.add(driver);
  128.                 columns++;
  129.             }

  130.         }

  131.         // Set estimated propagation parameters
  132.         this.estimatedPropagationParameters = new ParameterDriversList();
  133.         final List<String> estimatedPropagationParametersNames = new ArrayList<>();
  134.         for (final ParameterDriver driver : propagatorBuilder.getPropagationParametersDrivers().getDrivers()) {

  135.             // Verify if the driver reference date has been set
  136.             if (driver.getReferenceDate() == null) {
  137.                 driver.setReferenceDate(currentDate);
  138.             }

  139.             // Verify if the driver is selected
  140.             if (driver.isSelected()) {
  141.                 estimatedPropagationParameters.add(driver);
  142.                 final String driverName = driver.getName();
  143.                 // Add the driver name if it has not been added yet
  144.                 if (!estimatedPropagationParametersNames.contains(driverName)) {
  145.                     estimatedPropagationParametersNames.add(driverName);
  146.                     ++columns;
  147.                 }
  148.             }

  149.         }
  150.         estimatedPropagationParametersNames.sort(Comparator.naturalOrder());

  151.         // Set the estimated measurement parameters
  152.         for (final ParameterDriver parameter : estimatedMeasurementsParameters.getDrivers()) {
  153.             if (parameter.getReferenceDate() == null) {
  154.                 parameter.setReferenceDate(currentDate);
  155.             }
  156.             ++columns;
  157.         }

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

  160.         // Number of estimated dynamic parameters (orbital + propagation)
  161.         final int nbDyn  = estimatedOrbitalParameters.getNbParams() +
  162.                            estimatedPropagationParameters.getNbParams();

  163.         // Build the reference propagator
  164.         this.dsstPropagator = getEstimatedPropagator();
  165.         final SpacecraftState meanState = dsstPropagator.initialIsOsculating() ?
  166.                          DSSTPropagator.computeMeanState(dsstPropagator.getInitialState(), dsstPropagator.getAttitudeProvider(), dsstPropagator.getAllForceModels()) :
  167.                          dsstPropagator.getInitialState();
  168.         this.nominalMeanSpacecraftState         = meanState;
  169.         this.predictedSpacecraftState           = meanState;
  170.         this.correctedSpacecraftState           = predictedSpacecraftState;
  171.         this.previousNominalMeanSpacecraftState = nominalMeanSpacecraftState;

  172.         // Initialize the estimated mean element filter correction
  173.         this.predictedFilterCorrection = MatrixUtils.createRealVector(columns);
  174.         this.correctedFilterCorrection = predictedFilterCorrection;

  175.         // Covariance matrix
  176.         final RealMatrix noiseK = MatrixUtils.createRealMatrix(nbDyn + nbMeas, nbDyn + nbMeas);
  177.         final RealMatrix noiseP = covarianceMatrixProvider.getInitialCovarianceMatrix(nominalMeanSpacecraftState);
  178.         noiseK.setSubMatrix(noiseP.getData(), 0, 0);
  179.         if (measurementProcessNoiseMatrix != null) {
  180.             final RealMatrix noiseM = measurementProcessNoiseMatrix.getInitialCovarianceMatrix(nominalMeanSpacecraftState);
  181.             noiseK.setSubMatrix(noiseM.getData(), nbDyn, nbDyn);
  182.         }

  183.         KalmanEstimatorUtil.checkDimension(noiseK.getRowDimension(),
  184.                                            propagatorBuilder.getOrbitalParametersDrivers(),
  185.                                            propagatorBuilder.getPropagationParametersDrivers(),
  186.                                            estimatedMeasurementsParameters);

  187.         // Initialize corrected estimate
  188.         this.correctedEstimate = new ProcessEstimate(0.0, correctedFilterCorrection, noiseK);

  189.     }

  190.     /** {@inheritDoc} */
  191.     @Override
  192.     public KalmanObserver getObserver() {
  193.         return observer;
  194.     }

  195.     /** Set the observer.
  196.      * @param observer the observer
  197.      */
  198.     public void setObserver(final KalmanObserver observer) {
  199.         this.observer = observer;
  200.     }

  201.     /** Get the current corrected estimate.
  202.      * <p>
  203.      * For the Unscented Semi-analytical Kalman Filter
  204.      * it corresponds to the corrected filter correction.
  205.      * In other words, it doesn't represent an orbital state.
  206.      * </p>
  207.      * @return current corrected estimate
  208.      */
  209.     public ProcessEstimate getEstimate() {
  210.         return correctedEstimate;
  211.     }

  212.     /** Process measurements.
  213.      * @param observedMeasurements the list of measurements to process
  214.      * @param filter Unscented Kalman Filter
  215.      * @return estimated propagator
  216.      */
  217.     public DSSTPropagator processMeasurements(final List<ObservedMeasurement<?>> observedMeasurements,
  218.                                               final UnscentedKalmanFilter<MeasurementDecorator> filter) {

  219.         // Sort the measurement
  220.         observedMeasurements.sort(new ChronologicalComparator());
  221.         final AbsoluteDate tStart             = observedMeasurements.get(0).getDate();
  222.         final AbsoluteDate tEnd               = observedMeasurements.get(observedMeasurements.size() - 1).getDate();
  223.         final double       overshootTimeRange = FastMath.nextAfter(tEnd.durationFrom(tStart),
  224.                                                 Double.POSITIVE_INFINITY);

  225.         // Initialize step handler and set it to a parallelized propagator
  226.         final SemiAnalyticalMeasurementHandler  stepHandler = new SemiAnalyticalMeasurementHandler(this, filter, observedMeasurements, builder.getInitialOrbitDate(), true);
  227.         dsstPropagator.getMultiplexer().add(stepHandler);
  228.         dsstPropagator.propagate(tStart, tStart.shiftedBy(overshootTimeRange));

  229.         // Return the last estimated propagator
  230.         return getEstimatedPropagator();

  231.     }

  232.     /** Get the propagator estimated with the values set in the propagator builder.
  233.      * @return propagator based on the current values in the builder
  234.      */
  235.     public DSSTPropagator getEstimatedPropagator() {
  236.         // Return propagator built with current instantiation of the propagator builder
  237.         return (DSSTPropagator) builder.buildPropagator();
  238.     }

  239.     /** {@inheritDoc} */
  240.     @Override
  241.     public UnscentedEvolution getEvolution(final double previousTime, final RealVector[] sigmaPoints,
  242.                                            final MeasurementDecorator measurement) {

  243.         // Set a reference date for all measurements parameters that lack one (including the not estimated ones)
  244.         final ObservedMeasurement<?> observedMeasurement = measurement.getObservedMeasurement();
  245.         for (final ParameterDriver driver : observedMeasurement.getParametersDrivers()) {
  246.             if (driver.getReferenceDate() == null) {
  247.                 driver.setReferenceDate(builder.getInitialOrbitDate());
  248.             }
  249.         }

  250.         // Increment measurement number
  251.         ++currentMeasurementNumber;

  252.         // Update the current date
  253.         currentDate = measurement.getObservedMeasurement().getDate();

  254.         // STM for the prediction of the filter correction
  255.         final RealMatrix stm = getStm();

  256.         // Predicted states
  257.         final RealVector[] predictedStates = new RealVector[sigmaPoints.length];
  258.         for (int k = 0; k < sigmaPoints.length; ++k) {
  259.             // Predict filter correction for the current sigma point
  260.             final RealVector predicted = stm.operate(sigmaPoints[k]);
  261.             predictedStates[k] = predicted;
  262.         }

  263.         // Number of estimated measurement parameters
  264.         final int nbMeas = getNumberSelectedMeasurementDrivers();

  265.         // Number of estimated dynamic parameters (orbital + propagation)
  266.         final int nbDyn  = getNumberSelectedOrbitalDrivers() + getNumberSelectedPropagationDrivers();

  267.         // Covariance matrix
  268.         final RealMatrix noiseK = MatrixUtils.createRealMatrix(nbDyn + nbMeas, nbDyn + nbMeas);
  269.         final RealMatrix noiseP = covarianceMatrixProvider.getProcessNoiseMatrix(previousNominalMeanSpacecraftState, nominalMeanSpacecraftState);
  270.         noiseK.setSubMatrix(noiseP.getData(), 0, 0);
  271.         if (measurementProcessNoiseMatrix != null) {
  272.             final RealMatrix noiseM = measurementProcessNoiseMatrix.getProcessNoiseMatrix(previousNominalMeanSpacecraftState, nominalMeanSpacecraftState);
  273.             noiseK.setSubMatrix(noiseM.getData(), nbDyn, nbDyn);
  274.         }

  275.         // Verify dimension
  276.         KalmanEstimatorUtil.checkDimension(noiseK.getRowDimension(),
  277.                                            builder.getOrbitalParametersDrivers(),
  278.                                            builder.getPropagationParametersDrivers(),
  279.                                            estimatedMeasurementsParameters);

  280.         // Return
  281.         return new UnscentedEvolution(measurement.getTime(), predictedStates, noiseK);

  282.     }

  283.     /** {@inheritDoc} */
  284.     @Override
  285.     public RealVector[] getPredictedMeasurements(final RealVector[] predictedSigmaPoints, final MeasurementDecorator measurement) {

  286.         // Observed measurement
  287.         final ObservedMeasurement<?> observedMeasurement = measurement.getObservedMeasurement();

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

  290.         // Loop on sigma points
  291.         for (int k = 0; k < predictedSigmaPoints.length; ++k) {

  292.             // Calculate the predicted osculating elements for the current mean state
  293.             final RealVector osculating = computeOsculatingElements(predictedSigmaPoints[k], nominalMeanSpacecraftState, shortPeriodicTerms);
  294.             final Orbit osculatingOrbit = orbitType.mapArrayToOrbit(osculating.toArray(), null, angleType,
  295.                                                                     currentDate, builder.getMu(), builder.getFrame());

  296.             // Then, estimate the measurement
  297.             final EstimatedMeasurement<?> estimated = estimateMeasurement(observedMeasurement, currentMeasurementNumber,
  298.                 new SpacecraftState[] { new SpacecraftState(osculatingOrbit) });
  299.             predictedMeasurements[k] = new ArrayRealVector(estimated.getEstimatedValue());

  300.         }

  301.         // Return
  302.         return predictedMeasurements;

  303.     }

  304.     /** {@inheritDoc} */
  305.     @Override
  306.     public RealVector getInnovation(final MeasurementDecorator measurement, final RealVector predictedMeas,
  307.                                     final RealVector predictedState, final RealMatrix innovationCovarianceMatrix) {

  308.         // Predicted filter correction
  309.         predictedFilterCorrection = predictedState;

  310.         // Predicted measurement
  311.         final RealVector osculating = computeOsculatingElements(predictedFilterCorrection, nominalMeanSpacecraftState, shortPeriodicTerms);
  312.         final Orbit osculatingOrbit = orbitType.mapArrayToOrbit(osculating.toArray(), null, angleType,
  313.                                                                 currentDate, builder.getMu(), builder.getFrame());
  314.         predictedSpacecraftState = new SpacecraftState(osculatingOrbit);
  315.         predictedMeasurement = estimateMeasurement(measurement.getObservedMeasurement(), currentMeasurementNumber,
  316.             getPredictedSpacecraftStates());
  317.         predictedMeasurement.setEstimatedValue(predictedMeas.toArray());

  318.         // Apply the dynamic outlier filter, if it exists
  319.         KalmanEstimatorUtil.applyDynamicOutlierFilter(predictedMeasurement, innovationCovarianceMatrix);

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

  322.     }


  323.     /** {@inheritDoc} */
  324.     @Override
  325.     public void finalizeEstimation(final ObservedMeasurement<?> observedMeasurement,
  326.                                    final ProcessEstimate estimate) {
  327.         // Update the process estimate
  328.         correctedEstimate = estimate;
  329.         // Corrected filter correction
  330.         correctedFilterCorrection = estimate.getState();

  331.         // Update the previous nominal mean spacecraft state
  332.         previousNominalMeanSpacecraftState = nominalMeanSpacecraftState;

  333.         // Update the previous nominal mean spacecraft state
  334.         // Calculate the corrected osculating elements
  335.         final RealVector osculating = computeOsculatingElements(correctedFilterCorrection, nominalMeanSpacecraftState, shortPeriodicTerms);
  336.         final Orbit osculatingOrbit = orbitType.mapArrayToOrbit(osculating.toArray(), null, builder.getPositionAngleType(),
  337.                                                                 currentDate, builder.getMu(), builder.getFrame());

  338.         // Compute the corrected measurements
  339.         correctedSpacecraftState = new SpacecraftState(osculatingOrbit);
  340.         correctedMeasurement = estimateMeasurement(observedMeasurement, currentMeasurementNumber,
  341.             getCorrectedSpacecraftStates());

  342.         // Call the observer if the user add one
  343.         if (observer != null) {
  344.             observer.evaluationPerformed(this);
  345.         }
  346.     }

  347.     /**
  348.      * Estimate measurement (without derivatives).
  349.      * @param <T> measurement type
  350.      * @param observedMeasurement observed measurement
  351.      * @param measurementNumber measurement number
  352.      * @param spacecraftStates states
  353.      * @return estimated measurements
  354.      * @since 12.1
  355.      */
  356.     private static <T extends ObservedMeasurement<T>> EstimatedMeasurement<?> estimateMeasurement(final ObservedMeasurement<T> observedMeasurement,
  357.                                                                                                   final int measurementNumber,
  358.                                                                                                   final SpacecraftState[] spacecraftStates) {
  359.         final EstimatedMeasurementBase<T> estimatedMeasurementBase = observedMeasurement.
  360.                 estimateWithoutDerivatives(measurementNumber, measurementNumber,
  361.                         KalmanEstimatorUtil.filterRelevant(observedMeasurement, spacecraftStates));
  362.         final EstimatedMeasurement<T> estimatedMeasurement = new EstimatedMeasurement<>(estimatedMeasurementBase.getObservedMeasurement(),
  363.                 estimatedMeasurementBase.getIteration(), estimatedMeasurementBase.getCount(),
  364.                 estimatedMeasurementBase.getStates(), estimatedMeasurementBase.getParticipants());
  365.         estimatedMeasurement.setEstimatedValue(estimatedMeasurementBase.getEstimatedValue());
  366.         return estimatedMeasurement;
  367.     }

  368.     /** Get the state transition matrix used to predict the filter correction.
  369.      * <p>
  370.      * The state transition matrix is not computed by the DSST propagator.
  371.      * It is analytically calculated considering Keplerian contribution only
  372.      * </p>
  373.      * @return the state transition matrix used to predict the filter correction
  374.      */
  375.     private RealMatrix getStm() {

  376.         // initialize the STM
  377.         final int nbDym  = getNumberSelectedOrbitalDrivers() + getNumberSelectedPropagationDrivers();
  378.         final int nbMeas = getNumberSelectedMeasurementDrivers();
  379.         final RealMatrix stm = MatrixUtils.createRealIdentityMatrix(nbDym + nbMeas);

  380.         // State transition matrix using Keplerian contribution only
  381.         final double mu  = builder.getMu();
  382.         final double sma = previousNominalMeanSpacecraftState.getA();
  383.         final double dt  = currentDate.durationFrom(previousNominalMeanSpacecraftState.getDate());
  384.         final double contribution = -1.5 * dt * FastMath.sqrt(mu / FastMath.pow(sma, 5));
  385.         stm.setEntry(5, 0, contribution);

  386.         // Return
  387.         return stm;

  388.     }

  389.     /** {@inheritDoc} */
  390.     @Override
  391.     public void finalizeOperationsObservationGrid() {
  392.         // Update parameters
  393.         updateParameters();
  394.     }

  395.     /** {@inheritDoc} */
  396.     @Override
  397.     public ParameterDriversList getEstimatedOrbitalParameters() {
  398.         return estimatedOrbitalParameters;
  399.     }

  400.     /** {@inheritDoc} */
  401.     @Override
  402.     public ParameterDriversList getEstimatedPropagationParameters() {
  403.         return estimatedPropagationParameters;
  404.     }

  405.     /** {@inheritDoc} */
  406.     @Override
  407.     public ParameterDriversList getEstimatedMeasurementsParameters() {
  408.         return estimatedMeasurementsParameters;
  409.     }

  410.     /** {@inheritDoc}
  411.      * <p>
  412.      * Predicted state is osculating.
  413.      * </p>
  414.      */
  415.     @Override
  416.     public SpacecraftState[] getPredictedSpacecraftStates() {
  417.         return new SpacecraftState[] {predictedSpacecraftState};
  418.     }

  419.     /** {@inheritDoc}
  420.      * <p>
  421.      * Corrected state is osculating.
  422.      * </p>
  423.      */
  424.     @Override
  425.     public SpacecraftState[] getCorrectedSpacecraftStates() {
  426.         return new SpacecraftState[] {correctedSpacecraftState};
  427.     }

  428.     /** {@inheritDoc} */
  429.     @Override
  430.     public RealVector getPhysicalEstimatedState() {
  431.         // Method {@link ParameterDriver#getValue()} is used to get
  432.         // the physical values of the state.
  433.         // The scales'array is used to get the size of the state vector
  434.         final RealVector physicalEstimatedState = new ArrayRealVector(getEstimate().getState().getDimension());
  435.         int i = 0;
  436.         for (final DelegatingDriver driver : getEstimatedOrbitalParameters().getDrivers()) {
  437.             physicalEstimatedState.setEntry(i++, driver.getValue());
  438.         }
  439.         for (final DelegatingDriver driver : getEstimatedPropagationParameters().getDrivers()) {
  440.             physicalEstimatedState.setEntry(i++, driver.getValue());
  441.         }
  442.         for (final DelegatingDriver driver : getEstimatedMeasurementsParameters().getDrivers()) {
  443.             physicalEstimatedState.setEntry(i++, driver.getValue());
  444.         }

  445.         return physicalEstimatedState;
  446.     }

  447.     /** {@inheritDoc} */
  448.     @Override
  449.     public RealMatrix getPhysicalEstimatedCovarianceMatrix() {
  450.         return correctedEstimate.getCovariance();
  451.     }

  452.     /** {@inheritDoc} */
  453.     @Override
  454.     public RealMatrix getPhysicalStateTransitionMatrix() {
  455.         return null;
  456.     }

  457.     /** {@inheritDoc} */
  458.     @Override
  459.     public RealMatrix getPhysicalMeasurementJacobian() {
  460.         return null;
  461.     }

  462.     /** {@inheritDoc} */
  463.     @Override
  464.     public RealMatrix getPhysicalInnovationCovarianceMatrix() {
  465.         return correctedEstimate.getInnovationCovariance();
  466.     }

  467.     /** {@inheritDoc} */
  468.     @Override
  469.     public RealMatrix getPhysicalKalmanGain() {
  470.         return correctedEstimate.getKalmanGain();
  471.     }

  472.     /** {@inheritDoc} */
  473.     @Override
  474.     public int getCurrentMeasurementNumber() {
  475.         return currentMeasurementNumber;
  476.     }

  477.     /** {@inheritDoc} */
  478.     @Override
  479.     public AbsoluteDate getCurrentDate() {
  480.         return currentDate;
  481.     }

  482.     /** {@inheritDoc} */
  483.     @Override
  484.     public EstimatedMeasurement<?> getPredictedMeasurement() {
  485.         return predictedMeasurement;
  486.     }

  487.     /** {@inheritDoc} */
  488.     @Override
  489.     public EstimatedMeasurement<?> getCorrectedMeasurement() {
  490.         return correctedMeasurement;
  491.     }

  492.     /** {@inheritDoc} */
  493.     @Override
  494.     public void updateNominalSpacecraftState(final SpacecraftState nominal) {
  495.         this.nominalMeanSpacecraftState = nominal;
  496.         // Short period terms
  497.         shortPeriodicTerms = new ArrayRealVector(dsstPropagator.getShortPeriodTermsValue(nominalMeanSpacecraftState));
  498.         // Update the builder with the nominal mean elements orbit
  499.         builder.resetOrbit(nominal.getOrbit(), PropagationType.MEAN);
  500.     }

  501.     /** {@inheritDoc} */
  502.     @Override
  503.     public void updateShortPeriods(final SpacecraftState state) {
  504.         // Loop on DSST force models
  505.         for (final DSSTForceModel model : dsstPropagator.getAllForceModels()) {
  506.             model.updateShortPeriodTerms(model.getParameters(), state);
  507.         }
  508.     }

  509.     /** {@inheritDoc} */
  510.     @Override
  511.     public void initializeShortPeriodicTerms(final SpacecraftState meanState) {
  512.         final List<ShortPeriodTerms> shortPeriodTerms = new ArrayList<>();
  513.         for (final DSSTForceModel force :  builder.getAllForceModels()) {
  514.             shortPeriodTerms.addAll(force.initializeShortPeriodTerms(new AuxiliaryElements(meanState.getOrbit(), 1), PropagationType.OSCULATING, force.getParameters()));
  515.         }
  516.         dsstPropagator.setShortPeriodTerms(shortPeriodTerms);
  517.     }

  518.     /** Compute the predicted osculating elements.
  519.      * @param filterCorrection physical kalman filter correction
  520.      * @param meanState mean spacecraft state
  521.      * @param shortPeriodTerms short period terms for the given mean state
  522.      * @return the predicted osculating element
  523.      */
  524.     private RealVector computeOsculatingElements(final RealVector filterCorrection,
  525.                                                  final SpacecraftState meanState,
  526.                                                  final RealVector shortPeriodTerms) {

  527.         // Convert the input predicted mean state to a SpacecraftState
  528.         final RealVector stateVector = toRealVector(meanState);

  529.         // Return
  530.         return stateVector.add(filterCorrection).add(shortPeriodTerms);

  531.     }

  532.     /** Convert a SpacecraftState to a RealVector.
  533.      * @param state the input SpacecraftState
  534.      * @return the corresponding RealVector
  535.      */
  536.     private RealVector toRealVector(final SpacecraftState state) {

  537.         // Convert orbit to array
  538.         final double[] stateArray = new double[6];
  539.         orbitType.mapOrbitToArray(state.getOrbit(), angleType, stateArray, null);

  540.         // Return the RealVector
  541.         return new ArrayRealVector(stateArray);

  542.     }

  543.     /** Get the number of estimated orbital parameters.
  544.      * @return the number of estimated orbital parameters
  545.      */
  546.     public int getNumberSelectedOrbitalDrivers() {
  547.         return estimatedOrbitalParameters.getNbParams();
  548.     }

  549.     /** Get the number of estimated propagation parameters.
  550.      * @return the number of estimated propagation parameters
  551.      */
  552.     public int getNumberSelectedPropagationDrivers() {
  553.         return estimatedPropagationParameters.getNbParams();
  554.     }

  555.     /** Get the number of estimated measurement parameters.
  556.      * @return the number of estimated measurement parameters
  557.      */
  558.     public int getNumberSelectedMeasurementDrivers() {
  559.         return estimatedMeasurementsParameters.getNbParams();
  560.     }

  561.     /** Update the estimated parameters after the correction phase of the filter.
  562.      * The min/max allowed values are handled by the parameter themselves.
  563.      */
  564.     private void updateParameters() {
  565.         final RealVector correctedState = correctedEstimate.getState();
  566.         int i = 0;
  567.         for (final DelegatingDriver driver : getEstimatedOrbitalParameters().getDrivers()) {
  568.             // let the parameter handle min/max clipping
  569.             driver.setValue(driver.getValue() + correctedState.getEntry(i++));
  570.         }
  571.         for (final DelegatingDriver driver : getEstimatedPropagationParameters().getDrivers()) {
  572.             // let the parameter handle min/max clipping
  573.             driver.setValue(driver.getValue() + correctedState.getEntry(i++));
  574.         }
  575.         for (final DelegatingDriver driver : getEstimatedMeasurementsParameters().getDrivers()) {
  576.             // let the parameter handle min/max clipping
  577.             driver.setValue(driver.getValue() + correctedState.getEntry(i++));
  578.         }
  579.     }

  580. }