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 OrbitType getType() {
401 return OrbitType.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
927 final Vector3D nonKeplerianAcceleration = nonKeplerianAcceleration();
928
929
930 keplerianShifted.computePVWithoutA();
931 final Vector3D fixedP = new Vector3D(1, keplerianShifted.partialPV.getPosition(),
932 0.5 * dtS * dtS, nonKeplerianAcceleration);
933 final double fixedR2 = fixedP.getNorm2Sq();
934 final double fixedR = FastMath.sqrt(fixedR2);
935 final Vector3D fixedV = new Vector3D(1, keplerianShifted.partialPV.getVelocity(),
936 dtS, nonKeplerianAcceleration);
937 final Vector3D fixedA = new Vector3D(-getMu() / (fixedR2 * fixedR), keplerianShifted.partialPV.getPosition(),
938 1, nonKeplerianAcceleration);
939
940
941 return new KeplerianOrbit(new TimeStampedPVCoordinates(keplerianShifted.getDate(),
942 fixedP, fixedV, fixedA),
943 keplerianShifted.getFrame(), keplerianShifted.getMu());
944
945 } else {
946
947 return keplerianShifted;
948 }
949
950 }
951
952
953 @Override
954 protected double[][] computeJacobianMeanWrtCartesian() {
955 if (isElliptical()) {
956 return computeJacobianMeanWrtCartesianElliptical();
957 } else {
958 return computeJacobianMeanWrtCartesianHyperbolic();
959 }
960 }
961
962
963
964
965
966
967
968
969
970 private double[][] computeJacobianMeanWrtCartesianElliptical() {
971
972 final double[][] jacobian = new double[6][6];
973
974
975 computePVWithoutA();
976 final Vector3D position = partialPV.getPosition();
977 final Vector3D velocity = partialPV.getVelocity();
978 final Vector3D momentum = partialPV.getMomentum();
979 final double v2 = velocity.getNorm2Sq();
980 final double r2 = position.getNorm2Sq();
981 final double r = FastMath.sqrt(r2);
982 final double r3 = r * r2;
983
984 final double px = position.getX();
985 final double py = position.getY();
986 final double pz = position.getZ();
987 final double vx = velocity.getX();
988 final double vy = velocity.getY();
989 final double vz = velocity.getZ();
990 final double mx = momentum.getX();
991 final double my = momentum.getY();
992 final double mz = momentum.getZ();
993
994 final double mu = getMu();
995 final double sqrtMuA = FastMath.sqrt(a * mu);
996 final double sqrtAoMu = FastMath.sqrt(a / mu);
997 final double a2 = a * a;
998 final double twoA = 2 * a;
999 final double rOnA = r / a;
1000
1001 final double oMe2 = 1 - e * e;
1002 final double epsilon = FastMath.sqrt(oMe2);
1003 final double sqrtRec = 1 / epsilon;
1004
1005 final SinCos scI = FastMath.sinCos(i);
1006 final SinCos scPA = FastMath.sinCos(pa);
1007 final double cosI = scI.cos();
1008 final double sinI = scI.sin();
1009 final double cosPA = scPA.cos();
1010 final double sinPA = scPA.sin();
1011
1012 final double pv = Vector3D.dotProduct(position, velocity);
1013 final double cosE = (a - r) / (a * e);
1014 final double sinE = pv / (e * sqrtMuA);
1015
1016
1017 final Vector3D vectorAR = new Vector3D(2 * a2 / r3, position);
1018 final Vector3D vectorARDot = velocity.scalarMultiply(2 * a2 / mu);
1019 fillHalfRow(1, vectorAR, jacobian[0], 0);
1020 fillHalfRow(1, vectorARDot, jacobian[0], 3);
1021
1022
1023 final double factorER3 = pv / twoA;
1024 final Vector3D vectorER = new Vector3D(cosE * v2 / (r * mu), position,
1025 sinE / sqrtMuA, velocity,
1026 -factorER3 * sinE / sqrtMuA, vectorAR);
1027 final Vector3D vectorERDot = new Vector3D(sinE / sqrtMuA, position,
1028 cosE * 2 * r / mu, velocity,
1029 -factorER3 * sinE / sqrtMuA, vectorARDot);
1030 fillHalfRow(1, vectorER, jacobian[1], 0);
1031 fillHalfRow(1, vectorERDot, jacobian[1], 3);
1032
1033
1034 final double coefE = cosE / (e * sqrtMuA);
1035 final Vector3D vectorEAnR =
1036 new Vector3D(-sinE * v2 / (e * r * mu), position, coefE, velocity,
1037 -factorER3 * coefE, vectorAR);
1038
1039
1040 final Vector3D vectorEAnRDot =
1041 new Vector3D(-sinE * 2 * r / (e * mu), velocity, coefE, position,
1042 -factorER3 * coefE, vectorARDot);
1043
1044
1045 final double s1 = -sinE * pz / r - cosE * vz * sqrtAoMu;
1046 final double s2 = -cosE * pz / r3;
1047 final double s3 = -sinE * vz / (2 * sqrtMuA);
1048 final double t1 = sqrtRec * (cosE * pz / r - sinE * vz * sqrtAoMu);
1049 final double t2 = sqrtRec * (-sinE * pz / r3);
1050 final double t3 = sqrtRec * (cosE - e) * vz / (2 * sqrtMuA);
1051 final double t4 = sqrtRec * (e * sinI * cosPA * sqrtRec - vz * sqrtAoMu);
1052 final Vector3D s = new Vector3D(cosE / r, Vector3D.PLUS_K,
1053 s1, vectorEAnR,
1054 s2, position,
1055 s3, vectorAR);
1056 final Vector3D sDot = new Vector3D(-sinE * sqrtAoMu, Vector3D.PLUS_K,
1057 s1, vectorEAnRDot,
1058 s3, vectorARDot);
1059 final Vector3D t =
1060 new Vector3D(sqrtRec * sinE / r, Vector3D.PLUS_K).add(new Vector3D(t1, vectorEAnR,
1061 t2, position,
1062 t3, vectorAR,
1063 t4, vectorER));
1064 final Vector3D tDot = new Vector3D(sqrtRec * (cosE - e) * sqrtAoMu, Vector3D.PLUS_K,
1065 t1, vectorEAnRDot,
1066 t3, vectorARDot,
1067 t4, vectorERDot);
1068
1069
1070 final double factorI1 = -sinI * sqrtRec / sqrtMuA;
1071 final double i1 = factorI1;
1072 final double i2 = -factorI1 * mz / twoA;
1073 final double i3 = factorI1 * mz * e / oMe2;
1074 final double i4 = cosI * sinPA;
1075 final double i5 = cosI * cosPA;
1076 fillHalfRow(i1, new Vector3D(vy, -vx, 0), i2, vectorAR, i3, vectorER, i4, s, i5, t,
1077 jacobian[2], 0);
1078 fillHalfRow(i1, new Vector3D(-py, px, 0), i2, vectorARDot, i3, vectorERDot, i4, sDot, i5, tDot,
1079 jacobian[2], 3);
1080
1081
1082 fillHalfRow(cosPA / sinI, s, -sinPA / sinI, t, jacobian[3], 0);
1083 fillHalfRow(cosPA / sinI, sDot, -sinPA / sinI, tDot, jacobian[3], 3);
1084
1085
1086 final double factorRaanR = 1 / (mu * a * oMe2 * sinI * sinI);
1087 fillHalfRow(-factorRaanR * my, new Vector3D( 0, vz, -vy),
1088 factorRaanR * mx, new Vector3D(-vz, 0, vx),
1089 jacobian[4], 0);
1090 fillHalfRow(-factorRaanR * my, new Vector3D( 0, -pz, py),
1091 factorRaanR * mx, new Vector3D(pz, 0, -px),
1092 jacobian[4], 3);
1093
1094
1095 fillHalfRow(rOnA, vectorEAnR, -sinE, vectorER, jacobian[5], 0);
1096 fillHalfRow(rOnA, vectorEAnRDot, -sinE, vectorERDot, jacobian[5], 3);
1097
1098 return jacobian;
1099
1100 }
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110 private double[][] computeJacobianMeanWrtCartesianHyperbolic() {
1111
1112 final double[][] jacobian = new double[6][6];
1113
1114
1115 computePVWithoutA();
1116 final Vector3D position = partialPV.getPosition();
1117 final Vector3D velocity = partialPV.getVelocity();
1118 final Vector3D momentum = partialPV.getMomentum();
1119 final double r2 = position.getNorm2Sq();
1120 final double r = FastMath.sqrt(r2);
1121 final double r3 = r * r2;
1122
1123 final double x = position.getX();
1124 final double y = position.getY();
1125 final double z = position.getZ();
1126 final double vx = velocity.getX();
1127 final double vy = velocity.getY();
1128 final double vz = velocity.getZ();
1129 final double mx = momentum.getX();
1130 final double my = momentum.getY();
1131 final double mz = momentum.getZ();
1132
1133 final double mu = getMu();
1134 final double absA = -a;
1135 final double sqrtMuA = FastMath.sqrt(absA * mu);
1136 final double a2 = a * a;
1137 final double rOa = r / absA;
1138
1139 final SinCos scI = FastMath.sinCos(i);
1140 final double cosI = scI.cos();
1141 final double sinI = scI.sin();
1142
1143 final double pv = Vector3D.dotProduct(position, velocity);
1144
1145
1146 final Vector3D vectorAR = new Vector3D(-2 * a2 / r3, position);
1147 final Vector3D vectorARDot = velocity.scalarMultiply(-2 * a2 / mu);
1148 fillHalfRow(-1, vectorAR, jacobian[0], 0);
1149 fillHalfRow(-1, vectorARDot, jacobian[0], 3);
1150
1151
1152 final double m = momentum.getNorm();
1153 final double oOm = 1 / m;
1154 final Vector3D dcXP = new Vector3D( 0, vz, -vy);
1155 final Vector3D dcYP = new Vector3D(-vz, 0, vx);
1156 final Vector3D dcZP = new Vector3D( vy, -vx, 0);
1157 final Vector3D dcXV = new Vector3D( 0, -z, y);
1158 final Vector3D dcYV = new Vector3D( z, 0, -x);
1159 final Vector3D dcZV = new Vector3D( -y, x, 0);
1160 final Vector3D dCP = new Vector3D(mx * oOm, dcXP, my * oOm, dcYP, mz * oOm, dcZP);
1161 final Vector3D dCV = new Vector3D(mx * oOm, dcXV, my * oOm, dcYV, mz * oOm, dcZV);
1162
1163
1164 final double mOMu = m / mu;
1165 final Vector3D dpP = new Vector3D(2 * mOMu, dCP);
1166 final Vector3D dpV = new Vector3D(2 * mOMu, dCV);
1167
1168
1169 final double p = m * mOMu;
1170 final double moO2ae = 1 / (2 * absA * e);
1171 final double m2OaMu = -p / absA;
1172 fillHalfRow(moO2ae, dpP, m2OaMu * moO2ae, vectorAR, jacobian[1], 0);
1173 fillHalfRow(moO2ae, dpV, m2OaMu * moO2ae, vectorARDot, jacobian[1], 3);
1174
1175
1176 final double cI1 = 1 / (m * sinI);
1177 final double cI2 = cosI * cI1;
1178 fillHalfRow(cI2, dCP, -cI1, dcZP, jacobian[2], 0);
1179 fillHalfRow(cI2, dCV, -cI1, dcZV, jacobian[2], 3);
1180
1181
1182 final double cP1 = y * oOm;
1183 final double cP2 = -x * oOm;
1184 final double cP3 = -(mx * cP1 + my * cP2);
1185 final double cP4 = cP3 * oOm;
1186 final double cP5 = -1 / (r2 * sinI * sinI);
1187 final double cP6 = z * cP5;
1188 final double cP7 = cP3 * cP5;
1189 final Vector3D dacP = new Vector3D(cP1, dcXP, cP2, dcYP, cP4, dCP, oOm, new Vector3D(-my, mx, 0));
1190 final Vector3D dacV = new Vector3D(cP1, dcXV, cP2, dcYV, cP4, dCV);
1191 final Vector3D dpoP = new Vector3D(cP6, dacP, cP7, Vector3D.PLUS_K);
1192 final Vector3D dpoV = new Vector3D(cP6, dacV);
1193
1194 final double re2 = r2 * e * e;
1195 final double recOre2 = (p - r) / re2;
1196 final double resOre2 = (pv * mOMu) / re2;
1197 final Vector3D dreP = new Vector3D(mOMu, velocity, pv / mu, dCP);
1198 final Vector3D dreV = new Vector3D(mOMu, position, pv / mu, dCV);
1199 final Vector3D davP = new Vector3D(-resOre2, dpP, recOre2, dreP, resOre2 / r, position);
1200 final Vector3D davV = new Vector3D(-resOre2, dpV, recOre2, dreV);
1201 fillHalfRow(1, dpoP, -1, davP, jacobian[3], 0);
1202 fillHalfRow(1, dpoV, -1, davV, jacobian[3], 3);
1203
1204
1205 final double cO0 = cI1 * cI1;
1206 final double cO1 = mx * cO0;
1207 final double cO2 = -my * cO0;
1208 fillHalfRow(cO1, dcYP, cO2, dcXP, jacobian[4], 0);
1209 fillHalfRow(cO1, dcYV, cO2, dcXV, jacobian[4], 3);
1210
1211
1212 final double s2a = pv / (2 * absA);
1213 final double oObux = 1 / FastMath.sqrt(m * m + mu * absA);
1214 final double scasbu = pv * oObux;
1215 final Vector3D dauP = new Vector3D(1 / sqrtMuA, velocity, -s2a / sqrtMuA, vectorAR);
1216 final Vector3D dauV = new Vector3D(1 / sqrtMuA, position, -s2a / sqrtMuA, vectorARDot);
1217 final Vector3D dbuP = new Vector3D(oObux * mu / 2, vectorAR, m * oObux, dCP);
1218 final Vector3D dbuV = new Vector3D(oObux * mu / 2, vectorARDot, m * oObux, dCV);
1219 final Vector3D dcuP = new Vector3D(oObux, velocity, -scasbu * oObux, dbuP);
1220 final Vector3D dcuV = new Vector3D(oObux, position, -scasbu * oObux, dbuV);
1221 fillHalfRow(1, dauP, -e / (1 + rOa), dcuP, jacobian[5], 0);
1222 fillHalfRow(1, dauV, -e / (1 + rOa), dcuV, jacobian[5], 3);
1223
1224 return jacobian;
1225
1226 }
1227
1228
1229 @Override
1230 protected double[][] computeJacobianEccentricWrtCartesian() {
1231 if (isElliptical()) {
1232 return computeJacobianEccentricWrtCartesianElliptical();
1233 } else {
1234 return computeJacobianEccentricWrtCartesianHyperbolic();
1235 }
1236 }
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246 private double[][] computeJacobianEccentricWrtCartesianElliptical() {
1247
1248
1249 final double[][] jacobian = computeJacobianMeanWrtCartesianElliptical();
1250
1251
1252
1253
1254
1255 final SinCos scE = FastMath.sinCos(getEccentricAnomaly());
1256 final double aOr = 1 / (1 - e * scE.cos());
1257
1258
1259 final double[] eRow = jacobian[1];
1260 final double[] anomalyRow = jacobian[5];
1261 for (int j = 0; j < anomalyRow.length; ++j) {
1262 anomalyRow[j] = aOr * (anomalyRow[j] + scE.sin() * eRow[j]);
1263 }
1264
1265 return jacobian;
1266
1267 }
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277 private double[][] computeJacobianEccentricWrtCartesianHyperbolic() {
1278
1279
1280 final double[][] jacobian = computeJacobianMeanWrtCartesianHyperbolic();
1281
1282
1283
1284
1285
1286 final double H = getEccentricAnomaly();
1287 final double coshH = FastMath.cosh(H);
1288 final double sinhH = FastMath.sinh(H);
1289 final double absaOr = 1 / (e * coshH - 1);
1290
1291
1292 final double[] eRow = jacobian[1];
1293 final double[] anomalyRow = jacobian[5];
1294 for (int j = 0; j < anomalyRow.length; ++j) {
1295 anomalyRow[j] = absaOr * (anomalyRow[j] - sinhH * eRow[j]);
1296 }
1297
1298 return jacobian;
1299
1300 }
1301
1302
1303 @Override
1304 protected double[][] computeJacobianTrueWrtCartesian() {
1305 if (isElliptical()) {
1306 return computeJacobianTrueWrtCartesianElliptical();
1307 } else {
1308 return computeJacobianTrueWrtCartesianHyperbolic();
1309 }
1310 }
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320 private double[][] computeJacobianTrueWrtCartesianElliptical() {
1321
1322
1323 final double[][] jacobian = computeJacobianEccentricWrtCartesianElliptical();
1324
1325
1326
1327
1328
1329
1330 final double e2 = e * e;
1331 final double oMe2 = 1 - e2;
1332 final double epsilon = FastMath.sqrt(oMe2);
1333 final SinCos scE = FastMath.sinCos(getEccentricAnomaly());
1334 final double aOr = 1 / (1 - e * scE.cos());
1335 final double aFactor = epsilon * aOr;
1336 final double eFactor = scE.sin() * aOr / epsilon;
1337
1338
1339 final double[] eRow = jacobian[1];
1340 final double[] anomalyRow = jacobian[5];
1341 for (int j = 0; j < anomalyRow.length; ++j) {
1342 anomalyRow[j] = aFactor * anomalyRow[j] + eFactor * eRow[j];
1343 }
1344
1345 return jacobian;
1346
1347 }
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357 private double[][] computeJacobianTrueWrtCartesianHyperbolic() {
1358
1359
1360 final double[][] jacobian = computeJacobianEccentricWrtCartesianHyperbolic();
1361
1362
1363
1364
1365
1366
1367 final double e2 = e * e;
1368 final double e2Mo = e2 - 1;
1369 final double epsilon = FastMath.sqrt(e2Mo);
1370 final double H = getEccentricAnomaly();
1371 final double coshH = FastMath.cosh(H);
1372 final double sinhH = FastMath.sinh(H);
1373 final double aOr = 1 / (e * coshH - 1);
1374 final double aFactor = epsilon * aOr;
1375 final double eFactor = sinhH * aOr / epsilon;
1376
1377
1378 final double[] eRow = jacobian[1];
1379 final double[] anomalyRow = jacobian[5];
1380 for (int j = 0; j < anomalyRow.length; ++j) {
1381 anomalyRow[j] = aFactor * anomalyRow[j] - eFactor * eRow[j];
1382 }
1383
1384 return jacobian;
1385
1386 }
1387
1388
1389 @Override
1390 public void addKeplerContribution(final PositionAngleType type, final double gm,
1391 final double[] pDot) {
1392 pDot[5] += computeKeplerianAnomalyDot(type, a, e, gm, cachedAnomaly, cachedPositionAngleType);
1393 }
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406 private static double computeKeplerianAnomalyDot(final PositionAngleType type, final double a, final double e,
1407 final double mu, final double anomaly, final PositionAngleType cachedType) {
1408 final double absA = FastMath.abs(a);
1409 final double n = FastMath.sqrt(mu / absA) / absA;
1410 if (type == PositionAngleType.MEAN) {
1411 return n;
1412 }
1413 final double oMe2 = FastMath.abs(1 - e * e);
1414 final double ksi = 1 + e * FastMath.cos(KeplerianAnomalyUtility.convertAnomaly(cachedType, anomaly, e, PositionAngleType.TRUE));
1415 if (type == PositionAngleType.ECCENTRIC) {
1416 return n * ksi / oMe2;
1417 } else {
1418 return n * ksi * ksi / (oMe2 * FastMath.sqrt(oMe2));
1419 }
1420 }
1421
1422
1423
1424
1425 public String toString() {
1426 return "Keplerian parameters: " + '{' +
1427 "a: " + a +
1428 "; e: " + e +
1429 "; i: " + FastMath.toDegrees(i) +
1430 "; pa: " + FastMath.toDegrees(pa) +
1431 "; raan: " + FastMath.toDegrees(raan) +
1432 "; v: " + FastMath.toDegrees(getTrueAnomaly()) +
1433 ";}";
1434 }
1435
1436
1437 @Override
1438 public PositionAngleType getCachedPositionAngleType() {
1439 return cachedPositionAngleType;
1440 }
1441
1442
1443 @Override
1444 public boolean hasNonKeplerianRates() {
1445 return hasNonKeplerianAcceleration();
1446 }
1447
1448
1449 @Override
1450 public KeplerianOrbit withKeplerianRates() {
1451 return new KeplerianOrbit(getKeplerianParameters(), getFrame(), getDate(), getMu());
1452 }
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468 private void checkParameterRangeInclusive(final String parameterName, final double parameter,
1469 final double lowerBound, final double upperBound) {
1470 if (parameter < lowerBound || parameter > upperBound) {
1471 throw new OrekitException(OrekitMessages.INVALID_PARAMETER_RANGE, parameterName,
1472 parameter, lowerBound, upperBound);
1473 }
1474 }
1475
1476 }