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.ArrayList;
21 import java.util.Collection;
22 import java.util.List;
23
24 import org.apache.commons.math3.exception.ConvergenceException;
25 import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
26 import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
27 import org.apache.commons.math3.util.FastMath;
28 import org.orekit.errors.OrekitMessages;
29 import org.orekit.frames.Frame;
30 import org.orekit.time.AbsoluteDate;
31 import org.orekit.utils.CartesianDerivativesFilter;
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 public class CartesianOrbit extends Orbit {
71
72
73 private static final long serialVersionUID = 20140723L;
74
75
76 private transient EquinoctialOrbit equinoctial;
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 public CartesianOrbit(final TimeStampedPVCoordinates pvaCoordinates,
93 final Frame frame, final double mu)
94 throws IllegalArgumentException {
95 super(pvaCoordinates, frame, mu);
96 equinoctial = null;
97 }
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114 public CartesianOrbit(final PVCoordinates pvaCoordinates, final Frame frame,
115 final AbsoluteDate date, final double mu)
116 throws IllegalArgumentException {
117 this(new TimeStampedPVCoordinates(date, pvaCoordinates), frame, mu);
118 }
119
120
121
122
123 public CartesianOrbit(final Orbit op) {
124 super(op.getPVCoordinates(), op.getFrame(), op.getMu());
125 if (op instanceof EquinoctialOrbit) {
126 equinoctial = (EquinoctialOrbit) op;
127 } else if (op instanceof CartesianOrbit) {
128 equinoctial = ((CartesianOrbit) op).equinoctial;
129 } else {
130 equinoctial = null;
131 }
132 }
133
134
135 public OrbitType getType() {
136 return OrbitType.CARTESIAN;
137 }
138
139
140 private void initEquinoctial() {
141 if (equinoctial == null) {
142 equinoctial = new EquinoctialOrbit(getPVCoordinates(), getFrame(), getDate(), getMu());
143 }
144 }
145
146
147 public double getA() {
148
149 final double r = getPVCoordinates().getPosition().getNorm();
150 final double V2 = getPVCoordinates().getVelocity().getNormSq();
151 return r / (2 - r * V2 / getMu());
152 }
153
154
155 public double getE() {
156 final Vector3D pvP = getPVCoordinates().getPosition();
157 final Vector3D pvV = getPVCoordinates().getVelocity();
158 final double rV2OnMu = pvP.getNorm() * pvV.getNormSq() / getMu();
159 final double eSE = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(getMu() * getA());
160 final double eCE = rV2OnMu - 1;
161 return FastMath.sqrt(eCE * eCE + eSE * eSE);
162 }
163
164
165 public double getI() {
166 return Vector3D.angle(Vector3D.PLUS_K, getPVCoordinates().getMomentum());
167 }
168
169
170 public double getEquinoctialEx() {
171 initEquinoctial();
172 return equinoctial.getEquinoctialEx();
173 }
174
175
176 public double getEquinoctialEy() {
177 initEquinoctial();
178 return equinoctial.getEquinoctialEy();
179 }
180
181
182 public double getHx() {
183 final Vector3D w = getPVCoordinates().getMomentum().normalize();
184
185 if (((w.getX() * w.getX() + w.getY() * w.getY()) == 0) && w.getZ() < 0) {
186 return Double.NaN;
187 }
188 return -w.getY() / (1 + w.getZ());
189 }
190
191
192 public double getHy() {
193 final Vector3D w = getPVCoordinates().getMomentum().normalize();
194
195 if (((w.getX() * w.getX() + w.getY() * w.getY()) == 0) && w.getZ() < 0) {
196 return Double.NaN;
197 }
198 return w.getX() / (1 + w.getZ());
199 }
200
201
202 public double getLv() {
203 initEquinoctial();
204 return equinoctial.getLv();
205 }
206
207
208 public double getLE() {
209 initEquinoctial();
210 return equinoctial.getLE();
211 }
212
213
214 public double getLM() {
215 initEquinoctial();
216 return equinoctial.getLM();
217 }
218
219
220 protected TimeStampedPVCoordinates initPVCoordinates() {
221
222 return getPVCoordinates();
223 }
224
225
226 public CartesianOrbit shiftedBy(final double dt) {
227 final PVCoordinates shiftedPV = (getA() < 0) ? shiftPVHyperbolic(dt) : shiftPVElliptic(dt);
228 return new CartesianOrbit(shiftedPV, getFrame(), getDate().shiftedBy(dt), getMu());
229 }
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250 public CartesianOrbit interpolate(final AbsoluteDate date, final Collection<Orbit> sample) {
251 final List<TimeStampedPVCoordinates> datedPV = new ArrayList<TimeStampedPVCoordinates>(sample.size());
252 for (final Orbit o : sample) {
253 datedPV.add(new TimeStampedPVCoordinates(o.getDate(),
254 o.getPVCoordinates().getPosition(),
255 o.getPVCoordinates().getVelocity(),
256 o.getPVCoordinates().getAcceleration()));
257 }
258 final TimeStampedPVCoordinates interpolated =
259 TimeStampedPVCoordinates.interpolate(date, CartesianDerivativesFilter.USE_PVA, datedPV);
260 return new CartesianOrbit(interpolated, getFrame(), date, getMu());
261 }
262
263
264
265
266
267 private PVCoordinates shiftPVElliptic(final double dt) {
268
269
270 final Vector3D pvP = getPVCoordinates().getPosition();
271 final Vector3D pvV = getPVCoordinates().getVelocity();
272 final double r = pvP.getNorm();
273 final double rV2OnMu = r * pvV.getNormSq() / getMu();
274 final double a = getA();
275 final double eSE = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(getMu() * a);
276 final double eCE = rV2OnMu - 1;
277 final double e2 = eCE * eCE + eSE * eSE;
278
279
280
281 final Vector3D u = pvP.normalize();
282 final Vector3D v = Vector3D.crossProduct(getPVCoordinates().getMomentum(), u).normalize();
283
284
285
286 final double ex = (eCE - e2) * a / r;
287 final double ey = -FastMath.sqrt(1 - e2) * eSE * a / r;
288 final double beta = 1 / (1 + FastMath.sqrt(1 - e2));
289 final double thetaE0 = FastMath.atan2(ey + eSE * beta * ex, r / a + ex - eSE * beta * ey);
290 final double thetaM0 = thetaE0 - ex * FastMath.sin(thetaE0) + ey * FastMath.cos(thetaE0);
291
292
293 final double thetaM1 = thetaM0 + getKeplerianMeanMotion() * dt;
294 final double thetaE1 = meanToEccentric(thetaM1, ex, ey);
295 final double cTE = FastMath.cos(thetaE1);
296 final double sTE = FastMath.sin(thetaE1);
297
298
299 final double exey = ex * ey;
300 final double exCeyS = ex * cTE + ey * sTE;
301 final double x = a * ((1 - beta * ey * ey) * cTE + beta * exey * sTE - ex);
302 final double y = a * ((1 - beta * ex * ex) * sTE + beta * exey * cTE - ey);
303 final double factor = FastMath.sqrt(getMu() / a) / (1 - exCeyS);
304 final double xDot = factor * (-sTE + beta * ey * exCeyS);
305 final double yDot = factor * ( cTE - beta * ex * exCeyS);
306
307 final Vector3D shiftedP = new Vector3D(x, u, y, v);
308 final double r2 = x * x + y * y;
309 final Vector3D shiftedV = new Vector3D(xDot, u, yDot, v);
310 final Vector3D shiftedA = new Vector3D(-getMu() / (r2 * FastMath.sqrt(r2)), shiftedP);
311 return new PVCoordinates(shiftedP, shiftedV, shiftedA);
312
313 }
314
315
316
317
318
319 private PVCoordinates shiftPVHyperbolic(final double dt) {
320
321 final PVCoordinates pv = getPVCoordinates();
322 final Vector3D pvP = pv.getPosition();
323 final Vector3D pvV = pv.getVelocity();
324 final Vector3D pvM = pv.getMomentum();
325 final double r = pvP.getNorm();
326 final double rV2OnMu = r * pvV.getNormSq() / getMu();
327 final double a = getA();
328 final double muA = getMu() * a;
329 final double e = FastMath.sqrt(1 - Vector3D.dotProduct(pvM, pvM) / muA);
330 final double sqrt = FastMath.sqrt((e + 1) / (e - 1));
331
332
333 final double eSH = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(-muA);
334 final double eCH = rV2OnMu - 1;
335 final double H0 = FastMath.log((eCH + eSH) / (eCH - eSH)) / 2;
336 final double M0 = e * FastMath.sinh(H0) - H0;
337
338
339 final double v0 = 2 * FastMath.atan(sqrt * FastMath.tanh(H0 / 2));
340 final Vector3D p = new Rotation(pvM, -v0).applyTo(pvP).normalize();
341 final Vector3D q = Vector3D.crossProduct(pvM, p).normalize();
342
343
344 final double M1 = M0 + getKeplerianMeanMotion() * dt;
345 final double H1 = meanToHyperbolicEccentric(M1, e);
346
347
348 final double cH = FastMath.cosh(H1);
349 final double sH = FastMath.sinh(H1);
350 final double sE2m1 = FastMath.sqrt((e - 1) * (e + 1));
351
352
353 final double x = a * (cH - e);
354 final double y = -a * sE2m1 * sH;
355 final double factor = FastMath.sqrt(getMu() / -a) / (e * cH - 1);
356 final double xDot = -factor * sH;
357 final double yDot = factor * sE2m1 * cH;
358
359 final Vector3D shiftedP = new Vector3D(x, p, y, q);
360 final double r2 = x * x + y * y;
361 final Vector3D shiftedV = new Vector3D(xDot, p, yDot, q);
362 final Vector3D shiftedA = new Vector3D(-getMu() / (r2 * FastMath.sqrt(r2)), shiftedP);
363 return new PVCoordinates(shiftedP, shiftedV, shiftedA);
364
365 }
366
367
368
369
370
371
372
373 private double meanToEccentric(final double thetaM, final double ex, final double ey) {
374
375
376
377
378 double thetaE = thetaM;
379 double thetaEMthetaM = 0.0;
380 int iter = 0;
381 do {
382 final double cosThetaE = FastMath.cos(thetaE);
383 final double sinThetaE = FastMath.sin(thetaE);
384
385 final double f2 = ex * sinThetaE - ey * cosThetaE;
386 final double f1 = 1.0 - ex * cosThetaE - ey * sinThetaE;
387 final double f0 = thetaEMthetaM - f2;
388
389 final double f12 = 2.0 * f1;
390 final double shift = f0 * f12 / (f1 * f12 - f0 * f2);
391
392 thetaEMthetaM -= shift;
393 thetaE = thetaM + thetaEMthetaM;
394
395 if (FastMath.abs(shift) <= 1.0e-12) {
396 return thetaE;
397 }
398
399 } while (++iter < 50);
400
401 throw new ConvergenceException();
402
403 }
404
405
406
407
408
409
410
411
412
413
414 private double meanToHyperbolicEccentric(final double M, final double ecc) {
415
416
417
418
419 double H;
420 if (ecc < 1.6) {
421 if ((-FastMath.PI < M && M < 0.) || M > FastMath.PI) {
422 H = M - ecc;
423 } else {
424 H = M + ecc;
425 }
426 } else {
427 if (ecc < 3.6 && FastMath.abs(M) > FastMath.PI) {
428 H = M - FastMath.copySign(ecc, M);
429 } else {
430 H = M / (ecc - 1.);
431 }
432 }
433
434
435 int iter = 0;
436 do {
437 final double f3 = ecc * FastMath.cosh(H);
438 final double f2 = ecc * FastMath.sinh(H);
439 final double f1 = f3 - 1.;
440 final double f0 = f2 - H - M;
441 final double f12 = 2. * f1;
442 final double d = f0 / f12;
443 final double fdf = f1 - d * f2;
444 final double ds = f0 / fdf;
445
446 final double shift = f0 / (fdf + ds * ds * f3 / 6.);
447
448 H -= shift;
449
450 if (FastMath.abs(shift) <= 1.0e-12) {
451 return H;
452 }
453
454 } while (++iter < 50);
455
456 throw new ConvergenceException(OrekitMessages.UNABLE_TO_COMPUTE_HYPERBOLIC_ECCENTRIC_ANOMALY,
457 iter);
458 }
459
460 @Override
461 public void getJacobianWrtCartesian(final PositionAngle type, final double[][] jacobian) {
462
463 for (int i = 0; i < 6; i++) {
464 for (int j = 0; j < 6; j++) {
465 jacobian[i][j] = 0;
466 }
467 jacobian[i][i] = 1;
468 }
469 }
470
471 @Override
472 protected double[][] computeJacobianMeanWrtCartesian() {
473
474 return null;
475 }
476 @Override
477 protected double[][] computeJacobianEccentricWrtCartesian() {
478
479 return null;
480 }
481
482 @Override
483 protected double[][] computeJacobianTrueWrtCartesian() {
484
485 return null;
486 }
487
488
489 public void addKeplerContribution(final PositionAngle type, final double gm,
490 final double[] pDot) {
491
492 final PVCoordinates pv = getPVCoordinates();
493
494
495 final Vector3D velocity = pv.getVelocity();
496 pDot[0] += velocity.getX();
497 pDot[1] += velocity.getY();
498 pDot[2] += velocity.getZ();
499
500
501 final Vector3D position = pv.getPosition();
502 final double r2 = position.getNormSq();
503 final double coeff = -gm / (r2 * FastMath.sqrt(r2));
504 pDot[3] += coeff * position.getX();
505 pDot[4] += coeff * position.getY();
506 pDot[5] += coeff * position.getZ();
507
508 }
509
510
511
512
513 public String toString() {
514 return "cartesian parameters: " + getPVCoordinates().toString();
515 }
516
517
518
519
520
521
522
523
524
525 private Object writeReplace() {
526 return new DTO(this);
527 }
528
529
530 private static class DTO implements Serializable {
531
532
533 private static final long serialVersionUID = 20140723L;
534
535
536 private double[] d;
537
538
539 private final Frame frame;
540
541
542
543
544 private DTO(final CartesianOrbit orbit) {
545
546 final TimeStampedPVCoordinates pv = orbit.getPVCoordinates();
547
548
549 final double epoch = FastMath.floor(pv.getDate().durationFrom(AbsoluteDate.J2000_EPOCH));
550 final double offset = pv.getDate().durationFrom(AbsoluteDate.J2000_EPOCH.shiftedBy(epoch));
551
552 this.d = new double[] {
553 epoch, offset, orbit.getMu(),
554 pv.getPosition().getX(), pv.getPosition().getY(), pv.getPosition().getZ(),
555 pv.getVelocity().getX(), pv.getVelocity().getY(), pv.getVelocity().getZ(),
556 pv.getAcceleration().getX(), pv.getAcceleration().getY(), pv.getAcceleration().getZ(),
557 };
558
559 this.frame = orbit.getFrame();
560
561 }
562
563
564
565
566 private Object readResolve() {
567 return new CartesianOrbit(new TimeStampedPVCoordinates(AbsoluteDate.J2000_EPOCH.shiftedBy(d[0]).shiftedBy(d[1]),
568 new Vector3D(d[3], d[ 4], d[ 5]),
569 new Vector3D(d[6], d[ 7], d[ 8]),
570 new Vector3D(d[9], d[10], d[11])),
571 frame, d[2]);
572 }
573
574 }
575
576 }