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