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