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.measurements;
18
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Map;
23
24 import org.hipparchus.analysis.differentiation.Gradient;
25 import org.hipparchus.exception.LocalizedCoreFormats;
26 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
27 import org.hipparchus.geometry.euclidean.threed.Vector3D;
28 import org.orekit.errors.OrekitException;
29 import org.orekit.propagation.SpacecraftState;
30 import org.orekit.time.AbsoluteDate;
31 import org.orekit.utils.ParameterDriver;
32 import org.orekit.utils.TimeStampedFieldPVCoordinates;
33 import org.orekit.utils.TimeStampedPVCoordinates;
34
35 /** Abstract class handling measurements boilerplate.
36 * @param <T> the type of the measurement
37 * @author Luc Maisonobe
38 * @since 8.0
39 */
40 public abstract class AbstractMeasurement<T extends ObservedMeasurement<T>> implements ObservedMeasurement<T> {
41
42 /** List of the supported parameters. */
43 private final List<ParameterDriver> supportedParameters;
44
45 /** Satellites related to this measurement.
46 * @since 9.3
47 */
48 private final List<ObservableSatellite> satellites;
49
50 /** Date of the measurement. */
51 private final AbsoluteDate date;
52
53 /** Observed value. */
54 private double[] observed;
55
56 /** Measurement data. */
57 private final MeasurementQuality measurementQuality;
58
59 /** Modifiers that apply to the measurement.*/
60 private final List<EstimationModifier<T>> modifiers;
61
62 /** Enabling status. */
63 private boolean enabled;
64
65 /** Simple constructor for mono-dimensional measurements.
66 * <p>
67 * At construction, a measurement is enabled.
68 * </p>
69 * @param date date of the measurement
70 * @param observed observed value
71 * @param sigma theoretical standard deviation
72 * @param baseWeight base weight
73 * @param satellites satellites related to this measurement
74 * @since 14.0
75 */
76 protected AbstractMeasurement(final AbsoluteDate date, final double observed,
77 final double sigma, final double baseWeight,
78 final List<ObservableSatellite> satellites) {
79 this(date, new double[] {observed}, new double[] {sigma}, new double[] {baseWeight}, satellites);
80 }
81
82 /** Simple constructor, for multi-dimensional measurements.
83 * <p>
84 * At construction, a measurement is enabled.
85 * </p>
86 * @param date date of the measurement
87 * @param observed observed value
88 * @param sigma theoretical standard deviation
89 * @param baseWeight base weight
90 * @param satellites satellites related to this measurement
91 * @since 14.0
92 */
93 protected AbstractMeasurement(final AbsoluteDate date, final double[] observed,
94 final double[] sigma, final double[] baseWeight,
95 final List<ObservableSatellite> satellites) {
96 this(date, observed, new MeasurementQuality(sigma, baseWeight), satellites);
97 }
98
99 /** Simple constructor, for multi-dimensional measurements.
100 * <p>
101 * At construction, a measurement is enabled.
102 * </p>
103 * @param date date of the measurement
104 * @param observed observed value
105 * @param measurementQuality measurement quality data
106 * @param satellites satellites related to this measurement
107 * @since 14.0
108 */
109 protected AbstractMeasurement(final AbsoluteDate date, final double[] observed,
110 final MeasurementQuality measurementQuality,
111 final List<ObservableSatellite> satellites) {
112 if (measurementQuality.getDimension() != observed.length) {
113 throw new OrekitException(LocalizedCoreFormats.DIMENSIONS_MISMATCH, measurementQuality.getDimension(), observed.length);
114 }
115 this.supportedParameters = new ArrayList<>();
116
117 this.date = date;
118 this.observed = observed.clone();
119 this.measurementQuality = measurementQuality;
120 this.satellites = satellites;
121
122 // Add parameter drivers
123 satellites.forEach(s -> addParametersDrivers(s.getParametersDrivers()));
124
125 this.modifiers = new ArrayList<>();
126 setEnabled(true);
127 }
128
129 /** {@inheritDoc} */
130 @Override
131 public void setObservedValue(final double[] newObserved) {
132 this.observed = newObserved.clone();
133 }
134
135 /** Add a parameter driver.
136 * @param driver parameter driver to add
137 * @since 9.3
138 */
139 protected void addParameterDriver(final ParameterDriver driver) {
140 supportedParameters.add(driver);
141 }
142
143 /** Add a list of parameter drivers all at once.
144 * @param drivers list of parameter drivers to add
145 * @since 14.0
146 */
147 protected void addParametersDrivers(final List<ParameterDriver> drivers) {
148 for (final ParameterDriver driver : drivers) {
149 addParameterDriver(driver);
150 }
151 }
152
153 /** {@inheritDoc} */
154 @Override
155 public List<ParameterDriver> getParametersDrivers() {
156 return Collections.unmodifiableList(supportedParameters);
157 }
158
159 /** {@inheritDoc} */
160 @Override
161 public final void setEnabled(final boolean enabled) {
162 this.enabled = enabled;
163 }
164
165 /** {@inheritDoc} */
166 @Override
167 public boolean isEnabled() {
168 return enabled;
169 }
170
171 /** {@inheritDoc} */
172 @Override
173 public MeasurementQuality getMeasurementQuality() {
174 return measurementQuality;
175 }
176
177 /** {@inheritDoc} */
178 @Override
179 public List<ObservableSatellite> getSatellites() {
180 return satellites;
181 }
182
183 /** Estimate the theoretical value without derivatives.
184 * The default implementation uses the computation with derivatives and ought to be overwritten for performance.
185 * <p>
186 * The theoretical value does not have <em>any</em> modifiers applied.
187 * </p>
188 * @param iteration iteration number
189 * @param evaluation evaluation number
190 * @param states orbital states at measurement date
191 * @return theoretical value
192 * @see #estimate(int, int, SpacecraftState[])
193 * @since 12.0
194 */
195 protected EstimatedMeasurementBase<T> theoreticalEvaluationWithoutDerivatives(final int iteration,
196 final int evaluation,
197 final SpacecraftState[] states) {
198 return theoreticalEvaluationWithoutDerivatives(iteration, evaluation, states, true);
199 }
200
201 /** Estimate the theoretical value without derivatives.
202 * The default implementation uses the computation with derivatives and ought to be overwritten for performance.
203 * <p>
204 * The theoretical value does not have <em>any</em> modifiers applied.
205 * </p>
206 * @param iteration iteration number
207 * @param evaluation evaluation number
208 * @param states orbital states at measurement date
209 * @param fillParticipants flag to compute and store participants dynamical states at measurement date and along signal path if applicable
210 * @return theoretical value
211 * @see #estimate(int, int, SpacecraftState[])
212 * @since 14.0
213 */
214 protected EstimatedMeasurementBase<T> theoreticalEvaluationWithoutDerivatives(final int iteration,
215 final int evaluation,
216 final SpacecraftState[] states,
217 final boolean fillParticipants) {
218 final EstimatedMeasurement<T> estimatedMeasurement = theoreticalEvaluation(iteration, evaluation, states);
219 final TimeStampedPVCoordinates[] participants = fillParticipants ? estimatedMeasurement.getParticipants() :
220 new TimeStampedPVCoordinates[0];
221 final EstimatedMeasurementBase<T> estimatedMeasurementBase = new EstimatedMeasurementBase<>(estimatedMeasurement.getObservedMeasurement(),
222 iteration, evaluation, states, participants);
223 estimatedMeasurementBase.setEstimatedValue(estimatedMeasurement.getEstimatedValue());
224 estimatedMeasurementBase.setStatus(estimatedMeasurement.getStatus());
225 return estimatedMeasurementBase;
226 }
227
228 /** Estimate the theoretical value.
229 * <p>
230 * The theoretical value does not have <em>any</em> modifiers applied.
231 * </p>
232 * @param iteration iteration number
233 * @param evaluation evaluation number
234 * @param states orbital states at measurement date
235 * @return theoretical value
236 * @see #estimate(int, int, SpacecraftState[])
237 */
238 protected abstract EstimatedMeasurement<T> theoreticalEvaluation(int iteration, int evaluation, SpacecraftState[] states);
239
240 /** {@inheritDoc}
241 * <p>
242 * For the sake of computational performance, the output will contain the participant's states only if at least
243 * one measurement modifier explicitly requires it (note that the estimated states can still be accessed {@link EstimatedMeasurementBase#getStates()}).
244 * </p>
245 */
246 @Override
247 public EstimatedMeasurementBase<T> estimateWithoutDerivatives(final int iteration, final int evaluation,
248 final SpacecraftState[] states) {
249
250 // compute the theoretical value
251 final boolean fillParticipants = modifiers.stream().anyMatch(EstimationModifier::dependsOnParticipantsStates);
252 final EstimatedMeasurementBase<T> estimation = theoreticalEvaluationWithoutDerivatives(iteration, evaluation, states, fillParticipants);
253
254 // apply the modifiers
255 for (final EstimationModifier<T> modifier : modifiers) {
256 modifier.modifyWithoutDerivatives(estimation);
257 }
258
259 return estimation;
260
261 }
262
263 /** {@inheritDoc} */
264 @Override
265 public EstimatedMeasurement<T> estimate(final int iteration, final int evaluation, final SpacecraftState[] states) {
266
267 // compute the theoretical value
268 final EstimatedMeasurement<T> estimation = theoreticalEvaluation(iteration, evaluation, states);
269
270 // apply the modifiers
271 for (final EstimationModifier<T> modifier : modifiers) {
272 modifier.modify(estimation);
273 }
274
275 return estimation;
276
277 }
278
279 /** {@inheritDoc} */
280 @Override
281 public AbsoluteDate getDate() {
282 return date;
283 }
284
285 /** {@inheritDoc} */
286 @Override
287 public double[] getObservedValue() {
288 return observed.clone();
289 }
290
291 /** {@inheritDoc} */
292 @Override
293 public void addModifier(final EstimationModifier<T> modifier) {
294
295 // combine the measurement parameters and the modifier parameters
296 supportedParameters.addAll(modifier.getParametersDrivers());
297
298 modifiers.add(modifier);
299
300 }
301
302 /** {@inheritDoc} */
303 @Override
304 public List<EstimationModifier<T>> getModifiers() {
305 return Collections.unmodifiableList(modifiers);
306 }
307
308 /** Get Cartesian coordinates as derivatives.
309 * <p>
310 * The position will correspond to variables {@code firstDerivative},
311 * {@code firstDerivative + 1} and {@code firstDerivative + 2}.
312 * The velocity will correspond to variables {@code firstDerivative + 3},
313 * {@code firstDerivative + 4} and {@code firstDerivative + 5}.
314 * The acceleration will correspond to constants.
315 * </p>
316 * @param state state of the satellite considered
317 * @param firstDerivative index of the first derivative
318 * @param freeParameters total number of free parameters in the gradient
319 * @return Cartesian coordinates as derivatives
320 * @since 10.2
321 */
322 public static TimeStampedFieldPVCoordinates<Gradient> getCoordinates(final SpacecraftState state,
323 final int firstDerivative,
324 final int freeParameters) {
325
326 // Position of the satellite expressed as a gradient
327 // The components of the position are the 3 first derivative parameters
328 final Vector3D p = state.getPosition();
329 final FieldVector3D<Gradient> pDS =
330 new FieldVector3D<>(Gradient.variable(freeParameters, firstDerivative, p.getX()),
331 Gradient.variable(freeParameters, firstDerivative + 1, p.getY()),
332 Gradient.variable(freeParameters, firstDerivative + 2, p.getZ()));
333
334 // Velocity of the satellite expressed as a gradient
335 // The components of the velocity are the 3 second derivative parameters
336 final Vector3D v = state.getVelocity();
337 final FieldVector3D<Gradient> vDS =
338 new FieldVector3D<>(Gradient.variable(freeParameters, firstDerivative + 3, v.getX()),
339 Gradient.variable(freeParameters, firstDerivative + 4, v.getY()),
340 Gradient.variable(freeParameters, firstDerivative + 5, v.getZ()));
341
342 // Acceleration of the satellite
343 // The components of the acceleration are not derivative parameters
344 final Vector3D a = state.getPVCoordinates().getAcceleration();
345 final FieldVector3D<Gradient> aDS =
346 new FieldVector3D<>(Gradient.constant(freeParameters, a.getX()),
347 Gradient.constant(freeParameters, a.getY()),
348 Gradient.constant(freeParameters, a.getZ()));
349
350 return new TimeStampedFieldPVCoordinates<>(state.getDate(), pDS, vDS, aDS);
351
352 }
353
354 /**
355 * Form the mapping between parameters' names and derivatives' indices.
356 * @param states observables
357 * @return map
358 * @since 14.0
359 */
360 protected Map<String, Integer> getParameterIndices(final SpacecraftState[] states) {
361 return Observer.getParameterIndices(states, getParametersDrivers());
362 }
363
364 }