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.Collections;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Map;
23
24 import org.hipparchus.Field;
25 import org.hipparchus.analysis.differentiation.Gradient;
26 import org.hipparchus.analysis.differentiation.GradientField;
27 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
28 import org.hipparchus.geometry.euclidean.threed.Vector3D;
29 import org.hipparchus.util.FastMath;
30 import org.hipparchus.util.MathUtils;
31 import org.orekit.annotation.DefaultDataContext;
32 import org.orekit.data.DataContext;
33 import org.orekit.errors.OrekitException;
34 import org.orekit.errors.OrekitMessages;
35 import org.orekit.estimation.measurements.AngularRaDec;
36 import org.orekit.estimation.measurements.EstimatedMeasurement;
37 import org.orekit.estimation.measurements.EstimatedMeasurementBase;
38 import org.orekit.estimation.measurements.EstimationModifier;
39 import org.orekit.estimation.measurements.GroundStation;
40 import org.orekit.frames.FieldTransform;
41 import org.orekit.frames.Frame;
42 import org.orekit.time.AbsoluteDate;
43 import org.orekit.time.FieldAbsoluteDate;
44 import org.orekit.utils.Constants;
45 import org.orekit.utils.FieldPVCoordinates;
46 import org.orekit.utils.PVCoordinates;
47 import org.orekit.utils.ParameterDriver;
48 import org.orekit.utils.TimeSpanMap;
49 import org.orekit.utils.TimeStampedFieldPVCoordinates;
50
51
52
53
54
55
56
57
58
59 public class AberrationModifier implements EstimationModifier<AngularRaDec> {
60
61
62 private final DataContext dataContext;
63
64
65
66
67
68
69
70
71 @DefaultDataContext
72 public AberrationModifier() {
73 this(DataContext.getDefault());
74 }
75
76
77
78
79
80
81 public AberrationModifier(final DataContext dataContext) {
82 this.dataContext = dataContext;
83 }
84
85
86
87
88
89
90
91
92
93
94 @DefaultDataContext
95 public static double[] naturalToProper(final double[] naturalRaDec, final GroundStation station,
96 final AbsoluteDate date, final Frame frame) {
97 return naturalToProper(naturalRaDec, station, date, frame, DataContext.getDefault());
98 }
99
100
101
102
103
104
105
106
107
108
109
110
111 public static double[] naturalToProper(final double[] naturalRaDec, final GroundStation station,
112 final AbsoluteDate date, final Frame frame, final DataContext context) {
113
114 ensureFrameIsPseudoInertial(frame);
115
116
117 final PVCoordinates baryPV = context.getCelestialBodies().getSolarSystemBarycenter().getPVCoordinates(date, frame);
118 final PVCoordinates stationPV = station.getBaseFrame().getPVCoordinates(date, frame);
119 final Vector3D stationBaryVel = stationPV.getVelocity()
120 .subtract(baryPV.getVelocity())
121 .scalarMultiply(1.0 / Constants.SPEED_OF_LIGHT);
122
123
124 return lorentzVelocitySum(naturalRaDec, stationBaryVel);
125 }
126
127
128
129
130
131
132
133
134
135
136 @DefaultDataContext
137 public static double[] properToNatural(final double[] properRaDec, final GroundStation station,
138 final AbsoluteDate date, final Frame frame) {
139 return properToNatural(properRaDec, station, date, frame, DataContext.getDefault());
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153 public static double[] properToNatural(final double[] properRaDec, final GroundStation station,
154 final AbsoluteDate date, final Frame frame, final DataContext context) {
155
156
157 ensureFrameIsPseudoInertial(frame);
158
159
160 final PVCoordinates baryPV = context.getCelestialBodies().getSolarSystemBarycenter().getPVCoordinates(date, frame);
161 final PVCoordinates stationPV = station.getBaseFrame().getPVCoordinates(date, frame);
162 final Vector3D baryStationVel = baryPV.getVelocity()
163 .subtract(stationPV.getVelocity())
164 .scalarMultiply(1.0 / Constants.SPEED_OF_LIGHT);
165
166
167 return lorentzVelocitySum(properRaDec, baryStationVel);
168 }
169
170
171
172
173
174
175
176
177
178 private static double[] lorentzVelocitySum(final double[] raDec, final Vector3D velocity) {
179
180
181 final Vector3D direction = new Vector3D(raDec[0], raDec[1]);
182
183
184 final double inverseBeta = FastMath.sqrt(1.0 - velocity.getNormSq());
185 final double velocityScale = 1.0 + direction.dotProduct(velocity) / (1.0 + inverseBeta);
186
187
188 final Vector3D transformDirection = (direction.scalarMultiply(inverseBeta))
189 .add(velocity.scalarMultiply(velocityScale));
190 return new double[] {transformDirection.getAlpha(), transformDirection.getDelta()};
191 }
192
193
194
195
196
197
198
199
200
201 @DefaultDataContext
202 public static Gradient[] fieldNaturalToProper(final Gradient[] naturalRaDec,
203 final FieldTransform<Gradient> stationToInertial,
204 final Frame frame) {
205 return fieldNaturalToProper(naturalRaDec, stationToInertial, frame, DataContext.getDefault());
206 }
207
208
209
210
211
212
213
214
215
216
217
218 public static Gradient[] fieldNaturalToProper(final Gradient[] naturalRaDec,
219 final FieldTransform<Gradient> stationToInertial,
220 final Frame frame,
221 final DataContext context) {
222
223
224 ensureFrameIsPseudoInertial(frame);
225
226
227 final Field<Gradient> field = naturalRaDec[0].getField();
228 final FieldVector3D<Gradient> zero = FieldVector3D.getZero(field);
229 final FieldAbsoluteDate<Gradient> date = stationToInertial.getFieldDate();
230
231
232 final FieldPVCoordinates<Gradient> baryPV = context.getCelestialBodies().getSolarSystemBarycenter().getPVCoordinates(date, frame);
233
234
235 final TimeStampedFieldPVCoordinates<Gradient> stationPV =
236 stationToInertial.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(date, zero, zero, zero));
237
238
239 final FieldVector3D<Gradient> stationBaryVel = stationPV.getVelocity()
240 .subtract(baryPV.getVelocity())
241 .scalarMultiply(1.0 / Constants.SPEED_OF_LIGHT);
242
243 return fieldLorentzVelocitySum(naturalRaDec, stationBaryVel);
244 }
245
246
247
248
249
250
251
252
253
254 @DefaultDataContext
255 public static Gradient[] fieldProperToNatural(final Gradient[] properRaDec,
256 final FieldTransform<Gradient> stationToInertial,
257 final Frame frame) {
258 return fieldProperToNatural(properRaDec, stationToInertial, frame, DataContext.getDefault());
259 }
260
261
262
263
264
265
266
267
268
269
270
271 public static Gradient[] fieldProperToNatural(final Gradient[] properRaDec,
272 final FieldTransform<Gradient> stationToInertial,
273 final Frame frame,
274 final DataContext context) {
275
276
277 ensureFrameIsPseudoInertial(frame);
278
279
280 final Field<Gradient> field = properRaDec[0].getField();
281 final FieldVector3D<Gradient> zero = FieldVector3D.getZero(field);
282 final FieldAbsoluteDate<Gradient> date = stationToInertial.getFieldDate();
283
284
285 final FieldPVCoordinates<Gradient> baryPV = context.getCelestialBodies().getSolarSystemBarycenter().getPVCoordinates(date, frame);
286
287
288 final TimeStampedFieldPVCoordinates<Gradient> stationPV =
289 stationToInertial.transformPVCoordinates(new TimeStampedFieldPVCoordinates<>(date, zero, zero, zero));
290
291
292 final FieldVector3D<Gradient> stationBaryVel = stationPV.getVelocity()
293 .negate()
294 .add(baryPV.getVelocity())
295 .scalarMultiply(1.0 / Constants.SPEED_OF_LIGHT);
296
297 return fieldLorentzVelocitySum(properRaDec, stationBaryVel);
298 }
299
300
301
302
303
304
305
306
307
308 private static Gradient[] fieldLorentzVelocitySum(final Gradient[] raDec,
309 final FieldVector3D<Gradient> velocity) {
310
311
312 final FieldVector3D<Gradient> direction = new FieldVector3D<>(raDec[0], raDec[1]);
313
314
315 final Gradient inverseBeta = (velocity.getNormSq().negate().add(1.0)).sqrt();
316 final Gradient velocityScale = (direction.dotProduct(velocity)).divide(inverseBeta.add(1.0)).add(1.0);
317
318
319 final FieldVector3D<Gradient> transformDirection = (direction.scalarMultiply(inverseBeta))
320 .add(velocity.scalarMultiply(velocityScale));
321 return new Gradient[] {transformDirection.getAlpha(), transformDirection.getDelta()};
322 }
323
324
325
326 @Override
327 public List<ParameterDriver> getParametersDrivers() {
328 return Collections.emptyList();
329 }
330
331
332 @Override
333 public void modifyWithoutDerivatives(final EstimatedMeasurementBase<AngularRaDec> estimated) {
334
335
336 final AbsoluteDate date = estimated.getDate();
337
338
339 final GroundStation station = estimated.getObservedMeasurement().getStation();
340
341
342 final Frame frame = estimated.getObservedMeasurement().getReferenceFrame();
343
344
345 final double[] estimatedRaDec = estimated.getEstimatedValue();
346 final double[] naturalRaDec = properToNatural(estimatedRaDec, station, date, frame, dataContext);
347
348
349 final double[] observed = estimated.getObservedValue();
350 final double baseRightAscension = naturalRaDec[0];
351 final double twoPiWrap = MathUtils.normalizeAngle(baseRightAscension, observed[0]) - baseRightAscension;
352 final double rightAscension = baseRightAscension + twoPiWrap;
353
354
355 estimated.modifyEstimatedValue(this, rightAscension, naturalRaDec[1]);
356
357 }
358
359
360 @Override
361 public void modify(final EstimatedMeasurement<AngularRaDec> estimated) {
362
363
364 final AbsoluteDate date = estimated.getDate();
365
366
367 final Frame frame = estimated.getObservedMeasurement().getReferenceFrame();
368
369
370 int nbParams = 6;
371 final Map<String, Integer> indices = new HashMap<>();
372 for (ParameterDriver driver : estimated.getObservedMeasurement().getParametersDrivers()) {
373 if (driver.isSelected()) {
374 for (TimeSpanMap.Span<String> span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
375 if (!indices.containsKey(span.getData())) {
376 indices.put(span.getData(), nbParams++);
377 }
378 }
379 }
380 }
381 final Field<Gradient> field = GradientField.getField(nbParams);
382
383
384 final FieldTransform<Gradient> stationToInertial =
385 estimated.getObservedMeasurement().getStation().getOffsetToInertial(frame, date, nbParams, indices);
386
387
388 final double[] estimatedRaDec = estimated.getEstimatedValue();
389 final Gradient[] estimatedRaDecDS = new Gradient[] {
390 field.getZero().add(estimatedRaDec[0]),
391 field.getZero().add(estimatedRaDec[1])
392 };
393 final Gradient[] naturalRaDec = fieldProperToNatural(estimatedRaDecDS, stationToInertial, frame, dataContext);
394
395
396 final double[] observed = estimated.getObservedValue();
397 final Gradient baseRightAscension = naturalRaDec[0];
398 final double twoPiWrap = MathUtils.normalizeAngle(baseRightAscension.getReal(),
399 observed[0]) - baseRightAscension.getReal();
400 final Gradient rightAscension = baseRightAscension.add(twoPiWrap);
401
402
403 estimated.modifyEstimatedValue(this, rightAscension.getValue(), naturalRaDec[1].getValue());
404
405
406 final double[] raDerivatives = rightAscension.getGradient();
407 final double[] decDerivatives = naturalRaDec[1].getGradient();
408
409 for (final ParameterDriver driver : estimated.getObservedMeasurement().getParametersDrivers()) {
410 for (TimeSpanMap.Span<String> span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
411 final Integer index = indices.get(span.getData());
412 if (index != null) {
413 final double[] parameterDerivative = estimated.getParameterDerivatives(driver);
414 parameterDerivative[0] += raDerivatives[index];
415 parameterDerivative[1] += decDerivatives[index];
416 estimated.setParameterDerivatives(driver, span.getStart(), parameterDerivative[0], parameterDerivative[1]);
417 }
418 }
419 }
420 }
421
422
423
424
425
426
427
428
429 private static void ensureFrameIsPseudoInertial(final Frame frame) {
430
431 if (!frame.isPseudoInertial()) {
432 throw new OrekitException(OrekitMessages.NON_PSEUDO_INERTIAL_FRAME, frame.getName());
433 }
434 }
435
436 }