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