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