1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.estimation.measurements;
18
19 import java.util.Arrays;
20
21 import org.hipparchus.CalculusFieldElement;
22 import org.hipparchus.analysis.differentiation.Gradient;
23 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
24 import org.hipparchus.geometry.euclidean.threed.Vector3D;
25 import org.hipparchus.util.FastMath;
26 import org.orekit.frames.FieldTransform;
27 import org.orekit.frames.Transform;
28 import org.orekit.propagation.SpacecraftState;
29 import org.orekit.time.AbsoluteDate;
30 import org.orekit.time.FieldAbsoluteDate;
31 import org.orekit.utils.Constants;
32 import org.orekit.utils.ParameterDriver;
33 import org.orekit.utils.TimeSpanMap.Span;
34 import org.orekit.utils.TimeStampedFieldPVCoordinates;
35 import org.orekit.utils.TimeStampedPVCoordinates;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 public class TDOA extends GroundReceiverMeasurement<TDOA> {
54
55
56 public static final String MEASUREMENT_TYPE = "TDOA";
57
58
59 private final GroundStation secondStation;
60
61
62
63
64
65
66
67
68
69
70 public TDOA(final GroundStation primeStation, final GroundStation secondStation,
71 final AbsoluteDate date, final double tdoa, final double sigma,
72 final double baseWeight, final ObservableSatellite satellite) {
73 super(primeStation, false, date, tdoa, sigma, baseWeight, satellite);
74
75
76 addParameterDriver(secondStation.getClockOffsetDriver());
77 addParameterDriver(secondStation.getEastOffsetDriver());
78 addParameterDriver(secondStation.getNorthOffsetDriver());
79 addParameterDriver(secondStation.getZenithOffsetDriver());
80 addParameterDriver(secondStation.getPrimeMeridianOffsetDriver());
81 addParameterDriver(secondStation.getPrimeMeridianDriftDriver());
82 addParameterDriver(secondStation.getPolarOffsetXDriver());
83 addParameterDriver(secondStation.getPolarDriftXDriver());
84 addParameterDriver(secondStation.getPolarOffsetYDriver());
85 addParameterDriver(secondStation.getPolarDriftYDriver());
86 this.secondStation = secondStation;
87
88 }
89
90
91
92
93 public GroundStation getPrimeStation() {
94 return getStation();
95 }
96
97
98
99
100 public GroundStation getSecondStation() {
101 return secondStation;
102 }
103
104
105 @SuppressWarnings("checkstyle:WhitespaceAround")
106 @Override
107 protected EstimatedMeasurementBase<TDOA> theoreticalEvaluationWithoutDerivatives(final int iteration, final int evaluation,
108 final SpacecraftState[] states) {
109
110 final GroundReceiverCommonParametersWithoutDerivatives common = computeCommonParametersWithout(states[0]);
111 final TimeStampedPVCoordinates emitterPV = common.getTransitPV();
112 final AbsoluteDate emitterDate = emitterPV.getDate();
113
114
115 final Transform secondToInertial =
116 getSecondStation().getOffsetToInertial(common.getState().getFrame(), emitterDate, true);
117 final TimeStampedPVCoordinates secondApprox =
118 secondToInertial.transformPVCoordinates(new TimeStampedPVCoordinates(emitterDate,
119 Vector3D.ZERO, Vector3D.ZERO, Vector3D.ZERO));
120
121
122 final double tau2 = forwardSignalTimeOfFlight(secondApprox, emitterPV.getPosition(), emitterDate);
123
124
125 final TimeStampedPVCoordinates secondPV = secondApprox.shiftedBy(tau2);
126
127
128 final double offset1 = getPrimeStation().getClockOffsetDriver().getValue(emitterDate);
129 final double offset2 = getSecondStation().getClockOffsetDriver().getValue(emitterDate);
130 final double tdoa = (common.getTauD() + offset1) - (tau2 + offset2);
131
132
133
134 final EstimatedMeasurement<TDOA> estimated =
135 new EstimatedMeasurement<>(this, iteration, evaluation,
136 new SpacecraftState[] {
137 common.getTransitState()
138 },
139 new TimeStampedPVCoordinates[] {
140 emitterPV,
141 tdoa > 0.0 ? secondPV : common.getStationDownlink(),
142 tdoa > 0.0 ? common.getStationDownlink() : secondPV
143 });
144
145
146 estimated.setEstimatedValue(tdoa);
147
148 return estimated;
149 }
150
151
152 @Override
153 protected EstimatedMeasurement<TDOA> theoreticalEvaluation(final int iteration, final int evaluation,
154 final SpacecraftState[] states) {
155
156 final SpacecraftState state = states[0];
157
158
159
160
161
162
163
164
165
166 final GroundReceiverCommonParametersWithDerivatives common = computeCommonParametersWithDerivatives(state);
167 final int nbParams = common.getTauD().getFreeParameters();
168 final TimeStampedFieldPVCoordinates<Gradient> emitterPV = common.getTransitPV();
169 final FieldAbsoluteDate<Gradient> emitterDate = emitterPV.getDate();
170
171
172 final FieldVector3D<Gradient> zero = FieldVector3D.getZero(common.getTauD().getField());
173 final FieldTransform<Gradient> secondToInertial =
174 getSecondStation().getOffsetToInertial(state.getFrame(), emitterDate, nbParams, common.getIndices());
175 final TimeStampedFieldPVCoordinates<Gradient> secondApprox =
176 secondToInertial.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(emitterDate,
177 zero, zero, zero));
178
179
180 final Gradient tau2 = forwardSignalTimeOfFlight(secondApprox, emitterPV.getPosition(), emitterDate);
181
182
183 final TimeStampedFieldPVCoordinates<Gradient> secondPV = secondApprox.shiftedBy(tau2);
184
185
186 final Gradient offset1 = getPrimeStation().getClockOffsetDriver()
187 .getValue(nbParams, common.getIndices(), emitterDate.toAbsoluteDate());
188 final Gradient offset2 = getSecondStation().getClockOffsetDriver()
189 .getValue(nbParams, common.getIndices(), emitterDate.toAbsoluteDate());
190 final Gradient tdoaG = common.getTauD().add(offset1).subtract(tau2.add(offset2));
191 final double tdoa = tdoaG.getValue();
192
193
194
195 final TimeStampedPVCoordinates pv1 = common.getStationDownlink().toTimeStampedPVCoordinates();
196 final TimeStampedPVCoordinates pv2 = secondPV.toTimeStampedPVCoordinates();
197 final EstimatedMeasurement<TDOA> estimated =
198 new EstimatedMeasurement<>(this, iteration, evaluation,
199 new SpacecraftState[] {
200 common.getTransitState()
201 },
202 new TimeStampedPVCoordinates[] {
203 emitterPV.toTimeStampedPVCoordinates(),
204 tdoa > 0 ? pv2 : pv1,
205 tdoa > 0 ? pv1 : pv2
206 });
207
208
209 estimated.setEstimatedValue(tdoa);
210
211
212 final double[] derivatives = tdoaG.getGradient();
213 estimated.setStateDerivatives(0, Arrays.copyOfRange(derivatives, 0, 6));
214
215
216 for (final ParameterDriver driver : getParametersDrivers()) {
217 for (Span<String> span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
218 final Integer index = common.getIndices().get(span.getData());
219 if (index != null) {
220 estimated.setParameterDerivatives(driver, span.getStart(), derivatives[index]);
221 }
222 }
223 }
224
225 return estimated;
226 }
227
228
229
230
231
232
233
234
235
236
237
238 public static double forwardSignalTimeOfFlight(final TimeStampedPVCoordinates adjustableEmitterPV,
239 final Vector3D receiverPosition,
240 final AbsoluteDate signalArrivalDate) {
241
242
243
244
245 final double offset = signalArrivalDate.durationFrom(adjustableEmitterPV.getDate());
246 double delay = offset;
247
248
249 final double cReciprocal = 1.0 / Constants.SPEED_OF_LIGHT;
250 double delta;
251 int count = 0;
252 do {
253 final double previous = delay;
254 final Vector3D transitP = adjustableEmitterPV.shiftedBy(delay - offset).getPosition();
255 delay = receiverPosition.distance(transitP) * cReciprocal;
256 delta = FastMath.abs(delay - previous);
257 } while (count++ < 10 && delta >= 2 * FastMath.ulp(delay));
258
259 return delay;
260
261 }
262
263
264
265
266
267
268
269
270
271
272
273 public static <T extends CalculusFieldElement<T>> T forwardSignalTimeOfFlight(final TimeStampedFieldPVCoordinates<T> adjustableEmitterPV,
274 final FieldVector3D<T> receiverPosition,
275 final FieldAbsoluteDate<T> signalArrivalDate) {
276
277
278
279
280 final T offset = signalArrivalDate.durationFrom(adjustableEmitterPV.getDate());
281 T delay = offset;
282
283
284 final double cReciprocal = 1.0 / Constants.SPEED_OF_LIGHT;
285 double delta;
286 int count = 0;
287 do {
288 final double previous = delay.getReal();
289 final FieldVector3D<T> transitP = adjustableEmitterPV.shiftedBy(delay.subtract(offset)).getPosition();
290 delay = receiverPosition.distance(transitP).multiply(cReciprocal);
291 delta = FastMath.abs(delay.getReal() - previous);
292 } while (count++ < 10 && delta >= 2 * FastMath.ulp(delay.getReal()));
293
294 return delay;
295 }
296
297 }