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.geometry.euclidean.threed.Vector3D;
24 import org.apache.commons.math3.util.FastMath;
25 import org.apache.commons.math3.util.MathUtils;
26 import org.orekit.errors.OrekitIllegalArgumentException;
27 import org.orekit.errors.OrekitInternalError;
28 import org.orekit.errors.OrekitMessages;
29 import org.orekit.frames.Frame;
30 import org.orekit.time.AbsoluteDate;
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 public class EquinoctialOrbit extends Orbit {
74
75
76 private static final long serialVersionUID = 20141228L;
77
78
79 private final double a;
80
81
82 private final double ex;
83
84
85 private final double ey;
86
87
88 private final double hx;
89
90
91 private final double hy;
92
93
94 private final double lv;
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111 public EquinoctialOrbit(final double a, final double ex, final double ey,
112 final double hx, final double hy,
113 final double l, final PositionAngle type,
114 final Frame frame, final AbsoluteDate date, final double mu)
115 throws IllegalArgumentException {
116 super(frame, date, mu);
117 if (ex * ex + ey * ey >= 1.0) {
118 throw new OrekitIllegalArgumentException(OrekitMessages.HYPERBOLIC_ORBIT_NOT_HANDLED_AS,
119 getClass().getName());
120 }
121 this.a = a;
122 this.ex = ex;
123 this.ey = ey;
124 this.hx = hx;
125 this.hy = hy;
126
127 switch (type) {
128 case MEAN :
129 this.lv = eccentricToTrue(meanToEccentric(l));
130 break;
131 case ECCENTRIC :
132 this.lv = eccentricToTrue(l);
133 break;
134 case TRUE :
135 this.lv = l;
136 break;
137 default :
138 throw new OrekitInternalError(null);
139 }
140
141 }
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157 public EquinoctialOrbit(final TimeStampedPVCoordinates pvCoordinates,
158 final Frame frame, final double mu)
159 throws IllegalArgumentException {
160 super(pvCoordinates, frame, mu);
161
162
163 final Vector3D pvP = pvCoordinates.getPosition();
164 final Vector3D pvV = pvCoordinates.getVelocity();
165 final double r = pvP.getNorm();
166 final double V2 = pvV.getNormSq();
167 final double rV2OnMu = r * V2 / mu;
168
169 if (rV2OnMu > 2) {
170 throw new OrekitIllegalArgumentException(OrekitMessages.HYPERBOLIC_ORBIT_NOT_HANDLED_AS,
171 getClass().getName());
172 }
173
174
175 final Vector3D w = pvCoordinates.getMomentum().normalize();
176 final double d = 1.0 / (1 + w.getZ());
177 hx = -d * w.getY();
178 hy = d * w.getX();
179
180
181 final double cLv = (pvP.getX() - d * pvP.getZ() * w.getX()) / r;
182 final double sLv = (pvP.getY() - d * pvP.getZ() * w.getY()) / r;
183 lv = FastMath.atan2(sLv, cLv);
184
185
186
187 a = r / (2 - rV2OnMu);
188
189
190 final double eSE = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(mu * a);
191 final double eCE = rV2OnMu - 1;
192 final double e2 = eCE * eCE + eSE * eSE;
193 final double f = eCE - e2;
194 final double g = FastMath.sqrt(1 - e2) * eSE;
195 ex = a * (f * cLv + g * sLv) / r;
196 ey = a * (f * sLv - g * cLv) / r;
197
198 }
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215 public EquinoctialOrbit(final PVCoordinates pvCoordinates, final Frame frame,
216 final AbsoluteDate date, final double mu)
217 throws IllegalArgumentException {
218 this(new TimeStampedPVCoordinates(date, pvCoordinates), frame, mu);
219 }
220
221
222
223
224 public EquinoctialOrbit(final Orbit op) {
225 super(op.getFrame(), op.getDate(), op.getMu());
226 a = op.getA();
227 ex = op.getEquinoctialEx();
228 ey = op.getEquinoctialEy();
229 hx = op.getHx();
230 hy = op.getHy();
231 lv = op.getLv();
232 }
233
234
235 public OrbitType getType() {
236 return OrbitType.EQUINOCTIAL;
237 }
238
239
240 public double getA() {
241 return a;
242 }
243
244
245 public double getEquinoctialEx() {
246 return ex;
247 }
248
249
250 public double getEquinoctialEy() {
251 return ey;
252 }
253
254
255 public double getHx() {
256 return hx;
257 }
258
259
260 public double getHy() {
261 return hy;
262 }
263
264
265
266
267
268 public double getL(final PositionAngle type) {
269 return (type == PositionAngle.MEAN) ? getLM() :
270 ((type == PositionAngle.ECCENTRIC) ? getLE() :
271 getLv());
272 }
273
274
275 public double getLv() {
276 return lv;
277 }
278
279
280 public double getLE() {
281 final double epsilon = FastMath.sqrt(1 - ex * ex - ey * ey);
282 final double cosLv = FastMath.cos(lv);
283 final double sinLv = FastMath.sin(lv);
284 final double num = ey * cosLv - ex * sinLv;
285 final double den = epsilon + 1 + ex * cosLv + ey * sinLv;
286 return lv + 2 * FastMath.atan(num / den);
287 }
288
289
290
291
292
293 private double eccentricToTrue(final double lE) {
294 final double epsilon = FastMath.sqrt(1 - ex * ex - ey * ey);
295 final double cosLE = FastMath.cos(lE);
296 final double sinLE = FastMath.sin(lE);
297 final double num = ex * sinLE - ey * cosLE;
298 final double den = epsilon + 1 - ex * cosLE - ey * sinLE;
299 return lE + 2 * FastMath.atan(num / den);
300 }
301
302
303 public double getLM() {
304 final double lE = getLE();
305 return lE - ex * FastMath.sin(lE) + ey * FastMath.cos(lE);
306 }
307
308
309
310
311
312 private double meanToEccentric(final double lM) {
313
314
315
316 double lE = lM;
317 double shift = 0.0;
318 double lEmlM = 0.0;
319 double cosLE = FastMath.cos(lE);
320 double sinLE = FastMath.sin(lE);
321 int iter = 0;
322 do {
323 final double f2 = ex * sinLE - ey * cosLE;
324 final double f1 = 1.0 - ex * cosLE - ey * sinLE;
325 final double f0 = lEmlM - f2;
326
327 final double f12 = 2.0 * f1;
328 shift = f0 * f12 / (f1 * f12 - f0 * f2);
329
330 lEmlM -= shift;
331 lE = lM + lEmlM;
332 cosLE = FastMath.cos(lE);
333 sinLE = FastMath.sin(lE);
334
335 } while ((++iter < 50) && (FastMath.abs(shift) > 1.0e-12));
336
337 return lE;
338
339 }
340
341
342 public double getE() {
343 return FastMath.sqrt(ex * ex + ey * ey);
344 }
345
346
347 public double getI() {
348 return 2 * FastMath.atan(FastMath.sqrt(hx * hx + hy * hy));
349 }
350
351
352 protected TimeStampedPVCoordinates initPVCoordinates() {
353
354
355 final double lE = getLE();
356
357
358 final double hx2 = hx * hx;
359 final double hy2 = hy * hy;
360 final double factH = 1. / (1 + hx2 + hy2);
361
362
363 final double ux = (1 + hx2 - hy2) * factH;
364 final double uy = 2 * hx * hy * factH;
365 final double uz = -2 * hy * factH;
366
367 final double vx = uy;
368 final double vy = (1 - hx2 + hy2) * factH;
369 final double vz = 2 * hx * factH;
370
371
372 final double exey = ex * ey;
373 final double ex2 = ex * ex;
374 final double ey2 = ey * ey;
375 final double e2 = ex2 + ey2;
376 final double eta = 1 + FastMath.sqrt(1 - e2);
377 final double beta = 1. / eta;
378
379
380 final double cLe = FastMath.cos(lE);
381 final double sLe = FastMath.sin(lE);
382 final double exCeyS = ex * cLe + ey * sLe;
383
384
385 final double x = a * ((1 - beta * ey2) * cLe + beta * exey * sLe - ex);
386 final double y = a * ((1 - beta * ex2) * sLe + beta * exey * cLe - ey);
387
388 final double factor = FastMath.sqrt(getMu() / a) / (1 - exCeyS);
389 final double xdot = factor * (-sLe + beta * ey * exCeyS);
390 final double ydot = factor * ( cLe - beta * ex * exCeyS);
391
392 final Vector3D position =
393 new Vector3D(x * ux + y * vx, x * uy + y * vy, x * uz + y * vz);
394 final double r2 = position.getNormSq();
395 final Vector3D velocity =
396 new Vector3D(xdot * ux + ydot * vx, xdot * uy + ydot * vy, xdot * uz + ydot * vz);
397
398 final Vector3D acceleration = new Vector3D(-getMu() / (r2 * FastMath.sqrt(r2)), position);
399
400 return new TimeStampedPVCoordinates(getDate(), position, velocity, acceleration);
401
402 }
403
404
405 public EquinoctialOrbit shiftedBy(final double dt) {
406 return new EquinoctialOrbit(a, ex, ey, hx, hy,
407 getLM() + getKeplerianMeanMotion() * dt,
408 PositionAngle.MEAN, getFrame(),
409 getDate().shiftedBy(dt), getMu());
410 }
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432 public EquinoctialOrbit interpolate(final AbsoluteDate date, final Collection<Orbit> sample) {
433
434
435 final HermiteInterpolator interpolator = new HermiteInterpolator();
436
437
438 AbsoluteDate previousDate = null;
439 double previousLm = Double.NaN;
440 for (final Orbit orbit : sample) {
441 final EquinoctialOrbit equi = (EquinoctialOrbit) OrbitType.EQUINOCTIAL.convertType(orbit);
442 final double continuousLm;
443 if (previousDate == null) {
444 continuousLm = equi.getLM();
445 } else {
446 final double dt = equi.getDate().durationFrom(previousDate);
447 final double keplerLm = previousLm + equi.getKeplerianMeanMotion() * dt;
448 continuousLm = MathUtils.normalizeAngle(equi.getLM(), keplerLm);
449 }
450 previousDate = equi.getDate();
451 previousLm = continuousLm;
452 interpolator.addSamplePoint(equi.getDate().durationFrom(date),
453 new double[] {
454 equi.getA(),
455 equi.getEquinoctialEx(),
456 equi.getEquinoctialEy(),
457 equi.getHx(),
458 equi.getHy(),
459 continuousLm
460 });
461 }
462
463
464 final double[] interpolated = interpolator.value(0);
465
466
467 return new EquinoctialOrbit(interpolated[0], interpolated[1], interpolated[2],
468 interpolated[3], interpolated[4], interpolated[5],
469 PositionAngle.MEAN, getFrame(), date, getMu());
470
471 }
472
473
474 protected double[][] computeJacobianMeanWrtCartesian() {
475
476 final double[][] jacobian = new double[6][6];
477
478
479 final Vector3D position = getPVCoordinates().getPosition();
480 final Vector3D velocity = getPVCoordinates().getVelocity();
481 final double r2 = position.getNormSq();
482 final double r = FastMath.sqrt(r2);
483 final double r3 = r * r2;
484
485 final double mu = getMu();
486 final double sqrtMuA = FastMath.sqrt(a * mu);
487 final double a2 = a * a;
488
489 final double e2 = ex * ex + ey * ey;
490 final double oMe2 = 1 - e2;
491 final double epsilon = FastMath.sqrt(oMe2);
492 final double beta = 1 / (1 + epsilon);
493 final double ratio = epsilon * beta;
494
495 final double hx2 = hx * hx;
496 final double hy2 = hy * hy;
497 final double hxhy = hx * hy;
498
499
500 final Vector3D f = new Vector3D(1 - hy2 + hx2, 2 * hxhy, -2 * hy).normalize();
501 final Vector3D g = new Vector3D(2 * hxhy, 1 + hy2 - hx2, 2 * hx).normalize();
502 final Vector3D w = Vector3D.crossProduct(position, velocity).normalize();
503
504
505 final double x = Vector3D.dotProduct(position, f);
506 final double y = Vector3D.dotProduct(position, g);
507 final double xDot = Vector3D.dotProduct(velocity, f);
508 final double yDot = Vector3D.dotProduct(velocity, g);
509
510
511 final double c1 = a / (sqrtMuA * epsilon);
512 final double c2 = a * sqrtMuA * beta / r3;
513 final double c3 = sqrtMuA / (r3 * epsilon);
514 final Vector3D drDotSdEx = new Vector3D( c1 * xDot * yDot - c2 * ey * x - c3 * x * y, f,
515 -c1 * xDot * xDot - c2 * ey * y + c3 * x * x, g);
516
517
518 final Vector3D drDotSdEy = new Vector3D( c1 * yDot * yDot + c2 * ex * x - c3 * y * y, f,
519 -c1 * xDot * yDot + c2 * ex * y + c3 * x * y, g);
520
521
522 final Vector3D vectorAR = new Vector3D(2 * a2 / r3, position);
523 final Vector3D vectorARDot = new Vector3D(2 * a2 / mu, velocity);
524 fillHalfRow(1, vectorAR, jacobian[0], 0);
525 fillHalfRow(1, vectorARDot, jacobian[0], 3);
526
527
528 final double d1 = -a * ratio / r3;
529 final double d2 = (hy * xDot - hx * yDot) / (sqrtMuA * epsilon);
530 final double d3 = (hx * y - hy * x) / sqrtMuA;
531 final Vector3D vectorExRDot =
532 new Vector3D((2 * x * yDot - xDot * y) / mu, g, -y * yDot / mu, f, -ey * d3 / epsilon, w);
533 fillHalfRow(ex * d1, position, -ey * d2, w, epsilon / sqrtMuA, drDotSdEy, jacobian[1], 0);
534 fillHalfRow(1, vectorExRDot, jacobian[1], 3);
535
536
537 final Vector3D vectorEyRDot =
538 new Vector3D((2 * xDot * y - x * yDot) / mu, f, -x * xDot / mu, g, ex * d3 / epsilon, w);
539 fillHalfRow(ey * d1, position, ex * d2, w, -epsilon / sqrtMuA, drDotSdEx, jacobian[2], 0);
540 fillHalfRow(1, vectorEyRDot, jacobian[2], 3);
541
542
543 final double h = (1 + hx2 + hy2) / (2 * sqrtMuA * epsilon);
544 fillHalfRow(-h * xDot, w, jacobian[3], 0);
545 fillHalfRow( h * x, w, jacobian[3], 3);
546
547
548 fillHalfRow(-h * yDot, w, jacobian[4], 0);
549 fillHalfRow( h * y, w, jacobian[4], 3);
550
551
552 final double l = -ratio / sqrtMuA;
553 fillHalfRow(-1 / sqrtMuA, velocity, d2, w, l * ex, drDotSdEx, l * ey, drDotSdEy, jacobian[5], 0);
554 fillHalfRow(-2 / sqrtMuA, position, ex * beta, vectorEyRDot, -ey * beta, vectorExRDot, d3, w, jacobian[5], 3);
555
556 return jacobian;
557
558 }
559
560
561 protected double[][] computeJacobianEccentricWrtCartesian() {
562
563
564 final double[][] jacobian = computeJacobianMeanWrtCartesian();
565
566
567
568
569
570 final double le = getLE();
571 final double cosLe = FastMath.cos(le);
572 final double sinLe = FastMath.sin(le);
573 final double aOr = 1 / (1 - ex * cosLe - ey * sinLe);
574
575
576 final double[] rowEx = jacobian[1];
577 final double[] rowEy = jacobian[2];
578 final double[] rowL = jacobian[5];
579 for (int j = 0; j < 6; ++j) {
580 rowL[j] = aOr * (rowL[j] + sinLe * rowEx[j] - cosLe * rowEy[j]);
581 }
582
583 return jacobian;
584
585 }
586
587
588 protected double[][] computeJacobianTrueWrtCartesian() {
589
590
591 final double[][] jacobian = computeJacobianEccentricWrtCartesian();
592
593
594
595
596
597
598
599
600
601
602
603
604
605 final double le = getLE();
606 final double cosLe = FastMath.cos(le);
607 final double sinLe = FastMath.sin(le);
608 final double eSinE = ex * sinLe - ey * cosLe;
609 final double ecosE = ex * cosLe + ey * sinLe;
610 final double e2 = ex * ex + ey * ey;
611 final double epsilon = FastMath.sqrt(1 - e2);
612 final double onePeps = 1 + epsilon;
613 final double d = onePeps - ecosE;
614 final double cT = (d * d + eSinE * eSinE) / 2;
615 final double cE = ecosE * onePeps - e2;
616 final double cX = ex * eSinE / epsilon - ey + sinLe * onePeps;
617 final double cY = ey * eSinE / epsilon + ex - cosLe * onePeps;
618 final double factorLe = (cT + cE) / cT;
619 final double factorEx = cX / cT;
620 final double factorEy = cY / cT;
621
622
623 final double[] rowEx = jacobian[1];
624 final double[] rowEy = jacobian[2];
625 final double[] rowL = jacobian[5];
626 for (int j = 0; j < 6; ++j) {
627 rowL[j] = factorLe * rowL[j] + factorEx * rowEx[j] + factorEy * rowEy[j];
628 }
629
630 return jacobian;
631
632 }
633
634
635 public void addKeplerContribution(final PositionAngle type, final double gm,
636 final double[] pDot) {
637 final double oMe2;
638 final double ksi;
639 final double n = FastMath.sqrt(gm / a) / a;
640 switch (type) {
641 case MEAN :
642 pDot[5] += n;
643 break;
644 case ECCENTRIC :
645 oMe2 = 1 - ex * ex - ey * ey;
646 ksi = 1 + ex * FastMath.cos(lv) + ey * FastMath.sin(lv);
647 pDot[5] += n * ksi / oMe2;
648 break;
649 case TRUE :
650 oMe2 = 1 - ex * ex - ey * ey;
651 ksi = 1 + ex * FastMath.cos(lv) + ey * FastMath.sin(lv);
652 pDot[5] += n * ksi * ksi / (oMe2 * FastMath.sqrt(oMe2));
653 break;
654 default :
655 throw new OrekitInternalError(null);
656 }
657 }
658
659
660
661
662 public String toString() {
663 return new StringBuffer().append("equinoctial parameters: ").append('{').
664 append("a: ").append(a).
665 append("; ex: ").append(ex).append("; ey: ").append(ey).
666 append("; hx: ").append(hx).append("; hy: ").append(hy).
667 append("; lv: ").append(FastMath.toDegrees(lv)).
668 append(";}").toString();
669 }
670
671
672
673
674 private Object writeReplace() {
675 return new DTO(this);
676 }
677
678
679 private static class DTO implements Serializable {
680
681
682 private static final long serialVersionUID = 20140617L;
683
684
685 private double[] d;
686
687
688 private final Frame frame;
689
690
691
692
693 private DTO(final EquinoctialOrbit orbit) {
694
695 final TimeStampedPVCoordinates pv = orbit.getPVCoordinates();
696
697
698 final double epoch = FastMath.floor(pv.getDate().durationFrom(AbsoluteDate.J2000_EPOCH));
699 final double offset = pv.getDate().durationFrom(AbsoluteDate.J2000_EPOCH.shiftedBy(epoch));
700
701 this.d = new double[] {
702 epoch, offset, orbit.getMu(),
703 orbit.a, orbit.ex, orbit.ey,
704 orbit.hx, orbit.hy, orbit.lv
705 };
706
707 this.frame = orbit.getFrame();
708
709 }
710
711
712
713
714 private Object readResolve() {
715 return new EquinoctialOrbit(d[3], d[4], d[5], d[6], d[7], d[8], PositionAngle.TRUE,
716 frame, AbsoluteDate.J2000_EPOCH.shiftedBy(d[0]).shiftedBy(d[1]),
717 d[2]);
718 }
719
720 }
721
722 }