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