1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.utils;
18
19 import org.hipparchus.CalculusFieldElement;
20 import org.hipparchus.analysis.differentiation.DSFactory;
21 import org.hipparchus.analysis.differentiation.Derivative;
22 import org.hipparchus.analysis.differentiation.DerivativeStructure;
23 import org.hipparchus.analysis.differentiation.UnivariateDerivative1;
24 import org.hipparchus.analysis.differentiation.UnivariateDerivative2;
25 import org.hipparchus.exception.LocalizedCoreFormats;
26 import org.hipparchus.exception.MathIllegalArgumentException;
27 import org.hipparchus.exception.MathRuntimeException;
28 import org.hipparchus.geometry.euclidean.threed.FieldRotation;
29 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
30 import org.hipparchus.geometry.euclidean.threed.Rotation;
31 import org.hipparchus.geometry.euclidean.threed.RotationConvention;
32 import org.hipparchus.geometry.euclidean.threed.Vector3D;
33 import org.hipparchus.linear.DecompositionSolver;
34 import org.hipparchus.linear.MatrixUtils;
35 import org.hipparchus.linear.QRDecomposition;
36 import org.hipparchus.linear.RealMatrix;
37 import org.hipparchus.linear.RealVector;
38 import org.hipparchus.util.FastMath;
39 import org.hipparchus.util.MathArrays;
40 import org.orekit.errors.OrekitException;
41 import org.orekit.errors.OrekitMessages;
42 import org.orekit.time.TimeShiftable;
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public class AngularCoordinates implements TimeShiftable<AngularCoordinates> {
58
59
60
61
62 public static final AngularCoordinates IDENTITY =
63 new AngularCoordinates(Rotation.IDENTITY, Vector3D.ZERO, Vector3D.ZERO);
64
65
66 private final Rotation rotation;
67
68
69 private final Vector3D rotationRate;
70
71
72 private final Vector3D rotationAcceleration;
73
74
75
76
77 public AngularCoordinates() {
78 this(Rotation.IDENTITY, Vector3D.ZERO, Vector3D.ZERO);
79 }
80
81
82
83
84
85 public AngularCoordinates(final Rotation rotation, final Vector3D rotationRate) {
86 this(rotation, rotationRate, Vector3D.ZERO);
87 }
88
89
90
91
92
93
94 public AngularCoordinates(final Rotation rotation,
95 final Vector3D rotationRate, final Vector3D rotationAcceleration) {
96 this.rotation = rotation;
97 this.rotationRate = rotationRate;
98 this.rotationAcceleration = rotationAcceleration;
99 }
100
101
102
103
104
105
106
107 public AngularCoordinates(final Rotation rotation) {
108 this(rotation, Vector3D.ZERO);
109 }
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131 public AngularCoordinates(final PVCoordinates u1, final PVCoordinates u2,
132 final PVCoordinates v1, final PVCoordinates v2,
133 final double tolerance) {
134
135 try {
136
137 rotation = new Rotation(u1.getPosition(), u2.getPosition(),
138 v1.getPosition(), v2.getPosition());
139
140
141
142
143 final Vector3D ru1Dot = rotation.applyTo(u1.getVelocity());
144 final Vector3D ru2Dot = rotation.applyTo(u2.getVelocity());
145 rotationRate = inverseCrossProducts(v1.getPosition(), ru1Dot.subtract(v1.getVelocity()),
146 v2.getPosition(), ru2Dot.subtract(v2.getVelocity()),
147 tolerance);
148
149
150
151
152 final Vector3D ru1DotDot = rotation.applyTo(u1.getAcceleration());
153 final Vector3D oDotv1 = Vector3D.crossProduct(rotationRate, v1.getVelocity());
154 final Vector3D oov1 = Vector3D.crossProduct(rotationRate, Vector3D.crossProduct(rotationRate, v1.getPosition()));
155 final Vector3D c1 = new Vector3D(1, ru1DotDot, -2, oDotv1, -1, oov1, -1, v1.getAcceleration());
156 final Vector3D ru2DotDot = rotation.applyTo(u2.getAcceleration());
157 final Vector3D oDotv2 = Vector3D.crossProduct(rotationRate, v2.getVelocity());
158 final Vector3D oov2 = Vector3D.crossProduct(rotationRate, Vector3D.crossProduct(rotationRate, v2.getPosition()));
159 final Vector3D c2 = new Vector3D(1, ru2DotDot, -2, oDotv2, -1, oov2, -1, v2.getAcceleration());
160 rotationAcceleration = inverseCrossProducts(v1.getPosition(), c1, v2.getPosition(), c2, tolerance);
161
162 } catch (MathRuntimeException mrte) {
163 throw new OrekitException(mrte);
164 }
165
166 }
167
168
169
170
171
172
173
174
175
176
177
178
179
180 public AngularCoordinates(final PVCoordinates u, final PVCoordinates v) {
181 this(new FieldRotation<>(u.toDerivativeStructureVector(2),
182 v.toDerivativeStructureVector(2)));
183 }
184
185
186
187
188
189
190
191
192
193 public <U extends Derivative<U>> AngularCoordinates(final FieldRotation<U> r) {
194
195 final double q0 = r.getQ0().getReal();
196 final double q1 = r.getQ1().getReal();
197 final double q2 = r.getQ2().getReal();
198 final double q3 = r.getQ3().getReal();
199
200 rotation = new Rotation(q0, q1, q2, q3, false);
201 if (r.getQ0().getOrder() >= 1) {
202 final double q0Dot = r.getQ0().getPartialDerivative(1);
203 final double q1Dot = r.getQ1().getPartialDerivative(1);
204 final double q2Dot = r.getQ2().getPartialDerivative(1);
205 final double q3Dot = r.getQ3().getPartialDerivative(1);
206 rotationRate =
207 new Vector3D(2 * MathArrays.linearCombination(-q1, q0Dot, q0, q1Dot, q3, q2Dot, -q2, q3Dot),
208 2 * MathArrays.linearCombination(-q2, q0Dot, -q3, q1Dot, q0, q2Dot, q1, q3Dot),
209 2 * MathArrays.linearCombination(-q3, q0Dot, q2, q1Dot, -q1, q2Dot, q0, q3Dot));
210 if (r.getQ0().getOrder() >= 2) {
211 final double q0DotDot = r.getQ0().getPartialDerivative(2);
212 final double q1DotDot = r.getQ1().getPartialDerivative(2);
213 final double q2DotDot = r.getQ2().getPartialDerivative(2);
214 final double q3DotDot = r.getQ3().getPartialDerivative(2);
215 rotationAcceleration =
216 new Vector3D(2 * MathArrays.linearCombination(-q1, q0DotDot, q0, q1DotDot, q3, q2DotDot, -q2, q3DotDot),
217 2 * MathArrays.linearCombination(-q2, q0DotDot, -q3, q1DotDot, q0, q2DotDot, q1, q3DotDot),
218 2 * MathArrays.linearCombination(-q3, q0DotDot, q2, q1DotDot, -q1, q2DotDot, q0, q3DotDot));
219 } else {
220 rotationAcceleration = Vector3D.ZERO;
221 }
222 } else {
223 rotationRate = Vector3D.ZERO;
224 rotationAcceleration = Vector3D.ZERO;
225 }
226
227 }
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246 private static Vector3D inverseCrossProducts(final Vector3D v1, final Vector3D c1,
247 final Vector3D v2, final Vector3D c2,
248 final double tolerance)
249 throws MathIllegalArgumentException {
250
251 final double v12 = v1.getNorm2Sq();
252 final double v1n = FastMath.sqrt(v12);
253 final double v22 = v2.getNorm2Sq();
254 final double v2n = FastMath.sqrt(v22);
255 final double threshold = tolerance * FastMath.max(v1n, v2n);
256
257 Vector3D omega;
258
259 try {
260
261 final RealMatrix m = MatrixUtils.createRealMatrix(6, 3);
262 m.setEntry(0, 1, v1.getZ());
263 m.setEntry(0, 2, -v1.getY());
264 m.setEntry(1, 0, -v1.getZ());
265 m.setEntry(1, 2, v1.getX());
266 m.setEntry(2, 0, v1.getY());
267 m.setEntry(2, 1, -v1.getX());
268 m.setEntry(3, 1, v2.getZ());
269 m.setEntry(3, 2, -v2.getY());
270 m.setEntry(4, 0, -v2.getZ());
271 m.setEntry(4, 2, v2.getX());
272 m.setEntry(5, 0, v2.getY());
273 m.setEntry(5, 1, -v2.getX());
274
275 final RealVector rhs = MatrixUtils.createRealVector(new double[] {
276 c1.getX(), c1.getY(), c1.getZ(),
277 c2.getX(), c2.getY(), c2.getZ()
278 });
279
280
281 final DecompositionSolver solver = new QRDecomposition(m, threshold).getSolver();
282 final RealVector v = solver.solve(rhs);
283 omega = new Vector3D(v.getEntry(0), v.getEntry(1), v.getEntry(2));
284
285 } catch (MathIllegalArgumentException miae) {
286 if (miae.getSpecifier() == LocalizedCoreFormats.SINGULAR_MATRIX) {
287
288
289 final double c12 = c1.getNorm2Sq();
290 final double c1n = FastMath.sqrt(c12);
291 final double c22 = c2.getNorm2Sq();
292 final double c2n = FastMath.sqrt(c22);
293
294 if (c1n <= threshold && c2n <= threshold) {
295
296 return Vector3D.ZERO;
297 } else if (v1n <= threshold && c1n >= threshold) {
298
299 throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE, c1n, 0, true);
300 } else if (v2n <= threshold && c2n >= threshold) {
301
302 throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE, c2n, 0, true);
303 } else if (Vector3D.crossProduct(v1, v2).getNorm() <= threshold && v12 > threshold) {
304
305
306 omega = new Vector3D(1.0 / v12, Vector3D.crossProduct(v1, c1));
307 } else {
308 throw miae;
309 }
310 } else {
311 throw miae;
312 }
313
314 }
315
316
317 final double d1 = Vector3D.distance(Vector3D.crossProduct(omega, v1), c1);
318 if (d1 > threshold) {
319 throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE, d1, 0, true);
320 }
321
322 final double d2 = Vector3D.distance(Vector3D.crossProduct(omega, v2), c2);
323 if (d2 > threshold) {
324 throw new MathIllegalArgumentException(LocalizedCoreFormats.NUMBER_TOO_LARGE, d2, 0, true);
325 }
326
327 return omega;
328
329 }
330
331
332
333
334
335
336
337
338
339 public FieldRotation<DerivativeStructure> toDerivativeStructureRotation(final int order) {
340
341
342 final double q0 = rotation.getQ0();
343 final double q1 = rotation.getQ1();
344 final double q2 = rotation.getQ2();
345 final double q3 = rotation.getQ3();
346
347
348 final double oX = rotationRate.getX();
349 final double oY = rotationRate.getY();
350 final double oZ = rotationRate.getZ();
351 final double q0Dot = 0.5 * MathArrays.linearCombination(-q1, oX, -q2, oY, -q3, oZ);
352 final double q1Dot = 0.5 * MathArrays.linearCombination( q0, oX, -q3, oY, q2, oZ);
353 final double q2Dot = 0.5 * MathArrays.linearCombination( q3, oX, q0, oY, -q1, oZ);
354 final double q3Dot = 0.5 * MathArrays.linearCombination(-q2, oX, q1, oY, q0, oZ);
355
356
357 final double oXDot = rotationAcceleration.getX();
358 final double oYDot = rotationAcceleration.getY();
359 final double oZDot = rotationAcceleration.getZ();
360 final double q0DotDot = -0.5 * MathArrays.linearCombination(new double[] {
361 q1, q2, q3, q1Dot, q2Dot, q3Dot
362 }, new double[] {
363 oXDot, oYDot, oZDot, oX, oY, oZ
364 });
365 final double q1DotDot = 0.5 * MathArrays.linearCombination(new double[] {
366 q0, q2, -q3, q0Dot, q2Dot, -q3Dot
367 }, new double[] {
368 oXDot, oZDot, oYDot, oX, oZ, oY
369 });
370 final double q2DotDot = 0.5 * MathArrays.linearCombination(new double[] {
371 q0, q3, -q1, q0Dot, q3Dot, -q1Dot
372 }, new double[] {
373 oYDot, oXDot, oZDot, oY, oX, oZ
374 });
375 final double q3DotDot = 0.5 * MathArrays.linearCombination(new double[] {
376 q0, q1, -q2, q0Dot, q1Dot, -q2Dot
377 }, new double[] {
378 oZDot, oYDot, oXDot, oZ, oY, oX
379 });
380
381 final DSFactory factory;
382 final DerivativeStructure q0DS;
383 final DerivativeStructure q1DS;
384 final DerivativeStructure q2DS;
385 final DerivativeStructure q3DS;
386 switch (order) {
387 case 0 :
388 factory = new DSFactory(1, order);
389 q0DS = factory.build(q0);
390 q1DS = factory.build(q1);
391 q2DS = factory.build(q2);
392 q3DS = factory.build(q3);
393 break;
394 case 1 :
395 factory = new DSFactory(1, order);
396 q0DS = factory.build(q0, q0Dot);
397 q1DS = factory.build(q1, q1Dot);
398 q2DS = factory.build(q2, q2Dot);
399 q3DS = factory.build(q3, q3Dot);
400 break;
401 case 2 :
402 factory = new DSFactory(1, order);
403 q0DS = factory.build(q0, q0Dot, q0DotDot);
404 q1DS = factory.build(q1, q1Dot, q1DotDot);
405 q2DS = factory.build(q2, q2Dot, q2DotDot);
406 q3DS = factory.build(q3, q3Dot, q3DotDot);
407 break;
408 default :
409 throw new OrekitException(OrekitMessages.OUT_OF_RANGE_DERIVATION_ORDER, order);
410 }
411
412 return new FieldRotation<>(q0DS, q1DS, q2DS, q3DS, false);
413
414 }
415
416
417
418
419
420
421
422
423 public FieldRotation<UnivariateDerivative1> toUnivariateDerivative1Rotation() {
424
425
426 final double q0 = rotation.getQ0();
427 final double q1 = rotation.getQ1();
428 final double q2 = rotation.getQ2();
429 final double q3 = rotation.getQ3();
430
431
432 final double oX = rotationRate.getX();
433 final double oY = rotationRate.getY();
434 final double oZ = rotationRate.getZ();
435 final double q0Dot = 0.5 * MathArrays.linearCombination(-q1, oX, -q2, oY, -q3, oZ);
436 final double q1Dot = 0.5 * MathArrays.linearCombination( q0, oX, -q3, oY, q2, oZ);
437 final double q2Dot = 0.5 * MathArrays.linearCombination( q3, oX, q0, oY, -q1, oZ);
438 final double q3Dot = 0.5 * MathArrays.linearCombination(-q2, oX, q1, oY, q0, oZ);
439
440 final UnivariateDerivative1 q0UD = new UnivariateDerivative1(q0, q0Dot);
441 final UnivariateDerivative1 q1UD = new UnivariateDerivative1(q1, q1Dot);
442 final UnivariateDerivative1 q2UD = new UnivariateDerivative1(q2, q2Dot);
443 final UnivariateDerivative1 q3UD = new UnivariateDerivative1(q3, q3Dot);
444
445 return new FieldRotation<>(q0UD, q1UD, q2UD, q3UD, false);
446
447 }
448
449
450
451
452
453
454
455
456 public FieldRotation<UnivariateDerivative2> toUnivariateDerivative2Rotation() {
457
458
459 final double q0 = rotation.getQ0();
460 final double q1 = rotation.getQ1();
461 final double q2 = rotation.getQ2();
462 final double q3 = rotation.getQ3();
463
464
465 final double oX = rotationRate.getX();
466 final double oY = rotationRate.getY();
467 final double oZ = rotationRate.getZ();
468 final double q0Dot = 0.5 * MathArrays.linearCombination(-q1, oX, -q2, oY, -q3, oZ);
469 final double q1Dot = 0.5 * MathArrays.linearCombination( q0, oX, -q3, oY, q2, oZ);
470 final double q2Dot = 0.5 * MathArrays.linearCombination( q3, oX, q0, oY, -q1, oZ);
471 final double q3Dot = 0.5 * MathArrays.linearCombination(-q2, oX, q1, oY, q0, oZ);
472
473
474 final double oXDot = rotationAcceleration.getX();
475 final double oYDot = rotationAcceleration.getY();
476 final double oZDot = rotationAcceleration.getZ();
477 final double q0DotDot = -0.5 * MathArrays.linearCombination(new double[] {
478 q1, q2, q3, q1Dot, q2Dot, q3Dot
479 }, new double[] {
480 oXDot, oYDot, oZDot, oX, oY, oZ
481 });
482 final double q1DotDot = 0.5 * MathArrays.linearCombination(new double[] {
483 q0, q2, -q3, q0Dot, q2Dot, -q3Dot
484 }, new double[] {
485 oXDot, oZDot, oYDot, oX, oZ, oY
486 });
487 final double q2DotDot = 0.5 * MathArrays.linearCombination(new double[] {
488 q0, q3, -q1, q0Dot, q3Dot, -q1Dot
489 }, new double[] {
490 oYDot, oXDot, oZDot, oY, oX, oZ
491 });
492 final double q3DotDot = 0.5 * MathArrays.linearCombination(new double[] {
493 q0, q1, -q2, q0Dot, q1Dot, -q2Dot
494 }, new double[] {
495 oZDot, oYDot, oXDot, oZ, oY, oX
496 });
497
498 final UnivariateDerivative2 q0UD = new UnivariateDerivative2(q0, q0Dot, q0DotDot);
499 final UnivariateDerivative2 q1UD = new UnivariateDerivative2(q1, q1Dot, q1DotDot);
500 final UnivariateDerivative2 q2UD = new UnivariateDerivative2(q2, q2Dot, q2DotDot);
501 final UnivariateDerivative2 q3UD = new UnivariateDerivative2(q3, q3Dot, q3DotDot);
502
503 return new FieldRotation<>(q0UD, q1UD, q2UD, q3UD, false);
504
505 }
506
507
508
509
510
511
512
513
514
515 public static Vector3D estimateRate(final Rotation start, final Rotation end, final double dt) {
516 final Rotation evolution = start.compose(end.revert(), RotationConvention.VECTOR_OPERATOR);
517 return new Vector3D(evolution.getAngle() / dt, evolution.getAxis(RotationConvention.VECTOR_OPERATOR));
518 }
519
520
521
522
523
524
525 public AngularCoordinates revert() {
526 return new AngularCoordinates(rotation.revert(),
527 rotation.applyInverseTo(rotationRate).negate(),
528 rotation.applyInverseTo(rotationAcceleration).negate());
529 }
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544 public Rotation rotationShiftedBy(final double dt) {
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560 final double rate = rotationRate.getNorm();
561 final Rotation rateContribution = (rate == 0.0) ?
562 Rotation.IDENTITY :
563 new Rotation(rotationRate, rate * dt, RotationConvention.FRAME_TRANSFORM);
564
565
566 final Rotation linearPart =
567 rateContribution.compose(rotation, RotationConvention.VECTOR_OPERATOR);
568
569 final double acc = rotationAcceleration.getNorm();
570 if (acc == 0.0) {
571
572 return linearPart;
573 }
574
575
576
577
578
579 final Rotation quadraticContribution =
580 new Rotation(rotationAcceleration,
581 0.5 * acc * dt * dt,
582 RotationConvention.FRAME_TRANSFORM);
583
584
585
586
587
588 return quadraticContribution
589 .compose(linearPart, RotationConvention.VECTOR_OPERATOR);
590
591 }
592
593
594
595
596
597
598
599
600
601
602
603
604 public AngularCoordinates shiftedBy(final double dt) {
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620 final double rate = rotationRate.getNorm();
621 final Rotation rateContribution = (rate == 0.0) ?
622 Rotation.IDENTITY :
623 new Rotation(rotationRate, rate * dt, RotationConvention.FRAME_TRANSFORM);
624
625
626 final AngularCoordinates linearPart =
627 new AngularCoordinates(rateContribution.compose(rotation, RotationConvention.VECTOR_OPERATOR), rotationRate);
628
629 final double acc = rotationAcceleration.getNorm();
630 if (acc == 0.0) {
631
632 return linearPart;
633 }
634
635
636
637
638
639 final AngularCoordinates quadraticContribution =
640 new AngularCoordinates(new Rotation(rotationAcceleration,
641 0.5 * acc * dt * dt,
642 RotationConvention.FRAME_TRANSFORM),
643 new Vector3D(dt, rotationAcceleration),
644 rotationAcceleration);
645
646
647
648
649
650 return quadraticContribution.addOffset(linearPart);
651
652 }
653
654
655
656
657 public Rotation getRotation() {
658 return rotation;
659 }
660
661
662
663
664 public Vector3D getRotationRate() {
665 return rotationRate;
666 }
667
668
669
670
671 public Vector3D getRotationAcceleration() {
672 return rotationAcceleration;
673 }
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693 public AngularCoordinates addOffset(final AngularCoordinates offset) {
694 final Vector3D rOmega = rotation.applyTo(offset.rotationRate);
695 final Vector3D rOmegaDot = rotation.applyTo(offset.rotationAcceleration);
696 return new AngularCoordinates(rotation.compose(offset.rotation, RotationConvention.VECTOR_OPERATOR),
697 rotationRate.add(rOmega),
698 new Vector3D( 1.0, rotationAcceleration,
699 1.0, rOmegaDot,
700 -1.0, Vector3D.crossProduct(rotationRate, rOmega)));
701 }
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721 public AngularCoordinates subtractOffset(final AngularCoordinates offset) {
722 return addOffset(offset.revert());
723 }
724
725
726
727
728
729 public PVCoordinates applyTo(final PVCoordinates pv) {
730
731 final Vector3D transformedP = rotation.applyTo(pv.getPosition());
732 final Vector3D crossP = Vector3D.crossProduct(rotationRate, transformedP);
733 final Vector3D transformedV = rotation.applyTo(pv.getVelocity()).subtract(crossP);
734 final Vector3D crossV = Vector3D.crossProduct(rotationRate, transformedV);
735 final Vector3D crossCrossP = Vector3D.crossProduct(rotationRate, crossP);
736 final Vector3D crossDotP = Vector3D.crossProduct(rotationAcceleration, transformedP);
737 final Vector3D transformedA = new Vector3D( 1, rotation.applyTo(pv.getAcceleration()),
738 -2, crossV,
739 -1, crossCrossP,
740 -1, crossDotP);
741
742 return new PVCoordinates(transformedP, transformedV, transformedA);
743
744 }
745
746
747
748
749
750 public TimeStampedPVCoordinates applyTo(final TimeStampedPVCoordinates pv) {
751
752 final Vector3D transformedP = getRotation().applyTo(pv.getPosition());
753 final Vector3D crossP = Vector3D.crossProduct(getRotationRate(), transformedP);
754 final Vector3D transformedV = getRotation().applyTo(pv.getVelocity()).subtract(crossP);
755 final Vector3D crossV = Vector3D.crossProduct(getRotationRate(), transformedV);
756 final Vector3D crossCrossP = Vector3D.crossProduct(getRotationRate(), crossP);
757 final Vector3D crossDotP = Vector3D.crossProduct(getRotationAcceleration(), transformedP);
758 final Vector3D transformedA = new Vector3D( 1, getRotation().applyTo(pv.getAcceleration()),
759 -2, crossV,
760 -1, crossCrossP,
761 -1, crossDotP);
762
763 return new TimeStampedPVCoordinates(pv.getDate(), transformedP, transformedV, transformedA);
764
765 }
766
767
768
769
770
771
772
773 public <T extends CalculusFieldElement<T>> FieldPVCoordinates<T> applyTo(final FieldPVCoordinates<T> pv) {
774
775 final FieldVector3D<T> transformedP = FieldRotation.applyTo(rotation, pv.getPosition());
776 final FieldVector3D<T> crossP = FieldVector3D.crossProduct(rotationRate, transformedP);
777 final FieldVector3D<T> transformedV = FieldRotation.applyTo(rotation, pv.getVelocity()).subtract(crossP);
778 final FieldVector3D<T> crossV = FieldVector3D.crossProduct(rotationRate, transformedV);
779 final FieldVector3D<T> crossCrossP = FieldVector3D.crossProduct(rotationRate, crossP);
780 final FieldVector3D<T> crossDotP = FieldVector3D.crossProduct(rotationAcceleration, transformedP);
781 final FieldVector3D<T> transformedA = new FieldVector3D<>( 1, FieldRotation.applyTo(rotation, pv.getAcceleration()),
782 -2, crossV,
783 -1, crossCrossP,
784 -1, crossDotP);
785
786 return new FieldPVCoordinates<>(transformedP, transformedV, transformedA);
787
788 }
789
790
791
792
793
794
795
796 public <T extends CalculusFieldElement<T>> TimeStampedFieldPVCoordinates<T> applyTo(final TimeStampedFieldPVCoordinates<T> pv) {
797
798 final FieldVector3D<T> transformedP = FieldRotation.applyTo(rotation, pv.getPosition());
799 final FieldVector3D<T> crossP = FieldVector3D.crossProduct(rotationRate, transformedP);
800 final FieldVector3D<T> transformedV = FieldRotation.applyTo(rotation, pv.getVelocity()).subtract(crossP);
801 final FieldVector3D<T> crossV = FieldVector3D.crossProduct(rotationRate, transformedV);
802 final FieldVector3D<T> crossCrossP = FieldVector3D.crossProduct(rotationRate, crossP);
803 final FieldVector3D<T> crossDotP = FieldVector3D.crossProduct(rotationAcceleration, transformedP);
804 final FieldVector3D<T> transformedA = new FieldVector3D<>( 1, FieldRotation.applyTo(rotation, pv.getAcceleration()),
805 -2, crossV,
806 -1, crossCrossP,
807 -1, crossDotP);
808
809 return new TimeStampedFieldPVCoordinates<>(pv.getDate(), transformedP, transformedV, transformedA);
810
811 }
812
813
814
815
816
817
818
819
820
821
822
823 public double[][] getModifiedRodrigues(final double sign) {
824
825 final double q0 = sign * getRotation().getQ0();
826 final double q1 = sign * getRotation().getQ1();
827 final double q2 = sign * getRotation().getQ2();
828 final double q3 = sign * getRotation().getQ3();
829 final double oX = getRotationRate().getX();
830 final double oY = getRotationRate().getY();
831 final double oZ = getRotationRate().getZ();
832 final double oXDot = getRotationAcceleration().getX();
833 final double oYDot = getRotationAcceleration().getY();
834 final double oZDot = getRotationAcceleration().getZ();
835
836
837 final double q0Dot = 0.5 * MathArrays.linearCombination(-q1, oX, -q2, oY, -q3, oZ);
838 final double q1Dot = 0.5 * MathArrays.linearCombination( q0, oX, -q3, oY, q2, oZ);
839 final double q2Dot = 0.5 * MathArrays.linearCombination( q3, oX, q0, oY, -q1, oZ);
840 final double q3Dot = 0.5 * MathArrays.linearCombination(-q2, oX, q1, oY, q0, oZ);
841
842
843 final double q0DotDot = -0.5 * MathArrays.linearCombination(new double[] {
844 q1, q2, q3, q1Dot, q2Dot, q3Dot
845 }, new double[] {
846 oXDot, oYDot, oZDot, oX, oY, oZ
847 });
848 final double q1DotDot = 0.5 * MathArrays.linearCombination(new double[] {
849 q0, q2, -q3, q0Dot, q2Dot, -q3Dot
850 }, new double[] {
851 oXDot, oZDot, oYDot, oX, oZ, oY
852 });
853 final double q2DotDot = 0.5 * MathArrays.linearCombination(new double[] {
854 q0, q3, -q1, q0Dot, q3Dot, -q1Dot
855 }, new double[] {
856 oYDot, oXDot, oZDot, oY, oX, oZ
857 });
858 final double q3DotDot = 0.5 * MathArrays.linearCombination(new double[] {
859 q0, q1, -q2, q0Dot, q1Dot, -q2Dot
860 }, new double[] {
861 oZDot, oYDot, oXDot, oZ, oY, oX
862 });
863
864
865
866
867
868 final double inv = 1.0 / (1.0 + q0);
869 final double mTwoInvQ0Dot = -2 * inv * q0Dot;
870
871 final double r1 = inv * q1;
872 final double r2 = inv * q2;
873 final double r3 = inv * q3;
874
875 final double mInvR1 = -inv * r1;
876 final double mInvR2 = -inv * r2;
877 final double mInvR3 = -inv * r3;
878
879 final double r1Dot = MathArrays.linearCombination(inv, q1Dot, mInvR1, q0Dot);
880 final double r2Dot = MathArrays.linearCombination(inv, q2Dot, mInvR2, q0Dot);
881 final double r3Dot = MathArrays.linearCombination(inv, q3Dot, mInvR3, q0Dot);
882
883 final double r1DotDot = MathArrays.linearCombination(inv, q1DotDot, mTwoInvQ0Dot, r1Dot, mInvR1, q0DotDot);
884 final double r2DotDot = MathArrays.linearCombination(inv, q2DotDot, mTwoInvQ0Dot, r2Dot, mInvR2, q0DotDot);
885 final double r3DotDot = MathArrays.linearCombination(inv, q3DotDot, mTwoInvQ0Dot, r3Dot, mInvR3, q0DotDot);
886
887 return new double[][] {
888 {
889 r1, r2, r3
890 }, {
891 r1Dot, r2Dot, r3Dot
892 }, {
893 r1DotDot, r2DotDot, r3DotDot
894 }
895 };
896
897 }
898
899
900
901
902
903
904 public static AngularCoordinates createFromModifiedRodrigues(final double[][] r) {
905
906
907 final double rSquared = r[0][0] * r[0][0] + r[0][1] * r[0][1] + r[0][2] * r[0][2];
908 final double oPQ0 = 2 / (1 + rSquared);
909 final double q0 = oPQ0 - 1;
910 final double q1 = oPQ0 * r[0][0];
911 final double q2 = oPQ0 * r[0][1];
912 final double q3 = oPQ0 * r[0][2];
913
914
915 final double oPQ02 = oPQ0 * oPQ0;
916 final double q0Dot = -oPQ02 * MathArrays.linearCombination(r[0][0], r[1][0], r[0][1], r[1][1], r[0][2], r[1][2]);
917 final double q1Dot = oPQ0 * r[1][0] + r[0][0] * q0Dot;
918 final double q2Dot = oPQ0 * r[1][1] + r[0][1] * q0Dot;
919 final double q3Dot = oPQ0 * r[1][2] + r[0][2] * q0Dot;
920 final double oX = 2 * MathArrays.linearCombination(-q1, q0Dot, q0, q1Dot, q3, q2Dot, -q2, q3Dot);
921 final double oY = 2 * MathArrays.linearCombination(-q2, q0Dot, -q3, q1Dot, q0, q2Dot, q1, q3Dot);
922 final double oZ = 2 * MathArrays.linearCombination(-q3, q0Dot, q2, q1Dot, -q1, q2Dot, q0, q3Dot);
923
924
925 final double q0DotDot = (1 - q0) / oPQ0 * q0Dot * q0Dot -
926 oPQ02 * MathArrays.linearCombination(r[0][0], r[2][0], r[0][1], r[2][1], r[0][2], r[2][2]) -
927 (q1Dot * q1Dot + q2Dot * q2Dot + q3Dot * q3Dot);
928 final double q1DotDot = MathArrays.linearCombination(oPQ0, r[2][0], 2 * r[1][0], q0Dot, r[0][0], q0DotDot);
929 final double q2DotDot = MathArrays.linearCombination(oPQ0, r[2][1], 2 * r[1][1], q0Dot, r[0][1], q0DotDot);
930 final double q3DotDot = MathArrays.linearCombination(oPQ0, r[2][2], 2 * r[1][2], q0Dot, r[0][2], q0DotDot);
931 final double oXDot = 2 * MathArrays.linearCombination(-q1, q0DotDot, q0, q1DotDot, q3, q2DotDot, -q2, q3DotDot);
932 final double oYDot = 2 * MathArrays.linearCombination(-q2, q0DotDot, -q3, q1DotDot, q0, q2DotDot, q1, q3DotDot);
933 final double oZDot = 2 * MathArrays.linearCombination(-q3, q0DotDot, q2, q1DotDot, -q1, q2DotDot, q0, q3DotDot);
934
935 return new AngularCoordinates(new Rotation(q0, q1, q2, q3, false),
936 new Vector3D(oX, oY, oZ),
937 new Vector3D(oXDot, oYDot, oZDot));
938
939 }
940
941 }