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.measurements.generation;
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.random.CorrelatedRandomVectorGenerator;
25 import org.orekit.estimation.measurements.EstimatedMeasurementBase;
26 import org.orekit.estimation.measurements.EstimationModifier;
27 import org.orekit.estimation.measurements.ObservableSatellite;
28 import org.orekit.estimation.measurements.ObservedMeasurement;
29 import org.orekit.propagation.SpacecraftState;
30 import org.orekit.propagation.sampling.OrekitStepInterpolator;
31 import org.orekit.time.AbsoluteDate;
32 import org.orekit.utils.ParameterDriver;
33
34 /** Base class for {@link MeasurementBuilder measurements builders}.
35 * @param <T> the type of the measurement
36 * @author Luc Maisonobe
37 * @since 9.3
38 */
39 public abstract class AbstractMeasurementBuilder<T extends ObservedMeasurement<T>> implements MeasurementBuilder<T> {
40
41 /** Noise source (may be null). */
42 private final CorrelatedRandomVectorGenerator noiseSource;
43
44 /** Modifiers that apply to the measurement.*/
45 private final List<EstimationModifier<T>> modifiers;
46
47 /** Theoretical standard deviation. */
48 private final double[] sigma;
49
50 /** Base weight. */
51 private final double[] baseWeight;
52
53 /** Satellites related to this measurement. */
54 private final ObservableSatellite[] satellites;
55
56 /** Start of the measurements time span. */
57 private AbsoluteDate spanStart;
58
59 /** End of the measurements time span. */
60 private AbsoluteDate spanEnd;
61
62 /** Simple constructor.
63 * @param noiseSource noise source, may be null for generating perfect measurements
64 * @param sigma theoretical standard deviation
65 * @param baseWeight base weight
66 * @param satellites satellites related to this builder
67 */
68 protected AbstractMeasurementBuilder(final CorrelatedRandomVectorGenerator noiseSource,
69 final double sigma, final double baseWeight,
70 final ObservableSatellite... satellites) {
71 this(noiseSource,
72 new double[] {
73 sigma
74 }, new double[] {
75 baseWeight
76 }, satellites);
77 }
78
79 /** Simple constructor.
80 * @param noiseSource noise source, may be null for generating perfect measurements
81 * @param sigma theoretical standard deviation
82 * @param baseWeight base weight
83 * @param satellites satellites related to this builder
84 */
85 protected AbstractMeasurementBuilder(final CorrelatedRandomVectorGenerator noiseSource,
86 final double[] sigma, final double[] baseWeight,
87 final ObservableSatellite... satellites) {
88 this.noiseSource = noiseSource;
89 this.modifiers = new ArrayList<>();
90 this.sigma = sigma.clone();
91 this.baseWeight = baseWeight.clone();
92 this.satellites = satellites.clone();
93 }
94
95 /** {@inheritDoc}
96 * <p>
97 * This implementation stores the time span of the measurements generation.
98 * </p>
99 */
100 @Override
101 public void init(final AbsoluteDate start, final AbsoluteDate end) {
102 spanStart = start;
103 spanEnd = end;
104 }
105
106 /** {@inheritDoc} */
107 @Override
108 public void addModifier(final EstimationModifier<T> modifier) {
109 modifiers.add(modifier);
110 }
111
112 /** {@inheritDoc} */
113 @Override
114 public List<EstimationModifier<T>> getModifiers() {
115 return Collections.unmodifiableList(modifiers);
116 }
117
118 /** Get the start of the measurements time span.
119 * @return start of the measurements time span
120 */
121 protected AbsoluteDate getStart() {
122 return spanStart;
123 }
124
125 /** Get the end of the measurements time span.
126 * @return end of the measurements time span
127 */
128 protected AbsoluteDate getEnd() {
129 return spanEnd;
130 }
131
132 /** Generate a noise vector.
133 * @return noise vector (null if we generate perfect measurements)
134 */
135 protected double[] getNoise() {
136 return noiseSource == null ? null : noiseSource.nextVector();
137 }
138
139 /** Get the theoretical standard deviation.
140 * <p>
141 * The theoretical standard deviation is a theoretical value
142 * used for normalizing the residuals. It acts as a weighting
143 * factor to mix appropriately measurements with different units
144 * and different accuracy. The value has the same dimension as
145 * the measurement itself (i.e. when a residual is divided by
146 * this value, it becomes dimensionless).
147 * </p>
148 * @return expected standard deviation
149 * @see #getBaseWeight()
150 */
151 protected double[] getTheoreticalStandardDeviation() {
152 return sigma.clone();
153 }
154
155 /** Get the base weight associated with the measurement
156 * <p>
157 * The base weight is used on residuals already normalized thanks to
158 * {@link #getTheoreticalStandardDeviation()} to increase or
159 * decrease relative effect of some measurements with respect to
160 * other measurements. It is a dimensionless value, typically between
161 * 0 and 1 (but it can really have any non-negative value).
162 * </p>
163 * @return base weight
164 * @see #getTheoreticalStandardDeviation()
165 */
166 protected double[] getBaseWeight() {
167 return baseWeight.clone();
168 }
169
170 /** {@inheritDoc} */
171 @Override
172 public ObservableSatellite[] getSatellites() {
173 return satellites.clone();
174 }
175
176 /**
177 * Build a dummy observed measurement.
178 *
179 * @param date measurement date
180 * @param interpolators interpolators relevant for this builder
181 * @return dummy observed measurement
182 * @since 13.0
183 */
184 protected abstract T buildObserved(AbsoluteDate date,
185 Map<ObservableSatellite, OrekitStepInterpolator> interpolators);
186
187 /** {@inheritDoc} */
188 @Override
189 public EstimatedMeasurementBase<T> build(final AbsoluteDate date,
190 final Map<ObservableSatellite, OrekitStepInterpolator> interpolators) {
191
192 final SpacecraftState[] relevant = new SpacecraftState[satellites.length];
193 for (int i = 0; i < relevant.length; ++i) {
194 relevant[i] = interpolators.get(satellites[i]).getInterpolatedState(date);
195 }
196
197 // create a dummy observed measurement
198 final T observed = buildObserved(date, interpolators);
199 for (final EstimationModifier<T> modifier : getModifiers()) {
200 observed.addModifier(modifier);
201 }
202
203 // set a reference date for parameters missing one
204 for (final ParameterDriver driver : observed.getParametersDrivers()) {
205 if (driver.getReferenceDate() == null) {
206 final AbsoluteDate start = getStart();
207 final AbsoluteDate end = getEnd();
208 driver.setReferenceDate(start.durationFrom(end) <= 0 ? start : end);
209 }
210 }
211
212 // estimate the perfect value of the measurement
213 final EstimatedMeasurementBase<T> estimated = observed.estimateWithoutDerivatives(relevant);
214 final double[] value = estimated.getEstimatedValue();
215
216 // add the noise
217 final double[] noise = getNoise();
218 if (noise != null) {
219 for (int i = 0; i < value.length; ++i) {
220 value[i] += noise[i];
221 }
222 }
223
224 // update the dummy measurement (which is referenced by the estimated measurement)
225 observed.setObservedValue(value);
226
227 return estimated;
228
229 }
230
231 }