1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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.Orbit;
32 import org.orekit.orbits.OrbitType;
33 import org.orekit.orbits.PositionAngleType;
34 import org.orekit.propagation.PropagationType;
35 import org.orekit.propagation.SpacecraftState;
36 import org.orekit.propagation.conversion.DSSTPropagatorBuilder;
37 import org.orekit.propagation.semianalytical.dsst.DSSTPropagator;
38 import org.orekit.propagation.semianalytical.dsst.forces.DSSTForceModel;
39 import org.orekit.propagation.semianalytical.dsst.forces.ShortPeriodTerms;
40 import org.orekit.propagation.semianalytical.dsst.utilities.AuxiliaryElements;
41 import org.orekit.time.AbsoluteDate;
42 import org.orekit.time.ChronologicalComparator;
43 import org.orekit.utils.ParameterDriver;
44 import org.orekit.utils.ParameterDriversList;
45 import org.orekit.utils.ParameterDriversList.DelegatingDriver;
46
47 import java.util.ArrayList;
48 import java.util.Comparator;
49 import java.util.List;
50
51
52
53
54
55
56 public class SemiAnalyticalUnscentedKalmanModel implements KalmanEstimation, UnscentedProcess<MeasurementDecorator>, SemiAnalyticalProcess {
57
58
59 private final DSSTPropagatorBuilder builder;
60
61
62 private final ParameterDriversList estimatedOrbitalParameters;
63
64
65 private final ParameterDriversList estimatedPropagationParameters;
66
67
68 private final ParameterDriversList estimatedMeasurementsParameters;
69
70
71 private final CovarianceMatrixProvider covarianceMatrixProvider;
72
73
74 private final CovarianceMatrixProvider measurementProcessNoiseMatrix;
75
76
77 private final PositionAngleType angleType;
78
79
80 private final OrbitType orbitType;
81
82
83 private ProcessEstimate correctedEstimate;
84
85
86 private KalmanObserver observer;
87
88
89 private int currentMeasurementNumber;
90
91
92 private AbsoluteDate currentDate;
93
94
95 private SpacecraftState nominalMeanSpacecraftState;
96
97
98 private SpacecraftState previousNominalMeanSpacecraftState;
99
100
101 private SpacecraftState predictedSpacecraftState;
102
103
104 private SpacecraftState correctedSpacecraftState;
105
106
107 private EstimatedMeasurement<?> predictedMeasurement;
108
109
110 private EstimatedMeasurement<?> correctedMeasurement;
111
112
113 private RealVector predictedFilterCorrection;
114
115
116 private RealVector correctedFilterCorrection;
117
118
119 private DSSTPropagator dsstPropagator;
120
121
122 private RealVector shortPeriodicTerms;
123
124
125
126
127
128
129
130 protected SemiAnalyticalUnscentedKalmanModel(final DSSTPropagatorBuilder propagatorBuilder,
131 final CovarianceMatrixProvider covarianceMatrixProvider,
132 final ParameterDriversList estimatedMeasurementParameters,
133 final CovarianceMatrixProvider measurementProcessNoiseMatrix) {
134
135 this.builder = propagatorBuilder;
136 this.angleType = propagatorBuilder.getPositionAngleType();
137 this.orbitType = propagatorBuilder.getOrbitType();
138 this.estimatedMeasurementsParameters = estimatedMeasurementParameters;
139 this.currentMeasurementNumber = 0;
140 this.currentDate = propagatorBuilder.getInitialOrbitDate();
141 this.covarianceMatrixProvider = covarianceMatrixProvider;
142 this.measurementProcessNoiseMatrix = measurementProcessNoiseMatrix;
143
144
145 int columns = 0;
146
147
148 this.estimatedOrbitalParameters = new ParameterDriversList();
149 for (final ParameterDriver driver : propagatorBuilder.getOrbitalParametersDrivers().getDrivers()) {
150
151
152 if (driver.getReferenceDate() == null) {
153 driver.setReferenceDate(currentDate);
154 }
155
156
157 if (driver.isSelected()) {
158 estimatedOrbitalParameters.add(driver);
159 columns++;
160 }
161
162 }
163
164
165 this.estimatedPropagationParameters = new ParameterDriversList();
166 final List<String> estimatedPropagationParametersNames = new ArrayList<>();
167 for (final ParameterDriver driver : propagatorBuilder.getPropagationParametersDrivers().getDrivers()) {
168
169
170 if (driver.getReferenceDate() == null) {
171 driver.setReferenceDate(currentDate);
172 }
173
174
175 if (driver.isSelected()) {
176 estimatedPropagationParameters.add(driver);
177 final String driverName = driver.getName();
178
179 if (!estimatedPropagationParametersNames.contains(driverName)) {
180 estimatedPropagationParametersNames.add(driverName);
181 ++columns;
182 }
183 }
184
185 }
186 estimatedPropagationParametersNames.sort(Comparator.naturalOrder());
187
188
189 for (final ParameterDriver parameter : estimatedMeasurementsParameters.getDrivers()) {
190 if (parameter.getReferenceDate() == null) {
191 parameter.setReferenceDate(currentDate);
192 }
193 ++columns;
194 }
195
196
197 final int nbMeas = estimatedMeasurementParameters.getNbParams();
198
199
200 final int nbDyn = estimatedOrbitalParameters.getNbParams() +
201 estimatedPropagationParameters.getNbParams();
202
203
204 this.dsstPropagator = getEstimatedPropagator();
205 final SpacecraftState meanState = dsstPropagator.initialIsOsculating() ?
206 DSSTPropagator.computeMeanState(dsstPropagator.getInitialState(), dsstPropagator.getAttitudeProvider(), dsstPropagator.getAllForceModels()) :
207 dsstPropagator.getInitialState();
208 this.nominalMeanSpacecraftState = meanState;
209 this.predictedSpacecraftState = meanState;
210 this.correctedSpacecraftState = predictedSpacecraftState;
211 this.previousNominalMeanSpacecraftState = nominalMeanSpacecraftState;
212
213
214 this.predictedFilterCorrection = MatrixUtils.createRealVector(columns);
215 this.correctedFilterCorrection = predictedFilterCorrection;
216
217
218 final RealMatrix noiseK = MatrixUtils.createRealMatrix(nbDyn + nbMeas, nbDyn + nbMeas);
219 final RealMatrix noiseP = covarianceMatrixProvider.getInitialCovarianceMatrix(nominalMeanSpacecraftState);
220 noiseK.setSubMatrix(noiseP.getData(), 0, 0);
221 if (measurementProcessNoiseMatrix != null) {
222 final RealMatrix noiseM = measurementProcessNoiseMatrix.getInitialCovarianceMatrix(nominalMeanSpacecraftState);
223 noiseK.setSubMatrix(noiseM.getData(), nbDyn, nbDyn);
224 }
225
226 KalmanEstimatorUtil.checkDimension(noiseK.getRowDimension(),
227 propagatorBuilder.getOrbitalParametersDrivers(),
228 propagatorBuilder.getPropagationParametersDrivers(),
229 estimatedMeasurementsParameters);
230
231
232 this.correctedEstimate = new ProcessEstimate(0.0, correctedFilterCorrection, noiseK);
233
234 }
235
236
237 @Override
238 public KalmanObserver getObserver() {
239 return observer;
240 }
241
242
243
244
245 public void setObserver(final KalmanObserver observer) {
246 this.observer = observer;
247 }
248
249
250
251
252
253
254
255
256
257 public ProcessEstimate getEstimate() {
258 return correctedEstimate;
259 }
260
261
262
263
264
265
266 public DSSTPropagator processMeasurements(final List<ObservedMeasurement<?>> observedMeasurements,
267 final UnscentedKalmanFilter<MeasurementDecorator> filter) {
268
269
270 observedMeasurements.sort(new ChronologicalComparator());
271 final AbsoluteDate tStart = observedMeasurements.get(0).getDate();
272 final AbsoluteDate tEnd = observedMeasurements.get(observedMeasurements.size() - 1).getDate();
273 final double overshootTimeRange = FastMath.nextAfter(tEnd.durationFrom(tStart),
274 Double.POSITIVE_INFINITY);
275
276
277 final SemiAnalyticalMeasurementHandler stepHandler = new SemiAnalyticalMeasurementHandler(this, filter, observedMeasurements, builder.getInitialOrbitDate(), true);
278 dsstPropagator.getMultiplexer().add(stepHandler);
279 dsstPropagator.propagate(tStart, tStart.shiftedBy(overshootTimeRange));
280
281
282 return getEstimatedPropagator();
283
284 }
285
286
287
288
289 public DSSTPropagator getEstimatedPropagator() {
290
291 return (DSSTPropagator) builder.buildPropagator();
292 }
293
294
295 @Override
296 public UnscentedEvolution getEvolution(final double previousTime, final RealVector[] sigmaPoints,
297 final MeasurementDecorator measurement) {
298
299
300 final ObservedMeasurement<?> observedMeasurement = measurement.getObservedMeasurement();
301 for (final ParameterDriver driver : observedMeasurement.getParametersDrivers()) {
302 if (driver.getReferenceDate() == null) {
303 driver.setReferenceDate(builder.getInitialOrbitDate());
304 }
305 }
306
307
308 ++currentMeasurementNumber;
309
310
311 currentDate = measurement.getObservedMeasurement().getDate();
312
313
314 final RealMatrix stm = getStm();
315
316
317 final RealVector[] predictedStates = new RealVector[sigmaPoints.length];
318 for (int k = 0; k < sigmaPoints.length; ++k) {
319
320 final RealVector predicted = stm.operate(sigmaPoints[k]);
321 predictedStates[k] = predicted;
322 }
323
324
325 final int nbMeas = getNumberSelectedMeasurementDrivers();
326
327
328 final int nbDyn = getNumberSelectedOrbitalDrivers() + getNumberSelectedPropagationDrivers();
329
330
331 final RealMatrix noiseK = MatrixUtils.createRealMatrix(nbDyn + nbMeas, nbDyn + nbMeas);
332 final RealMatrix noiseP = covarianceMatrixProvider.getProcessNoiseMatrix(previousNominalMeanSpacecraftState, nominalMeanSpacecraftState);
333 noiseK.setSubMatrix(noiseP.getData(), 0, 0);
334 if (measurementProcessNoiseMatrix != null) {
335 final RealMatrix noiseM = measurementProcessNoiseMatrix.getProcessNoiseMatrix(previousNominalMeanSpacecraftState, nominalMeanSpacecraftState);
336 noiseK.setSubMatrix(noiseM.getData(), nbDyn, nbDyn);
337 }
338
339
340 KalmanEstimatorUtil.checkDimension(noiseK.getRowDimension(),
341 builder.getOrbitalParametersDrivers(),
342 builder.getPropagationParametersDrivers(),
343 estimatedMeasurementsParameters);
344
345
346 return new UnscentedEvolution(measurement.getTime(), predictedStates, noiseK);
347
348 }
349
350
351 @Override
352 public RealVector[] getPredictedMeasurements(final RealVector[] predictedSigmaPoints, final MeasurementDecorator measurement) {
353
354
355 final ObservedMeasurement<?> observedMeasurement = measurement.getObservedMeasurement();
356
357
358 final RealVector[] predictedMeasurements = new RealVector[predictedSigmaPoints.length];
359
360
361 for (int k = 0; k < predictedSigmaPoints.length; ++k) {
362
363
364 final RealVector osculating = computeOsculatingElements(predictedSigmaPoints[k], nominalMeanSpacecraftState, shortPeriodicTerms);
365 final Orbit osculatingOrbit = orbitType.mapArrayToOrbit(osculating.toArray(), null, angleType,
366 currentDate, builder.getMu(), builder.getFrame());
367
368
369 final EstimatedMeasurement<?> estimated = estimateMeasurement(observedMeasurement, currentMeasurementNumber,
370 new SpacecraftState[] { new SpacecraftState(osculatingOrbit) });
371 predictedMeasurements[k] = new ArrayRealVector(estimated.getEstimatedValue());
372
373 }
374
375
376 return predictedMeasurements;
377
378 }
379
380
381 @Override
382 public RealVector getInnovation(final MeasurementDecorator measurement, final RealVector predictedMeas,
383 final RealVector predictedState, final RealMatrix innovationCovarianceMatrix) {
384
385
386 predictedFilterCorrection = predictedState;
387
388
389 final RealVector osculating = computeOsculatingElements(predictedFilterCorrection, nominalMeanSpacecraftState, shortPeriodicTerms);
390 final Orbit osculatingOrbit = orbitType.mapArrayToOrbit(osculating.toArray(), null, angleType,
391 currentDate, builder.getMu(), builder.getFrame());
392 predictedSpacecraftState = new SpacecraftState(osculatingOrbit);
393 predictedMeasurement = estimateMeasurement(measurement.getObservedMeasurement(), currentMeasurementNumber,
394 getPredictedSpacecraftStates());
395 predictedMeasurement.setEstimatedValue(predictedMeas.toArray());
396
397
398 KalmanEstimatorUtil.applyDynamicOutlierFilter(predictedMeasurement, innovationCovarianceMatrix);
399
400
401 return KalmanEstimatorUtil.computeInnovationVector(predictedMeasurement);
402
403 }
404
405
406
407 @Override
408 public void finalizeEstimation(final ObservedMeasurement<?> observedMeasurement,
409 final ProcessEstimate estimate) {
410
411 correctedEstimate = estimate;
412
413 correctedFilterCorrection = estimate.getState();
414
415
416 previousNominalMeanSpacecraftState = nominalMeanSpacecraftState;
417
418
419
420 final RealVector osculating = computeOsculatingElements(correctedFilterCorrection, nominalMeanSpacecraftState, shortPeriodicTerms);
421 final Orbit osculatingOrbit = orbitType.mapArrayToOrbit(osculating.toArray(), null, builder.getPositionAngleType(),
422 currentDate, builder.getMu(), builder.getFrame());
423
424
425 correctedSpacecraftState = new SpacecraftState(osculatingOrbit);
426 correctedMeasurement = estimateMeasurement(observedMeasurement, currentMeasurementNumber,
427 getCorrectedSpacecraftStates());
428
429
430 if (observer != null) {
431 observer.evaluationPerformed(this);
432 }
433 }
434
435
436
437
438
439
440
441
442
443
444 private static <T extends ObservedMeasurement<T>> EstimatedMeasurement<?> estimateMeasurement(final ObservedMeasurement<T> observedMeasurement,
445 final int measurementNumber,
446 final SpacecraftState[] spacecraftStates) {
447 final EstimatedMeasurementBase<T> estimatedMeasurementBase = observedMeasurement.
448 estimateWithoutDerivatives(measurementNumber, measurementNumber,
449 KalmanEstimatorUtil.filterRelevant(observedMeasurement, spacecraftStates));
450 final EstimatedMeasurement<T> estimatedMeasurement = new EstimatedMeasurement<>(estimatedMeasurementBase.getObservedMeasurement(),
451 estimatedMeasurementBase.getIteration(), estimatedMeasurementBase.getCount(),
452 estimatedMeasurementBase.getStates(), estimatedMeasurementBase.getParticipants());
453 estimatedMeasurement.setEstimatedValue(estimatedMeasurementBase.getEstimatedValue());
454 return estimatedMeasurement;
455 }
456
457
458
459
460
461
462
463
464 private RealMatrix getStm() {
465
466
467 final int nbDym = getNumberSelectedOrbitalDrivers() + getNumberSelectedPropagationDrivers();
468 final int nbMeas = getNumberSelectedMeasurementDrivers();
469 final RealMatrix stm = MatrixUtils.createRealIdentityMatrix(nbDym + nbMeas);
470
471
472 final double mu = builder.getMu();
473 final double sma = previousNominalMeanSpacecraftState.getA();
474 final double dt = currentDate.durationFrom(previousNominalMeanSpacecraftState.getDate());
475 final double contribution = -1.5 * dt * FastMath.sqrt(mu / FastMath.pow(sma, 5));
476 stm.setEntry(5, 0, contribution);
477
478
479 return stm;
480
481 }
482
483
484 @Override
485 public void finalizeOperationsObservationGrid() {
486
487 updateParameters();
488 }
489
490
491 @Override
492 public ParameterDriversList getEstimatedOrbitalParameters() {
493 return estimatedOrbitalParameters;
494 }
495
496
497 @Override
498 public ParameterDriversList getEstimatedPropagationParameters() {
499 return estimatedPropagationParameters;
500 }
501
502
503 @Override
504 public ParameterDriversList getEstimatedMeasurementsParameters() {
505 return estimatedMeasurementsParameters;
506 }
507
508
509
510
511
512
513 @Override
514 public SpacecraftState[] getPredictedSpacecraftStates() {
515 return new SpacecraftState[] {predictedSpacecraftState};
516 }
517
518
519
520
521
522
523 @Override
524 public SpacecraftState[] getCorrectedSpacecraftStates() {
525 return new SpacecraftState[] {correctedSpacecraftState};
526 }
527
528
529 @Override
530 public RealVector getPhysicalEstimatedState() {
531
532
533
534 final RealVector physicalEstimatedState = new ArrayRealVector(getEstimate().getState().getDimension());
535 int i = 0;
536 for (final DelegatingDriver driver : getEstimatedOrbitalParameters().getDrivers()) {
537 physicalEstimatedState.setEntry(i++, driver.getValue());
538 }
539 for (final DelegatingDriver driver : getEstimatedPropagationParameters().getDrivers()) {
540 physicalEstimatedState.setEntry(i++, driver.getValue());
541 }
542 for (final DelegatingDriver driver : getEstimatedMeasurementsParameters().getDrivers()) {
543 physicalEstimatedState.setEntry(i++, driver.getValue());
544 }
545
546 return physicalEstimatedState;
547 }
548
549
550 @Override
551 public RealMatrix getPhysicalEstimatedCovarianceMatrix() {
552 return correctedEstimate.getCovariance();
553 }
554
555
556 @Override
557 public RealMatrix getPhysicalStateTransitionMatrix() {
558 return null;
559 }
560
561
562 @Override
563 public RealMatrix getPhysicalMeasurementJacobian() {
564 return null;
565 }
566
567
568 @Override
569 public RealMatrix getPhysicalInnovationCovarianceMatrix() {
570 return correctedEstimate.getInnovationCovariance();
571 }
572
573
574 @Override
575 public RealMatrix getPhysicalKalmanGain() {
576 return correctedEstimate.getKalmanGain();
577 }
578
579
580 @Override
581 public int getCurrentMeasurementNumber() {
582 return currentMeasurementNumber;
583 }
584
585
586 @Override
587 public AbsoluteDate getCurrentDate() {
588 return currentDate;
589 }
590
591
592 @Override
593 public EstimatedMeasurement<?> getPredictedMeasurement() {
594 return predictedMeasurement;
595 }
596
597
598 @Override
599 public EstimatedMeasurement<?> getCorrectedMeasurement() {
600 return correctedMeasurement;
601 }
602
603
604 @Override
605 public void updateNominalSpacecraftState(final SpacecraftState nominal) {
606 this.nominalMeanSpacecraftState = nominal;
607
608 shortPeriodicTerms = new ArrayRealVector(dsstPropagator.getShortPeriodTermsValue(nominalMeanSpacecraftState));
609
610 builder.resetOrbit(nominal.getOrbit(), PropagationType.MEAN);
611 }
612
613
614 @Override
615 public void updateShortPeriods(final SpacecraftState state) {
616
617 for (final DSSTForceModel model : dsstPropagator.getAllForceModels()) {
618 model.updateShortPeriodTerms(model.getParameters(), state);
619 }
620 }
621
622
623 @Override
624 public void initializeShortPeriodicTerms(final SpacecraftState meanState) {
625 final List<ShortPeriodTerms> shortPeriodTerms = new ArrayList<>();
626 for (final DSSTForceModel force : builder.getAllForceModels()) {
627 shortPeriodTerms.addAll(force.initializeShortPeriodTerms(new AuxiliaryElements(meanState.getOrbit(), 1), PropagationType.OSCULATING, force.getParameters()));
628 }
629 dsstPropagator.setShortPeriodTerms(shortPeriodTerms);
630 }
631
632
633
634
635
636
637
638 private RealVector computeOsculatingElements(final RealVector filterCorrection,
639 final SpacecraftState meanState,
640 final RealVector shortPeriodTerms) {
641
642
643 final RealVector stateVector = toRealVector(meanState);
644
645
646 return stateVector.add(filterCorrection).add(shortPeriodTerms);
647
648 }
649
650
651
652
653
654 private RealVector toRealVector(final SpacecraftState state) {
655
656
657 final double[] stateArray = new double[6];
658 orbitType.mapOrbitToArray(state.getOrbit(), angleType, stateArray, null);
659
660
661 return new ArrayRealVector(stateArray);
662
663 }
664
665
666
667
668 public int getNumberSelectedOrbitalDrivers() {
669 return estimatedOrbitalParameters.getNbParams();
670 }
671
672
673
674
675 public int getNumberSelectedPropagationDrivers() {
676 return estimatedPropagationParameters.getNbParams();
677 }
678
679
680
681
682 public int getNumberSelectedMeasurementDrivers() {
683 return estimatedMeasurementsParameters.getNbParams();
684 }
685
686
687
688
689 private void updateParameters() {
690 final RealVector correctedState = correctedEstimate.getState();
691 int i = 0;
692 for (final DelegatingDriver driver : getEstimatedOrbitalParameters().getDrivers()) {
693
694 driver.setValue(driver.getValue() + correctedState.getEntry(i++));
695 }
696 for (final DelegatingDriver driver : getEstimatedPropagationParameters().getDrivers()) {
697
698 driver.setValue(driver.getValue() + correctedState.getEntry(i++));
699 }
700 for (final DelegatingDriver driver : getEstimatedMeasurementsParameters().getDrivers()) {
701
702 driver.setValue(driver.getValue() + correctedState.getEntry(i++));
703 }
704 }
705
706 }