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