1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.orbits;
18
19 import java.io.Serializable;
20 import java.util.Collection;
21
22 import org.apache.commons.math3.analysis.interpolation.HermiteInterpolator;
23 import org.apache.commons.math3.exception.ConvergenceException;
24 import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
25 import org.apache.commons.math3.util.FastMath;
26 import org.apache.commons.math3.util.MathUtils;
27 import org.orekit.errors.OrekitIllegalArgumentException;
28 import org.orekit.errors.OrekitInternalError;
29 import org.orekit.errors.OrekitMessages;
30 import org.orekit.frames.Frame;
31 import org.orekit.time.AbsoluteDate;
32 import org.orekit.utils.PVCoordinates;
33 import org.orekit.utils.TimeStampedPVCoordinates;
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
75 public class KeplerianOrbit extends Orbit {
76
77
78 private static final long serialVersionUID = 20141228L;
79
80
81 private static final double A;
82
83
84 private static final double B;
85
86 static {
87 final double k1 = 3 * FastMath.PI + 2;
88 final double k2 = FastMath.PI - 1;
89 final double k3 = 6 * FastMath.PI - 1;
90 A = 3 * k2 * k2 / k1;
91 B = k3 * k3 / (6 * k1);
92 }
93
94
95 private final double a;
96
97
98 private final double e;
99
100
101 private final double i;
102
103
104 private final double pa;
105
106
107 private final double raan;
108
109
110 private final double v;
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128 public KeplerianOrbit(final double a, final double e, final double i,
129 final double pa, final double raan,
130 final double anomaly, final PositionAngle type,
131 final Frame frame, final AbsoluteDate date, final double mu)
132 throws IllegalArgumentException {
133 super(frame, date, mu);
134
135 if (a * (1 - e) < 0) {
136 throw new OrekitIllegalArgumentException(OrekitMessages.ORBIT_A_E_MISMATCH_WITH_CONIC_TYPE, a, e);
137 }
138
139 this.a = a;
140 this.e = e;
141 this.i = i;
142 this.pa = pa;
143 this.raan = raan;
144
145 final double tmpV;
146 switch (type) {
147 case MEAN :
148 tmpV = (a < 0) ? hyperbolicEccentricToTrue(meanToHyperbolicEccentric(anomaly, e)) :
149 ellipticEccentricToTrue(meanToEllipticEccentric(anomaly));
150 break;
151 case ECCENTRIC :
152 tmpV = (a < 0) ? hyperbolicEccentricToTrue(anomaly) :
153 ellipticEccentricToTrue(anomaly);
154 break;
155 case TRUE :
156 tmpV = anomaly;
157 break;
158 default :
159 throw new OrekitInternalError(null);
160 }
161
162
163 if (1 + e * FastMath.cos(tmpV) <= 0) {
164 final double vMax = FastMath.acos(-1 / e);
165 throw new OrekitIllegalArgumentException(OrekitMessages.ORBIT_ANOMALY_OUT_OF_HYPERBOLIC_RANGE,
166 tmpV, e, -vMax, vMax);
167 }
168 this.v = tmpV;
169
170 }
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186 public KeplerianOrbit(final TimeStampedPVCoordinates pvCoordinates,
187 final Frame frame, final double mu)
188 throws IllegalArgumentException {
189 super(pvCoordinates, frame, mu);
190
191
192 final Vector3D momentum = pvCoordinates.getMomentum();
193 final double m2 = momentum.getNormSq();
194 i = Vector3D.angle(momentum, Vector3D.PLUS_K);
195
196
197 raan = Vector3D.crossProduct(Vector3D.PLUS_K, momentum).getAlpha();
198
199
200 final Vector3D pvP = pvCoordinates.getPosition();
201 final Vector3D pvV = pvCoordinates.getVelocity();
202 final double r = pvP.getNorm();
203 final double V2 = pvV.getNormSq();
204 final double rV2OnMu = r * V2 / mu;
205
206
207 a = r / (2 - rV2OnMu);
208 final double muA = mu * a;
209
210
211 if (a > 0) {
212
213 final double eSE = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(muA);
214 final double eCE = rV2OnMu - 1;
215 e = FastMath.sqrt(eSE * eSE + eCE * eCE);
216 v = ellipticEccentricToTrue(FastMath.atan2(eSE, eCE));
217 } else {
218
219 final double eSH = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(-muA);
220 final double eCH = rV2OnMu - 1;
221 e = FastMath.sqrt(1 - m2 / muA);
222 v = hyperbolicEccentricToTrue(FastMath.log((eCH + eSH) / (eCH - eSH)) / 2);
223 }
224
225
226 final Vector3D node = new Vector3D(raan, 0.0);
227 final double px = Vector3D.dotProduct(pvP, node);
228 final double py = Vector3D.dotProduct(pvP, Vector3D.crossProduct(momentum, node)) / FastMath.sqrt(m2);
229 pa = FastMath.atan2(py, px) - v;
230
231 }
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248 public KeplerianOrbit(final PVCoordinates pvCoordinates,
249 final Frame frame, final AbsoluteDate date, final double mu)
250 throws IllegalArgumentException {
251 this(new TimeStampedPVCoordinates(date, pvCoordinates), frame, mu);
252 }
253
254
255
256
257 public KeplerianOrbit(final Orbit op) {
258 this(op.getPVCoordinates(), op.getFrame(), op.getDate(), op.getMu());
259 }
260
261
262 public OrbitType getType() {
263 return OrbitType.KEPLERIAN;
264 }
265
266
267 public double getA() {
268 return a;
269 }
270
271
272 public double getE() {
273 return e;
274 }
275
276
277 public double getI() {
278 return i;
279 }
280
281
282
283
284 public double getPerigeeArgument() {
285 return pa;
286 }
287
288
289
290
291 public double getRightAscensionOfAscendingNode() {
292 return raan;
293 }
294
295
296
297
298
299 public double getAnomaly(final PositionAngle type) {
300 return (type == PositionAngle.MEAN) ? getMeanAnomaly() :
301 ((type == PositionAngle.ECCENTRIC) ? getEccentricAnomaly() :
302 getTrueAnomaly());
303 }
304
305
306
307
308 public double getTrueAnomaly() {
309 return v;
310 }
311
312
313
314
315 public double getEccentricAnomaly() {
316 if (a < 0) {
317
318 final double sinhH = FastMath.sqrt(e * e - 1) * FastMath.sin(v) /
319 (1 + e * FastMath.cos(v));
320 return FastMath.asinh(sinhH);
321 }
322
323
324 final double beta = e / (1 + FastMath.sqrt((1 - e) * (1 + e)));
325 return v - 2 * FastMath.atan(beta * FastMath.sin(v) / (1 + beta * FastMath.cos(v)));
326
327 }
328
329
330
331
332
333 private double ellipticEccentricToTrue(final double E) {
334 final double beta = e / (1 + FastMath.sqrt((1 - e) * (1 + e)));
335 return E + 2 * FastMath.atan(beta * FastMath.sin(E) / (1 - beta * FastMath.cos(E)));
336 }
337
338
339
340
341
342 private double hyperbolicEccentricToTrue(final double H) {
343 return 2 * FastMath.atan(FastMath.sqrt((e + 1) / (e - 1)) * FastMath.tanh(H / 2));
344 }
345
346
347
348
349 public double getMeanAnomaly() {
350
351 if (a < 0) {
352
353 final double H = getEccentricAnomaly();
354 return e * FastMath.sinh(H) - H;
355 }
356
357
358 final double E = getEccentricAnomaly();
359 return E - e * FastMath.sin(E);
360
361 }
362
363
364
365
366
367
368
369
370
371
372 private double meanToEllipticEccentric(final double M) {
373
374
375 final double reducedM = MathUtils.normalizeAngle(M, 0.0);
376
377
378 double E;
379 if (FastMath.abs(reducedM) < 1.0 / 6.0) {
380 E = reducedM + e * (FastMath.cbrt(6 * reducedM) - reducedM);
381 } else {
382 if (reducedM < 0) {
383 final double w = FastMath.PI + reducedM;
384 E = reducedM + e * (A * w / (B - w) - FastMath.PI - reducedM);
385 } else {
386 final double w = FastMath.PI - reducedM;
387 E = reducedM + e * (FastMath.PI - A * w / (B - w) - reducedM);
388 }
389 }
390
391 final double e1 = 1 - e;
392 final boolean noCancellationRisk = (e1 + E * E / 6) >= 0.1;
393
394
395 for (int j = 0; j < 2; ++j) {
396 double f;
397 double fd;
398 final double fdd = e * FastMath.sin(E);
399 final double fddd = e * FastMath.cos(E);
400 if (noCancellationRisk) {
401 f = (E - fdd) - reducedM;
402 fd = 1 - fddd;
403 } else {
404 f = eMeSinE(E) - reducedM;
405 final double s = FastMath.sin(0.5 * E);
406 fd = e1 + 2 * e * s * s;
407 }
408 final double dee = f * fd / (0.5 * f * fdd - fd * fd);
409
410
411 final double w = fd + 0.5 * dee * (fdd + dee * fddd / 3);
412 fd += dee * (fdd + 0.5 * dee * fddd);
413 E -= (f - dee * (fd - w)) / fd;
414
415 }
416
417
418 E += M - reducedM;
419
420 return E;
421
422 }
423
424
425
426
427
428
429
430
431
432 private double eMeSinE(final double E) {
433 double x = (1 - e) * FastMath.sin(E);
434 final double mE2 = -E * E;
435 double term = E;
436 double d = 0;
437
438 for (double x0 = Double.NaN; x != x0;) {
439 d += 2;
440 term *= mE2 / (d * (d + 1));
441 x0 = x;
442 x = x - term;
443 }
444 return x;
445 }
446
447
448
449
450
451
452
453
454
455
456 private double meanToHyperbolicEccentric(final double M, final double ecc) {
457
458
459
460
461 double H;
462 if (ecc < 1.6) {
463 if ((-FastMath.PI < M && M < 0.) || M > FastMath.PI) {
464 H = M - ecc;
465 } else {
466 H = M + ecc;
467 }
468 } else {
469 if (ecc < 3.6 && FastMath.abs(M) > FastMath.PI) {
470 H = M - FastMath.copySign(ecc, M);
471 } else {
472 H = M / (ecc - 1.);
473 }
474 }
475
476
477 int iter = 0;
478 do {
479 final double f3 = ecc * FastMath.cosh(H);
480 final double f2 = ecc * FastMath.sinh(H);
481 final double f1 = f3 - 1.;
482 final double f0 = f2 - H - M;
483 final double f12 = 2. * f1;
484 final double d = f0 / f12;
485 final double fdf = f1 - d * f2;
486 final double ds = f0 / fdf;
487
488 final double shift = f0 / (fdf + ds * ds * f3 / 6.);
489
490 H -= shift;
491
492 if (FastMath.abs(shift) <= 1.0e-12) {
493 return H;
494 }
495
496 } while (++iter < 50);
497
498 throw new ConvergenceException(OrekitMessages.UNABLE_TO_COMPUTE_HYPERBOLIC_ECCENTRIC_ANOMALY,
499 iter);
500 }
501
502
503 public double getEquinoctialEx() {
504 return e * FastMath.cos(pa + raan);
505 }
506
507
508 public double getEquinoctialEy() {
509 return e * FastMath.sin(pa + raan);
510 }
511
512
513 public double getHx() {
514
515 if (FastMath.abs(i - FastMath.PI) < 1.0e-10) {
516 return Double.NaN;
517 }
518 return FastMath.cos(raan) * FastMath.tan(i / 2);
519 }
520
521
522 public double getHy() {
523
524 if (FastMath.abs(i - FastMath.PI) < 1.0e-10) {
525 return Double.NaN;
526 }
527 return FastMath.sin(raan) * FastMath.tan(i / 2);
528 }
529
530
531 public double getLv() {
532 return pa + raan + v;
533 }
534
535
536 public double getLE() {
537 return pa + raan + getEccentricAnomaly();
538 }
539
540
541 public double getLM() {
542 return pa + raan + getMeanAnomaly();
543 }
544
545
546 protected TimeStampedPVCoordinates initPVCoordinates() {
547
548
549 final double cosRaan = FastMath.cos(raan);
550 final double sinRaan = FastMath.sin(raan);
551 final double cosPa = FastMath.cos(pa);
552 final double sinPa = FastMath.sin(pa);
553 final double cosI = FastMath.cos(i);
554 final double sinI = FastMath.sin(i);
555
556 final double crcp = cosRaan * cosPa;
557 final double crsp = cosRaan * sinPa;
558 final double srcp = sinRaan * cosPa;
559 final double srsp = sinRaan * sinPa;
560
561
562 final Vector3D p = new Vector3D( crcp - cosI * srsp, srcp + cosI * crsp, sinI * sinPa);
563 final Vector3D q = new Vector3D(-crsp - cosI * srcp, -srsp + cosI * crcp, sinI * cosPa);
564
565 return (a > 0) ? initPVCoordinatesElliptical(p, q) : initPVCoordinatesHyperbolic(p, q);
566
567 }
568
569
570
571
572
573
574 private TimeStampedPVCoordinates initPVCoordinatesElliptical(final Vector3D p, final Vector3D q) {
575
576
577 final double uME2 = (1 - e) * (1 + e);
578 final double s1Me2 = FastMath.sqrt(uME2);
579 final double E = getEccentricAnomaly();
580 final double cosE = FastMath.cos(E);
581 final double sinE = FastMath.sin(E);
582
583
584 final double x = a * (cosE - e);
585 final double y = a * sinE * s1Me2;
586 final double factor = FastMath.sqrt(getMu() / a) / (1 - e * cosE);
587 final double xDot = -sinE * factor;
588 final double yDot = cosE * s1Me2 * factor;
589
590
591 final Vector3D position = new Vector3D(x, p, y, q);
592 final double r2 = x * x + y * y;
593 final Vector3D velocity = new Vector3D(xDot, p, yDot, q);
594 final Vector3D acceleration = new Vector3D(-getMu() / (r2 * FastMath.sqrt(r2)), position);
595 return new TimeStampedPVCoordinates(getDate(), position, velocity, acceleration);
596
597 }
598
599
600
601
602
603
604 private TimeStampedPVCoordinates initPVCoordinatesHyperbolic(final Vector3D p, final Vector3D q) {
605
606
607 final double sinV = FastMath.sin(v);
608 final double cosV = FastMath.cos(v);
609 final double f = a * (1 - e * e);
610 final double posFactor = f / (1 + e * cosV);
611 final double velFactor = FastMath.sqrt(getMu() / f);
612
613 final Vector3D position = new Vector3D( posFactor * cosV, p, posFactor * sinV, q);
614 final Vector3D velocity = new Vector3D(-velFactor * sinV, p, velFactor * (e + cosV), q);
615 final Vector3D acceleration = new Vector3D(-getMu() / (posFactor * posFactor * posFactor), position);
616 return new TimeStampedPVCoordinates(getDate(), position, velocity, acceleration);
617
618 }
619
620
621 public KeplerianOrbit shiftedBy(final double dt) {
622 return new KeplerianOrbit(a, e, i, pa, raan,
623 getMeanAnomaly() + getKeplerianMeanMotion() * dt,
624 PositionAngle.MEAN, getFrame(), getDate().shiftedBy(dt), getMu());
625 }
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647 public KeplerianOrbit interpolate(final AbsoluteDate date, final Collection<Orbit> sample) {
648
649
650 final HermiteInterpolator interpolator = new HermiteInterpolator();
651
652
653 AbsoluteDate previousDate = null;
654 double previousPA = Double.NaN;
655 double previousRAAN = Double.NaN;
656 double previousM = Double.NaN;
657 for (final Orbit orbit : sample) {
658 final KeplerianOrbit kep = (KeplerianOrbit) OrbitType.KEPLERIAN.convertType(orbit);
659 final double continuousPA;
660 final double continuousRAAN;
661 final double continuousM;
662 if (previousDate == null) {
663 continuousPA = kep.getPerigeeArgument();
664 continuousRAAN = kep.getRightAscensionOfAscendingNode();
665 continuousM = kep.getMeanAnomaly();
666 } else {
667 final double dt = kep.getDate().durationFrom(previousDate);
668 final double keplerM = previousM + kep.getKeplerianMeanMotion() * dt;
669 continuousPA = MathUtils.normalizeAngle(kep.getPerigeeArgument(), previousPA);
670 continuousRAAN = MathUtils.normalizeAngle(kep.getRightAscensionOfAscendingNode(), previousRAAN);
671 continuousM = MathUtils.normalizeAngle(kep.getMeanAnomaly(), keplerM);
672 }
673 previousDate = kep.getDate();
674 previousPA = continuousPA;
675 previousRAAN = continuousRAAN;
676 previousM = continuousM;
677 interpolator.addSamplePoint(kep.getDate().durationFrom(date),
678 new double[] {
679 kep.getA(),
680 kep.getE(),
681 kep.getI(),
682 continuousPA,
683 continuousRAAN,
684 continuousM
685 });
686 }
687
688
689 final double[] interpolated = interpolator.value(0);
690
691
692 return new KeplerianOrbit(interpolated[0], interpolated[1], interpolated[2],
693 interpolated[3], interpolated[4], interpolated[5],
694 PositionAngle.MEAN, getFrame(), date, getMu());
695
696 }
697
698
699 protected double[][] computeJacobianMeanWrtCartesian() {
700 if (a > 0) {
701 return computeJacobianMeanWrtCartesianElliptical();
702 } else {
703 return computeJacobianMeanWrtCartesianHyperbolic();
704 }
705 }
706
707
708
709
710
711
712
713
714
715 private double[][] computeJacobianMeanWrtCartesianElliptical() {
716
717 final double[][] jacobian = new double[6][6];
718
719
720 final PVCoordinates pvc = getPVCoordinates();
721 final Vector3D position = pvc.getPosition();
722 final Vector3D velocity = pvc.getVelocity();
723 final Vector3D momentum = pvc.getMomentum();
724 final double v2 = velocity.getNormSq();
725 final double r2 = position.getNormSq();
726 final double r = FastMath.sqrt(r2);
727 final double r3 = r * r2;
728
729 final double px = position.getX();
730 final double py = position.getY();
731 final double pz = position.getZ();
732 final double vx = velocity.getX();
733 final double vy = velocity.getY();
734 final double vz = velocity.getZ();
735 final double mx = momentum.getX();
736 final double my = momentum.getY();
737 final double mz = momentum.getZ();
738
739 final double mu = getMu();
740 final double sqrtMuA = FastMath.sqrt(a * mu);
741 final double sqrtAoMu = FastMath.sqrt(a / mu);
742 final double a2 = a * a;
743 final double twoA = 2 * a;
744 final double rOnA = r / a;
745
746 final double oMe2 = 1 - e * e;
747 final double epsilon = FastMath.sqrt(oMe2);
748 final double sqrtRec = 1 / epsilon;
749
750 final double cosI = FastMath.cos(i);
751 final double sinI = FastMath.sin(i);
752 final double cosPA = FastMath.cos(pa);
753 final double sinPA = FastMath.sin(pa);
754
755 final double pv = Vector3D.dotProduct(position, velocity);
756 final double cosE = (a - r) / (a * e);
757 final double sinE = pv / (e * sqrtMuA);
758
759
760 final Vector3D vectorAR = new Vector3D(2 * a2 / r3, position);
761 final Vector3D vectorARDot = velocity.scalarMultiply(2 * a2 / mu);
762 fillHalfRow(1, vectorAR, jacobian[0], 0);
763 fillHalfRow(1, vectorARDot, jacobian[0], 3);
764
765
766 final double factorER3 = pv / twoA;
767 final Vector3D vectorER = new Vector3D(cosE * v2 / (r * mu), position,
768 sinE / sqrtMuA, velocity,
769 -factorER3 * sinE / sqrtMuA, vectorAR);
770 final Vector3D vectorERDot = new Vector3D(sinE / sqrtMuA, position,
771 cosE * 2 * r / mu, velocity,
772 -factorER3 * sinE / sqrtMuA, vectorARDot);
773 fillHalfRow(1, vectorER, jacobian[1], 0);
774 fillHalfRow(1, vectorERDot, jacobian[1], 3);
775
776
777 final double coefE = cosE / (e * sqrtMuA);
778 final Vector3D vectorEAnR =
779 new Vector3D(-sinE * v2 / (e * r * mu), position, coefE, velocity,
780 -factorER3 * coefE, vectorAR);
781
782
783 final Vector3D vectorEAnRDot =
784 new Vector3D(-sinE * 2 * r / (e * mu), velocity, coefE, position,
785 -factorER3 * coefE, vectorARDot);
786
787
788 final double s1 = -sinE * pz / r - cosE * vz * sqrtAoMu;
789 final double s2 = -cosE * pz / r3;
790 final double s3 = -sinE * vz / (2 * sqrtMuA);
791 final double t1 = sqrtRec * (cosE * pz / r - sinE * vz * sqrtAoMu);
792 final double t2 = sqrtRec * (-sinE * pz / r3);
793 final double t3 = sqrtRec * (cosE - e) * vz / (2 * sqrtMuA);
794 final double t4 = sqrtRec * (e * sinI * cosPA * sqrtRec - vz * sqrtAoMu);
795 final Vector3D s = new Vector3D(cosE / r, Vector3D.PLUS_K,
796 s1, vectorEAnR,
797 s2, position,
798 s3, vectorAR);
799 final Vector3D sDot = new Vector3D(-sinE * sqrtAoMu, Vector3D.PLUS_K,
800 s1, vectorEAnRDot,
801 s3, vectorARDot);
802 final Vector3D t =
803 new Vector3D(sqrtRec * sinE / r, Vector3D.PLUS_K).add(new Vector3D(t1, vectorEAnR,
804 t2, position,
805 t3, vectorAR,
806 t4, vectorER));
807 final Vector3D tDot = new Vector3D(sqrtRec * (cosE - e) * sqrtAoMu, Vector3D.PLUS_K,
808 t1, vectorEAnRDot,
809 t3, vectorARDot,
810 t4, vectorERDot);
811
812
813 final double factorI1 = -sinI * sqrtRec / sqrtMuA;
814 final double i1 = factorI1;
815 final double i2 = -factorI1 * mz / twoA;
816 final double i3 = factorI1 * mz * e / oMe2;
817 final double i4 = cosI * sinPA;
818 final double i5 = cosI * cosPA;
819 fillHalfRow(i1, new Vector3D(vy, -vx, 0), i2, vectorAR, i3, vectorER, i4, s, i5, t,
820 jacobian[2], 0);
821 fillHalfRow(i1, new Vector3D(-py, px, 0), i2, vectorARDot, i3, vectorERDot, i4, sDot, i5, tDot,
822 jacobian[2], 3);
823
824
825 fillHalfRow(cosPA / sinI, s, -sinPA / sinI, t, jacobian[3], 0);
826 fillHalfRow(cosPA / sinI, sDot, -sinPA / sinI, tDot, jacobian[3], 3);
827
828
829 final double factorRaanR = 1 / (mu * a * oMe2 * sinI * sinI);
830 fillHalfRow(-factorRaanR * my, new Vector3D( 0, vz, -vy),
831 factorRaanR * mx, new Vector3D(-vz, 0, vx),
832 jacobian[4], 0);
833 fillHalfRow(-factorRaanR * my, new Vector3D( 0, -pz, py),
834 factorRaanR * mx, new Vector3D(pz, 0, -px),
835 jacobian[4], 3);
836
837
838 fillHalfRow(rOnA, vectorEAnR, -sinE, vectorER, jacobian[5], 0);
839 fillHalfRow(rOnA, vectorEAnRDot, -sinE, vectorERDot, jacobian[5], 3);
840
841 return jacobian;
842
843 }
844
845
846
847
848
849
850
851
852
853 private double[][] computeJacobianMeanWrtCartesianHyperbolic() {
854
855 final double[][] jacobian = new double[6][6];
856
857
858 final PVCoordinates pvc = getPVCoordinates();
859 final Vector3D position = pvc.getPosition();
860 final Vector3D velocity = pvc.getVelocity();
861 final Vector3D momentum = pvc.getMomentum();
862 final double r2 = position.getNormSq();
863 final double r = FastMath.sqrt(r2);
864 final double r3 = r * r2;
865
866 final double x = position.getX();
867 final double y = position.getY();
868 final double z = position.getZ();
869 final double vx = velocity.getX();
870 final double vy = velocity.getY();
871 final double vz = velocity.getZ();
872 final double mx = momentum.getX();
873 final double my = momentum.getY();
874 final double mz = momentum.getZ();
875
876 final double mu = getMu();
877 final double absA = -a;
878 final double sqrtMuA = FastMath.sqrt(absA * mu);
879 final double a2 = a * a;
880 final double rOa = r / absA;
881
882 final double cosI = FastMath.cos(i);
883 final double sinI = FastMath.sin(i);
884
885 final double pv = Vector3D.dotProduct(position, velocity);
886
887
888 final Vector3D vectorAR = new Vector3D(-2 * a2 / r3, position);
889 final Vector3D vectorARDot = velocity.scalarMultiply(-2 * a2 / mu);
890 fillHalfRow(-1, vectorAR, jacobian[0], 0);
891 fillHalfRow(-1, vectorARDot, jacobian[0], 3);
892
893
894 final double m = momentum.getNorm();
895 final double oOm = 1 / m;
896 final Vector3D dcXP = new Vector3D( 0, vz, -vy);
897 final Vector3D dcYP = new Vector3D(-vz, 0, vx);
898 final Vector3D dcZP = new Vector3D( vy, -vx, 0);
899 final Vector3D dcXV = new Vector3D( 0, -z, y);
900 final Vector3D dcYV = new Vector3D( z, 0, -x);
901 final Vector3D dcZV = new Vector3D( -y, x, 0);
902 final Vector3D dCP = new Vector3D(mx * oOm, dcXP, my * oOm, dcYP, mz * oOm, dcZP);
903 final Vector3D dCV = new Vector3D(mx * oOm, dcXV, my * oOm, dcYV, mz * oOm, dcZV);
904
905
906 final double mOMu = m / mu;
907 final Vector3D dpP = new Vector3D(2 * mOMu, dCP);
908 final Vector3D dpV = new Vector3D(2 * mOMu, dCV);
909
910
911 final double p = m * mOMu;
912 final double moO2ae = 1 / (2 * absA * e);
913 final double m2OaMu = -p / absA;
914 fillHalfRow(moO2ae, dpP, m2OaMu * moO2ae, vectorAR, jacobian[1], 0);
915 fillHalfRow(moO2ae, dpV, m2OaMu * moO2ae, vectorARDot, jacobian[1], 3);
916
917
918 final double cI1 = 1 / (m * sinI);
919 final double cI2 = cosI * cI1;
920 fillHalfRow(cI2, dCP, -cI1, dcZP, jacobian[2], 0);
921 fillHalfRow(cI2, dCV, -cI1, dcZV, jacobian[2], 3);
922
923
924 final double cP1 = y * oOm;
925 final double cP2 = -x * oOm;
926 final double cP3 = -(mx * cP1 + my * cP2);
927 final double cP4 = cP3 * oOm;
928 final double cP5 = -1 / (r2 * sinI * sinI);
929 final double cP6 = z * cP5;
930 final double cP7 = cP3 * cP5;
931 final Vector3D dacP = new Vector3D(cP1, dcXP, cP2, dcYP, cP4, dCP, oOm, new Vector3D(-my, mx, 0));
932 final Vector3D dacV = new Vector3D(cP1, dcXV, cP2, dcYV, cP4, dCV);
933 final Vector3D dpoP = new Vector3D(cP6, dacP, cP7, Vector3D.PLUS_K);
934 final Vector3D dpoV = new Vector3D(cP6, dacV);
935
936 final double re2 = r2 * e * e;
937 final double recOre2 = (p - r) / re2;
938 final double resOre2 = (pv * mOMu) / re2;
939 final Vector3D dreP = new Vector3D(mOMu, velocity, pv / mu, dCP);
940 final Vector3D dreV = new Vector3D(mOMu, position, pv / mu, dCV);
941 final Vector3D davP = new Vector3D(-resOre2, dpP, recOre2, dreP, resOre2 / r, position);
942 final Vector3D davV = new Vector3D(-resOre2, dpV, recOre2, dreV);
943 fillHalfRow(1, dpoP, -1, davP, jacobian[3], 0);
944 fillHalfRow(1, dpoV, -1, davV, jacobian[3], 3);
945
946
947 final double cO0 = cI1 * cI1;
948 final double cO1 = mx * cO0;
949 final double cO2 = -my * cO0;
950 fillHalfRow(cO1, dcYP, cO2, dcXP, jacobian[4], 0);
951 fillHalfRow(cO1, dcYV, cO2, dcXV, jacobian[4], 3);
952
953
954 final double s2a = pv / (2 * absA);
955 final double oObux = 1 / FastMath.sqrt(m * m + mu * absA);
956 final double scasbu = pv * oObux;
957 final Vector3D dauP = new Vector3D(1 / sqrtMuA, velocity, -s2a / sqrtMuA, vectorAR);
958 final Vector3D dauV = new Vector3D(1 / sqrtMuA, position, -s2a / sqrtMuA, vectorARDot);
959 final Vector3D dbuP = new Vector3D(oObux * mu / 2, vectorAR, m * oObux, dCP);
960 final Vector3D dbuV = new Vector3D(oObux * mu / 2, vectorARDot, m * oObux, dCV);
961 final Vector3D dcuP = new Vector3D(oObux, velocity, -scasbu * oObux, dbuP);
962 final Vector3D dcuV = new Vector3D(oObux, position, -scasbu * oObux, dbuV);
963 fillHalfRow(1, dauP, -e / (1 + rOa), dcuP, jacobian[5], 0);
964 fillHalfRow(1, dauV, -e / (1 + rOa), dcuV, jacobian[5], 3);
965
966 return jacobian;
967
968 }
969
970
971 protected double[][] computeJacobianEccentricWrtCartesian() {
972 if (a > 0) {
973 return computeJacobianEccentricWrtCartesianElliptical();
974 } else {
975 return computeJacobianEccentricWrtCartesianHyperbolic();
976 }
977 }
978
979
980
981
982
983
984
985
986
987 private double[][] computeJacobianEccentricWrtCartesianElliptical() {
988
989
990 final double[][] jacobian = computeJacobianMeanWrtCartesianElliptical();
991
992
993
994
995
996 final double eccentricAnomaly = getEccentricAnomaly();
997 final double cosE = FastMath.cos(eccentricAnomaly);
998 final double sinE = FastMath.sin(eccentricAnomaly);
999 final double aOr = 1 / (1 - e * cosE);
1000
1001
1002 final double[] eRow = jacobian[1];
1003 final double[] anomalyRow = jacobian[5];
1004 for (int j = 0; j < anomalyRow.length; ++j) {
1005 anomalyRow[j] = aOr * (anomalyRow[j] + sinE * eRow[j]);
1006 }
1007
1008 return jacobian;
1009
1010 }
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020 private double[][] computeJacobianEccentricWrtCartesianHyperbolic() {
1021
1022
1023 final double[][] jacobian = computeJacobianMeanWrtCartesianHyperbolic();
1024
1025
1026
1027
1028
1029 final double H = getEccentricAnomaly();
1030 final double coshH = FastMath.cosh(H);
1031 final double sinhH = FastMath.sinh(H);
1032 final double absaOr = 1 / (e * coshH - 1);
1033
1034
1035 final double[] eRow = jacobian[1];
1036 final double[] anomalyRow = jacobian[5];
1037 for (int j = 0; j < anomalyRow.length; ++j) {
1038 anomalyRow[j] = absaOr * (anomalyRow[j] - sinhH * eRow[j]);
1039 }
1040
1041 return jacobian;
1042
1043 }
1044
1045
1046 protected double[][] computeJacobianTrueWrtCartesian() {
1047 if (a > 0) {
1048 return computeJacobianTrueWrtCartesianElliptical();
1049 } else {
1050 return computeJacobianTrueWrtCartesianHyperbolic();
1051 }
1052 }
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062 private double[][] computeJacobianTrueWrtCartesianElliptical() {
1063
1064
1065 final double[][] jacobian = computeJacobianEccentricWrtCartesianElliptical();
1066
1067
1068
1069
1070
1071
1072 final double e2 = e * e;
1073 final double oMe2 = 1 - e2;
1074 final double epsilon = FastMath.sqrt(oMe2);
1075 final double eccentricAnomaly = getEccentricAnomaly();
1076 final double cosE = FastMath.cos(eccentricAnomaly);
1077 final double sinE = FastMath.sin(eccentricAnomaly);
1078 final double aOr = 1 / (1 - e * cosE);
1079 final double aFactor = epsilon * aOr;
1080 final double eFactor = sinE * aOr / epsilon;
1081
1082
1083 final double[] eRow = jacobian[1];
1084 final double[] anomalyRow = jacobian[5];
1085 for (int j = 0; j < anomalyRow.length; ++j) {
1086 anomalyRow[j] = aFactor * anomalyRow[j] + eFactor * eRow[j];
1087 }
1088
1089 return jacobian;
1090
1091 }
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101 private double[][] computeJacobianTrueWrtCartesianHyperbolic() {
1102
1103
1104 final double[][] jacobian = computeJacobianEccentricWrtCartesianHyperbolic();
1105
1106
1107
1108
1109
1110
1111 final double e2 = e * e;
1112 final double e2Mo = e2 - 1;
1113 final double epsilon = FastMath.sqrt(e2Mo);
1114 final double H = getEccentricAnomaly();
1115 final double coshH = FastMath.cosh(H);
1116 final double sinhH = FastMath.sinh(H);
1117 final double aOr = 1 / (e * coshH - 1);
1118 final double aFactor = epsilon * aOr;
1119 final double eFactor = sinhH * aOr / epsilon;
1120
1121
1122 final double[] eRow = jacobian[1];
1123 final double[] anomalyRow = jacobian[5];
1124 for (int j = 0; j < anomalyRow.length; ++j) {
1125 anomalyRow[j] = aFactor * anomalyRow[j] - eFactor * eRow[j];
1126 }
1127
1128 return jacobian;
1129
1130 }
1131
1132
1133 public void addKeplerContribution(final PositionAngle type, final double gm,
1134 final double[] pDot) {
1135 final double oMe2;
1136 final double ksi;
1137 final double absA = FastMath.abs(a);
1138 final double n = FastMath.sqrt(gm / absA) / absA;
1139 switch (type) {
1140 case MEAN :
1141 pDot[5] += n;
1142 break;
1143 case ECCENTRIC :
1144 oMe2 = FastMath.abs(1 - e * e);
1145 ksi = 1 + e * FastMath.cos(v);
1146 pDot[5] += n * ksi / oMe2;
1147 break;
1148 case TRUE :
1149 oMe2 = FastMath.abs(1 - e * e);
1150 ksi = 1 + e * FastMath.cos(v);
1151 pDot[5] += n * ksi * ksi / (oMe2 * FastMath.sqrt(oMe2));
1152 break;
1153 default :
1154 throw new OrekitInternalError(null);
1155 }
1156 }
1157
1158
1159
1160
1161 public String toString() {
1162 return new StringBuffer().append("keplerian parameters: ").append('{').
1163 append("a: ").append(a).
1164 append("; e: ").append(e).
1165 append("; i: ").append(FastMath.toDegrees(i)).
1166 append("; pa: ").append(FastMath.toDegrees(pa)).
1167 append("; raan: ").append(FastMath.toDegrees(raan)).
1168 append("; v: ").append(FastMath.toDegrees(v)).
1169 append(";}").toString();
1170 }
1171
1172
1173
1174
1175 private Object writeReplace() {
1176 return new DTO(this);
1177 }
1178
1179
1180 private static class DTO implements Serializable {
1181
1182
1183 private static final long serialVersionUID = 20140617L;
1184
1185
1186 private double[] d;
1187
1188
1189 private final Frame frame;
1190
1191
1192
1193
1194 private DTO(final KeplerianOrbit orbit) {
1195
1196 final TimeStampedPVCoordinates pv = orbit.getPVCoordinates();
1197
1198
1199 final double epoch = FastMath.floor(pv.getDate().durationFrom(AbsoluteDate.J2000_EPOCH));
1200 final double offset = pv.getDate().durationFrom(AbsoluteDate.J2000_EPOCH.shiftedBy(epoch));
1201
1202 this.d = new double[] {
1203 epoch, offset, orbit.getMu(),
1204 orbit.a, orbit.e, orbit.i,
1205 orbit.pa, orbit.raan, orbit.v
1206 };
1207
1208 this.frame = orbit.getFrame();
1209
1210 }
1211
1212
1213
1214
1215 private Object readResolve() {
1216 return new KeplerianOrbit(d[3], d[4], d[5], d[6], d[7], d[8], PositionAngle.TRUE,
1217 frame, AbsoluteDate.J2000_EPOCH.shiftedBy(d[0]).shiftedBy(d[1]),
1218 d[2]);
1219 }
1220
1221 }
1222
1223 }