1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.estimation.measurements.modifiers;
18
19 import java.util.Arrays;
20 import java.util.List;
21
22 import org.hipparchus.CalculusFieldElement;
23 import org.hipparchus.Field;
24 import org.hipparchus.analysis.differentiation.Gradient;
25 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
26 import org.hipparchus.geometry.euclidean.threed.Vector3D;
27 import org.orekit.attitudes.FrameAlignedProvider;
28 import org.orekit.estimation.measurements.EstimatedMeasurement;
29 import org.orekit.estimation.measurements.EstimatedMeasurementBase;
30 import org.orekit.estimation.measurements.EstimationModifier;
31 import org.orekit.estimation.measurements.GroundStation;
32 import org.orekit.estimation.measurements.TurnAroundRange;
33 import org.orekit.models.earth.troposphere.TroposphericModel;
34 import org.orekit.propagation.FieldSpacecraftState;
35 import org.orekit.propagation.SpacecraftState;
36 import org.orekit.time.AbsoluteDate;
37 import org.orekit.utils.Differentiation;
38 import org.orekit.utils.FieldTrackingCoordinates;
39 import org.orekit.utils.ParameterDriver;
40 import org.orekit.utils.ParameterFunction;
41 import org.orekit.utils.TimeSpanMap.Span;
42 import org.orekit.utils.TrackingCoordinates;
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public class TurnAroundRangeTroposphericDelayModifier implements EstimationModifier<TurnAroundRange> {
58
59
60 private final TroposphericModel tropoModel;
61
62
63
64
65
66
67 public TurnAroundRangeTroposphericDelayModifier(final TroposphericModel model) {
68 tropoModel = model;
69 }
70
71
72 @Override
73 public String getEffectName() {
74 return "troposphere";
75 }
76
77
78
79
80
81
82 private double rangeErrorTroposphericModel(final GroundStation station, final SpacecraftState state) {
83
84 final Vector3D position = state.getPosition();
85
86
87 final TrackingCoordinates trackingCoordinates =
88 station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate());
89
90
91 if (trackingCoordinates.getElevation() > 0) {
92
93 return tropoModel.pathDelay(trackingCoordinates,
94 station.getOffsetGeodeticPoint(state.getDate()),
95 tropoModel.getParameters(state.getDate()), state.getDate()).
96 getDelay();
97 }
98
99 return 0;
100 }
101
102
103
104
105
106
107
108
109 private <T extends CalculusFieldElement<T>> T rangeErrorTroposphericModel(final GroundStation station,
110 final FieldSpacecraftState<T> state,
111 final T[] parameters) {
112
113 final Field<T> field = state.getDate().getField();
114 final T zero = field.getZero();
115
116
117 final FieldVector3D<T> position = state.getPosition();
118 final FieldTrackingCoordinates<T> trackingCoordinates =
119 station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate());
120
121
122 if (trackingCoordinates.getElevation().getReal() > 0) {
123
124 return tropoModel.pathDelay(trackingCoordinates,
125 station.getOffsetGeodeticPoint(state.getDate()),
126 parameters, state.getDate()).
127 getDelay();
128 }
129
130 return zero;
131 }
132
133
134
135
136
137
138
139
140 private double[][] rangeErrorJacobianState(final double[] derivatives) {
141 final double[][] finiteDifferencesJacobian = new double[1][6];
142 System.arraycopy(derivatives, 0, finiteDifferencesJacobian[0], 0, 6);
143 return finiteDifferencesJacobian;
144 }
145
146
147
148
149
150
151
152
153
154 private double rangeErrorParameterDerivative(final GroundStation station,
155 final ParameterDriver driver,
156 final SpacecraftState state) {
157
158 final ParameterFunction rangeError = new ParameterFunction() {
159
160 @Override
161 public double value(final ParameterDriver parameterDriver, final AbsoluteDate date) {
162 return rangeErrorTroposphericModel(station, state);
163 }
164 };
165
166 final ParameterFunction rangeErrorDerivative = Differentiation.differentiate(rangeError, 3, 10.0 * driver.getScale());
167
168 return rangeErrorDerivative.value(driver, state.getDate());
169
170 }
171
172
173
174
175
176
177
178
179 private double[] rangeErrorParameterDerivative(final double[] derivatives, final int freeStateParameters) {
180
181
182 return Arrays.copyOfRange(derivatives, freeStateParameters, derivatives.length);
183 }
184
185
186 @Override
187 public List<ParameterDriver> getParametersDrivers() {
188 return tropoModel.getParametersDrivers();
189 }
190
191
192 @Override
193 public void modifyWithoutDerivatives(final EstimatedMeasurementBase<TurnAroundRange> estimated) {
194
195 final TurnAroundRange measurement = estimated.getObservedMeasurement();
196 final GroundStation primaryStation = measurement.getPrimaryStation();
197 final GroundStation secondaryStation = measurement.getSecondaryStation();
198 final SpacecraftState state = estimated.getStates()[0];
199
200
201
202 final double[] newValue = estimated.getEstimatedValue();
203 final double primaryDelay = rangeErrorTroposphericModel(primaryStation, state);
204 final double secondaryDelay = rangeErrorTroposphericModel(secondaryStation, state);
205 newValue[0] = newValue[0] + primaryDelay + secondaryDelay;
206 estimated.modifyEstimatedValue(this, newValue);
207
208 }
209
210 @Override
211 public void modify(final EstimatedMeasurement<TurnAroundRange> estimated) {
212 final TurnAroundRange measurement = estimated.getObservedMeasurement();
213 final GroundStation primaryStation = measurement.getPrimaryStation();
214 final GroundStation secondaryStation = measurement.getSecondaryStation();
215 final SpacecraftState state = estimated.getStates()[0];
216
217 final double[] oldValue = estimated.getEstimatedValue();
218
219
220 final ModifierGradientConverter converter =
221 new ModifierGradientConverter(state, 6, new FrameAlignedProvider(state.getFrame()));
222 final FieldSpacecraftState<Gradient> gState = converter.getState(tropoModel);
223 final Gradient[] gParameters = converter.getParametersAtStateDate(gState, tropoModel);
224 final Gradient primaryGDelay = rangeErrorTroposphericModel(primaryStation, gState, gParameters);
225 final Gradient secondaryGDelay = rangeErrorTroposphericModel(secondaryStation, gState, gParameters);
226 final double[] primaryDerivatives = primaryGDelay.getGradient();
227 final double[] secondaryDerivatives = secondaryGDelay.getGradient();
228
229 final double[][] primaryDjac = rangeErrorJacobianState(primaryDerivatives);
230 final double[][] secondaryDjac = rangeErrorJacobianState(secondaryDerivatives);
231 final double[][] stateDerivatives = estimated.getStateDerivatives(0);
232 for (int irow = 0; irow < stateDerivatives.length; ++irow) {
233 for (int jcol = 0; jcol < stateDerivatives[0].length; ++jcol) {
234 stateDerivatives[irow][jcol] += primaryDjac[irow][jcol] + secondaryDjac[irow][jcol];
235 }
236 }
237 estimated.setStateDerivatives(0, stateDerivatives);
238
239 int indexPrimary = 0;
240 for (final ParameterDriver driver : getParametersDrivers()) {
241 if (driver.isSelected()) {
242
243 for (Span<String> span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
244 double parameterDerivative = estimated.getParameterDerivatives(driver, span.getStart())[0];
245 final double[] derivatives = rangeErrorParameterDerivative(primaryDerivatives, converter.getFreeStateParameters());
246 parameterDerivative += derivatives[indexPrimary];
247 estimated.setParameterDerivatives(driver, span.getStart(), parameterDerivative);
248 indexPrimary += 1;
249 }
250 }
251
252 }
253
254 int indexSecondary = 0;
255 for (final ParameterDriver driver : getParametersDrivers()) {
256 if (driver.isSelected()) {
257
258 for (Span<String> span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
259 double parameterDerivative = estimated.getParameterDerivatives(driver, span.getStart())[0];
260 final double[] derivatives = rangeErrorParameterDerivative(secondaryDerivatives, converter.getFreeStateParameters());
261 parameterDerivative += derivatives[indexSecondary];
262 estimated.setParameterDerivatives(driver, span.getStart(), parameterDerivative);
263 indexSecondary += 1;
264 }
265 }
266
267 }
268
269
270 for (final ParameterDriver driver : Arrays.asList(primaryStation.getClockOffsetDriver(),
271 primaryStation.getEastOffsetDriver(),
272 primaryStation.getNorthOffsetDriver(),
273 primaryStation.getZenithOffsetDriver())) {
274 if (driver.isSelected()) {
275 for (Span<String> span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
276
277 double parameterDerivative = estimated.getParameterDerivatives(driver, span.getStart())[0];
278 parameterDerivative += rangeErrorParameterDerivative(primaryStation, driver, state);
279 estimated.setParameterDerivatives(driver, span.getStart(), parameterDerivative);
280 }
281 }
282 }
283
284
285 for (final ParameterDriver driver : Arrays.asList(secondaryStation.getEastOffsetDriver(),
286 secondaryStation.getNorthOffsetDriver(),
287 secondaryStation.getZenithOffsetDriver())) {
288 if (driver.isSelected()) {
289 for (Span<String> span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
290
291 double parameterDerivative = estimated.getParameterDerivatives(driver, span.getStart())[0];
292 parameterDerivative += rangeErrorParameterDerivative(secondaryStation, driver, state);
293 estimated.setParameterDerivatives(driver, span.getStart(), parameterDerivative);
294 }
295 }
296 }
297
298
299
300 final double[] newValue = oldValue.clone();
301 newValue[0] = newValue[0] + primaryGDelay.getReal() + secondaryGDelay.getReal();
302 estimated.modifyEstimatedValue(this, newValue);
303
304 }
305
306 }