1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.orbits;
18
19 import org.hipparchus.analysis.differentiation.UnivariateDerivative1;
20 import org.hipparchus.geometry.euclidean.threed.Vector3D;
21 import org.hipparchus.util.FastMath;
22 import org.hipparchus.util.SinCos;
23 import org.orekit.errors.OrekitException;
24 import org.orekit.errors.OrekitIllegalArgumentException;
25 import org.orekit.errors.OrekitInternalError;
26 import org.orekit.errors.OrekitMessages;
27 import org.orekit.frames.Frame;
28 import org.orekit.frames.KinematicTransform;
29 import org.orekit.time.AbsoluteDate;
30 import org.orekit.time.TimeOffset;
31 import org.orekit.utils.PVCoordinates;
32 import org.orekit.utils.TimeStampedPVCoordinates;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 public class KeplerianOrbit extends Orbit implements PositionAngleBased<KeplerianOrbit> {
75
76
77 private static final String ECCENTRICITY = "eccentricity";
78
79
80 private final double a;
81
82
83 private final double e;
84
85
86 private final double i;
87
88
89 private final double pa;
90
91
92 private final double raan;
93
94
95 private final double cachedAnomaly;
96
97
98 private final double aDot;
99
100
101 private final double eDot;
102
103
104 private final double iDot;
105
106
107 private final double paDot;
108
109
110 private final double raanDot;
111
112
113 private final double cachedAnomalyDot;
114
115
116 private final PositionAngleType cachedPositionAngleType;
117
118
119 private PVCoordinates partialPV;
120
121
122
123
124
125
126
127
128
129
130
131
132 public KeplerianOrbit(final KeplerianParameters keplerianParameters, final Frame frame, final AbsoluteDate date,
133 final double mu)
134 throws IllegalArgumentException {
135 this(keplerianParameters, 0., 0., 0., 0., 0.,
136 computeKeplerianAnomalyDot(keplerianParameters.positionAngleType(), keplerianParameters.a(), keplerianParameters.e(), mu, keplerianParameters.anomaly(), keplerianParameters.positionAngleType()),
137 keplerianParameters.positionAngleType(), frame, date, mu);
138 }
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156 public KeplerianOrbit(final double a, final double e, final double i, final double pa, final double raan,
157 final double anomaly, final PositionAngleType type, final Frame frame,
158 final AbsoluteDate date, final double mu)
159 throws IllegalArgumentException {
160 this(new KeplerianParameters(a, e, i, pa, raan, anomaly, type), frame, date, mu);
161 }
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181 public KeplerianOrbit(final KeplerianParameters keplerianParameters,
182 final double aDot, final double eDot, final double iDot,
183 final double paDot, final double raanDot, final double anomalyDot,
184 final PositionAngleType cachedPositionAngleType,
185 final Frame frame, final AbsoluteDate date, final double mu)
186 throws IllegalArgumentException {
187 super(frame, date, mu);
188 this.cachedPositionAngleType = cachedPositionAngleType;
189
190 this.a = keplerianParameters.a();
191 this.e = keplerianParameters.e();
192 if (a * (1 - e) < 0) {
193 throw new OrekitIllegalArgumentException(OrekitMessages.ORBIT_A_E_MISMATCH_WITH_CONIC_TYPE, a, e);
194 }
195
196
197 checkParameterRangeInclusive(ECCENTRICITY, e, 0.0, Double.POSITIVE_INFINITY);
198
199 this.aDot = aDot;
200 this.eDot = eDot;
201 this.i = keplerianParameters.i();
202 this.iDot = iDot;
203 this.pa = keplerianParameters.pa();
204 this.paDot = paDot;
205 this.raan = keplerianParameters.raan();
206 this.raanDot = raanDot;
207
208 final UnivariateDerivative1 cachedAnomalyUD = initializeCachedAnomaly(keplerianParameters.anomaly(), anomalyDot,
209 keplerianParameters.positionAngleType());
210 this.cachedAnomaly = cachedAnomalyUD.getValue();
211 this.cachedAnomalyDot = cachedAnomalyUD.getFirstDerivative();
212
213
214 if (!isElliptical()) {
215 final double trueAnomaly = getTrueAnomaly();
216 if (1 + e * FastMath.cos(trueAnomaly) <= 0) {
217 final double vMax = FastMath.acos(-1 / e);
218 throw new OrekitIllegalArgumentException(OrekitMessages.ORBIT_ANOMALY_OUT_OF_HYPERBOLIC_RANGE,
219 trueAnomaly, e, -vMax, vMax);
220 }
221 }
222
223 this.partialPV = null;
224
225 }
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250 public KeplerianOrbit(final double a, final double e, final double i,
251 final double pa, final double raan, final double anomaly,
252 final double aDot, final double eDot, final double iDot,
253 final double paDot, final double raanDot, final double anomalyDot,
254 final PositionAngleType type,
255 final Frame frame, final AbsoluteDate date, final double mu)
256 throws IllegalArgumentException {
257 this(new KeplerianParameters(a, e, i, pa, raan, anomaly, type), aDot, eDot, iDot, paDot, raanDot, anomalyDot, type,
258 frame, date, mu);
259 }
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275 public KeplerianOrbit(final TimeStampedPVCoordinates pvCoordinates,
276 final Frame frame, final double mu)
277 throws IllegalArgumentException {
278 this(pvCoordinates, frame, mu, hasNonKeplerianAcceleration(pvCoordinates, mu));
279 }
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296 private KeplerianOrbit(final TimeStampedPVCoordinates pvCoordinates,
297 final Frame frame, final double mu,
298 final boolean reliableAcceleration)
299 throws IllegalArgumentException {
300 super(pvCoordinates, frame, mu);
301
302
303 final KeplerianParametersConverter converter = new KeplerianParametersConverter(mu);
304 cachedPositionAngleType = PositionAngleType.ECCENTRIC;
305 final KeplerianParameters element = converter.toParameters(pvCoordinates, cachedPositionAngleType);
306 a = element.a();
307 e = element.e();
308 i = element.i();
309 raan = element.raan();
310 pa = element.pa();
311 cachedAnomaly = element.anomaly();
312
313
314 checkParameterRangeInclusive(ECCENTRICITY, e, 0.0, Double.POSITIVE_INFINITY);
315
316 partialPV = pvCoordinates;
317
318 if (reliableAcceleration) {
319
320
321 final double[][] jacobian = new double[6][6];
322 getJacobianWrtCartesian(PositionAngleType.MEAN, jacobian);
323
324 final Vector3D pvP = pvCoordinates.getPosition();
325 final double r2 = pvP.getNorm2Sq();
326 final double r = FastMath.sqrt(r2);
327 final Vector3D keplerianAcceleration = new Vector3D(-mu / (r * r2), pvP);
328 final Vector3D pvA = pvCoordinates.getAcceleration();
329 final Vector3D nonKeplerianAcceleration = pvA.subtract(keplerianAcceleration);
330 final double aX = nonKeplerianAcceleration.getX();
331 final double aY = nonKeplerianAcceleration.getY();
332 final double aZ = nonKeplerianAcceleration.getZ();
333 aDot = jacobian[0][3] * aX + jacobian[0][4] * aY + jacobian[0][5] * aZ;
334 eDot = jacobian[1][3] * aX + jacobian[1][4] * aY + jacobian[1][5] * aZ;
335 iDot = jacobian[2][3] * aX + jacobian[2][4] * aY + jacobian[2][5] * aZ;
336 paDot = jacobian[3][3] * aX + jacobian[3][4] * aY + jacobian[3][5] * aZ;
337 raanDot = jacobian[4][3] * aX + jacobian[4][4] * aY + jacobian[4][5] * aZ;
338
339
340
341 final double MDot = getKeplerianMeanMotion() +
342 jacobian[5][3] * aX + jacobian[5][4] * aY + jacobian[5][5] * aZ;
343 final UnivariateDerivative1 eUD = new UnivariateDerivative1(e, eDot);
344 final UnivariateDerivative1 MUD = new UnivariateDerivative1(getMeanAnomaly(), MDot);
345 final UnivariateDerivative1 EUD = (a < 0) ?
346 FieldKeplerianAnomalyUtility.hyperbolicMeanToEccentric(eUD, MUD) :
347 FieldKeplerianAnomalyUtility.ellipticMeanToEccentric(eUD, MUD);
348 cachedAnomalyDot = EUD.getFirstDerivative();
349
350 } else {
351
352
353 aDot = 0.;
354 eDot = 0.;
355 iDot = 0.;
356 paDot = 0.;
357 raanDot = 0.;
358 cachedAnomalyDot = computeKeplerianAnomalyDot(cachedPositionAngleType, a, e, mu, cachedAnomaly, cachedPositionAngleType);
359 }
360
361 }
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378 public KeplerianOrbit(final PVCoordinates pvCoordinates,
379 final Frame frame, final AbsoluteDate date, final double mu)
380 throws IllegalArgumentException {
381 this(new TimeStampedPVCoordinates(date, pvCoordinates), frame, mu);
382 }
383
384
385
386
387 public KeplerianOrbit(final Orbit op) {
388 this(op.getPVCoordinates(), op.getFrame(), op.getMu(), op.hasNonKeplerianAcceleration());
389 }
390
391
392 @Override
393 public boolean hasNonKeplerianAcceleration() {
394 return aDot != 0. || eDot != 0. || paDot != 0. || iDot != 0. || raanDot != 0. ||
395 FastMath.abs(cachedAnomalyDot - computeKeplerianAnomalyDot(cachedPositionAngleType, a, e, getMu(), cachedAnomaly, cachedPositionAngleType)) > TOLERANCE_POSITION_ANGLE_RATE;
396 }
397
398
399 @Override
400 public OrbitParamsType getType() {
401 return OrbitParamsType.KEPLERIAN;
402 }
403
404
405 @Override
406 public AbstractOrbitFactory<KeplerianOrbit> factory(final PositionAngleType positionAngleType,
407 final double positionScale) {
408 return new KeplerianOrbitFactory(this, positionScale, positionAngleType);
409 }
410
411
412 @Override
413 public double getA() {
414 return a;
415 }
416
417
418 @Override
419 public double getADot() {
420 return aDot;
421 }
422
423
424 @Override
425 public double getE() {
426 return e;
427 }
428
429
430 @Override
431 public double getEDot() {
432 return eDot;
433 }
434
435
436 @Override
437 public double getI() {
438 return i;
439 }
440
441
442 @Override
443 public double getIDot() {
444 return iDot;
445 }
446
447
448
449
450 public double getPeriapsisArgument() {
451 return pa;
452 }
453
454
455
456
457
458
459
460
461 public double getPeriapsisArgumentDot() {
462 return paDot;
463 }
464
465
466
467
468 public double getRightAscensionOfAscendingNode() {
469 return raan;
470 }
471
472
473
474
475
476
477
478
479 public double getRightAscensionOfAscendingNodeDot() {
480 return raanDot;
481 }
482
483
484
485
486 public double getTrueAnomaly() {
487 return getAnomaly(PositionAngleType.TRUE);
488 }
489
490
491
492
493 public double getTrueAnomalyDot() {
494 return switch (cachedPositionAngleType) {
495 case MEAN -> {
496 final UnivariateDerivative1 eUD = new UnivariateDerivative1(e, eDot);
497 final UnivariateDerivative1 MUD = new UnivariateDerivative1(cachedAnomaly, cachedAnomalyDot);
498 final UnivariateDerivative1 vUD = (a < 0) ?
499 FieldKeplerianAnomalyUtility.hyperbolicMeanToTrue(eUD, MUD) :
500 FieldKeplerianAnomalyUtility.ellipticMeanToTrue(eUD, MUD);
501 yield vUD.getFirstDerivative();
502 }
503
504 case TRUE -> cachedAnomalyDot;
505
506 case ECCENTRIC -> {
507 final UnivariateDerivative1 eUD2 = new UnivariateDerivative1(e, eDot);
508 final UnivariateDerivative1 EUD = new UnivariateDerivative1(cachedAnomaly, cachedAnomalyDot);
509 final UnivariateDerivative1 vUD2 = (a < 0) ?
510 FieldKeplerianAnomalyUtility.hyperbolicEccentricToTrue(eUD2, EUD) :
511 FieldKeplerianAnomalyUtility.ellipticEccentricToTrue(eUD2, EUD);
512 yield vUD2.getFirstDerivative();
513 }
514 };
515 }
516
517
518
519
520 public double getEccentricAnomaly() {
521 return getAnomaly(PositionAngleType.ECCENTRIC);
522 }
523
524
525
526
527
528 public double getEccentricAnomalyDot() {
529 return switch (cachedPositionAngleType) {
530 case ECCENTRIC -> cachedAnomalyDot;
531
532 case TRUE -> {
533 final UnivariateDerivative1 eUD = new UnivariateDerivative1(e, eDot);
534 final UnivariateDerivative1 vUD = new UnivariateDerivative1(cachedAnomaly, cachedAnomalyDot);
535 final UnivariateDerivative1 EUD = (a < 0) ?
536 FieldKeplerianAnomalyUtility.hyperbolicTrueToEccentric(eUD, vUD) :
537 FieldKeplerianAnomalyUtility.ellipticTrueToEccentric(eUD, vUD);
538 yield EUD.getFirstDerivative();
539 }
540
541 case MEAN -> {
542 final UnivariateDerivative1 eUD2 = new UnivariateDerivative1(e, eDot);
543 final UnivariateDerivative1 MUD = new UnivariateDerivative1(cachedAnomaly, cachedAnomalyDot);
544 final UnivariateDerivative1 EUD2 = (a < 0) ?
545 FieldKeplerianAnomalyUtility.hyperbolicMeanToEccentric(eUD2, MUD) :
546 FieldKeplerianAnomalyUtility.ellipticMeanToEccentric(eUD2, MUD);
547 yield EUD2.getFirstDerivative();
548 }
549 };
550 }
551
552
553
554
555 public double getMeanAnomaly() {
556 return getAnomaly(PositionAngleType.MEAN);
557 }
558
559
560
561
562
563 public double getMeanAnomalyDot() {
564 return switch (cachedPositionAngleType) {
565 case MEAN -> cachedAnomalyDot;
566
567 case ECCENTRIC -> {
568 final UnivariateDerivative1 eUD = new UnivariateDerivative1(e, eDot);
569 final UnivariateDerivative1 EUD = new UnivariateDerivative1(cachedAnomaly, cachedAnomalyDot);
570 final UnivariateDerivative1 MUD = (a < 0) ?
571 FieldKeplerianAnomalyUtility.hyperbolicEccentricToMean(eUD, EUD) :
572 FieldKeplerianAnomalyUtility.ellipticEccentricToMean(eUD, EUD);
573 yield MUD.getFirstDerivative();
574 }
575
576 case TRUE -> {
577 final UnivariateDerivative1 eUD2 = new UnivariateDerivative1(e, eDot);
578 final UnivariateDerivative1 vUD = new UnivariateDerivative1(cachedAnomaly, cachedAnomalyDot);
579 final UnivariateDerivative1 MUD2 = (a < 0) ?
580 FieldKeplerianAnomalyUtility.hyperbolicTrueToMean(eUD2, vUD) :
581 FieldKeplerianAnomalyUtility.ellipticTrueToMean(eUD2, vUD);
582 yield MUD2.getFirstDerivative();
583 }
584 };
585 }
586
587
588
589
590
591 public double getAnomaly(final PositionAngleType type) {
592 return getKeplerianParameters().withPositionAngleType(type).anomaly();
593 }
594
595
596
597
598
599
600 public double getAnomalyDot(final PositionAngleType type) {
601 return switch (type) {
602 case MEAN -> getMeanAnomalyDot();
603 case ECCENTRIC -> getEccentricAnomalyDot();
604 case TRUE -> getTrueAnomalyDot();
605 };
606 }
607
608
609
610
611
612
613 public KeplerianParameters getKeplerianParameters() {
614 return new KeplerianParameters(a, e, i, pa, raan, cachedAnomaly, cachedPositionAngleType);
615 }
616
617
618 @Override
619 public double getEquinoctialEx() {
620 return e * FastMath.cos(pa + raan);
621 }
622
623
624 @Override
625 public double getEquinoctialExDot() {
626 if (!hasNonKeplerianAcceleration()) {
627 return 0.;
628 }
629 final double paPraan = pa + raan;
630 final SinCos sc = FastMath.sinCos(paPraan);
631 return eDot * sc.cos() - e * sc.sin() * (paDot + raanDot);
632 }
633
634
635 @Override
636 public double getEquinoctialEy() {
637 return e * FastMath.sin(pa + raan);
638 }
639
640
641 @Override
642 public double getEquinoctialEyDot() {
643 if (!hasNonKeplerianAcceleration()) {
644 return 0.;
645 }
646 final double paPraan = pa + raan;
647 final SinCos sc = FastMath.sinCos(paPraan);
648 return eDot * sc.sin() + e * sc.cos() * (paDot + raanDot);
649 }
650
651
652 @Override
653 public double getHx() {
654
655 if (FastMath.abs(i - FastMath.PI) < 1.0e-10) {
656 return Double.NaN;
657 }
658 return FastMath.cos(raan) * FastMath.tan(0.5 * i);
659 }
660
661
662 @Override
663 public double getHxDot() {
664
665 if (FastMath.abs(i - FastMath.PI) < 1.0e-10) {
666 return Double.NaN;
667 }
668 if (!hasNonKeplerianAcceleration()) {
669 return 0.;
670 }
671 final SinCos sc = FastMath.sinCos(raan);
672 final double tan = FastMath.tan(0.5 * i);
673 return 0.5 * (1 + tan * tan) * sc.cos() * iDot - tan * sc.sin() * raanDot;
674 }
675
676
677 @Override
678 public double getHy() {
679
680 if (FastMath.abs(i - FastMath.PI) < 1.0e-10) {
681 return Double.NaN;
682 }
683 return FastMath.sin(raan) * FastMath.tan(0.5 * i);
684 }
685
686
687 @Override
688 public double getHyDot() {
689
690 if (FastMath.abs(i - FastMath.PI) < 1.0e-10) {
691 return Double.NaN;
692 }
693 if (!hasNonKeplerianAcceleration()) {
694 return 0.;
695 }
696 final SinCos sc = FastMath.sinCos(raan);
697 final double tan = FastMath.tan(0.5 * i);
698 return 0.5 * (1 + tan * tan) * sc.sin() * iDot + tan * sc.cos() * raanDot;
699 }
700
701
702 @Override
703 public double getLv() {
704 return pa + raan + getTrueAnomaly();
705 }
706
707
708 @Override
709 public double getLvDot() {
710 return paDot + raanDot + getTrueAnomalyDot();
711 }
712
713
714 @Override
715 public double getLE() {
716 return pa + raan + getEccentricAnomaly();
717 }
718
719
720 @Override
721 public double getLEDot() {
722 return paDot + raanDot + getEccentricAnomalyDot();
723 }
724
725
726 @Override
727 public double getLM() {
728 return pa + raan + getMeanAnomaly();
729 }
730
731
732 @Override
733 public double getLMDot() {
734 return paDot + raanDot + getMeanAnomalyDot();
735 }
736
737
738
739
740
741
742
743
744 private UnivariateDerivative1 initializeCachedAnomaly(final double anomaly, final double anomalyDot,
745 final PositionAngleType inputType) {
746 if (cachedPositionAngleType == inputType) {
747 return new UnivariateDerivative1(anomaly, anomalyDot);
748
749 } else {
750 final UnivariateDerivative1 eUD = new UnivariateDerivative1(e, eDot);
751 final UnivariateDerivative1 anomalyUD = new UnivariateDerivative1(anomaly, anomalyDot);
752
753 if (a < 0) {
754 switch (cachedPositionAngleType) {
755 case MEAN:
756 if (inputType == PositionAngleType.ECCENTRIC) {
757 return FieldKeplerianAnomalyUtility.hyperbolicEccentricToMean(eUD, anomalyUD);
758 } else {
759 return FieldKeplerianAnomalyUtility.hyperbolicTrueToMean(eUD, anomalyUD);
760 }
761
762 case ECCENTRIC:
763 if (inputType == PositionAngleType.MEAN) {
764 return FieldKeplerianAnomalyUtility.hyperbolicMeanToEccentric(eUD, anomalyUD);
765 } else {
766 return FieldKeplerianAnomalyUtility.hyperbolicTrueToEccentric(eUD, anomalyUD);
767 }
768
769 case TRUE:
770 if (inputType == PositionAngleType.MEAN) {
771 return FieldKeplerianAnomalyUtility.hyperbolicMeanToTrue(eUD, anomalyUD);
772 } else {
773 return FieldKeplerianAnomalyUtility.hyperbolicEccentricToTrue(eUD, anomalyUD);
774 }
775
776 default:
777 break;
778 }
779
780 } else {
781 switch (cachedPositionAngleType) {
782 case MEAN:
783 if (inputType == PositionAngleType.ECCENTRIC) {
784 return FieldKeplerianAnomalyUtility.ellipticEccentricToMean(eUD, anomalyUD);
785 } else {
786 return FieldKeplerianAnomalyUtility.ellipticTrueToMean(eUD, anomalyUD);
787 }
788
789 case ECCENTRIC:
790 if (inputType == PositionAngleType.MEAN) {
791 return FieldKeplerianAnomalyUtility.ellipticMeanToEccentric(eUD, anomalyUD);
792 } else {
793 return FieldKeplerianAnomalyUtility.ellipticTrueToEccentric(eUD, anomalyUD);
794 }
795
796 case TRUE:
797 if (inputType == PositionAngleType.MEAN) {
798 return FieldKeplerianAnomalyUtility.ellipticMeanToTrue(eUD, anomalyUD);
799 } else {
800 return FieldKeplerianAnomalyUtility.ellipticEccentricToTrue(eUD, anomalyUD);
801 }
802
803 default:
804 break;
805 }
806
807 }
808 throw new OrekitInternalError(null);
809 }
810
811 }
812
813
814
815 private void computePVWithoutA() {
816
817 if (partialPV != null) {
818
819 return;
820 }
821
822 final KeplerianParametersConverter converter = new KeplerianParametersConverter(getMu());
823 partialPV = converter.toCartesian(getKeplerianParameters());
824
825 }
826
827
828 @Override
829 protected Vector3D initPosition() {
830
831 final Vector3D[] axes = KeplerianParametersConverter.referenceAxes(i, pa, raan);
832
833 if (isElliptical()) {
834
835
836
837
838 final double uME2 = (1 - e) * (1 + e);
839 final double s1Me2 = FastMath.sqrt(uME2);
840 final SinCos scE = FastMath.sinCos(getEccentricAnomaly());
841 final double cosE = scE.cos();
842 final double sinE = scE.sin();
843
844 return new Vector3D(a * (cosE - e), axes[0], a * sinE * s1Me2, axes[1]);
845
846 } else {
847
848
849
850
851 final SinCos scV = FastMath.sinCos(getTrueAnomaly());
852 final double sinV = scV.sin();
853 final double cosV = scV.cos();
854 final double f = a * (1 - e * e);
855 final double posFactor = f / (1 + e * cosV);
856
857 return new Vector3D(posFactor * cosV, axes[0], posFactor * sinV, axes[1]);
858
859 }
860
861 }
862
863
864 @Override
865 protected TimeStampedPVCoordinates initPVCoordinates() {
866
867
868 computePVWithoutA();
869
870
871 final double r2 = partialPV.getPosition().getNorm2Sq();
872 final Vector3D keplerianAcceleration = new Vector3D(-getMu() / (r2 * FastMath.sqrt(r2)), partialPV.getPosition());
873 final Vector3D acceleration = hasNonKeplerianAcceleration() ?
874 keplerianAcceleration.add(nonKeplerianAcceleration()) :
875 keplerianAcceleration;
876
877 return new TimeStampedPVCoordinates(getDate(), partialPV.getPosition(), partialPV.getVelocity(), acceleration);
878
879 }
880
881
882 @Override
883 public KeplerianOrbit inFrame(final Frame inertialFrame) {
884 final PVCoordinates pvCoordinates;
885 if (hasNonKeplerianAcceleration()) {
886 pvCoordinates = getPVCoordinates(inertialFrame);
887 } else {
888 final KinematicTransform transform = getFrame().getKinematicTransformTo(inertialFrame, getDate());
889 pvCoordinates = transform.transformOnlyPV(getPVCoordinates());
890 }
891 final KeplerianOrbit keplerianOrbit = new KeplerianOrbit(pvCoordinates, inertialFrame, getDate(), getMu());
892 if (keplerianOrbit.getCachedPositionAngleType() == getCachedPositionAngleType()) {
893 return keplerianOrbit;
894 } else {
895 return keplerianOrbit.withCachedPositionAngleType(getCachedPositionAngleType());
896 }
897 }
898
899
900 @Override
901 public KeplerianOrbit withCachedPositionAngleType(final PositionAngleType positionAngleType) {
902 return new KeplerianOrbit(a, e, i, pa, raan, getAnomaly(positionAngleType), aDot, eDot, iDot, paDot, raanDot,
903 getAnomalyDot(positionAngleType), positionAngleType, getFrame(), getDate(), getMu());
904 }
905
906
907 @Override
908 public KeplerianOrbit shiftedBy(final double dt) {
909 return shiftedBy(new TimeOffset(dt));
910 }
911
912
913 @Override
914 public KeplerianOrbit shiftedBy(final TimeOffset dt) {
915
916 final double dtS = dt.toDouble();
917
918
919 final KeplerianParameters shiftedElements = new KeplerianParameters(a, e, i, pa, raan, getMeanAnomaly() + getKeplerianMeanMotion() * dtS,
920 PositionAngleType.MEAN).withPositionAngleType(cachedPositionAngleType);
921 final KeplerianOrbit keplerianShifted = new KeplerianOrbit(shiftedElements, getFrame(),
922 getDate().shiftedBy(dt), getMu());
923
924 if (dtS != 0. && hasNonKeplerianAcceleration()) {
925
926 return new KeplerianOrbit(new TimeStampedPVCoordinates(keplerianShifted.getDate(),
927 shiftPVNonKeplerian(keplerianShifted.getPVCoordinates(), dt.toDouble())),
928 keplerianShifted.getFrame(), keplerianShifted.getMu());
929
930 } else {
931
932 return keplerianShifted;
933 }
934
935 }
936
937
938 @Override
939 protected KeplerianOrbit keplerianShiftedBy(final double dt) {
940 return new KeplerianOrbit(a, e, i, pa, raan, getMeanAnomaly() + dt * getKeplerianMeanMotion(),
941 PositionAngleType.MEAN, getFrame(), getDate().shiftedBy(dt), getMu());
942 }
943
944
945 @Override
946 protected double[][] computeJacobianMeanWrtCartesian() {
947 if (isElliptical()) {
948 return computeJacobianMeanWrtCartesianElliptical();
949 } else {
950 return computeJacobianMeanWrtCartesianHyperbolic();
951 }
952 }
953
954
955
956
957
958
959
960
961
962 private double[][] computeJacobianMeanWrtCartesianElliptical() {
963
964 final double[][] jacobian = new double[6][6];
965
966
967 computePVWithoutA();
968 final Vector3D position = partialPV.getPosition();
969 final Vector3D velocity = partialPV.getVelocity();
970 final Vector3D momentum = partialPV.getMomentum();
971 final double v2 = velocity.getNorm2Sq();
972 final double r2 = position.getNorm2Sq();
973 final double r = FastMath.sqrt(r2);
974 final double r3 = r * r2;
975
976 final double px = position.getX();
977 final double py = position.getY();
978 final double pz = position.getZ();
979 final double vx = velocity.getX();
980 final double vy = velocity.getY();
981 final double vz = velocity.getZ();
982 final double mx = momentum.getX();
983 final double my = momentum.getY();
984 final double mz = momentum.getZ();
985
986 final double mu = getMu();
987 final double sqrtMuA = FastMath.sqrt(a * mu);
988 final double sqrtAoMu = FastMath.sqrt(a / mu);
989 final double a2 = a * a;
990 final double twoA = 2 * a;
991 final double rOnA = r / a;
992
993 final double oMe2 = 1 - e * e;
994 final double epsilon = FastMath.sqrt(oMe2);
995 final double sqrtRec = 1 / epsilon;
996
997 final SinCos scI = FastMath.sinCos(i);
998 final SinCos scPA = FastMath.sinCos(pa);
999 final double cosI = scI.cos();
1000 final double sinI = scI.sin();
1001 final double cosPA = scPA.cos();
1002 final double sinPA = scPA.sin();
1003
1004 final double pv = Vector3D.dotProduct(position, velocity);
1005 final double cosE = (a - r) / (a * e);
1006 final double sinE = pv / (e * sqrtMuA);
1007
1008
1009 final Vector3D vectorAR = new Vector3D(2 * a2 / r3, position);
1010 final Vector3D vectorARDot = velocity.scalarMultiply(2 * a2 / mu);
1011 fillHalfRow(1, vectorAR, jacobian[0], 0);
1012 fillHalfRow(1, vectorARDot, jacobian[0], 3);
1013
1014
1015 final double factorER3 = pv / twoA;
1016 final Vector3D vectorER = new Vector3D(cosE * v2 / (r * mu), position,
1017 sinE / sqrtMuA, velocity,
1018 -factorER3 * sinE / sqrtMuA, vectorAR);
1019 final Vector3D vectorERDot = new Vector3D(sinE / sqrtMuA, position,
1020 cosE * 2 * r / mu, velocity,
1021 -factorER3 * sinE / sqrtMuA, vectorARDot);
1022 fillHalfRow(1, vectorER, jacobian[1], 0);
1023 fillHalfRow(1, vectorERDot, jacobian[1], 3);
1024
1025
1026 final double coefE = cosE / (e * sqrtMuA);
1027 final Vector3D vectorEAnR =
1028 new Vector3D(-sinE * v2 / (e * r * mu), position, coefE, velocity,
1029 -factorER3 * coefE, vectorAR);
1030
1031
1032 final Vector3D vectorEAnRDot =
1033 new Vector3D(-sinE * 2 * r / (e * mu), velocity, coefE, position,
1034 -factorER3 * coefE, vectorARDot);
1035
1036
1037 final double s1 = -sinE * pz / r - cosE * vz * sqrtAoMu;
1038 final double s2 = -cosE * pz / r3;
1039 final double s3 = -sinE * vz / (2 * sqrtMuA);
1040 final double t1 = sqrtRec * (cosE * pz / r - sinE * vz * sqrtAoMu);
1041 final double t2 = sqrtRec * (-sinE * pz / r3);
1042 final double t3 = sqrtRec * (cosE - e) * vz / (2 * sqrtMuA);
1043 final double t4 = sqrtRec * (e * sinI * cosPA * sqrtRec - vz * sqrtAoMu);
1044 final Vector3D s = new Vector3D(cosE / r, Vector3D.PLUS_K,
1045 s1, vectorEAnR,
1046 s2, position,
1047 s3, vectorAR);
1048 final Vector3D sDot = new Vector3D(-sinE * sqrtAoMu, Vector3D.PLUS_K,
1049 s1, vectorEAnRDot,
1050 s3, vectorARDot);
1051 final Vector3D t =
1052 new Vector3D(sqrtRec * sinE / r, Vector3D.PLUS_K).add(new Vector3D(t1, vectorEAnR,
1053 t2, position,
1054 t3, vectorAR,
1055 t4, vectorER));
1056 final Vector3D tDot = new Vector3D(sqrtRec * (cosE - e) * sqrtAoMu, Vector3D.PLUS_K,
1057 t1, vectorEAnRDot,
1058 t3, vectorARDot,
1059 t4, vectorERDot);
1060
1061
1062 final double factorI1 = -sinI * sqrtRec / sqrtMuA;
1063 final double i1 = factorI1;
1064 final double i2 = -factorI1 * mz / twoA;
1065 final double i3 = factorI1 * mz * e / oMe2;
1066 final double i4 = cosI * sinPA;
1067 final double i5 = cosI * cosPA;
1068 fillHalfRow(i1, new Vector3D(vy, -vx, 0), i2, vectorAR, i3, vectorER, i4, s, i5, t,
1069 jacobian[2], 0);
1070 fillHalfRow(i1, new Vector3D(-py, px, 0), i2, vectorARDot, i3, vectorERDot, i4, sDot, i5, tDot,
1071 jacobian[2], 3);
1072
1073
1074 fillHalfRow(cosPA / sinI, s, -sinPA / sinI, t, jacobian[3], 0);
1075 fillHalfRow(cosPA / sinI, sDot, -sinPA / sinI, tDot, jacobian[3], 3);
1076
1077
1078 final double factorRaanR = 1 / (mu * a * oMe2 * sinI * sinI);
1079 fillHalfRow(-factorRaanR * my, new Vector3D( 0, vz, -vy),
1080 factorRaanR * mx, new Vector3D(-vz, 0, vx),
1081 jacobian[4], 0);
1082 fillHalfRow(-factorRaanR * my, new Vector3D( 0, -pz, py),
1083 factorRaanR * mx, new Vector3D(pz, 0, -px),
1084 jacobian[4], 3);
1085
1086
1087 fillHalfRow(rOnA, vectorEAnR, -sinE, vectorER, jacobian[5], 0);
1088 fillHalfRow(rOnA, vectorEAnRDot, -sinE, vectorERDot, jacobian[5], 3);
1089
1090 return jacobian;
1091
1092 }
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102 private double[][] computeJacobianMeanWrtCartesianHyperbolic() {
1103
1104 final double[][] jacobian = new double[6][6];
1105
1106
1107 computePVWithoutA();
1108 final Vector3D position = partialPV.getPosition();
1109 final Vector3D velocity = partialPV.getVelocity();
1110 final Vector3D momentum = partialPV.getMomentum();
1111 final double r2 = position.getNorm2Sq();
1112 final double r = FastMath.sqrt(r2);
1113 final double r3 = r * r2;
1114
1115 final double x = position.getX();
1116 final double y = position.getY();
1117 final double z = position.getZ();
1118 final double vx = velocity.getX();
1119 final double vy = velocity.getY();
1120 final double vz = velocity.getZ();
1121 final double mx = momentum.getX();
1122 final double my = momentum.getY();
1123 final double mz = momentum.getZ();
1124
1125 final double mu = getMu();
1126 final double absA = -a;
1127 final double sqrtMuA = FastMath.sqrt(absA * mu);
1128 final double a2 = a * a;
1129 final double rOa = r / absA;
1130
1131 final SinCos scI = FastMath.sinCos(i);
1132 final double cosI = scI.cos();
1133 final double sinI = scI.sin();
1134
1135 final double pv = Vector3D.dotProduct(position, velocity);
1136
1137
1138 final Vector3D vectorAR = new Vector3D(-2 * a2 / r3, position);
1139 final Vector3D vectorARDot = velocity.scalarMultiply(-2 * a2 / mu);
1140 fillHalfRow(-1, vectorAR, jacobian[0], 0);
1141 fillHalfRow(-1, vectorARDot, jacobian[0], 3);
1142
1143
1144 final double m = momentum.getNorm();
1145 final double oOm = 1 / m;
1146 final Vector3D dcXP = new Vector3D( 0, vz, -vy);
1147 final Vector3D dcYP = new Vector3D(-vz, 0, vx);
1148 final Vector3D dcZP = new Vector3D( vy, -vx, 0);
1149 final Vector3D dcXV = new Vector3D( 0, -z, y);
1150 final Vector3D dcYV = new Vector3D( z, 0, -x);
1151 final Vector3D dcZV = new Vector3D( -y, x, 0);
1152 final Vector3D dCP = new Vector3D(mx * oOm, dcXP, my * oOm, dcYP, mz * oOm, dcZP);
1153 final Vector3D dCV = new Vector3D(mx * oOm, dcXV, my * oOm, dcYV, mz * oOm, dcZV);
1154
1155
1156 final double mOMu = m / mu;
1157 final Vector3D dpP = new Vector3D(2 * mOMu, dCP);
1158 final Vector3D dpV = new Vector3D(2 * mOMu, dCV);
1159
1160
1161 final double p = m * mOMu;
1162 final double moO2ae = 1 / (2 * absA * e);
1163 final double m2OaMu = -p / absA;
1164 fillHalfRow(moO2ae, dpP, m2OaMu * moO2ae, vectorAR, jacobian[1], 0);
1165 fillHalfRow(moO2ae, dpV, m2OaMu * moO2ae, vectorARDot, jacobian[1], 3);
1166
1167
1168 final double cI1 = 1 / (m * sinI);
1169 final double cI2 = cosI * cI1;
1170 fillHalfRow(cI2, dCP, -cI1, dcZP, jacobian[2], 0);
1171 fillHalfRow(cI2, dCV, -cI1, dcZV, jacobian[2], 3);
1172
1173
1174 final double cP1 = y * oOm;
1175 final double cP2 = -x * oOm;
1176 final double cP3 = -(mx * cP1 + my * cP2);
1177 final double cP4 = cP3 * oOm;
1178 final double cP5 = -1 / (r2 * sinI * sinI);
1179 final double cP6 = z * cP5;
1180 final double cP7 = cP3 * cP5;
1181 final Vector3D dacP = new Vector3D(cP1, dcXP, cP2, dcYP, cP4, dCP, oOm, new Vector3D(-my, mx, 0));
1182 final Vector3D dacV = new Vector3D(cP1, dcXV, cP2, dcYV, cP4, dCV);
1183 final Vector3D dpoP = new Vector3D(cP6, dacP, cP7, Vector3D.PLUS_K);
1184 final Vector3D dpoV = new Vector3D(cP6, dacV);
1185
1186 final double re2 = r2 * e * e;
1187 final double recOre2 = (p - r) / re2;
1188 final double resOre2 = (pv * mOMu) / re2;
1189 final Vector3D dreP = new Vector3D(mOMu, velocity, pv / mu, dCP);
1190 final Vector3D dreV = new Vector3D(mOMu, position, pv / mu, dCV);
1191 final Vector3D davP = new Vector3D(-resOre2, dpP, recOre2, dreP, resOre2 / r, position);
1192 final Vector3D davV = new Vector3D(-resOre2, dpV, recOre2, dreV);
1193 fillHalfRow(1, dpoP, -1, davP, jacobian[3], 0);
1194 fillHalfRow(1, dpoV, -1, davV, jacobian[3], 3);
1195
1196
1197 final double cO0 = cI1 * cI1;
1198 final double cO1 = mx * cO0;
1199 final double cO2 = -my * cO0;
1200 fillHalfRow(cO1, dcYP, cO2, dcXP, jacobian[4], 0);
1201 fillHalfRow(cO1, dcYV, cO2, dcXV, jacobian[4], 3);
1202
1203
1204 final double s2a = pv / (2 * absA);
1205 final double oObux = 1 / FastMath.sqrt(m * m + mu * absA);
1206 final double scasbu = pv * oObux;
1207 final Vector3D dauP = new Vector3D(1 / sqrtMuA, velocity, -s2a / sqrtMuA, vectorAR);
1208 final Vector3D dauV = new Vector3D(1 / sqrtMuA, position, -s2a / sqrtMuA, vectorARDot);
1209 final Vector3D dbuP = new Vector3D(oObux * mu / 2, vectorAR, m * oObux, dCP);
1210 final Vector3D dbuV = new Vector3D(oObux * mu / 2, vectorARDot, m * oObux, dCV);
1211 final Vector3D dcuP = new Vector3D(oObux, velocity, -scasbu * oObux, dbuP);
1212 final Vector3D dcuV = new Vector3D(oObux, position, -scasbu * oObux, dbuV);
1213 fillHalfRow(1, dauP, -e / (1 + rOa), dcuP, jacobian[5], 0);
1214 fillHalfRow(1, dauV, -e / (1 + rOa), dcuV, jacobian[5], 3);
1215
1216 return jacobian;
1217
1218 }
1219
1220
1221 @Override
1222 protected double[][] computeJacobianEccentricWrtCartesian() {
1223 if (isElliptical()) {
1224 return computeJacobianEccentricWrtCartesianElliptical();
1225 } else {
1226 return computeJacobianEccentricWrtCartesianHyperbolic();
1227 }
1228 }
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238 private double[][] computeJacobianEccentricWrtCartesianElliptical() {
1239
1240
1241 final double[][] jacobian = computeJacobianMeanWrtCartesianElliptical();
1242
1243
1244
1245
1246
1247 final SinCos scE = FastMath.sinCos(getEccentricAnomaly());
1248 final double aOr = 1 / (1 - e * scE.cos());
1249
1250
1251 final double[] eRow = jacobian[1];
1252 final double[] anomalyRow = jacobian[5];
1253 for (int j = 0; j < anomalyRow.length; ++j) {
1254 anomalyRow[j] = aOr * (anomalyRow[j] + scE.sin() * eRow[j]);
1255 }
1256
1257 return jacobian;
1258
1259 }
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269 private double[][] computeJacobianEccentricWrtCartesianHyperbolic() {
1270
1271
1272 final double[][] jacobian = computeJacobianMeanWrtCartesianHyperbolic();
1273
1274
1275
1276
1277
1278 final double H = getEccentricAnomaly();
1279 final double coshH = FastMath.cosh(H);
1280 final double sinhH = FastMath.sinh(H);
1281 final double absaOr = 1 / (e * coshH - 1);
1282
1283
1284 final double[] eRow = jacobian[1];
1285 final double[] anomalyRow = jacobian[5];
1286 for (int j = 0; j < anomalyRow.length; ++j) {
1287 anomalyRow[j] = absaOr * (anomalyRow[j] - sinhH * eRow[j]);
1288 }
1289
1290 return jacobian;
1291
1292 }
1293
1294
1295 @Override
1296 protected double[][] computeJacobianTrueWrtCartesian() {
1297 if (isElliptical()) {
1298 return computeJacobianTrueWrtCartesianElliptical();
1299 } else {
1300 return computeJacobianTrueWrtCartesianHyperbolic();
1301 }
1302 }
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312 private double[][] computeJacobianTrueWrtCartesianElliptical() {
1313
1314
1315 final double[][] jacobian = computeJacobianEccentricWrtCartesianElliptical();
1316
1317
1318
1319
1320
1321
1322 final double e2 = e * e;
1323 final double oMe2 = 1 - e2;
1324 final double epsilon = FastMath.sqrt(oMe2);
1325 final SinCos scE = FastMath.sinCos(getEccentricAnomaly());
1326 final double aOr = 1 / (1 - e * scE.cos());
1327 final double aFactor = epsilon * aOr;
1328 final double eFactor = scE.sin() * aOr / epsilon;
1329
1330
1331 final double[] eRow = jacobian[1];
1332 final double[] anomalyRow = jacobian[5];
1333 for (int j = 0; j < anomalyRow.length; ++j) {
1334 anomalyRow[j] = aFactor * anomalyRow[j] + eFactor * eRow[j];
1335 }
1336
1337 return jacobian;
1338
1339 }
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349 private double[][] computeJacobianTrueWrtCartesianHyperbolic() {
1350
1351
1352 final double[][] jacobian = computeJacobianEccentricWrtCartesianHyperbolic();
1353
1354
1355
1356
1357
1358
1359 final double e2 = e * e;
1360 final double e2Mo = e2 - 1;
1361 final double epsilon = FastMath.sqrt(e2Mo);
1362 final double H = getEccentricAnomaly();
1363 final double coshH = FastMath.cosh(H);
1364 final double sinhH = FastMath.sinh(H);
1365 final double aOr = 1 / (e * coshH - 1);
1366 final double aFactor = epsilon * aOr;
1367 final double eFactor = sinhH * aOr / epsilon;
1368
1369
1370 final double[] eRow = jacobian[1];
1371 final double[] anomalyRow = jacobian[5];
1372 for (int j = 0; j < anomalyRow.length; ++j) {
1373 anomalyRow[j] = aFactor * anomalyRow[j] - eFactor * eRow[j];
1374 }
1375
1376 return jacobian;
1377
1378 }
1379
1380
1381 @Override
1382 public void addKeplerContribution(final PositionAngleType type, final double gm,
1383 final double[] pDot) {
1384 pDot[5] += computeKeplerianAnomalyDot(type, a, e, gm, cachedAnomaly, cachedPositionAngleType);
1385 }
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398 private static double computeKeplerianAnomalyDot(final PositionAngleType type, final double a, final double e,
1399 final double mu, final double anomaly, final PositionAngleType cachedType) {
1400 final double absA = FastMath.abs(a);
1401 final double n = FastMath.sqrt(mu / absA) / absA;
1402 if (type == PositionAngleType.MEAN) {
1403 return n;
1404 }
1405 final double oMe2 = FastMath.abs(1 - e * e);
1406 final double ksi = 1 + e * FastMath.cos(KeplerianAnomalyUtility.convertAnomaly(cachedType, anomaly, e, PositionAngleType.TRUE));
1407 if (type == PositionAngleType.ECCENTRIC) {
1408 return n * ksi / oMe2;
1409 } else {
1410 return n * ksi * ksi / (oMe2 * FastMath.sqrt(oMe2));
1411 }
1412 }
1413
1414
1415
1416
1417 public String toString() {
1418 return "Keplerian parameters: " + '{' +
1419 "a: " + a +
1420 "; e: " + e +
1421 "; i: " + FastMath.toDegrees(i) +
1422 "; pa: " + FastMath.toDegrees(pa) +
1423 "; raan: " + FastMath.toDegrees(raan) +
1424 "; v: " + FastMath.toDegrees(getTrueAnomaly()) +
1425 ";}";
1426 }
1427
1428
1429 @Override
1430 public PositionAngleType getCachedPositionAngleType() {
1431 return cachedPositionAngleType;
1432 }
1433
1434
1435 @Override
1436 public boolean hasNonKeplerianRates() {
1437 return hasNonKeplerianAcceleration();
1438 }
1439
1440
1441 @Override
1442 public KeplerianOrbit withKeplerianRates() {
1443 return new KeplerianOrbit(getKeplerianParameters(), getFrame(), getDate(), getMu());
1444 }
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460 private void checkParameterRangeInclusive(final String parameterName, final double parameter,
1461 final double lowerBound, final double upperBound) {
1462 if (parameter < lowerBound || parameter > upperBound) {
1463 throw new OrekitException(OrekitMessages.INVALID_PARAMETER_RANGE, parameterName,
1464 parameter, lowerBound, upperBound);
1465 }
1466 }
1467
1468 }