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