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.OrekitIllegalArgumentException;
24 import org.orekit.errors.OrekitInternalError;
25 import org.orekit.errors.OrekitMessages;
26 import org.orekit.frames.Frame;
27 import org.orekit.frames.KinematicTransform;
28 import org.orekit.time.AbsoluteDate;
29 import org.orekit.time.TimeOffset;
30 import org.orekit.utils.PVCoordinates;
31 import org.orekit.utils.TimeStampedPVCoordinates;
32
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 public class EquinoctialOrbit extends Orbit implements PositionAngleBased<EquinoctialOrbit> {
74
75
76 private final double a;
77
78
79 private final double ex;
80
81
82 private final double ey;
83
84
85 private final double hx;
86
87
88 private final double hy;
89
90
91 private final double cachedL;
92
93
94 private final PositionAngleType cachedPositionAngleType;
95
96
97 private final double aDot;
98
99
100 private final double exDot;
101
102
103 private final double eyDot;
104
105
106 private final double hxDot;
107
108
109 private final double hyDot;
110
111
112 private final double cachedLDot;
113
114
115 private PVCoordinates partialPV;
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134 public EquinoctialOrbit(final double a, final double ex, final double ey,
135 final double hx, final double hy, final double l,
136 final PositionAngleType type, final PositionAngleType cachedPositionAngleType,
137 final Frame frame, final AbsoluteDate date, final double mu)
138 throws IllegalArgumentException {
139 this(a, ex, ey, hx, hy, l,
140 0., 0., 0., 0., 0., computeKeplerianLDot(type, a, ex, ey, mu, l, type),
141 type, cachedPositionAngleType, frame, date, mu);
142 }
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159 public EquinoctialOrbit(final double a, final double ex, final double ey,
160 final double hx, final double hy, final double l,
161 final PositionAngleType type,
162 final Frame frame, final AbsoluteDate date, final double mu)
163 throws IllegalArgumentException {
164 this(a, ex, ey, hx, hy, l, type, type, frame, date, mu);
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190 public EquinoctialOrbit(final double a, final double ex, final double ey,
191 final double hx, final double hy, final double l,
192 final double aDot, final double exDot, final double eyDot,
193 final double hxDot, final double hyDot, final double lDot,
194 final PositionAngleType type, final PositionAngleType cachedPositionAngleType,
195 final Frame frame, final AbsoluteDate date, final double mu)
196 throws IllegalArgumentException {
197 super(frame, date, mu);
198 if (ex * ex + ey * ey >= 1.0) {
199 throw new OrekitIllegalArgumentException(OrekitMessages.HYPERBOLIC_ORBIT_NOT_HANDLED_AS,
200 getClass().getName());
201 }
202 this.cachedPositionAngleType = cachedPositionAngleType;
203 this.a = a;
204 this.aDot = aDot;
205 this.ex = ex;
206 this.exDot = exDot;
207 this.ey = ey;
208 this.eyDot = eyDot;
209 this.hx = hx;
210 this.hxDot = hxDot;
211 this.hy = hy;
212 this.hyDot = hyDot;
213
214 final UnivariateDerivative1 lUD = initializeCachedL(l, lDot, type);
215 this.cachedL = lUD.getValue();
216 this.cachedLDot = lUD.getFirstDerivative();
217
218 this.partialPV = null;
219
220 }
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243 public EquinoctialOrbit(final double a, final double ex, final double ey,
244 final double hx, final double hy, final double l,
245 final double aDot, final double exDot, final double eyDot,
246 final double hxDot, final double hyDot, final double lDot,
247 final PositionAngleType type,
248 final Frame frame, final AbsoluteDate date, final double mu)
249 throws IllegalArgumentException {
250 this(a, ex, ey, hx, hy, l, aDot, exDot, eyDot, hxDot, hyDot, lDot, type, type, frame, date, mu);
251 }
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267 public EquinoctialOrbit(final TimeStampedPVCoordinates pvCoordinates,
268 final Frame frame, final double mu)
269 throws IllegalArgumentException {
270 super(pvCoordinates, frame, mu);
271
272
273 final Vector3D pvP = pvCoordinates.getPosition();
274 final Vector3D pvV = pvCoordinates.getVelocity();
275 final Vector3D pvA = pvCoordinates.getAcceleration();
276 final double r2 = pvP.getNorm2Sq();
277 final double r = FastMath.sqrt(r2);
278 final double V2 = pvV.getNorm2Sq();
279 final double rV2OnMu = r * V2 / mu;
280
281
282 a = r / (2 - rV2OnMu);
283
284 if (!isElliptical()) {
285 throw new OrekitIllegalArgumentException(OrekitMessages.HYPERBOLIC_ORBIT_NOT_HANDLED_AS,
286 getClass().getName());
287 }
288
289
290 final Vector3D w = pvCoordinates.getMomentum().normalize();
291 final double d = 1.0 / (1 + w.getZ());
292 hx = -d * w.getY();
293 hy = d * w.getX();
294
295
296 cachedPositionAngleType = PositionAngleType.TRUE;
297 final double cLv = (pvP.getX() - d * pvP.getZ() * w.getX()) / r;
298 final double sLv = (pvP.getY() - d * pvP.getZ() * w.getY()) / r;
299 cachedL = FastMath.atan2(sLv, cLv);
300
301
302 final double eSE = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(mu * a);
303 final double eCE = rV2OnMu - 1;
304 final double e2 = eCE * eCE + eSE * eSE;
305 final double f = eCE - e2;
306 final double g = FastMath.sqrt(1 - e2) * eSE;
307 ex = a * (f * cLv + g * sLv) / r;
308 ey = a * (f * sLv - g * cLv) / r;
309
310 partialPV = pvCoordinates;
311
312 if (hasNonKeplerianAcceleration(pvCoordinates, mu)) {
313
314
315 final double[][] jacobian = new double[6][6];
316 getJacobianWrtCartesian(PositionAngleType.MEAN, jacobian);
317
318 final Vector3D keplerianAcceleration = new Vector3D(-mu / (r * r2), pvP);
319 final Vector3D nonKeplerianAcceleration = pvA.subtract(keplerianAcceleration);
320 final double aX = nonKeplerianAcceleration.getX();
321 final double aY = nonKeplerianAcceleration.getY();
322 final double aZ = nonKeplerianAcceleration.getZ();
323 aDot = jacobian[0][3] * aX + jacobian[0][4] * aY + jacobian[0][5] * aZ;
324 exDot = jacobian[1][3] * aX + jacobian[1][4] * aY + jacobian[1][5] * aZ;
325 eyDot = jacobian[2][3] * aX + jacobian[2][4] * aY + jacobian[2][5] * aZ;
326 hxDot = jacobian[3][3] * aX + jacobian[3][4] * aY + jacobian[3][5] * aZ;
327 hyDot = jacobian[4][3] * aX + jacobian[4][4] * aY + jacobian[4][5] * aZ;
328
329
330
331 final double lMDot = getKeplerianMeanMotion() +
332 jacobian[5][3] * aX + jacobian[5][4] * aY + jacobian[5][5] * aZ;
333 final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot);
334 final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot);
335 final UnivariateDerivative1 lMUD = new UnivariateDerivative1(getLM(), lMDot);
336 final UnivariateDerivative1 lvUD = FieldEquinoctialLongitudeArgumentUtility.meanToTrue(exUD, eyUD, lMUD);
337 cachedLDot = lvUD.getFirstDerivative();
338
339 } else {
340
341
342
343 aDot = 0.;
344 exDot = 0.;
345 eyDot = 0.;
346 hxDot = 0.;
347 hyDot = 0.;
348 cachedLDot = computeKeplerianLDot(cachedPositionAngleType, a, ex, ey, mu, cachedL, cachedPositionAngleType);
349 }
350
351 }
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368 public EquinoctialOrbit(final PVCoordinates pvCoordinates, final Frame frame,
369 final AbsoluteDate date, final double mu)
370 throws IllegalArgumentException {
371 this(new TimeStampedPVCoordinates(date, pvCoordinates), frame, mu);
372 }
373
374
375
376
377 public EquinoctialOrbit(final Orbit op) {
378 super(op.getFrame(), op.getDate(), op.getMu());
379 a = op.getA();
380 aDot = op.getADot();
381 ex = op.getEquinoctialEx();
382 exDot = op.getEquinoctialExDot();
383 ey = op.getEquinoctialEy();
384 eyDot = op.getEquinoctialEyDot();
385 hx = op.getHx();
386 hxDot = op.getHxDot();
387 hy = op.getHy();
388 hyDot = op.getHyDot();
389 cachedPositionAngleType = PositionAngleType.TRUE;
390 cachedL = op.getLv();
391 cachedLDot = op.hasNonKeplerianAcceleration() ? op.getLvDot() :
392 computeKeplerianLDot(cachedPositionAngleType, a, ex, ey, op.getMu(), cachedL, cachedPositionAngleType);
393 partialPV = null;
394 }
395
396
397 @Override
398 public boolean hasNonKeplerianAcceleration() {
399 return aDot != 0. || exDot != 0. || eyDot != 0. || hxDot != 0. || hyDot != 0. ||
400 FastMath.abs(cachedLDot - computeKeplerianLDot(cachedPositionAngleType, a, ex, ey, getMu(), cachedL, cachedPositionAngleType)) > TOLERANCE_POSITION_ANGLE_RATE;
401 }
402
403
404 @Override
405 public OrbitType getType() {
406 return OrbitType.EQUINOCTIAL;
407 }
408
409
410 @Override
411 public AbstractOrbitFactory<EquinoctialOrbit> factory(final PositionAngleType positionAngleType,
412 final double positionScale) {
413 return new EquinoctialOrbitFactory(this, positionScale, positionAngleType);
414 }
415
416
417 @Override
418 public double getA() {
419 return a;
420 }
421
422
423 @Override
424 public double getADot() {
425 return aDot;
426 }
427
428
429 @Override
430 public double getEquinoctialEx() {
431 return ex;
432 }
433
434
435 @Override
436 public double getEquinoctialExDot() {
437 return exDot;
438 }
439
440
441 @Override
442 public double getEquinoctialEy() {
443 return ey;
444 }
445
446
447 @Override
448 public double getEquinoctialEyDot() {
449 return eyDot;
450 }
451
452
453 @Override
454 public double getHx() {
455 return hx;
456 }
457
458
459 @Override
460 public double getHxDot() {
461 return hxDot;
462 }
463
464
465 @Override
466 public double getHy() {
467 return hy;
468 }
469
470
471 @Override
472 public double getHyDot() {
473 return hyDot;
474 }
475
476
477 @Override
478 public double getLv() {
479 return switch (cachedPositionAngleType) {
480 case TRUE -> cachedL;
481 case ECCENTRIC -> EquinoctialLongitudeArgumentUtility.eccentricToTrue(ex, ey, cachedL);
482 case MEAN -> EquinoctialLongitudeArgumentUtility.meanToTrue(ex, ey, cachedL);
483 };
484 }
485
486
487 @Override
488 public double getLvDot() {
489 switch (cachedPositionAngleType) {
490 case ECCENTRIC:
491 final UnivariateDerivative1 lEUD = new UnivariateDerivative1(cachedL, cachedLDot);
492 final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot);
493 final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot);
494 final UnivariateDerivative1 lvUD = FieldEquinoctialLongitudeArgumentUtility.eccentricToTrue(exUD, eyUD,
495 lEUD);
496 return lvUD.getFirstDerivative();
497
498 case TRUE:
499 return cachedLDot;
500
501 case MEAN:
502 final UnivariateDerivative1 lMUD = new UnivariateDerivative1(cachedL, cachedLDot);
503 final UnivariateDerivative1 exUD2 = new UnivariateDerivative1(ex, exDot);
504 final UnivariateDerivative1 eyUD2 = new UnivariateDerivative1(ey, eyDot);
505 final UnivariateDerivative1 lvUD2 = FieldEquinoctialLongitudeArgumentUtility.meanToTrue(exUD2,
506 eyUD2, lMUD);
507 return lvUD2.getFirstDerivative();
508
509 default:
510 throw new OrekitInternalError(null);
511 }
512 }
513
514
515 @Override
516 public double getLE() {
517 return switch (cachedPositionAngleType) {
518 case TRUE -> EquinoctialLongitudeArgumentUtility.trueToEccentric(ex, ey, cachedL);
519 case ECCENTRIC -> cachedL;
520 case MEAN -> EquinoctialLongitudeArgumentUtility.meanToEccentric(ex, ey, cachedL);
521 };
522 }
523
524
525 @Override
526 public double getLEDot() {
527 switch (cachedPositionAngleType) {
528 case TRUE:
529 final UnivariateDerivative1 lvUD = new UnivariateDerivative1(cachedL, cachedLDot);
530 final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot);
531 final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot);
532 final UnivariateDerivative1 lEUD = FieldEquinoctialLongitudeArgumentUtility.trueToEccentric(exUD, eyUD,
533 lvUD);
534 return lEUD.getFirstDerivative();
535
536 case ECCENTRIC:
537 return cachedLDot;
538
539 case MEAN:
540 final UnivariateDerivative1 lMUD = new UnivariateDerivative1(cachedL, cachedLDot);
541 final UnivariateDerivative1 exUD2 = new UnivariateDerivative1(ex, exDot);
542 final UnivariateDerivative1 eyUD2 = new UnivariateDerivative1(ey, eyDot);
543 final UnivariateDerivative1 lEUD2 = FieldEquinoctialLongitudeArgumentUtility.meanToEccentric(exUD2,
544 eyUD2, lMUD);
545 return lEUD2.getFirstDerivative();
546
547 default:
548 throw new OrekitInternalError(null);
549 }
550 }
551
552
553 @Override
554 public double getLM() {
555 return switch (cachedPositionAngleType) {
556 case TRUE -> EquinoctialLongitudeArgumentUtility.trueToMean(ex, ey, cachedL);
557 case MEAN -> cachedL;
558 case ECCENTRIC -> EquinoctialLongitudeArgumentUtility.eccentricToMean(ex, ey, cachedL);
559 };
560 }
561
562
563 @Override
564 public double getLMDot() {
565 switch (cachedPositionAngleType) {
566 case TRUE:
567 final UnivariateDerivative1 lvUD = new UnivariateDerivative1(cachedL, cachedLDot);
568 final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot);
569 final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot);
570 final UnivariateDerivative1 lMUD = FieldEquinoctialLongitudeArgumentUtility.trueToMean(exUD, eyUD, lvUD);
571 return lMUD.getFirstDerivative();
572
573 case MEAN:
574 return cachedLDot;
575
576 case ECCENTRIC:
577 final UnivariateDerivative1 lEUD = new UnivariateDerivative1(cachedL, cachedLDot);
578 final UnivariateDerivative1 exUD2 = new UnivariateDerivative1(ex, exDot);
579 final UnivariateDerivative1 eyUD2 = new UnivariateDerivative1(ey, eyDot);
580 final UnivariateDerivative1 lMUD2 = FieldEquinoctialLongitudeArgumentUtility.eccentricToMean(exUD2,
581 eyUD2, lEUD);
582 return lMUD2.getFirstDerivative();
583
584 default:
585 throw new OrekitInternalError(null);
586 }
587 }
588
589
590
591
592
593 public double getL(final PositionAngleType type) {
594 return (type == PositionAngleType.MEAN) ? getLM() :
595 ((type == PositionAngleType.ECCENTRIC) ? getLE() :
596 getLv());
597 }
598
599
600
601
602
603 public double getLDot(final PositionAngleType type) {
604 return (type == PositionAngleType.MEAN) ? getLMDot() :
605 ((type == PositionAngleType.ECCENTRIC) ? getLEDot() :
606 getLvDot());
607 }
608
609
610 @Override
611 public double getE() {
612 return FastMath.sqrt(ex * ex + ey * ey);
613 }
614
615
616 @Override
617 public double getEDot() {
618 if (!hasNonKeplerianAcceleration()) {
619 return 0.;
620 }
621 return (ex * exDot + ey * eyDot) / FastMath.sqrt(ex * ex + ey * ey);
622 }
623
624
625 @Override
626 public double getI() {
627 return 2 * FastMath.atan(FastMath.sqrt(hx * hx + hy * hy));
628 }
629
630
631 @Override
632 public double getIDot() {
633 if (!hasNonKeplerianAcceleration()) {
634 return 0.;
635 }
636 final double h2 = hx * hx + hy * hy;
637 final double h = FastMath.sqrt(h2);
638 return 2 * (hx * hxDot + hy * hyDot) / (h * (1 + h2));
639 }
640
641
642
643 private void computePVWithoutA() {
644
645 if (partialPV != null) {
646
647 return;
648 }
649
650
651 final double lE = getLE();
652
653
654 final double hx2 = hx * hx;
655 final double hy2 = hy * hy;
656 final double factH = 1. / (1 + hx2 + hy2);
657
658
659 final double ux = (1 + hx2 - hy2) * factH;
660 final double uy = 2 * hx * hy * factH;
661 final double uz = -2 * hy * factH;
662
663 final double vx = uy;
664 final double vy = (1 - hx2 + hy2) * factH;
665 final double vz = 2 * hx * factH;
666
667
668 final double exey = ex * ey;
669 final double ex2 = ex * ex;
670 final double ey2 = ey * ey;
671 final double e2 = ex2 + ey2;
672 final double eta = 1 + FastMath.sqrt(1 - e2);
673 final double beta = 1. / eta;
674
675
676 final SinCos scLe = FastMath.sinCos(lE);
677 final double cLe = scLe.cos();
678 final double sLe = scLe.sin();
679 final double exCeyS = ex * cLe + ey * sLe;
680
681
682 final double x = a * ((1 - beta * ey2) * cLe + beta * exey * sLe - ex);
683 final double y = a * ((1 - beta * ex2) * sLe + beta * exey * cLe - ey);
684
685 final double factor = FastMath.sqrt(getMu() / a) / (1 - exCeyS);
686 final double xdot = factor * (-sLe + beta * ey * exCeyS);
687 final double ydot = factor * ( cLe - beta * ex * exCeyS);
688
689 final Vector3D position =
690 new Vector3D(x * ux + y * vx, x * uy + y * vy, x * uz + y * vz);
691 final Vector3D velocity =
692 new Vector3D(xdot * ux + ydot * vx, xdot * uy + ydot * vy, xdot * uz + ydot * vz);
693 partialPV = new PVCoordinates(position, velocity);
694
695 }
696
697
698
699
700
701
702
703
704 private UnivariateDerivative1 initializeCachedL(final double l, final double lDot,
705 final PositionAngleType inputType) {
706 if (cachedPositionAngleType == inputType) {
707 return new UnivariateDerivative1(l, lDot);
708
709 } else {
710 final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot);
711 final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot);
712 final UnivariateDerivative1 lUD = new UnivariateDerivative1(l, lDot);
713
714 switch (cachedPositionAngleType) {
715
716 case ECCENTRIC:
717 if (inputType == PositionAngleType.MEAN) {
718 return FieldEquinoctialLongitudeArgumentUtility.meanToEccentric(exUD, eyUD, lUD);
719 } else {
720 return FieldEquinoctialLongitudeArgumentUtility.trueToEccentric(exUD, eyUD, lUD);
721 }
722
723 case TRUE:
724 if (inputType == PositionAngleType.MEAN) {
725 return FieldEquinoctialLongitudeArgumentUtility.meanToTrue(exUD, eyUD, lUD);
726 } else {
727 return FieldEquinoctialLongitudeArgumentUtility.eccentricToTrue(exUD, eyUD, lUD);
728 }
729
730 case MEAN:
731 if (inputType == PositionAngleType.TRUE) {
732 return FieldEquinoctialLongitudeArgumentUtility.trueToMean(exUD, eyUD, lUD);
733 } else {
734 return FieldEquinoctialLongitudeArgumentUtility.eccentricToMean(exUD, eyUD, lUD);
735 }
736
737 default:
738 throw new OrekitInternalError(null);
739
740 }
741
742 }
743
744 }
745
746
747 @Override
748 protected Vector3D initPosition() {
749
750
751 final double lE = getLE();
752
753
754 final double hx2 = hx * hx;
755 final double hy2 = hy * hy;
756 final double factH = 1. / (1 + hx2 + hy2);
757
758
759 final double ux = (1 + hx2 - hy2) * factH;
760 final double uy = 2 * hx * hy * factH;
761 final double uz = -2 * hy * factH;
762
763 final double vx = uy;
764 final double vy = (1 - hx2 + hy2) * factH;
765 final double vz = 2 * hx * factH;
766
767
768 final double exey = ex * ey;
769 final double ex2 = ex * ex;
770 final double ey2 = ey * ey;
771 final double e2 = ex2 + ey2;
772 final double eta = 1 + FastMath.sqrt(1 - e2);
773 final double beta = 1. / eta;
774
775
776 final SinCos scLe = FastMath.sinCos(lE);
777 final double cLe = scLe.cos();
778 final double sLe = scLe.sin();
779
780
781 final double x = a * ((1 - beta * ey2) * cLe + beta * exey * sLe - ex);
782 final double y = a * ((1 - beta * ex2) * sLe + beta * exey * cLe - ey);
783
784 return new Vector3D(x * ux + y * vx, x * uy + y * vy, x * uz + y * vz);
785
786 }
787
788
789 @Override
790 protected TimeStampedPVCoordinates initPVCoordinates() {
791
792
793 computePVWithoutA();
794
795
796 final double r2 = partialPV.getPosition().getNorm2Sq();
797 final Vector3D keplerianAcceleration = new Vector3D(-getMu() / (r2 * FastMath.sqrt(r2)), partialPV.getPosition());
798 final Vector3D acceleration = hasNonKeplerianRates() ?
799 keplerianAcceleration.add(nonKeplerianAcceleration()) :
800 keplerianAcceleration;
801
802 return new TimeStampedPVCoordinates(getDate(), partialPV.getPosition(), partialPV.getVelocity(), acceleration);
803
804 }
805
806
807 @Override
808 public EquinoctialOrbit inFrame(final Frame inertialFrame) {
809 final PVCoordinates pvCoordinates;
810 if (hasNonKeplerianAcceleration()) {
811 pvCoordinates = getPVCoordinates(inertialFrame);
812 } else {
813 final KinematicTransform transform = getFrame().getKinematicTransformTo(inertialFrame, getDate());
814 pvCoordinates = transform.transformOnlyPV(getPVCoordinates());
815 }
816 final EquinoctialOrbit equinoctialOrbit = new EquinoctialOrbit(pvCoordinates, inertialFrame, getDate(), getMu());
817 if (equinoctialOrbit.getCachedPositionAngleType() == getCachedPositionAngleType()) {
818 return equinoctialOrbit;
819 } else {
820 return equinoctialOrbit.withCachedPositionAngleType(getCachedPositionAngleType());
821 }
822 }
823
824
825 @Override
826 public EquinoctialOrbit withCachedPositionAngleType(final PositionAngleType positionAngleType) {
827 return new EquinoctialOrbit(a, ex, ey, hx, hy, getL(positionAngleType), aDot, exDot, eyDot, hxDot, hyDot,
828 getLDot(positionAngleType), positionAngleType, getFrame(), getDate(), getMu());
829 }
830
831
832 @Override
833 public EquinoctialOrbit shiftedBy(final double dt) {
834 return shiftedBy(new TimeOffset(dt));
835 }
836
837
838 @Override
839 public EquinoctialOrbit shiftedBy(final TimeOffset dt) {
840
841 final double dtS = dt.toDouble();
842
843
844 final EquinoctialOrbit keplerianShifted = new EquinoctialOrbit(a, ex, ey, hx, hy,
845 getLM() + getKeplerianMeanMotion() * dtS,
846 PositionAngleType.MEAN, cachedPositionAngleType,
847 getFrame(),
848 getDate().shiftedBy(dt), getMu());
849
850 if (dtS != 0. && hasNonKeplerianRates()) {
851 final PVCoordinates pvCoordinates = shiftNonKeplerian(keplerianShifted.getPVCoordinates(), dtS);
852
853
854 return new EquinoctialOrbit(new TimeStampedPVCoordinates(keplerianShifted.getDate(), pvCoordinates),
855 keplerianShifted.getFrame(), keplerianShifted.getMu());
856
857 } else {
858
859 return keplerianShifted;
860 }
861
862 }
863
864
865 @Override
866 protected double[][] computeJacobianMeanWrtCartesian() {
867
868 final double[][] jacobian = new double[6][6];
869
870
871 computePVWithoutA();
872 final Vector3D position = partialPV.getPosition();
873 final Vector3D velocity = partialPV.getVelocity();
874 final double r2 = position.getNorm2Sq();
875 final double r = FastMath.sqrt(r2);
876 final double r3 = r * r2;
877
878 final double mu = getMu();
879 final double sqrtMuA = FastMath.sqrt(a * mu);
880 final double a2 = a * a;
881
882 final double e2 = ex * ex + ey * ey;
883 final double oMe2 = 1 - e2;
884 final double epsilon = FastMath.sqrt(oMe2);
885 final double beta = 1 / (1 + epsilon);
886 final double ratio = epsilon * beta;
887
888 final double hx2 = hx * hx;
889 final double hy2 = hy * hy;
890 final double hxhy = hx * hy;
891
892
893 final Vector3D f = new Vector3D(1 - hy2 + hx2, 2 * hxhy, -2 * hy).normalize();
894 final Vector3D g = new Vector3D(2 * hxhy, 1 + hy2 - hx2, 2 * hx).normalize();
895 final Vector3D w = Vector3D.crossProduct(position, velocity).normalize();
896
897
898 final double x = Vector3D.dotProduct(position, f);
899 final double y = Vector3D.dotProduct(position, g);
900 final double xDot = Vector3D.dotProduct(velocity, f);
901 final double yDot = Vector3D.dotProduct(velocity, g);
902
903
904 final double c1 = a / (sqrtMuA * epsilon);
905 final double c2 = a * sqrtMuA * beta / r3;
906 final double c3 = sqrtMuA / (r3 * epsilon);
907 final Vector3D drDotSdEx = new Vector3D( c1 * xDot * yDot - c2 * ey * x - c3 * x * y, f,
908 -c1 * xDot * xDot - c2 * ey * y + c3 * x * x, g);
909
910
911 final Vector3D drDotSdEy = new Vector3D( c1 * yDot * yDot + c2 * ex * x - c3 * y * y, f,
912 -c1 * xDot * yDot + c2 * ex * y + c3 * x * y, g);
913
914
915 final Vector3D vectorAR = new Vector3D(2 * a2 / r3, position);
916 final Vector3D vectorARDot = new Vector3D(2 * a2 / mu, velocity);
917 fillHalfRow(1, vectorAR, jacobian[0], 0);
918 fillHalfRow(1, vectorARDot, jacobian[0], 3);
919
920
921 final double d1 = -a * ratio / r3;
922 final double d2 = (hy * xDot - hx * yDot) / (sqrtMuA * epsilon);
923 final double d3 = (hx * y - hy * x) / sqrtMuA;
924 final Vector3D vectorExRDot =
925 new Vector3D((2 * x * yDot - xDot * y) / mu, g, -y * yDot / mu, f, -ey * d3 / epsilon, w);
926 fillHalfRow(ex * d1, position, -ey * d2, w, epsilon / sqrtMuA, drDotSdEy, jacobian[1], 0);
927 fillHalfRow(1, vectorExRDot, jacobian[1], 3);
928
929
930 final Vector3D vectorEyRDot =
931 new Vector3D((2 * xDot * y - x * yDot) / mu, f, -x * xDot / mu, g, ex * d3 / epsilon, w);
932 fillHalfRow(ey * d1, position, ex * d2, w, -epsilon / sqrtMuA, drDotSdEx, jacobian[2], 0);
933 fillHalfRow(1, vectorEyRDot, jacobian[2], 3);
934
935
936 final double h = (1 + hx2 + hy2) / (2 * sqrtMuA * epsilon);
937 fillHalfRow(-h * xDot, w, jacobian[3], 0);
938 fillHalfRow( h * x, w, jacobian[3], 3);
939
940
941 fillHalfRow(-h * yDot, w, jacobian[4], 0);
942 fillHalfRow( h * y, w, jacobian[4], 3);
943
944
945 final double l = -ratio / sqrtMuA;
946 fillHalfRow(-1 / sqrtMuA, velocity, d2, w, l * ex, drDotSdEx, l * ey, drDotSdEy, jacobian[5], 0);
947 fillHalfRow(-2 / sqrtMuA, position, ex * beta, vectorEyRDot, -ey * beta, vectorExRDot, d3, w, jacobian[5], 3);
948
949 return jacobian;
950
951 }
952
953
954 @Override
955 protected double[][] computeJacobianEccentricWrtCartesian() {
956
957
958 final double[][] jacobian = computeJacobianMeanWrtCartesian();
959
960
961
962
963
964 final SinCos scLe = FastMath.sinCos(getLE());
965 final double cosLe = scLe.cos();
966 final double sinLe = scLe.sin();
967 final double aOr = 1 / (1 - ex * cosLe - ey * sinLe);
968
969
970 final double[] rowEx = jacobian[1];
971 final double[] rowEy = jacobian[2];
972 final double[] rowL = jacobian[5];
973 for (int j = 0; j < 6; ++j) {
974 rowL[j] = aOr * (rowL[j] + sinLe * rowEx[j] - cosLe * rowEy[j]);
975 }
976
977 return jacobian;
978
979 }
980
981
982 @Override
983 protected double[][] computeJacobianTrueWrtCartesian() {
984
985
986 final double[][] jacobian = computeJacobianEccentricWrtCartesian();
987
988
989
990
991
992
993
994
995
996
997
998
999
1000 final SinCos scLe = FastMath.sinCos(getLE());
1001 final double cosLe = scLe.cos();
1002 final double sinLe = scLe.sin();
1003 final double eSinE = ex * sinLe - ey * cosLe;
1004 final double ecosE = ex * cosLe + ey * sinLe;
1005 final double e2 = ex * ex + ey * ey;
1006 final double epsilon = FastMath.sqrt(1 - e2);
1007 final double onePeps = 1 + epsilon;
1008 final double d = onePeps - ecosE;
1009 final double cT = (d * d + eSinE * eSinE) / 2;
1010 final double cE = ecosE * onePeps - e2;
1011 final double cX = ex * eSinE / epsilon - ey + sinLe * onePeps;
1012 final double cY = ey * eSinE / epsilon + ex - cosLe * onePeps;
1013 final double factorLe = (cT + cE) / cT;
1014 final double factorEx = cX / cT;
1015 final double factorEy = cY / cT;
1016
1017
1018 final double[] rowEx = jacobian[1];
1019 final double[] rowEy = jacobian[2];
1020 final double[] rowL = jacobian[5];
1021 for (int j = 0; j < 6; ++j) {
1022 rowL[j] = factorLe * rowL[j] + factorEx * rowEx[j] + factorEy * rowEy[j];
1023 }
1024
1025 return jacobian;
1026
1027 }
1028
1029
1030 @Override
1031 public void addKeplerContribution(final PositionAngleType type, final double gm,
1032 final double[] pDot) {
1033 pDot[5] += computeKeplerianLDot(type, a, ex, ey, gm, cachedL, cachedPositionAngleType);
1034 }
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048 private static double computeKeplerianLDot(final PositionAngleType type, final double a, final double ex,
1049 final double ey, final double mu,
1050 final double l, final PositionAngleType cachedType) {
1051 final double n = FastMath.sqrt(mu / a) / a;
1052 if (type == PositionAngleType.MEAN) {
1053 return n;
1054 }
1055 final double oMe2;
1056 final double ksi;
1057 final SinCos sc;
1058 if (type == PositionAngleType.ECCENTRIC) {
1059 sc = FastMath.sinCos(EquinoctialLongitudeArgumentUtility.convertL(cachedType, l, ex, ey, type));
1060 ksi = 1. / (1 - ex * sc.cos() - ey * sc.sin());
1061 return n * ksi;
1062 } else {
1063 sc = FastMath.sinCos(EquinoctialLongitudeArgumentUtility.convertL(cachedType, l, ex, ey, type));
1064 oMe2 = 1 - ex * ex - ey * ey;
1065 ksi = 1 + ex * sc.cos() + ey * sc.sin();
1066 return n * ksi * ksi / (oMe2 * FastMath.sqrt(oMe2));
1067 }
1068 }
1069
1070
1071
1072
1073 public String toString() {
1074 return new StringBuilder().append("equinoctial parameters: ").append('{').
1075 append("a: ").append(a).
1076 append("; ex: ").append(ex).append("; ey: ").append(ey).
1077 append("; hx: ").append(hx).append("; hy: ").append(hy).
1078 append("; lv: ").append(FastMath.toDegrees(getLv())).
1079 append(";}").toString();
1080 }
1081
1082
1083 @Override
1084 public PositionAngleType getCachedPositionAngleType() {
1085 return cachedPositionAngleType;
1086 }
1087
1088
1089 @Override
1090 public boolean hasNonKeplerianRates() {
1091 return hasNonKeplerianAcceleration();
1092 }
1093
1094
1095 @Override
1096 public EquinoctialOrbit withKeplerianRates() {
1097 final PositionAngleType positionAngleType = getCachedPositionAngleType();
1098 return new EquinoctialOrbit(getA(), getEquinoctialEx(), getEquinoctialEy(), getHx(), getHy(),
1099 getL(positionAngleType), positionAngleType, getFrame(), getDate(), getMu());
1100 }
1101
1102 }