1   /* Copyright 2002-2026 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  
19  import org.hipparchus.filtering.kalman.ProcessEstimate;
20  import org.hipparchus.filtering.kalman.unscented.UnscentedEvolution;
21  import org.hipparchus.filtering.kalman.unscented.UnscentedKalmanFilter;
22  import org.hipparchus.filtering.kalman.unscented.UnscentedProcess;
23  import org.hipparchus.linear.ArrayRealVector;
24  import org.hipparchus.linear.MatrixUtils;
25  import org.hipparchus.linear.RealMatrix;
26  import org.hipparchus.linear.RealVector;
27  import org.hipparchus.util.FastMath;
28  import org.orekit.estimation.measurements.EstimatedMeasurement;
29  import org.orekit.estimation.measurements.EstimatedMeasurementBase;
30  import org.orekit.estimation.measurements.ObservedMeasurement;
31  import org.orekit.orbits.EquinoctialOrbitFactory;
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  
48  import java.util.ArrayList;
49  import java.util.Comparator;
50  import java.util.List;
51  
52  /** Class defining the process model dynamics to use with a {@link SemiAnalyticalUnscentedKalmanEstimator}.
53   * @author Gaƫtan Pierre
54   * @author Bryan Cazabonne
55   * @since 11.3
56   */
57  public class SemiAnalyticalUnscentedKalmanModel implements KalmanEstimation, UnscentedProcess<MeasurementDecorator>, SemiAnalyticalProcess {
58  
59      /** Initial builder for propagator. */
60      private final DSSTPropagatorBuilder builder;
61  
62      /** Estimated orbital parameters. */
63      private final ParameterDriversList estimatedOrbitalParameters;
64  
65      /** Estimated propagation parameters. */
66      private final ParameterDriversList estimatedPropagationParameters;
67  
68      /** Estimated measurements parameters. */
69      private final ParameterDriversList estimatedMeasurementsParameters;
70  
71      /** Provider for covariance matrice. */
72      private final CovarianceMatrixProvider covarianceMatrixProvider;
73  
74      /** Process noise matrix provider for measurement parameters. */
75      private final CovarianceMatrixProvider measurementProcessNoiseMatrix;
76  
77      /** Position angle type used during orbit determination. */
78      private final PositionAngleType angleType;
79  
80      /** Orbit type used during orbit determination. */
81      private final OrbitType orbitType;
82  
83      /** Current corrected estimate. */
84      private ProcessEstimate correctedEstimate;
85  
86      /** Observer to retrieve current estimation info. */
87      private KalmanObserver observer;
88  
89      /** Current number of measurement. */
90      private int currentMeasurementNumber;
91  
92      /** Current date. */
93      private AbsoluteDate currentDate;
94  
95      /** Nominal mean spacecraft state. */
96      private SpacecraftState nominalMeanSpacecraftState;
97  
98      /** Previous nominal mean spacecraft state. */
99      private SpacecraftState previousNominalMeanSpacecraftState;
100 
101     /** Predicted osculating spacecraft state. */
102     private SpacecraftState predictedSpacecraftState;
103 
104     /** Corrected mean spacecraft state. */
105     private SpacecraftState correctedSpacecraftState;
106 
107     /** Predicted measurement. */
108     private EstimatedMeasurement<?> predictedMeasurement;
109 
110     /** Corrected measurement. */
111     private EstimatedMeasurement<?> correctedMeasurement;
112 
113     /** Predicted mean element filter correction. */
114     private RealVector predictedFilterCorrection;
115 
116     /** Corrected mean element filter correction. */
117     private RealVector correctedFilterCorrection;
118 
119     /** Propagators for the reference trajectories, up to current date. */
120     private final DSSTPropagator dsstPropagator;
121 
122     /** Short period terms for the nominal mean spacecraft state. */
123     private RealVector shortPeriodicTerms;
124 
125     /** Unscented Kalman process model constructor (package private).
126      * @param propagatorBuilder propagators builders used to evaluate the orbits.
127      * @param covarianceMatrixProvider provider for covariance matrix
128      * @param estimatedMeasurementParameters measurement parameters to estimate
129      * @param measurementProcessNoiseMatrix provider for measurement process noise matrix
130      */
131     protected SemiAnalyticalUnscentedKalmanModel(final DSSTPropagatorBuilder propagatorBuilder,
132                                                  final CovarianceMatrixProvider covarianceMatrixProvider,
133                                                  final ParameterDriversList estimatedMeasurementParameters,
134                                                  final CovarianceMatrixProvider measurementProcessNoiseMatrix) {
135 
136         final EquinoctialOrbitFactory factory = propagatorBuilder.getOrbitalParameterFactory();
137         this.builder                         = propagatorBuilder;
138         this.angleType                       = factory.getPositionAngleType();
139         this.orbitType                       = factory.getOrbitType();
140         this.estimatedMeasurementsParameters = estimatedMeasurementParameters;
141         this.currentMeasurementNumber        = 0;
142         this.currentDate                     = factory.getDate();
143         this.covarianceMatrixProvider        = covarianceMatrixProvider;
144         this.measurementProcessNoiseMatrix   = measurementProcessNoiseMatrix;
145 
146         // Number of estimated parameters
147         int columns = 0;
148 
149         // Set estimated orbital parameters
150         this.estimatedOrbitalParameters = new ParameterDriversList();
151         for (final ParameterDriver driver : factory.getOrbitalParametersDrivers().getDrivers()) {
152 
153             // Verify if the driver reference date has been set
154             if (driver.getReferenceDate() == null) {
155                 driver.setReferenceDate(currentDate);
156             }
157 
158             // Verify if the driver is selected
159             if (driver.isSelected()) {
160                 estimatedOrbitalParameters.add(driver);
161                 columns++;
162             }
163 
164         }
165 
166         // Set estimated propagation parameters
167         this.estimatedPropagationParameters = new ParameterDriversList();
168         final List<String> estimatedPropagationParametersNames = new ArrayList<>();
169         for (final ParameterDriver driver : propagatorBuilder.getPropagationParametersDrivers().getDrivers()) {
170 
171             // Verify if the driver reference date has been set
172             if (driver.getReferenceDate() == null) {
173                 driver.setReferenceDate(currentDate);
174             }
175 
176             // Verify if the driver is selected
177             if (driver.isSelected()) {
178                 estimatedPropagationParameters.add(driver);
179                 final String driverName = driver.getName();
180                 // Add the driver name if it has not been added yet
181                 if (!estimatedPropagationParametersNames.contains(driverName)) {
182                     estimatedPropagationParametersNames.add(driverName);
183                     ++columns;
184                 }
185             }
186 
187         }
188         estimatedPropagationParametersNames.sort(Comparator.naturalOrder());
189 
190         // Set the estimated measurement parameters
191         for (final ParameterDriver parameter : estimatedMeasurementsParameters.getDrivers()) {
192             if (parameter.getReferenceDate() == null) {
193                 parameter.setReferenceDate(currentDate);
194             }
195             ++columns;
196         }
197 
198         // Number of estimated measurement parameters
199         final int nbMeas = estimatedMeasurementParameters.getNbParams();
200 
201         // Number of estimated dynamic parameters (orbital + propagation)
202         final int nbDyn  = estimatedOrbitalParameters.getNbParams() +
203                            estimatedPropagationParameters.getNbParams();
204 
205         // Build the reference propagator
206         this.dsstPropagator = getEstimatedPropagator();
207         final SpacecraftState meanState = dsstPropagator.initialIsOsculating() ?
208                          DSSTPropagator.computeMeanState(dsstPropagator.getInitialState(), dsstPropagator.getAttitudeProvider(), dsstPropagator.getAllForceModels()) :
209                          dsstPropagator.getInitialState();
210         this.nominalMeanSpacecraftState         = meanState;
211         this.predictedSpacecraftState           = meanState;
212         this.correctedSpacecraftState           = predictedSpacecraftState;
213         this.previousNominalMeanSpacecraftState = nominalMeanSpacecraftState;
214 
215         // Initialize the estimated mean element filter correction
216         this.predictedFilterCorrection = MatrixUtils.createRealVector(columns);
217         this.correctedFilterCorrection = predictedFilterCorrection;
218 
219         // Covariance matrix
220         final RealMatrix noiseK = MatrixUtils.createRealMatrix(nbDyn + nbMeas, nbDyn + nbMeas);
221         final RealMatrix noiseP = covarianceMatrixProvider.getInitialCovarianceMatrix(nominalMeanSpacecraftState);
222         noiseK.setSubMatrix(noiseP.getData(), 0, 0);
223         if (measurementProcessNoiseMatrix != null) {
224             final RealMatrix noiseM = measurementProcessNoiseMatrix.getInitialCovarianceMatrix(nominalMeanSpacecraftState);
225             noiseK.setSubMatrix(noiseM.getData(), nbDyn, nbDyn);
226         }
227 
228         KalmanEstimatorUtil.checkDimension(noiseK.getRowDimension(),
229                                            factory.getOrbitalParametersDrivers(),
230                                            propagatorBuilder.getPropagationParametersDrivers(),
231                                            estimatedMeasurementsParameters);
232 
233         // Initialize corrected estimate
234         this.correctedEstimate = new ProcessEstimate(0.0, correctedFilterCorrection, noiseK);
235 
236     }
237 
238     /** {@inheritDoc} */
239     @Override
240     public KalmanObserver getObserver() {
241         return observer;
242     }
243 
244     /** Set the observer.
245      * @param observer the observer
246      */
247     public void setObserver(final KalmanObserver observer) {
248         this.observer = observer;
249     }
250 
251     /** Get the current corrected estimate.
252      * <p>
253      * For the Unscented Semi-analytical Kalman Filter
254      * it corresponds to the corrected filter correction.
255      * In other words, it doesn't represent an orbital state.
256      * </p>
257      * @return current corrected estimate
258      */
259     public ProcessEstimate getEstimate() {
260         return correctedEstimate;
261     }
262 
263     /** Process measurements.
264      * @param observedMeasurements the list of measurements to process
265      * @param filter Unscented Kalman Filter
266      * @return estimated propagator
267      */
268     public DSSTPropagator processMeasurements(final List<ObservedMeasurement<?>> observedMeasurements,
269                                               final UnscentedKalmanFilter<MeasurementDecorator> filter) {
270 
271         // Sort the measurement
272         observedMeasurements.sort(new ChronologicalComparator());
273         final AbsoluteDate tStart             = observedMeasurements.getFirst().getDate();
274         final AbsoluteDate tEnd               = observedMeasurements.getLast().getDate();
275         final double       overshootTimeRange = FastMath.nextAfter(tEnd.durationFrom(tStart),
276                                                 Double.POSITIVE_INFINITY);
277 
278         // Initialize step handler and set it to a parallelized propagator
279         final SemiAnalyticalMeasurementHandler  stepHandler =
280             new SemiAnalyticalMeasurementHandler(this, filter, observedMeasurements,
281                                                  builder.getOrbitalParameterFactory().getDate(), true);
282         dsstPropagator.getMultiplexer().add(stepHandler);
283         dsstPropagator.propagate(tStart, tStart.shiftedBy(overshootTimeRange));
284 
285         // Return the last estimated propagator
286         return getEstimatedPropagator();
287 
288     }
289 
290     /** Get the propagator estimated with the values set in the propagator builder.
291      * @return propagator based on the current values in the builder
292      */
293     public DSSTPropagator getEstimatedPropagator() {
294         // Return propagator built with current instantiation of the propagator builder
295         return (DSSTPropagator) builder.buildPropagator();
296     }
297 
298     /** {@inheritDoc} */
299     @Override
300     public UnscentedEvolution getEvolution(final double previousTime, final RealVector[] sigmaPoints,
301                                            final MeasurementDecorator measurement) {
302 
303         // Set a reference date for all measurements parameters that lack one (including the not estimated ones)
304         final ObservedMeasurement<?> observedMeasurement = measurement.getObservedMeasurement();
305         for (final ParameterDriver driver : observedMeasurement.getParametersDrivers()) {
306             if (driver.getReferenceDate() == null) {
307                 driver.setReferenceDate(builder.getOrbitalParameterFactory().getDate());
308             }
309         }
310 
311         // Increment measurement number
312         ++currentMeasurementNumber;
313 
314         // Update the current date
315         currentDate = measurement.getObservedMeasurement().getDate();
316 
317         // STM for the prediction of the filter correction
318         final RealMatrix stm = getStm();
319 
320         // Predicted states
321         final RealVector[] predictedStates = new RealVector[sigmaPoints.length];
322         for (int k = 0; k < sigmaPoints.length; ++k) {
323             // Predict filter correction for the current sigma point
324             final RealVector predicted = stm.operate(sigmaPoints[k]);
325             predictedStates[k] = predicted;
326         }
327 
328         // Return
329         return new UnscentedEvolution(measurement.getTime(), predictedStates);
330 
331     }
332 
333     /** {@inheritDoc} */
334     @Override
335     public RealMatrix getProcessNoiseMatrix(final double previousTime, final RealVector predictedState,
336                                             final MeasurementDecorator measurement) {
337 
338         // Number of estimated measurement parameters
339         final int nbMeas = getNumberSelectedMeasurementDrivers();
340 
341         // Number of estimated dynamic parameters (orbital + propagation)
342         final int nbDyn  = getNumberSelectedOrbitalDrivers() + getNumberSelectedPropagationDrivers();
343 
344         // Covariance matrix
345         final RealMatrix noiseK = MatrixUtils.createRealMatrix(nbDyn + nbMeas, nbDyn + nbMeas);
346         final RealMatrix noiseP = covarianceMatrixProvider.getProcessNoiseMatrix(previousNominalMeanSpacecraftState, nominalMeanSpacecraftState);
347         noiseK.setSubMatrix(noiseP.getData(), 0, 0);
348         if (measurementProcessNoiseMatrix != null) {
349             final RealMatrix noiseM = measurementProcessNoiseMatrix.getProcessNoiseMatrix(previousNominalMeanSpacecraftState, nominalMeanSpacecraftState);
350             noiseK.setSubMatrix(noiseM.getData(), nbDyn, nbDyn);
351         }
352 
353         // Verify dimension
354         KalmanEstimatorUtil.checkDimension(noiseK.getRowDimension(),
355                                            builder.getOrbitalParameterFactory().getOrbitalParametersDrivers(),
356                                            builder.getPropagationParametersDrivers(),
357                                            estimatedMeasurementsParameters);
358 
359         return noiseK;
360     }
361 
362     /** {@inheritDoc} */
363     @Override
364     public RealVector[] getPredictedMeasurements(final RealVector[] predictedSigmaPoints, final MeasurementDecorator measurement) {
365 
366         // Observed measurement
367         final ObservedMeasurement<?> observedMeasurement = measurement.getObservedMeasurement();
368 
369         // Initialize arrays of predicted states and measurements
370         final RealVector[] predictedMeasurements = new RealVector[predictedSigmaPoints.length];
371 
372         // Loop on sigma points
373         final EquinoctialOrbitFactory factory = builder.getOrbitalParameterFactory();
374         for (int k = 0; k < predictedSigmaPoints.length; ++k) {
375 
376             // Calculate the predicted osculating elements for the current mean state
377             final RealVector osculating = computeOsculatingElements(predictedSigmaPoints[k],
378                                                                     nominalMeanSpacecraftState,
379                                                                     shortPeriodicTerms);
380             final Orbit osculatingOrbit = orbitType.mapArrayToOrbit(osculating.toArray(), null, angleType,
381                                                                     currentDate, factory.getMu(), factory.getFrame());
382 
383             // Then, estimate the measurement
384             final EstimatedMeasurement<?> estimated = estimateMeasurement(observedMeasurement, currentMeasurementNumber,
385                 new SpacecraftState[] { new SpacecraftState(osculatingOrbit) });
386             predictedMeasurements[k] = new ArrayRealVector(estimated.getEstimatedValue());
387 
388         }
389 
390         // Return
391         return predictedMeasurements;
392 
393     }
394 
395     /** {@inheritDoc} */
396     @Override
397     public RealVector getInnovation(final MeasurementDecorator measurement, final RealVector predictedMeas,
398                                     final RealVector predictedState, final RealMatrix innovationCovarianceMatrix) {
399 
400         // Predicted filter correction
401         predictedFilterCorrection = predictedState;
402 
403         // Predicted measurement
404         final RealVector osculating = computeOsculatingElements(predictedFilterCorrection, nominalMeanSpacecraftState, shortPeriodicTerms);
405         final EquinoctialOrbitFactory factory = builder.getOrbitalParameterFactory();
406         final Orbit osculatingOrbit = orbitType.mapArrayToOrbit(osculating.toArray(), null, angleType,
407                                                                 currentDate, factory.getMu(), factory.getFrame());
408         predictedSpacecraftState = new SpacecraftState(osculatingOrbit);
409         predictedMeasurement = estimateMeasurement(measurement.getObservedMeasurement(), currentMeasurementNumber,
410             getPredictedSpacecraftStates());
411         predictedMeasurement.setEstimatedValue(predictedMeas.toArray());
412 
413         // Apply the dynamic outlier filter, if it exists
414         KalmanEstimatorUtil.applyDynamicOutlierFilter(predictedMeasurement, innovationCovarianceMatrix);
415 
416         // Compute the innovation vector (not normalized for unscented Kalman filter)
417         return KalmanEstimatorUtil.computeInnovationVector(predictedMeasurement);
418 
419     }
420 
421 
422     /** {@inheritDoc} */
423     @Override
424     public void finalizeEstimation(final ObservedMeasurement<?> observedMeasurement,
425                                    final ProcessEstimate estimate) {
426         // Update the process estimate
427         correctedEstimate = estimate;
428         // Corrected filter correction
429         correctedFilterCorrection = estimate.getState();
430 
431         // Update the previous nominal mean spacecraft state
432         previousNominalMeanSpacecraftState = nominalMeanSpacecraftState;
433 
434         // Update the previous nominal mean spacecraft state
435         // Calculate the corrected osculating elements
436         final RealVector osculating = computeOsculatingElements(correctedFilterCorrection, nominalMeanSpacecraftState, shortPeriodicTerms);
437         final EquinoctialOrbitFactory factory = builder.getOrbitalParameterFactory();
438         final Orbit osculatingOrbit = orbitType.mapArrayToOrbit(osculating.toArray(), null,
439                                                                 factory.getPositionAngleType(),
440                                                                 currentDate, factory.getMu(), factory.getFrame());
441 
442         // Compute the corrected measurements
443         correctedSpacecraftState = new SpacecraftState(osculatingOrbit);
444         correctedMeasurement = estimateMeasurement(observedMeasurement, currentMeasurementNumber,
445             getCorrectedSpacecraftStates());
446 
447         // Call the observer if the user add one
448         if (observer != null) {
449             observer.evaluationPerformed(this);
450         }
451     }
452 
453     /**
454      * Estimate measurement (without derivatives).
455      * @param <T> measurement type
456      * @param observedMeasurement observed measurement
457      * @param measurementNumber measurement number
458      * @param spacecraftStates states
459      * @return estimated measurements
460      * @since 12.1
461      */
462     private static <T extends ObservedMeasurement<T>> EstimatedMeasurement<?> estimateMeasurement(final ObservedMeasurement<T> observedMeasurement,
463                                                                                                   final int measurementNumber,
464                                                                                                   final SpacecraftState[] spacecraftStates) {
465         final EstimatedMeasurementBase<T> estimatedMeasurementBase = observedMeasurement.
466                 estimateWithoutDerivatives(measurementNumber, measurementNumber,
467                         KalmanEstimatorUtil.filterRelevant(observedMeasurement, spacecraftStates));
468         final EstimatedMeasurement<T> estimatedMeasurement = new EstimatedMeasurement<>(estimatedMeasurementBase.getObservedMeasurement(),
469                 estimatedMeasurementBase.getIteration(), estimatedMeasurementBase.getCount(),
470                 estimatedMeasurementBase.getStates(), estimatedMeasurementBase.getParticipants());
471         estimatedMeasurement.setEstimatedValue(estimatedMeasurementBase.getEstimatedValue());
472         return estimatedMeasurement;
473     }
474 
475     /** Get the state transition matrix used to predict the filter correction.
476      * <p>
477      * The state transition matrix is not computed by the DSST propagator.
478      * It is analytically calculated considering Keplerian contribution only
479      * </p>
480      * @return the state transition matrix used to predict the filter correction
481      */
482     private RealMatrix getStm() {
483 
484         // initialize the STM
485         final int nbDym  = getNumberSelectedOrbitalDrivers() + getNumberSelectedPropagationDrivers();
486         final int nbMeas = getNumberSelectedMeasurementDrivers();
487         final RealMatrix stm = MatrixUtils.createRealIdentityMatrix(nbDym + nbMeas);
488 
489         // State transition matrix using Keplerian contribution only
490         final double mu  = builder.getOrbitalParameterFactory().getMu();
491         final double sma = previousNominalMeanSpacecraftState.getOrbit().getA();
492         final double dt  = currentDate.durationFrom(previousNominalMeanSpacecraftState.getDate());
493         final double contribution = -1.5 * dt * FastMath.sqrt(mu / FastMath.pow(sma, 5));
494         stm.setEntry(5, 0, contribution);
495 
496         // Return
497         return stm;
498 
499     }
500 
501     /** {@inheritDoc} */
502     @Override
503     public void finalizeOperationsObservationGrid() {
504         // Update parameters
505         updateParameters();
506     }
507 
508     /** {@inheritDoc} */
509     @Override
510     public ParameterDriversList getEstimatedOrbitalParameters() {
511         return estimatedOrbitalParameters;
512     }
513 
514     /** {@inheritDoc} */
515     @Override
516     public ParameterDriversList getEstimatedPropagationParameters() {
517         return estimatedPropagationParameters;
518     }
519 
520     /** {@inheritDoc} */
521     @Override
522     public ParameterDriversList getEstimatedMeasurementsParameters() {
523         return estimatedMeasurementsParameters;
524     }
525 
526     /** {@inheritDoc}
527      * <p>
528      * Predicted state is osculating.
529      * </p>
530      */
531     @Override
532     public SpacecraftState[] getPredictedSpacecraftStates() {
533         return new SpacecraftState[] {predictedSpacecraftState};
534     }
535 
536     /** {@inheritDoc}
537      * <p>
538      * Corrected state is osculating.
539      * </p>
540      */
541     @Override
542     public SpacecraftState[] getCorrectedSpacecraftStates() {
543         return new SpacecraftState[] {correctedSpacecraftState};
544     }
545 
546     /** {@inheritDoc} */
547     @Override
548     public RealVector getPhysicalEstimatedState() {
549         // Method {@link ParameterDriver#getValue()} is used to get
550         // the physical values of the state.
551         // The scales'array is used to get the size of the state vector
552         final RealVector physicalEstimatedState = new ArrayRealVector(getEstimate().getState().getDimension());
553         int i = 0;
554         for (final DelegatingDriver driver : getEstimatedOrbitalParameters().getDrivers()) {
555             physicalEstimatedState.setEntry(i++, driver.getValue());
556         }
557         for (final DelegatingDriver driver : getEstimatedPropagationParameters().getDrivers()) {
558             physicalEstimatedState.setEntry(i++, driver.getValue());
559         }
560         for (final DelegatingDriver driver : getEstimatedMeasurementsParameters().getDrivers()) {
561             physicalEstimatedState.setEntry(i++, driver.getValue());
562         }
563 
564         return physicalEstimatedState;
565     }
566 
567     /** {@inheritDoc} */
568     @Override
569     public RealMatrix getPhysicalEstimatedCovarianceMatrix() {
570         return correctedEstimate.getCovariance();
571     }
572 
573     /** {@inheritDoc} */
574     @Override
575     public RealMatrix getPhysicalStateTransitionMatrix() {
576         return null;
577     }
578 
579     /** {@inheritDoc} */
580     @Override
581     public RealMatrix getPhysicalMeasurementJacobian() {
582         return null;
583     }
584 
585     /** {@inheritDoc} */
586     @Override
587     public RealMatrix getPhysicalInnovationCovarianceMatrix() {
588         return correctedEstimate.getInnovationCovariance();
589     }
590 
591     /** {@inheritDoc} */
592     @Override
593     public RealMatrix getPhysicalKalmanGain() {
594         return correctedEstimate.getKalmanGain();
595     }
596 
597     /** {@inheritDoc} */
598     @Override
599     public int getCurrentMeasurementNumber() {
600         return currentMeasurementNumber;
601     }
602 
603     /** {@inheritDoc} */
604     @Override
605     public AbsoluteDate getCurrentDate() {
606         return currentDate;
607     }
608 
609     /** {@inheritDoc} */
610     @Override
611     public EstimatedMeasurement<?> getPredictedMeasurement() {
612         return predictedMeasurement;
613     }
614 
615     /** {@inheritDoc} */
616     @Override
617     public EstimatedMeasurement<?> getCorrectedMeasurement() {
618         return correctedMeasurement;
619     }
620 
621     /** {@inheritDoc} */
622     @Override
623     public void updateNominalSpacecraftState(final SpacecraftState nominal) {
624         this.nominalMeanSpacecraftState = nominal;
625         // Short period terms
626         shortPeriodicTerms = new ArrayRealVector(dsstPropagator.getShortPeriodTermsValue(nominalMeanSpacecraftState));
627         // Update the builder with the nominal mean elements orbit
628         builder.resetOrbit(nominal.getOrbit(), PropagationType.MEAN);
629     }
630 
631     /** {@inheritDoc} */
632     @Override
633     public void updateShortPeriods(final SpacecraftState state) {
634         // Loop on DSST force models
635         for (final DSSTForceModel model : dsstPropagator.getAllForceModels()) {
636             model.updateShortPeriodTerms(model.getParameters(), state);
637         }
638     }
639 
640     /** {@inheritDoc} */
641     @Override
642     public void initializeShortPeriodicTerms(final SpacecraftState meanState) {
643         final List<ShortPeriodTerms> shortPeriodTerms = new ArrayList<>();
644         for (final DSSTForceModel force :  builder.getAllForceModels()) {
645             shortPeriodTerms.addAll(force.initializeShortPeriodTerms(new AuxiliaryElements(meanState.getOrbit(), 1), PropagationType.OSCULATING, force.getParameters()));
646         }
647         dsstPropagator.setShortPeriodTerms(shortPeriodTerms);
648     }
649 
650     /** Compute the predicted osculating elements.
651      * @param filterCorrection physical kalman filter correction
652      * @param meanState mean spacecraft state
653      * @param shortPeriodTerms short period terms for the given mean state
654      * @return the predicted osculating element
655      */
656     private RealVector computeOsculatingElements(final RealVector filterCorrection,
657                                                  final SpacecraftState meanState,
658                                                  final RealVector shortPeriodTerms) {
659 
660         // Convert the input predicted mean state to a SpacecraftState
661         final RealVector stateVector = toRealVector(meanState);
662 
663         // Return
664         return stateVector.add(filterCorrection).add(shortPeriodTerms);
665 
666     }
667 
668     /** Convert a SpacecraftState to a RealVector.
669      * @param state the input SpacecraftState
670      * @return the corresponding RealVector
671      */
672     private RealVector toRealVector(final SpacecraftState state) {
673 
674         // Convert orbit to array
675         final double[] stateArray = new double[6];
676         orbitType.mapOrbitToArray(state.getOrbit(), angleType, stateArray, null);
677 
678         // Return the RealVector
679         return new ArrayRealVector(stateArray);
680 
681     }
682 
683     /** Get the number of estimated orbital parameters.
684      * @return the number of estimated orbital parameters
685      */
686     public int getNumberSelectedOrbitalDrivers() {
687         return estimatedOrbitalParameters.getNbParams();
688     }
689 
690     /** Get the number of estimated propagation parameters.
691      * @return the number of estimated propagation parameters
692      */
693     public int getNumberSelectedPropagationDrivers() {
694         return estimatedPropagationParameters.getNbParams();
695     }
696 
697     /** Get the number of estimated measurement parameters.
698      * @return the number of estimated measurement parameters
699      */
700     public int getNumberSelectedMeasurementDrivers() {
701         return estimatedMeasurementsParameters.getNbParams();
702     }
703 
704     /** Update the estimated parameters after the correction phase of the filter.
705      * The min/max allowed values are handled by the parameter themselves.
706      */
707     private void updateParameters() {
708         final RealVector correctedState = correctedEstimate.getState();
709         int i = 0;
710         for (final DelegatingDriver driver : getEstimatedOrbitalParameters().getDrivers()) {
711             // let the parameter handle min/max clipping
712             driver.setValue(driver.getValue() + correctedState.getEntry(i++));
713         }
714         for (final DelegatingDriver driver : getEstimatedPropagationParameters().getDrivers()) {
715             // let the parameter handle min/max clipping
716             driver.setValue(driver.getValue() + correctedState.getEntry(i++));
717         }
718         for (final DelegatingDriver driver : getEstimatedMeasurementsParameters().getDrivers()) {
719             // let the parameter handle min/max clipping
720             driver.setValue(driver.getValue() + correctedState.getEntry(i++));
721         }
722     }
723 
724 }