SemiAnalyticalUnscentedKalmanModel.java

  1. /* Copyright 2002-2025 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 final 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.         // Return
  264.         return new UnscentedEvolution(measurement.getTime(), predictedStates);

  265.     }

  266.     /** {@inheritDoc} */
  267.     @Override
  268.     public RealMatrix getProcessNoiseMatrix(final double previousTime, final RealVector predictedState,
  269.                                             final MeasurementDecorator measurement) {

  270.         // Number of estimated measurement parameters
  271.         final int nbMeas = getNumberSelectedMeasurementDrivers();

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

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

  282.         // Verify dimension
  283.         KalmanEstimatorUtil.checkDimension(noiseK.getRowDimension(),
  284.                 builder.getOrbitalParametersDrivers(),
  285.                 builder.getPropagationParametersDrivers(),
  286.                 estimatedMeasurementsParameters);

  287.         return noiseK;
  288.     }

  289.     /** {@inheritDoc} */
  290.     @Override
  291.     public RealVector[] getPredictedMeasurements(final RealVector[] predictedSigmaPoints, final MeasurementDecorator measurement) {

  292.         // Observed measurement
  293.         final ObservedMeasurement<?> observedMeasurement = measurement.getObservedMeasurement();

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

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

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

  302.             // Then, estimate the measurement
  303.             final EstimatedMeasurement<?> estimated = estimateMeasurement(observedMeasurement, currentMeasurementNumber,
  304.                 new SpacecraftState[] { new SpacecraftState(osculatingOrbit) });
  305.             predictedMeasurements[k] = new ArrayRealVector(estimated.getEstimatedValue());

  306.         }

  307.         // Return
  308.         return predictedMeasurements;

  309.     }

  310.     /** {@inheritDoc} */
  311.     @Override
  312.     public RealVector getInnovation(final MeasurementDecorator measurement, final RealVector predictedMeas,
  313.                                     final RealVector predictedState, final RealMatrix innovationCovarianceMatrix) {

  314.         // Predicted filter correction
  315.         predictedFilterCorrection = predictedState;

  316.         // Predicted measurement
  317.         final RealVector osculating = computeOsculatingElements(predictedFilterCorrection, nominalMeanSpacecraftState, shortPeriodicTerms);
  318.         final Orbit osculatingOrbit = orbitType.mapArrayToOrbit(osculating.toArray(), null, angleType,
  319.                                                                 currentDate, builder.getMu(), builder.getFrame());
  320.         predictedSpacecraftState = new SpacecraftState(osculatingOrbit);
  321.         predictedMeasurement = estimateMeasurement(measurement.getObservedMeasurement(), currentMeasurementNumber,
  322.             getPredictedSpacecraftStates());
  323.         predictedMeasurement.setEstimatedValue(predictedMeas.toArray());

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

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

  328.     }


  329.     /** {@inheritDoc} */
  330.     @Override
  331.     public void finalizeEstimation(final ObservedMeasurement<?> observedMeasurement,
  332.                                    final ProcessEstimate estimate) {
  333.         // Update the process estimate
  334.         correctedEstimate = estimate;
  335.         // Corrected filter correction
  336.         correctedFilterCorrection = estimate.getState();

  337.         // Update the previous nominal mean spacecraft state
  338.         previousNominalMeanSpacecraftState = nominalMeanSpacecraftState;

  339.         // Update the previous nominal mean spacecraft state
  340.         // Calculate the corrected osculating elements
  341.         final RealVector osculating = computeOsculatingElements(correctedFilterCorrection, nominalMeanSpacecraftState, shortPeriodicTerms);
  342.         final Orbit osculatingOrbit = orbitType.mapArrayToOrbit(osculating.toArray(), null, builder.getPositionAngleType(),
  343.                                                                 currentDate, builder.getMu(), builder.getFrame());

  344.         // Compute the corrected measurements
  345.         correctedSpacecraftState = new SpacecraftState(osculatingOrbit);
  346.         correctedMeasurement = estimateMeasurement(observedMeasurement, currentMeasurementNumber,
  347.             getCorrectedSpacecraftStates());

  348.         // Call the observer if the user add one
  349.         if (observer != null) {
  350.             observer.evaluationPerformed(this);
  351.         }
  352.     }

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

  374.     /** Get the state transition matrix used to predict the filter correction.
  375.      * <p>
  376.      * The state transition matrix is not computed by the DSST propagator.
  377.      * It is analytically calculated considering Keplerian contribution only
  378.      * </p>
  379.      * @return the state transition matrix used to predict the filter correction
  380.      */
  381.     private RealMatrix getStm() {

  382.         // initialize the STM
  383.         final int nbDym  = getNumberSelectedOrbitalDrivers() + getNumberSelectedPropagationDrivers();
  384.         final int nbMeas = getNumberSelectedMeasurementDrivers();
  385.         final RealMatrix stm = MatrixUtils.createRealIdentityMatrix(nbDym + nbMeas);

  386.         // State transition matrix using Keplerian contribution only
  387.         final double mu  = builder.getMu();
  388.         final double sma = previousNominalMeanSpacecraftState.getOrbit().getA();
  389.         final double dt  = currentDate.durationFrom(previousNominalMeanSpacecraftState.getDate());
  390.         final double contribution = -1.5 * dt * FastMath.sqrt(mu / FastMath.pow(sma, 5));
  391.         stm.setEntry(5, 0, contribution);

  392.         // Return
  393.         return stm;

  394.     }

  395.     /** {@inheritDoc} */
  396.     @Override
  397.     public void finalizeOperationsObservationGrid() {
  398.         // Update parameters
  399.         updateParameters();
  400.     }

  401.     /** {@inheritDoc} */
  402.     @Override
  403.     public ParameterDriversList getEstimatedOrbitalParameters() {
  404.         return estimatedOrbitalParameters;
  405.     }

  406.     /** {@inheritDoc} */
  407.     @Override
  408.     public ParameterDriversList getEstimatedPropagationParameters() {
  409.         return estimatedPropagationParameters;
  410.     }

  411.     /** {@inheritDoc} */
  412.     @Override
  413.     public ParameterDriversList getEstimatedMeasurementsParameters() {
  414.         return estimatedMeasurementsParameters;
  415.     }

  416.     /** {@inheritDoc}
  417.      * <p>
  418.      * Predicted state is osculating.
  419.      * </p>
  420.      */
  421.     @Override
  422.     public SpacecraftState[] getPredictedSpacecraftStates() {
  423.         return new SpacecraftState[] {predictedSpacecraftState};
  424.     }

  425.     /** {@inheritDoc}
  426.      * <p>
  427.      * Corrected state is osculating.
  428.      * </p>
  429.      */
  430.     @Override
  431.     public SpacecraftState[] getCorrectedSpacecraftStates() {
  432.         return new SpacecraftState[] {correctedSpacecraftState};
  433.     }

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

  451.         return physicalEstimatedState;
  452.     }

  453.     /** {@inheritDoc} */
  454.     @Override
  455.     public RealMatrix getPhysicalEstimatedCovarianceMatrix() {
  456.         return correctedEstimate.getCovariance();
  457.     }

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

  463.     /** {@inheritDoc} */
  464.     @Override
  465.     public RealMatrix getPhysicalMeasurementJacobian() {
  466.         return null;
  467.     }

  468.     /** {@inheritDoc} */
  469.     @Override
  470.     public RealMatrix getPhysicalInnovationCovarianceMatrix() {
  471.         return correctedEstimate.getInnovationCovariance();
  472.     }

  473.     /** {@inheritDoc} */
  474.     @Override
  475.     public RealMatrix getPhysicalKalmanGain() {
  476.         return correctedEstimate.getKalmanGain();
  477.     }

  478.     /** {@inheritDoc} */
  479.     @Override
  480.     public int getCurrentMeasurementNumber() {
  481.         return currentMeasurementNumber;
  482.     }

  483.     /** {@inheritDoc} */
  484.     @Override
  485.     public AbsoluteDate getCurrentDate() {
  486.         return currentDate;
  487.     }

  488.     /** {@inheritDoc} */
  489.     @Override
  490.     public EstimatedMeasurement<?> getPredictedMeasurement() {
  491.         return predictedMeasurement;
  492.     }

  493.     /** {@inheritDoc} */
  494.     @Override
  495.     public EstimatedMeasurement<?> getCorrectedMeasurement() {
  496.         return correctedMeasurement;
  497.     }

  498.     /** {@inheritDoc} */
  499.     @Override
  500.     public void updateNominalSpacecraftState(final SpacecraftState nominal) {
  501.         this.nominalMeanSpacecraftState = nominal;
  502.         // Short period terms
  503.         shortPeriodicTerms = new ArrayRealVector(dsstPropagator.getShortPeriodTermsValue(nominalMeanSpacecraftState));
  504.         // Update the builder with the nominal mean elements orbit
  505.         builder.resetOrbit(nominal.getOrbit(), PropagationType.MEAN);
  506.     }

  507.     /** {@inheritDoc} */
  508.     @Override
  509.     public void updateShortPeriods(final SpacecraftState state) {
  510.         // Loop on DSST force models
  511.         for (final DSSTForceModel model : dsstPropagator.getAllForceModels()) {
  512.             model.updateShortPeriodTerms(model.getParameters(), state);
  513.         }
  514.     }

  515.     /** {@inheritDoc} */
  516.     @Override
  517.     public void initializeShortPeriodicTerms(final SpacecraftState meanState) {
  518.         final List<ShortPeriodTerms> shortPeriodTerms = new ArrayList<>();
  519.         for (final DSSTForceModel force :  builder.getAllForceModels()) {
  520.             shortPeriodTerms.addAll(force.initializeShortPeriodTerms(new AuxiliaryElements(meanState.getOrbit(), 1), PropagationType.OSCULATING, force.getParameters()));
  521.         }
  522.         dsstPropagator.setShortPeriodTerms(shortPeriodTerms);
  523.     }

  524.     /** Compute the predicted osculating elements.
  525.      * @param filterCorrection physical kalman filter correction
  526.      * @param meanState mean spacecraft state
  527.      * @param shortPeriodTerms short period terms for the given mean state
  528.      * @return the predicted osculating element
  529.      */
  530.     private RealVector computeOsculatingElements(final RealVector filterCorrection,
  531.                                                  final SpacecraftState meanState,
  532.                                                  final RealVector shortPeriodTerms) {

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

  535.         // Return
  536.         return stateVector.add(filterCorrection).add(shortPeriodTerms);

  537.     }

  538.     /** Convert a SpacecraftState to a RealVector.
  539.      * @param state the input SpacecraftState
  540.      * @return the corresponding RealVector
  541.      */
  542.     private RealVector toRealVector(final SpacecraftState state) {

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

  546.         // Return the RealVector
  547.         return new ArrayRealVector(stateArray);

  548.     }

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

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

  561.     /** Get the number of estimated measurement parameters.
  562.      * @return the number of estimated measurement parameters
  563.      */
  564.     public int getNumberSelectedMeasurementDrivers() {
  565.         return estimatedMeasurementsParameters.getNbParams();
  566.     }

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

  586. }