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
19 import java.util.List;
20
21 import org.hipparchus.exception.MathRuntimeException;
22 import org.hipparchus.filtering.kalman.KalmanFilter;
23 import org.hipparchus.filtering.kalman.ProcessEstimate;
24 import org.orekit.errors.OrekitException;
25 import org.orekit.estimation.measurements.ObservedMeasurement;
26 import org.orekit.propagation.SpacecraftState;
27 import org.orekit.propagation.sampling.OrekitStepHandler;
28 import org.orekit.propagation.sampling.OrekitStepInterpolator;
29 import org.orekit.time.AbsoluteDate;
30
31 /** {@link org.orekit.propagation.sampling.OrekitStepHandler Step handler} picking up
32 * {@link ObservedMeasurement measurements} for both {@link SemiAnalyticalUnscentedKalmanEstimator} and {@link SemiAnalyticalKalmanEstimator}.
33 * @author Gaƫtan Pierre
34 * @author Bryan Cazabonne
35 * @author Julie Bayard
36 * @author Maxime Journot
37 * @since 11.3
38 */
39 public class SemiAnalyticalMeasurementHandler implements OrekitStepHandler {
40
41 /** Index of the next measurement component in the model. */
42 private int index;
43
44 /** Reference date. */
45 private AbsoluteDate referenceDate;
46
47 /** Kalman model. */
48 private final SemiAnalyticalProcess model;
49
50 /** Kalman Filter. */
51 private final KalmanFilter<MeasurementDecorator> filter;
52
53 /** Underlying measurements. */
54 private final List<ObservedMeasurement<?>> observedMeasurements;
55
56 /** Flag indicating if the handler is used by a unscented kalman filter. */
57 private final boolean isUnscented;
58
59 /** Simple constructor.
60 * <p>
61 * Using this constructor, the Kalman filter is supposed to be extended.
62 * </p>
63 * @param model semi-analytical kalman model
64 * @param filter kalman filter instance
65 * @param observedMeasurements list of observed measurements
66 * @param referenceDate reference date
67 * @see #SemiAnalyticalMeasurementHandler(SemiAnalyticalProcess, KalmanFilter, List, AbsoluteDate, boolean)
68 */
69 public SemiAnalyticalMeasurementHandler(final SemiAnalyticalProcess model,
70 final KalmanFilter<MeasurementDecorator> filter,
71 final List<ObservedMeasurement<?>> observedMeasurements,
72 final AbsoluteDate referenceDate) {
73 this(model, filter, observedMeasurements, referenceDate, false);
74 }
75
76 /** Simple constructor.
77 * @param model semi-analytical kalman model
78 * @param filter kalman filter instance
79 * @param observedMeasurements list of observed measurements
80 * @param referenceDate reference date
81 * @param isUnscented true if the Kalman filter is unscented
82 * @since 11.3.2
83 */
84 public SemiAnalyticalMeasurementHandler(final SemiAnalyticalProcess model,
85 final KalmanFilter<MeasurementDecorator> filter,
86 final List<ObservedMeasurement<?>> observedMeasurements,
87 final AbsoluteDate referenceDate,
88 final boolean isUnscented) {
89 this.model = model;
90 this.filter = filter;
91 this.observedMeasurements = observedMeasurements;
92 this.referenceDate = referenceDate;
93 this.isUnscented = isUnscented;
94 }
95
96 /** {@inheritDoc} */
97 @Override
98 public void init(final SpacecraftState s0, final AbsoluteDate t) {
99 this.index = 0;
100 // Initialize short periodic terms.
101 model.initializeShortPeriodicTerms(s0);
102 model.updateShortPeriods(s0);
103 }
104
105 /** {@inheritDoc} */
106 @Override
107 public void handleStep(final OrekitStepInterpolator interpolator) {
108
109 // Current date
110 final AbsoluteDate currentDate = interpolator.getCurrentState().getDate();
111
112 // Update the short period terms with the current MEAN state
113 model.updateShortPeriods(interpolator.getCurrentState());
114
115 // Process the measurements between previous step and current step
116 while (index < observedMeasurements.size() && observedMeasurements.get(index).getDate().compareTo(currentDate) < 0) {
117
118 try {
119
120 // Update predicted spacecraft state
121 model.updateNominalSpacecraftState(interpolator.getInterpolatedState(observedMeasurements.get(index).getDate()));
122
123 // Process the current observation
124 final MeasurementDecorator decorated = isUnscented ?
125 KalmanEstimatorUtil.decorateUnscented(observedMeasurements.get(index), referenceDate) :
126 KalmanEstimatorUtil.decorate(observedMeasurements.get(index), referenceDate);
127 final ProcessEstimate estimate = filter.estimationStep(decorated);
128
129 // Finalize the estimation
130 model.finalizeEstimation(observedMeasurements.get(index), estimate);
131
132 } catch (MathRuntimeException mrte) {
133 throw new OrekitException(mrte);
134 }
135
136 // Increment the measurement index
137 index += 1;
138
139 }
140
141 // Reset the initial state of the propagator
142 model.finalizeOperationsObservationGrid();
143
144 }
145
146 }