SemiAnalyticalUnscentedKalmanModel.java

  1. /* Copyright 2002-2022 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.Comparator;
  20. import java.util.List;

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

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

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

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

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

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

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

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

  65.     /** Position angle type used during orbit determination. */
  66.     private final PositionAngle angleType;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  129.         }

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

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

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

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

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

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

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

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

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

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

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

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

  188.     }

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

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

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

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

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

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

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

  230.     }

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

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

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

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

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

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

  255.         // Estimate the measurement for each predicted state
  256.         final RealVector[] predictedStates       = new RealVector[sigmaPoints.length];
  257.         final RealVector[] predictedMeasurements = 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.             // Calculate the predicted osculating elements for the current mean state
  263.             final RealVector osculating = computeOsculatingElements(predicted, nominalMeanSpacecraftState, shortPeriodicTerms);
  264.             final Orbit osculatingOrbit = orbitType.mapArrayToOrbit(osculating.toArray(), null, angleType,
  265.                                                                     currentDate, builder.getMu(), builder.getFrame());

  266.             // Then, estimate the measurement
  267.             final EstimatedMeasurement<?> estimated = observedMeasurement.estimate(currentMeasurementNumber,
  268.                                                                                    currentMeasurementNumber,
  269.                                                                                    new SpacecraftState[] {
  270.                                                                                        new SpacecraftState(osculatingOrbit)
  271.                                                                                    });
  272.             predictedMeasurements[k] = new ArrayRealVector(estimated.getEstimatedValue());
  273.         }

  274.         // Number of estimated measurement parameters
  275.         final int nbMeas = getNumberSelectedMeasurementDrivers();

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

  278.         // Covariance matrix
  279.         final RealMatrix noiseK = MatrixUtils.createRealMatrix(nbDyn + nbMeas, nbDyn + nbMeas);
  280.         final RealMatrix noiseP = covarianceMatrixProvider.getProcessNoiseMatrix(previousNominalMeanSpacecraftState, nominalMeanSpacecraftState);
  281.         noiseK.setSubMatrix(noiseP.getData(), 0, 0);
  282.         if (measurementProcessNoiseMatrix != null) {
  283.             final RealMatrix noiseM = measurementProcessNoiseMatrix.getProcessNoiseMatrix(previousNominalMeanSpacecraftState, nominalMeanSpacecraftState);
  284.             noiseK.setSubMatrix(noiseM.getData(), nbDyn, nbDyn);
  285.         }

  286.         // Verify dimension
  287.         KalmanEstimatorUtil.checkDimension(noiseK.getRowDimension(),
  288.                                            builder.getOrbitalParametersDrivers(),
  289.                                            builder.getPropagationParametersDrivers(),
  290.                                            estimatedMeasurementsParameters);

  291.         // Return
  292.         return new UnscentedEvolution(measurement.getTime(), predictedStates, predictedMeasurements, noiseK);

  293.     }

  294.     /** {@inheritDoc} */
  295.     @Override
  296.     public RealVector getInnovation(final MeasurementDecorator measurement, final RealVector predictedMeas,
  297.                                     final RealVector predictedState, final RealMatrix innovationCovarianceMatrix) {

  298.         // Predicted filter correction
  299.         predictedFilterCorrection = predictedState;

  300.         // Predicted measurement
  301.         final RealVector osculating = computeOsculatingElements(predictedFilterCorrection, nominalMeanSpacecraftState, shortPeriodicTerms);
  302.         final Orbit osculatingOrbit = orbitType.mapArrayToOrbit(osculating.toArray(), null, angleType,
  303.                                                                 currentDate, builder.getMu(), builder.getFrame());
  304.         predictedSpacecraftState = new SpacecraftState(osculatingOrbit);
  305.         predictedMeasurement = measurement.getObservedMeasurement().estimate(currentMeasurementNumber, currentMeasurementNumber, getPredictedSpacecraftStates());

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

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

  310.     }


  311.     /** {@inheritDoc} */
  312.     @Override
  313.     public void finalizeEstimation(final ObservedMeasurement<?> observedMeasurement,
  314.                                    final ProcessEstimate estimate) {
  315.         // Update the process estimate
  316.         correctedEstimate = estimate;
  317.         // Corrected filter correction
  318.         correctedFilterCorrection = estimate.getState();

  319.         // Update the previous nominal mean spacecraft state
  320.         previousNominalMeanSpacecraftState = nominalMeanSpacecraftState;

  321.         // Update the previous nominal mean spacecraft state
  322.         // Calculate the corrected osculating elements
  323.         final RealVector osculating = computeOsculatingElements(correctedFilterCorrection, nominalMeanSpacecraftState, shortPeriodicTerms);
  324.         final Orbit osculatingOrbit = orbitType.mapArrayToOrbit(osculating.toArray(), null, builder.getPositionAngle(),
  325.                                                                 currentDate, builder.getMu(), builder.getFrame());

  326.         // Compute the corrected measurements
  327.         correctedSpacecraftState = new SpacecraftState(osculatingOrbit);
  328.         correctedMeasurement = observedMeasurement.estimate(currentMeasurementNumber,
  329.                                                             currentMeasurementNumber,
  330.                                                             getCorrectedSpacecraftStates());
  331.         // Call the observer if the user add one
  332.         if (observer != null) {
  333.             observer.evaluationPerformed(this);
  334.         }
  335.     }

  336.     /** Get the state transition matrix used to predict the filter correction.
  337.      * <p>
  338.      * The state transition matrix is not computed by the DSST propagator.
  339.      * It is analytically calculated considering Keplerian contribution only
  340.      * </p>
  341.      * @return the state transition matrix used to predict the filter correction
  342.      */
  343.     private RealMatrix getStm() {

  344.         // initialize the STM
  345.         final int nbDym  = getNumberSelectedOrbitalDrivers() + getNumberSelectedPropagationDrivers();
  346.         final int nbMeas = getNumberSelectedMeasurementDrivers();
  347.         final RealMatrix stm = MatrixUtils.createRealIdentityMatrix(nbDym + nbMeas);

  348.         // State transition matrix using Keplerian contribution only
  349.         final double mu  = builder.getMu();
  350.         final double sma = previousNominalMeanSpacecraftState.getA();
  351.         final double dt  = currentDate.durationFrom(previousNominalMeanSpacecraftState.getDate());
  352.         final double contribution = -1.5 * dt * FastMath.sqrt(mu / FastMath.pow(sma, 5));
  353.         stm.setEntry(5, 0, contribution);

  354.         // Return
  355.         return stm;

  356.     }

  357.     /** {@inheritDoc} */
  358.     @Override
  359.     public void finalizeOperationsObservationGrid() {
  360.         // Update parameters
  361.         updateParameters();
  362.     }

  363.     /** {@inheritDoc} */
  364.     @Override
  365.     public ParameterDriversList getEstimatedOrbitalParameters() {
  366.         return estimatedOrbitalParameters;
  367.     }

  368.     /** {@inheritDoc} */
  369.     @Override
  370.     public ParameterDriversList getEstimatedPropagationParameters() {
  371.         return estimatedPropagationParameters;
  372.     }

  373.     /** {@inheritDoc} */
  374.     @Override
  375.     public ParameterDriversList getEstimatedMeasurementsParameters() {
  376.         return estimatedMeasurementsParameters;
  377.     }

  378.     /** {@inheritDoc}
  379.      * <p>
  380.      * Predicted state is osculating.
  381.      * </p>
  382.      */
  383.     @Override
  384.     public SpacecraftState[] getPredictedSpacecraftStates() {
  385.         return new SpacecraftState[] {predictedSpacecraftState};
  386.     }

  387.     /** {@inheritDoc}
  388.      * <p>
  389.      * Corrected state is osculating.
  390.      * </p>
  391.      */
  392.     @Override
  393.     public SpacecraftState[] getCorrectedSpacecraftStates() {
  394.         return new SpacecraftState[] {correctedSpacecraftState};
  395.     }

  396.     /** {@inheritDoc} */
  397.     @Override
  398.     public RealVector getPhysicalEstimatedState() {
  399.         // Method {@link ParameterDriver#getValue()} is used to get
  400.         // the physical values of the state.
  401.         // The scales'array is used to get the size of the state vector
  402.         final RealVector physicalEstimatedState = new ArrayRealVector(getEstimate().getState().getDimension());
  403.         int i = 0;
  404.         for (final DelegatingDriver driver : getEstimatedOrbitalParameters().getDrivers()) {
  405.             physicalEstimatedState.setEntry(i++, driver.getValue());
  406.         }
  407.         for (final DelegatingDriver driver : getEstimatedPropagationParameters().getDrivers()) {
  408.             physicalEstimatedState.setEntry(i++, driver.getValue());
  409.         }
  410.         for (final DelegatingDriver driver : getEstimatedMeasurementsParameters().getDrivers()) {
  411.             physicalEstimatedState.setEntry(i++, driver.getValue());
  412.         }

  413.         return physicalEstimatedState;
  414.     }

  415.     /** {@inheritDoc} */
  416.     @Override
  417.     public RealMatrix getPhysicalEstimatedCovarianceMatrix() {
  418.         return correctedEstimate.getCovariance();
  419.     }

  420.     /** {@inheritDoc} */
  421.     @Override
  422.     public RealMatrix getPhysicalStateTransitionMatrix() {
  423.         return null;
  424.     }

  425.     /** {@inheritDoc} */
  426.     @Override
  427.     public RealMatrix getPhysicalMeasurementJacobian() {
  428.         return null;
  429.     }

  430.     /** {@inheritDoc} */
  431.     @Override
  432.     public RealMatrix getPhysicalInnovationCovarianceMatrix() {
  433.         return correctedEstimate.getInnovationCovariance();
  434.     }

  435.     /** {@inheritDoc} */
  436.     @Override
  437.     public RealMatrix getPhysicalKalmanGain() {
  438.         return correctedEstimate.getKalmanGain();
  439.     }

  440.     /** {@inheritDoc} */
  441.     @Override
  442.     public int getCurrentMeasurementNumber() {
  443.         return currentMeasurementNumber;
  444.     }

  445.     /** {@inheritDoc} */
  446.     @Override
  447.     public AbsoluteDate getCurrentDate() {
  448.         return currentDate;
  449.     }

  450.     /** {@inheritDoc} */
  451.     @Override
  452.     public EstimatedMeasurement<?> getPredictedMeasurement() {
  453.         return predictedMeasurement;
  454.     }

  455.     /** {@inheritDoc} */
  456.     @Override
  457.     public EstimatedMeasurement<?> getCorrectedMeasurement() {
  458.         return correctedMeasurement;
  459.     }

  460.     /** {@inheritDoc} */
  461.     @Override
  462.     public void updateNominalSpacecraftState(final SpacecraftState nominal) {
  463.         this.nominalMeanSpacecraftState = nominal;
  464.         // Short period terms
  465.         shortPeriodicTerms = new ArrayRealVector(dsstPropagator.getShortPeriodTermsValue(nominalMeanSpacecraftState));
  466.         // Update the builder with the nominal mean elements orbit
  467.         builder.resetOrbit(nominal.getOrbit(), PropagationType.MEAN);
  468.     }

  469.     /** {@inheritDoc} */
  470.     @Override
  471.     public void updateShortPeriods(final SpacecraftState state) {
  472.         // Loop on DSST force models
  473.         for (final DSSTForceModel model : dsstPropagator.getAllForceModels()) {
  474.             model.updateShortPeriodTerms(model.getParameters(), state);
  475.         }
  476.     }

  477.     /** {@inheritDoc} */
  478.     @Override
  479.     public void initializeShortPeriodicTerms(final SpacecraftState meanState) {
  480.         final List<ShortPeriodTerms> shortPeriodTerms = new ArrayList<ShortPeriodTerms>();
  481.         for (final DSSTForceModel force :  builder.getAllForceModels()) {
  482.             shortPeriodTerms.addAll(force.initializeShortPeriodTerms(new AuxiliaryElements(meanState.getOrbit(), 1), PropagationType.OSCULATING, force.getParameters()));
  483.         }
  484.         dsstPropagator.setShortPeriodTerms(shortPeriodTerms);
  485.     }

  486.     /** Compute the predicted osculating elements.
  487.      * @param filterCorrection physical kalman filter correction
  488.      * @param meanState mean spacecraft state
  489.      * @param shortPeriodTerms short period terms for the given mean state
  490.      * @return the predicted osculating element
  491.      */
  492.     private RealVector computeOsculatingElements(final RealVector filterCorrection,
  493.                                                  final SpacecraftState meanState,
  494.                                                  final RealVector shortPeriodTerms) {

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

  497.         // Return
  498.         return stateVector.add(filterCorrection).add(shortPeriodTerms);

  499.     }

  500.     /** Convert a SpacecraftState to a RealVector.
  501.      * @param state the input SpacecraftState
  502.      * @return the corresponding RealVector
  503.      */
  504.     private RealVector toRealVector(final SpacecraftState state) {

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

  508.         // Return the RealVector
  509.         return new ArrayRealVector(stateArray);

  510.     }

  511.     /** Get the number of estimated orbital parameters.
  512.      * @return the number of estimated orbital parameters
  513.      */
  514.     public int getNumberSelectedOrbitalDrivers() {
  515.         return estimatedOrbitalParameters.getNbParams();
  516.     }

  517.     /** Get the number of estimated propagation parameters.
  518.      * @return the number of estimated propagation parameters
  519.      */
  520.     public int getNumberSelectedPropagationDrivers() {
  521.         return estimatedPropagationParameters.getNbParams();
  522.     }

  523.     /** Get the number of estimated measurement parameters.
  524.      * @return the number of estimated measurement parameters
  525.      */
  526.     public int getNumberSelectedMeasurementDrivers() {
  527.         return estimatedMeasurementsParameters.getNbParams();
  528.     }

  529.     /** Update the estimated parameters after the correction phase of the filter.
  530.      * The min/max allowed values are handled by the parameter themselves.
  531.      */
  532.     private void updateParameters() {
  533.         final RealVector correctedState = correctedEstimate.getState();
  534.         int i = 0;
  535.         for (final DelegatingDriver driver : getEstimatedOrbitalParameters().getDrivers()) {
  536.             // let the parameter handle min/max clipping
  537.             driver.setValue(driver.getValue() + correctedState.getEntry(i++));
  538.         }
  539.         for (final DelegatingDriver driver : getEstimatedPropagationParameters().getDrivers()) {
  540.             // let the parameter handle min/max clipping
  541.             driver.setValue(driver.getValue() + correctedState.getEntry(i++));
  542.         }
  543.         for (final DelegatingDriver driver : getEstimatedMeasurementsParameters().getDrivers()) {
  544.             // let the parameter handle min/max clipping
  545.             driver.setValue(driver.getValue() + correctedState.getEntry(i++));
  546.         }
  547.     }

  548. }