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

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

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

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

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

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

  281.     }

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

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

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

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

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

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

  302.         }

  303.         // Return
  304.         return predictedMeasurements;

  305.     }

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

  310.         // Predicted filter correction
  311.         predictedFilterCorrection = predictedState;

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

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

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

  323.     }


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

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

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

  339.         // Compute the corrected measurements
  340.         correctedSpacecraftState = new SpacecraftState(osculatingOrbit);
  341.         correctedMeasurement = observedMeasurement.estimate(currentMeasurementNumber,
  342.                                                             currentMeasurementNumber,
  343.                                                             getCorrectedSpacecraftStates());
  344.         // Call the observer if the user add one
  345.         if (observer != null) {
  346.             observer.evaluationPerformed(this);
  347.         }
  348.     }

  349.     /** Get the state transition matrix used to predict the filter correction.
  350.      * <p>
  351.      * The state transition matrix is not computed by the DSST propagator.
  352.      * It is analytically calculated considering Keplerian contribution only
  353.      * </p>
  354.      * @return the state transition matrix used to predict the filter correction
  355.      */
  356.     private RealMatrix getStm() {

  357.         // initialize the STM
  358.         final int nbDym  = getNumberSelectedOrbitalDrivers() + getNumberSelectedPropagationDrivers();
  359.         final int nbMeas = getNumberSelectedMeasurementDrivers();
  360.         final RealMatrix stm = MatrixUtils.createRealIdentityMatrix(nbDym + nbMeas);

  361.         // State transition matrix using Keplerian contribution only
  362.         final double mu  = builder.getMu();
  363.         final double sma = previousNominalMeanSpacecraftState.getA();
  364.         final double dt  = currentDate.durationFrom(previousNominalMeanSpacecraftState.getDate());
  365.         final double contribution = -1.5 * dt * FastMath.sqrt(mu / FastMath.pow(sma, 5));
  366.         stm.setEntry(5, 0, contribution);

  367.         // Return
  368.         return stm;

  369.     }

  370.     /** {@inheritDoc} */
  371.     @Override
  372.     public void finalizeOperationsObservationGrid() {
  373.         // Update parameters
  374.         updateParameters();
  375.     }

  376.     /** {@inheritDoc} */
  377.     @Override
  378.     public ParameterDriversList getEstimatedOrbitalParameters() {
  379.         return estimatedOrbitalParameters;
  380.     }

  381.     /** {@inheritDoc} */
  382.     @Override
  383.     public ParameterDriversList getEstimatedPropagationParameters() {
  384.         return estimatedPropagationParameters;
  385.     }

  386.     /** {@inheritDoc} */
  387.     @Override
  388.     public ParameterDriversList getEstimatedMeasurementsParameters() {
  389.         return estimatedMeasurementsParameters;
  390.     }

  391.     /** {@inheritDoc}
  392.      * <p>
  393.      * Predicted state is osculating.
  394.      * </p>
  395.      */
  396.     @Override
  397.     public SpacecraftState[] getPredictedSpacecraftStates() {
  398.         return new SpacecraftState[] {predictedSpacecraftState};
  399.     }

  400.     /** {@inheritDoc}
  401.      * <p>
  402.      * Corrected state is osculating.
  403.      * </p>
  404.      */
  405.     @Override
  406.     public SpacecraftState[] getCorrectedSpacecraftStates() {
  407.         return new SpacecraftState[] {correctedSpacecraftState};
  408.     }

  409.     /** {@inheritDoc} */
  410.     @Override
  411.     public RealVector getPhysicalEstimatedState() {
  412.         // Method {@link ParameterDriver#getValue()} is used to get
  413.         // the physical values of the state.
  414.         // The scales'array is used to get the size of the state vector
  415.         final RealVector physicalEstimatedState = new ArrayRealVector(getEstimate().getState().getDimension());
  416.         int i = 0;
  417.         for (final DelegatingDriver driver : getEstimatedOrbitalParameters().getDrivers()) {
  418.             physicalEstimatedState.setEntry(i++, driver.getValue());
  419.         }
  420.         for (final DelegatingDriver driver : getEstimatedPropagationParameters().getDrivers()) {
  421.             physicalEstimatedState.setEntry(i++, driver.getValue());
  422.         }
  423.         for (final DelegatingDriver driver : getEstimatedMeasurementsParameters().getDrivers()) {
  424.             physicalEstimatedState.setEntry(i++, driver.getValue());
  425.         }

  426.         return physicalEstimatedState;
  427.     }

  428.     /** {@inheritDoc} */
  429.     @Override
  430.     public RealMatrix getPhysicalEstimatedCovarianceMatrix() {
  431.         return correctedEstimate.getCovariance();
  432.     }

  433.     /** {@inheritDoc} */
  434.     @Override
  435.     public RealMatrix getPhysicalStateTransitionMatrix() {
  436.         return null;
  437.     }

  438.     /** {@inheritDoc} */
  439.     @Override
  440.     public RealMatrix getPhysicalMeasurementJacobian() {
  441.         return null;
  442.     }

  443.     /** {@inheritDoc} */
  444.     @Override
  445.     public RealMatrix getPhysicalInnovationCovarianceMatrix() {
  446.         return correctedEstimate.getInnovationCovariance();
  447.     }

  448.     /** {@inheritDoc} */
  449.     @Override
  450.     public RealMatrix getPhysicalKalmanGain() {
  451.         return correctedEstimate.getKalmanGain();
  452.     }

  453.     /** {@inheritDoc} */
  454.     @Override
  455.     public int getCurrentMeasurementNumber() {
  456.         return currentMeasurementNumber;
  457.     }

  458.     /** {@inheritDoc} */
  459.     @Override
  460.     public AbsoluteDate getCurrentDate() {
  461.         return currentDate;
  462.     }

  463.     /** {@inheritDoc} */
  464.     @Override
  465.     public EstimatedMeasurement<?> getPredictedMeasurement() {
  466.         return predictedMeasurement;
  467.     }

  468.     /** {@inheritDoc} */
  469.     @Override
  470.     public EstimatedMeasurement<?> getCorrectedMeasurement() {
  471.         return correctedMeasurement;
  472.     }

  473.     /** {@inheritDoc} */
  474.     @Override
  475.     public void updateNominalSpacecraftState(final SpacecraftState nominal) {
  476.         this.nominalMeanSpacecraftState = nominal;
  477.         // Short period terms
  478.         shortPeriodicTerms = new ArrayRealVector(dsstPropagator.getShortPeriodTermsValue(nominalMeanSpacecraftState));
  479.         // Update the builder with the nominal mean elements orbit
  480.         builder.resetOrbit(nominal.getOrbit(), PropagationType.MEAN);
  481.     }

  482.     /** {@inheritDoc} */
  483.     @Override
  484.     public void updateShortPeriods(final SpacecraftState state) {
  485.         // Loop on DSST force models
  486.         for (final DSSTForceModel model : dsstPropagator.getAllForceModels()) {
  487.             model.updateShortPeriodTerms(model.getParameters(), state);
  488.         }
  489.     }

  490.     /** {@inheritDoc} */
  491.     @Override
  492.     public void initializeShortPeriodicTerms(final SpacecraftState meanState) {
  493.         final List<ShortPeriodTerms> shortPeriodTerms = new ArrayList<ShortPeriodTerms>();
  494.         for (final DSSTForceModel force :  builder.getAllForceModels()) {
  495.             shortPeriodTerms.addAll(force.initializeShortPeriodTerms(new AuxiliaryElements(meanState.getOrbit(), 1), PropagationType.OSCULATING, force.getParameters()));
  496.         }
  497.         dsstPropagator.setShortPeriodTerms(shortPeriodTerms);
  498.     }

  499.     /** Compute the predicted osculating elements.
  500.      * @param filterCorrection physical kalman filter correction
  501.      * @param meanState mean spacecraft state
  502.      * @param shortPeriodTerms short period terms for the given mean state
  503.      * @return the predicted osculating element
  504.      */
  505.     private RealVector computeOsculatingElements(final RealVector filterCorrection,
  506.                                                  final SpacecraftState meanState,
  507.                                                  final RealVector shortPeriodTerms) {

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

  510.         // Return
  511.         return stateVector.add(filterCorrection).add(shortPeriodTerms);

  512.     }

  513.     /** Convert a SpacecraftState to a RealVector.
  514.      * @param state the input SpacecraftState
  515.      * @return the corresponding RealVector
  516.      */
  517.     private RealVector toRealVector(final SpacecraftState state) {

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

  521.         // Return the RealVector
  522.         return new ArrayRealVector(stateArray);

  523.     }

  524.     /** Get the number of estimated orbital parameters.
  525.      * @return the number of estimated orbital parameters
  526.      */
  527.     public int getNumberSelectedOrbitalDrivers() {
  528.         return estimatedOrbitalParameters.getNbParams();
  529.     }

  530.     /** Get the number of estimated propagation parameters.
  531.      * @return the number of estimated propagation parameters
  532.      */
  533.     public int getNumberSelectedPropagationDrivers() {
  534.         return estimatedPropagationParameters.getNbParams();
  535.     }

  536.     /** Get the number of estimated measurement parameters.
  537.      * @return the number of estimated measurement parameters
  538.      */
  539.     public int getNumberSelectedMeasurementDrivers() {
  540.         return estimatedMeasurementsParameters.getNbParams();
  541.     }

  542.     /** Update the estimated parameters after the correction phase of the filter.
  543.      * The min/max allowed values are handled by the parameter themselves.
  544.      */
  545.     private void updateParameters() {
  546.         final RealVector correctedState = correctedEstimate.getState();
  547.         int i = 0;
  548.         for (final DelegatingDriver driver : getEstimatedOrbitalParameters().getDrivers()) {
  549.             // let the parameter handle min/max clipping
  550.             driver.setValue(driver.getValue() + correctedState.getEntry(i++));
  551.         }
  552.         for (final DelegatingDriver driver : getEstimatedPropagationParameters().getDrivers()) {
  553.             // let the parameter handle min/max clipping
  554.             driver.setValue(driver.getValue() + correctedState.getEntry(i++));
  555.         }
  556.         for (final DelegatingDriver driver : getEstimatedMeasurementsParameters().getDrivers()) {
  557.             // let the parameter handle min/max clipping
  558.             driver.setValue(driver.getValue() + correctedState.getEntry(i++));
  559.         }
  560.     }

  561. }