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.io.Serializable;
20 import java.util.Map;
21
22 import org.hipparchus.CalculusFieldElement;
23 import org.hipparchus.analysis.differentiation.Gradient;
24 import org.hipparchus.geometry.euclidean.threed.FieldRotation;
25 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
26 import org.hipparchus.geometry.euclidean.threed.Rotation;
27 import org.hipparchus.geometry.euclidean.threed.RotationConvention;
28 import org.hipparchus.geometry.euclidean.threed.Vector3D;
29 import org.hipparchus.util.FastMath;
30 import org.orekit.errors.OrekitException;
31 import org.orekit.errors.OrekitInternalError;
32 import org.orekit.errors.OrekitMessages;
33 import org.orekit.frames.FieldStaticTransform;
34 import org.orekit.frames.FieldTransform;
35 import org.orekit.frames.StaticTransform;
36 import org.orekit.frames.Transform;
37 import org.orekit.frames.TransformProvider;
38 import org.orekit.time.AbsoluteDate;
39 import org.orekit.time.FieldAbsoluteDate;
40 import org.orekit.time.UT1Scale;
41 import org.orekit.utils.IERSConventions;
42 import org.orekit.utils.ParameterDriver;
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 public class EstimatedEarthFrameProvider implements TransformProvider {
66
67
68 public static final double EARTH_ANGULAR_VELOCITY = 7.292115146706979e-5;
69
70
71 private static final long serialVersionUID = 20170922L;
72
73
74
75
76
77
78
79 private static final double ANGULAR_SCALE = FastMath.scalb(1.0, -22);
80
81
82 private final UT1Scale baseUT1;
83
84
85 private final transient UT1Scale estimatedUT1;
86
87
88 private final transient ParameterDriver primeMeridianOffsetDriver;
89
90
91 private final transient ParameterDriver primeMeridianDriftDriver;
92
93
94 private final transient ParameterDriver polarOffsetXDriver;
95
96
97 private final transient ParameterDriver polarDriftXDriver;
98
99
100 private final transient ParameterDriver polarOffsetYDriver;
101
102
103 private final transient ParameterDriver polarDriftYDriver;
104
105
106
107
108
109
110
111
112
113
114
115 public EstimatedEarthFrameProvider(final UT1Scale baseUT1) {
116
117 this.primeMeridianOffsetDriver = new ParameterDriver("prime-meridian-offset",
118 0.0, ANGULAR_SCALE,
119 -FastMath.PI, FastMath.PI);
120
121 this.primeMeridianDriftDriver = new ParameterDriver("prime-meridian-drift",
122 0.0, ANGULAR_SCALE,
123 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
124
125 this.polarOffsetXDriver = new ParameterDriver("polar-offset-X",
126 0.0, ANGULAR_SCALE,
127 -FastMath.PI, FastMath.PI);
128
129 this.polarDriftXDriver = new ParameterDriver("polar-drift-X",
130 0.0, ANGULAR_SCALE,
131 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
132
133 this.polarOffsetYDriver = new ParameterDriver("polar-offset-Y",
134 0.0, ANGULAR_SCALE,
135 -FastMath.PI, FastMath.PI);
136
137 this.polarDriftYDriver = new ParameterDriver("polar-drift-Y",
138 0.0, ANGULAR_SCALE,
139 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
140
141 this.baseUT1 = baseUT1;
142 this.estimatedUT1 = new EstimatedUT1Scale();
143
144 }
145
146
147
148
149
150
151
152
153
154 public ParameterDriver getPrimeMeridianOffsetDriver() {
155 return primeMeridianOffsetDriver;
156 }
157
158
159
160
161
162
163
164
165
166 public ParameterDriver getPrimeMeridianDriftDriver() {
167 return primeMeridianDriftDriver;
168 }
169
170
171
172
173
174
175
176 public ParameterDriver getPolarOffsetXDriver() {
177 return polarOffsetXDriver;
178 }
179
180
181
182
183
184
185
186 public ParameterDriver getPolarDriftXDriver() {
187 return polarDriftXDriver;
188 }
189
190
191
192
193
194
195
196 public ParameterDriver getPolarOffsetYDriver() {
197 return polarOffsetYDriver;
198 }
199
200
201
202
203
204
205
206 public ParameterDriver getPolarDriftYDriver() {
207 return polarDriftYDriver;
208 }
209
210
211
212
213 public UT1Scale getEstimatedUT1() {
214 return estimatedUT1;
215 }
216
217
218 @Override
219 public Transform getTransform(final AbsoluteDate date) {
220
221
222 final double theta = linearModel(date, primeMeridianOffsetDriver, primeMeridianDriftDriver);
223 final double thetaDot = primeMeridianDriftDriver.getValue();
224 final Transform meridianShift =
225 new Transform(date,
226 new Rotation(Vector3D.PLUS_K, theta, RotationConvention.FRAME_TRANSFORM),
227 new Vector3D(0, 0, thetaDot));
228
229
230 final double xpNeg = -linearModel(date, polarOffsetXDriver, polarDriftXDriver);
231 final double ypNeg = -linearModel(date, polarOffsetYDriver, polarDriftYDriver);
232 final double xpNegDot = -polarDriftXDriver.getValue();
233 final double ypNegDot = -polarDriftYDriver.getValue();
234 final Transform poleShift =
235 new Transform(date,
236 new Transform(date,
237 new Rotation(Vector3D.PLUS_J, xpNeg, RotationConvention.FRAME_TRANSFORM),
238 new Vector3D(0.0, xpNegDot, 0.0)),
239 new Transform(date,
240 new Rotation(Vector3D.PLUS_I, ypNeg, RotationConvention.FRAME_TRANSFORM),
241 new Vector3D(ypNegDot, 0.0, 0.0)));
242
243 return new Transform(date, meridianShift, poleShift);
244
245 }
246
247
248 @Override
249 public StaticTransform getStaticTransform(final AbsoluteDate date) {
250
251
252 final double theta = linearModel(date, primeMeridianOffsetDriver, primeMeridianDriftDriver);
253 final StaticTransform meridianShift = StaticTransform.of(
254 date,
255 new Rotation(Vector3D.PLUS_K, theta, RotationConvention.FRAME_TRANSFORM)
256 );
257
258
259 final double xpNeg = -linearModel(date, polarOffsetXDriver, polarDriftXDriver);
260 final double ypNeg = -linearModel(date, polarOffsetYDriver, polarDriftYDriver);
261 final StaticTransform poleShift = StaticTransform.compose(
262 date,
263 StaticTransform.of(
264 date,
265 new Rotation(Vector3D.PLUS_J, xpNeg, RotationConvention.FRAME_TRANSFORM)),
266 StaticTransform.of(
267 date,
268 new Rotation(Vector3D.PLUS_I, ypNeg, RotationConvention.FRAME_TRANSFORM)));
269
270 return StaticTransform.compose(date, meridianShift, poleShift);
271
272 }
273
274
275 @Override
276 public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
277
278 final T zero = date.getField().getZero();
279
280
281 final T theta = linearModel(date, primeMeridianOffsetDriver, primeMeridianDriftDriver);
282 final T thetaDot = zero.newInstance(primeMeridianDriftDriver.getValue());
283
284
285 final T xpNeg = linearModel(date, polarOffsetXDriver, polarDriftXDriver).negate();
286 final T ypNeg = linearModel(date, polarOffsetYDriver, polarDriftYDriver).negate();
287 final T xpNegDot = zero.subtract(polarDriftXDriver.getValue());
288 final T ypNegDot = zero.subtract(polarDriftYDriver.getValue());
289
290 return getTransform(date, theta, thetaDot, xpNeg, xpNegDot, ypNeg, ypNegDot);
291
292 }
293
294
295 @Override
296 public <T extends CalculusFieldElement<T>> FieldStaticTransform<T> getStaticTransform(final FieldAbsoluteDate<T> date) {
297
298
299 final T theta = linearModel(date, primeMeridianOffsetDriver, primeMeridianDriftDriver);
300 final FieldStaticTransform<T> meridianShift = FieldStaticTransform.of(
301 date,
302 new FieldRotation<>(FieldVector3D.getPlusK(date.getField()), theta, RotationConvention.FRAME_TRANSFORM)
303 );
304
305
306 final T xpNeg = linearModel(date, polarOffsetXDriver, polarDriftXDriver).negate();
307 final T ypNeg = linearModel(date, polarOffsetYDriver, polarDriftYDriver).negate();
308 final FieldStaticTransform<T> poleShift = FieldStaticTransform.compose(
309 date,
310 FieldStaticTransform.of(
311 date,
312 new FieldRotation<>(FieldVector3D.getPlusJ(date.getField()), xpNeg, RotationConvention.FRAME_TRANSFORM)),
313 FieldStaticTransform.of(
314 date,
315 new FieldRotation<>(FieldVector3D.getPlusI(date.getField()), ypNeg, RotationConvention.FRAME_TRANSFORM)));
316
317 return FieldStaticTransform.compose(date, meridianShift, poleShift);
318
319 }
320
321
322
323
324
325
326
327
328 public FieldTransform<Gradient> getTransform(final FieldAbsoluteDate<Gradient> date,
329 final int freeParameters,
330 final Map<String, Integer> indices) {
331
332
333 final Gradient theta = linearModel(freeParameters, date,
334 primeMeridianOffsetDriver, primeMeridianDriftDriver,
335 indices);
336 final Gradient thetaDot = primeMeridianDriftDriver.getValue(freeParameters, indices, date.toAbsoluteDate());
337
338
339 final Gradient xpNeg = linearModel(freeParameters, date,
340 polarOffsetXDriver, polarDriftXDriver, indices).negate();
341 final Gradient ypNeg = linearModel(freeParameters, date,
342 polarOffsetYDriver, polarDriftYDriver, indices).negate();
343 final Gradient xpNegDot = polarDriftXDriver.getValue(freeParameters, indices, date.toAbsoluteDate()).negate();
344 final Gradient ypNegDot = polarDriftYDriver.getValue(freeParameters, indices, date.toAbsoluteDate()).negate();
345
346 return getTransform(date, theta, thetaDot, xpNeg, xpNegDot, ypNeg, ypNegDot);
347
348 }
349
350
351
352
353
354
355
356
357
358
359
360
361 private <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date,
362 final T theta, final T thetaDot,
363 final T xpNeg, final T xpNegDot,
364 final T ypNeg, final T ypNegDot) {
365
366 final T zero = date.getField().getZero();
367 final FieldVector3D<T> plusI = FieldVector3D.getPlusI(date.getField());
368 final FieldVector3D<T> plusJ = FieldVector3D.getPlusJ(date.getField());
369 final FieldVector3D<T> plusK = FieldVector3D.getPlusK(date.getField());
370
371
372 final FieldTransform<T> meridianShift =
373 new FieldTransform<>(date,
374 new FieldRotation<>(plusK, theta, RotationConvention.FRAME_TRANSFORM),
375 new FieldVector3D<>(zero, zero, thetaDot));
376
377
378 final FieldTransform<T> poleShift =
379 new FieldTransform<>(date,
380 new FieldTransform<>(date,
381 new FieldRotation<>(plusJ, xpNeg, RotationConvention.FRAME_TRANSFORM),
382 new FieldVector3D<>(zero, xpNegDot, zero)),
383 new FieldTransform<>(date,
384 new FieldRotation<>(plusI, ypNeg, RotationConvention.FRAME_TRANSFORM),
385 new FieldVector3D<>(ypNegDot, zero, zero)));
386
387 return new FieldTransform<>(date, meridianShift, poleShift);
388
389 }
390
391
392
393
394
395
396
397 private double linearModel(final AbsoluteDate date,
398 final ParameterDriver offsetDriver, final ParameterDriver driftDriver) {
399 if (offsetDriver.getReferenceDate() == null) {
400 throw new OrekitException(OrekitMessages.NO_REFERENCE_DATE_FOR_PARAMETER,
401 offsetDriver.getName());
402 }
403 final double dt = date.durationFrom(offsetDriver.getReferenceDate());
404 final double offset = offsetDriver.getValue();
405 final double drift = driftDriver.getValue();
406 return dt * drift + offset;
407 }
408
409
410
411
412
413
414
415
416 private <T extends CalculusFieldElement<T>> T linearModel(final FieldAbsoluteDate<T> date,
417 final ParameterDriver offsetDriver,
418 final ParameterDriver driftDriver) {
419 if (offsetDriver.getReferenceDate() == null) {
420 throw new OrekitException(OrekitMessages.NO_REFERENCE_DATE_FOR_PARAMETER,
421 offsetDriver.getName());
422 }
423 final T dt = date.durationFrom(offsetDriver.getReferenceDate());
424 final double offset = offsetDriver.getValue();
425 final double drift = driftDriver.getValue();
426 return dt.multiply(drift).add(offset);
427 }
428
429
430
431
432
433
434
435
436
437
438 private Gradient linearModel(final int freeParameters, final FieldAbsoluteDate<Gradient> date,
439 final ParameterDriver offsetDriver, final ParameterDriver driftDriver,
440 final Map<String, Integer> indices) {
441 if (offsetDriver.getReferenceDate() == null) {
442 throw new OrekitException(OrekitMessages.NO_REFERENCE_DATE_FOR_PARAMETER,
443 offsetDriver.getName());
444 }
445 final Gradient dt = date.durationFrom(offsetDriver.getReferenceDate());
446 final Gradient offset = offsetDriver.getValue(freeParameters, indices, date.toAbsoluteDate());
447 final Gradient drift = driftDriver.getValue(freeParameters, indices, date.toAbsoluteDate());
448 return dt.multiply(drift).add(offset);
449 }
450
451
452
453
454
455
456
457
458 private Object writeReplace() {
459 return new DataTransferObject(baseUT1,
460 primeMeridianOffsetDriver.getValue(),
461 primeMeridianDriftDriver.getValue(),
462 polarOffsetXDriver.getValue(),
463 polarDriftXDriver.getValue(),
464 polarOffsetYDriver.getValue(),
465 polarDriftYDriver.getValue());
466 }
467
468
469 private class EstimatedUT1Scale extends UT1Scale {
470
471
472 private static final long serialVersionUID = 20170922L;
473
474
475
476 EstimatedUT1Scale() {
477 super(baseUT1.getEOPHistory(), baseUT1.getUTCScale());
478 }
479
480
481 @Override
482 public <T extends CalculusFieldElement<T>> T offsetFromTAI(final FieldAbsoluteDate<T> date) {
483 final T dut1 = linearModel(date, primeMeridianOffsetDriver, primeMeridianDriftDriver).divide(EARTH_ANGULAR_VELOCITY);
484 return baseUT1.offsetFromTAI(date).add(dut1);
485 }
486
487
488 @Override
489 public double offsetFromTAI(final AbsoluteDate date) {
490 final double dut1 = linearModel(date, primeMeridianOffsetDriver, primeMeridianDriftDriver) / EARTH_ANGULAR_VELOCITY;
491 return baseUT1.offsetFromTAI(date) + dut1;
492 }
493
494
495 @Override
496 public String getName() {
497 return baseUT1.getName() + "/estimated";
498 }
499
500 }
501
502
503 private static class DataTransferObject implements Serializable {
504
505
506 private static final long serialVersionUID = 20171124L;
507
508
509 private final UT1Scale baseUT1;
510
511
512 private final double primeMeridianOffset;
513
514
515 private final double primeMeridianDrift;
516
517
518 private final double polarOffsetX;
519
520
521 private final double polarDriftX;
522
523
524 private final double polarOffsetY;
525
526
527 private final double polarDriftY;
528
529
530
531
532
533
534
535
536
537
538 DataTransferObject(final UT1Scale baseUT1,
539 final double primeMeridianOffset, final double primeMeridianDrift,
540 final double polarOffsetX, final double polarDriftX,
541 final double polarOffsetY, final double polarDriftY) {
542 this.baseUT1 = baseUT1;
543 this.primeMeridianOffset = primeMeridianOffset;
544 this.primeMeridianDrift = primeMeridianDrift;
545 this.polarOffsetX = polarOffsetX;
546 this.polarDriftX = polarDriftX;
547 this.polarOffsetY = polarOffsetY;
548 this.polarDriftY = polarDriftY;
549 }
550
551
552
553
554 private Object readResolve() {
555 try {
556 final EstimatedEarthFrameProvider provider = new EstimatedEarthFrameProvider(baseUT1);
557 provider.getPrimeMeridianOffsetDriver().setValue(primeMeridianOffset);
558 provider.getPrimeMeridianDriftDriver().setValue(primeMeridianDrift);
559 provider.getPolarOffsetXDriver().setValue(polarOffsetX);
560 provider.getPolarDriftXDriver().setValue(polarDriftX);
561 provider.getPolarOffsetYDriver().setValue(polarOffsetY);
562 provider.getPolarDriftYDriver().setValue(polarDriftY);
563 return provider;
564 } catch (OrekitException oe) {
565
566 throw new OrekitInternalError(oe);
567 }
568 }
569
570 }
571
572 }