1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.attitudes;
18
19 import org.hipparchus.CalculusFieldElement;
20 import org.hipparchus.Field;
21 import org.hipparchus.complex.Complex;
22 import org.hipparchus.complex.ComplexField;
23 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
24 import org.hipparchus.geometry.euclidean.threed.Rotation;
25 import org.hipparchus.geometry.euclidean.threed.RotationConvention;
26 import org.hipparchus.geometry.euclidean.threed.Vector3D;
27 import org.hipparchus.util.Binary64Field;
28 import org.hipparchus.util.FastMath;
29 import org.junit.jupiter.api.AfterEach;
30 import org.junit.jupiter.api.Assertions;
31 import org.junit.jupiter.api.BeforeEach;
32 import org.junit.jupiter.api.Test;
33 import org.orekit.Utils;
34 import org.orekit.bodies.GeodeticPoint;
35 import org.orekit.bodies.OneAxisEllipsoid;
36 import org.orekit.errors.OrekitException;
37 import org.orekit.frames.Frame;
38 import org.orekit.frames.FramesFactory;
39 import org.orekit.orbits.*;
40 import org.orekit.propagation.FieldSpacecraftState;
41 import org.orekit.propagation.Propagator;
42 import org.orekit.propagation.SpacecraftState;
43 import org.orekit.propagation.analytical.KeplerianPropagator;
44 import org.orekit.time.AbsoluteDate;
45 import org.orekit.time.DateComponents;
46 import org.orekit.time.FieldAbsoluteDate;
47 import org.orekit.time.TimeComponents;
48 import org.orekit.time.TimeInterpolator;
49 import org.orekit.time.TimeScalesFactory;
50 import org.orekit.utils.*;
51
52 import java.util.ArrayList;
53 import java.util.List;
54
55
56 class NadirPointingTest {
57
58
59 private AbsoluteDate date;
60
61
62 private double mu;
63
64
65 private Frame itrf;
66
67 @Test
68 void testGetTargetPV() {
69
70 final OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 0., itrf);
71 final NadirPointing nadirAttitudeLaw = new NadirPointing(FramesFactory.getEME2000(), earthShape);
72 final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH;
73 final Frame frame = FramesFactory.getGCRF();
74 final PVCoordinatesProvider provider = (date1, frame1) -> {
75 final double duration = date1.durationFrom(AbsoluteDate.FIFTIES_EPOCH);
76 final Vector3D position = new Vector3D(duration * duration / 2, 0., 0.);
77 final Vector3D velocity = new Vector3D(duration, 0., 0.);
78 final Vector3D acceleration = new Vector3D(1, 0, 0);
79 return new TimeStampedPVCoordinates(date1, position, velocity, acceleration);
80 };
81
82 final TimeStampedPVCoordinates actualPV = nadirAttitudeLaw.getTargetPV(provider, date, frame);
83
84 final PVCoordinatesProvider providerWithoutAcceleration = (date12, frame12) -> {
85 final TimeStampedPVCoordinates originalPV = provider.getPVCoordinates(date12, frame12);
86 return new TimeStampedPVCoordinates(date12, originalPV.getPosition(), originalPV.getVelocity());
87 };
88 final TimeStampedPVCoordinates pv = nadirAttitudeLaw.getTargetPV(providerWithoutAcceleration, date, frame);
89 Assertions.assertEquals(pv.getDate(), actualPV.getDate());
90 final PVCoordinates relativePV = new PVCoordinates(pv, actualPV);
91 Assertions.assertEquals(0., relativePV.getPosition().getNorm(), 2e-9);
92 Assertions.assertEquals(0., relativePV.getVelocity().getNorm(), 1e-7);
93 }
94
95 @Test
96 void testGetTargetPVViaInterpolationField() {
97
98 final OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 0., itrf);
99 final NadirPointing nadirAttitudeLaw = new NadirPointing(FramesFactory.getEME2000(), earthShape);
100 final AbsoluteDate date = AbsoluteDate.ARBITRARY_EPOCH;
101 final Frame frame = FramesFactory.getGCRF();
102 final PVCoordinatesProvider provider = (dateIn, frameIn) -> new TimeStampedPVCoordinates(dateIn,
103 new Vector3D(dateIn.durationFrom(AbsoluteDate.FIFTIES_EPOCH), 0., 0.), Vector3D.PLUS_I);
104 final ComplexField field = ComplexField.getInstance();
105 final FieldAbsoluteDate<Complex> fieldDate = new FieldAbsoluteDate<>(field, date);
106 final FieldPVCoordinatesProvider<Complex> fieldProvider = (dateIn, frameIn) -> new TimeStampedFieldPVCoordinates<>(dateIn,
107 new FieldVector3D<>(dateIn.durationFrom(AbsoluteDate.FIFTIES_EPOCH), field.getZero(), field.getZero()),
108 FieldVector3D.getPlusI(field), FieldVector3D.getZero(field));
109
110 final TimeStampedFieldPVCoordinates<Complex> actualPV = nadirAttitudeLaw.getTargetPV(fieldProvider, fieldDate, frame);
111
112 final TimeStampedPVCoordinates pv = nadirAttitudeLaw.getTargetPV(provider, date, frame);
113 Assertions.assertEquals(pv.getDate(), actualPV.getDate().toAbsoluteDate());
114 final PVCoordinates relativePV = new PVCoordinates(pv, actualPV.toPVCoordinates());
115 final Vector3D positionDifference = relativePV.getPosition();
116 Assertions.assertEquals(0., positionDifference.getNorm(), 2e-9);
117 final Vector3D velocityDifference = relativePV.getVelocity();
118 Assertions.assertEquals(0., velocityDifference.getNorm(), 1e-6);
119 }
120
121 @Test
122 void testGetTargetPosition() {
123
124 final OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 0., itrf);
125 final NadirPointing nadirAttitudeLaw = new NadirPointing(FramesFactory.getEME2000(), earthShape);
126 final CircularOrbit circ =
127 new CircularOrbit(7178000.0, 0.5e-4, -0.5e-4, FastMath.toRadians(50.), FastMath.toRadians(270.),
128 FastMath.toRadians(5.300), PositionAngleType.MEAN,
129 FramesFactory.getEME2000(), date, mu);
130
131 final Vector3D actualPosition = nadirAttitudeLaw.getTargetPosition(circ, circ.getDate(), circ.getFrame());
132
133 final Vector3D expectedPosition = nadirAttitudeLaw.getTargetPV(circ, circ.getDate(), circ.getFrame()).getPosition();
134 Assertions.assertEquals(0., expectedPosition.subtract(actualPosition).getNorm(), 1e-9);
135 }
136
137 @Test
138 void testGetTargetPositionField() {
139
140 final OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 0., itrf);
141 final NadirPointing nadirAttitudeLaw = new NadirPointing(FramesFactory.getEME2000(), earthShape);
142 final CircularOrbit circ =
143 new CircularOrbit(7178000.0, 0.5e-4, -0.5e-4, FastMath.toRadians(50.), FastMath.toRadians(270.),
144 FastMath.toRadians(5.300), PositionAngleType.MEAN,
145 FramesFactory.getEME2000(), date, mu);
146 final FieldCircularOrbit<Complex> fieldOrbit = new FieldCircularOrbit<>(ComplexField.getInstance(), circ);
147
148 final FieldVector3D<Complex> actualPosition = nadirAttitudeLaw.getTargetPosition(fieldOrbit, fieldOrbit.getDate(), fieldOrbit.getFrame());
149
150 final FieldVector3D<Complex> expectedPosition = nadirAttitudeLaw.getTargetPV(fieldOrbit, fieldOrbit.getDate(), fieldOrbit.getFrame()).getPosition();
151 Assertions.assertEquals(0., expectedPosition.subtract(actualPosition).getNorm().getReal(), 1e-9);
152 }
153
154
155
156
157 @Test
158 void testSphericEarth() {
159
160
161 OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 0., itrf);
162
163
164 NadirPointing nadirAttitudeLaw = new NadirPointing(FramesFactory.getEME2000(), earthShape);
165
166
167 BodyCenterPointing earthCenterAttitudeLaw =
168 new BodyCenterPointing(FramesFactory.getEME2000(), earthShape);
169
170
171 CircularOrbit circ =
172 new CircularOrbit(7178000.0, 0.5e-4, -0.5e-4, FastMath.toRadians(50.), FastMath.toRadians(270.),
173 FastMath.toRadians(5.300), PositionAngleType.MEAN,
174 FramesFactory.getEME2000(), date, mu);
175
176
177 Rotation rotNadir = nadirAttitudeLaw.getAttitude(circ, date, circ.getFrame()).getRotation();
178
179
180 Rotation rotCenter = earthCenterAttitudeLaw.getAttitude(circ, date, circ.getFrame()).getRotation();
181
182
183
184
185 Rotation rotCompo = rotCenter.composeInverse(rotNadir, RotationConvention.VECTOR_OPERATOR);
186 double angle = rotCompo.getAngle();
187 Assertions.assertEquals(angle, 0.0, Utils.epsilonAngle);
188
189 }
190
191
192
193
194
195 @Test
196 void testNonSphericEarth() {
197
198
199 OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 1 / 298.257222101, itrf);
200
201
202 NadirPointing nadirAttitudeLaw = new NadirPointing(FramesFactory.getEME2000(), earthShape);
203
204
205 BodyCenterPointing earthCenterAttitudeLaw =
206 new BodyCenterPointing(FramesFactory.getEME2000(), earthShape);
207
208
209
210 KeplerianOrbit kep =
211 new KeplerianOrbit(7178000.0, 1.e-8, FastMath.toRadians(50.), 0., 0.,
212 0., PositionAngleType.TRUE, FramesFactory.getEME2000(), date, mu);
213
214
215 Rotation rotNadir = nadirAttitudeLaw.getAttitude(kep, date, kep.getFrame()).getRotation();
216
217 checkField(Binary64Field.getInstance(), nadirAttitudeLaw, kep, kep.getDate(), kep.getFrame());
218
219
220 Rotation rotCenter = earthCenterAttitudeLaw.getAttitude(kep, date, kep.getFrame()).getRotation();
221
222
223
224
225 Rotation rotCompo = rotCenter.composeInverse(rotNadir, RotationConvention.VECTOR_OPERATOR);
226 double angle = rotCompo.getAngle();
227 Assertions.assertEquals(0.0, angle, 5.e-6);
228
229
230
231 CircularOrbit circ =
232 new CircularOrbit(7178000.0, 1.e-5, 0., FastMath.toRadians(90.), 0.,
233 FastMath.toRadians(90.), PositionAngleType.TRUE,
234 FramesFactory.getEME2000(), date, mu);
235
236
237 rotNadir = nadirAttitudeLaw.getAttitude(circ, date, circ.getFrame()).getRotation();
238
239
240 rotCenter = earthCenterAttitudeLaw.getAttitude(circ, date, circ.getFrame()).getRotation();
241
242
243
244
245 rotCompo = rotCenter.composeInverse(rotNadir, RotationConvention.VECTOR_OPERATOR);
246 angle = rotCompo.getAngle();
247 Assertions.assertEquals(angle, 0.0, 5.e-6);
248
249
250
251 circ =
252 new CircularOrbit(7178000.0, 1.e-5, 0., FastMath.toRadians(50.), 0.,
253 FastMath.toRadians(90.), PositionAngleType.TRUE,
254 FramesFactory.getEME2000(), date, mu);
255
256
257 rotNadir = nadirAttitudeLaw.getAttitude(circ, date, circ.getFrame()).getRotation();
258
259
260 rotCenter = earthCenterAttitudeLaw.getAttitude(circ, date, circ.getFrame()).getRotation();
261
262
263
264
265 rotCompo = rotCenter.composeInverse(rotNadir, RotationConvention.VECTOR_OPERATOR);
266 angle = rotCompo.getAngle();
267 Assertions.assertEquals(angle, FastMath.toRadians(0.16797386586252272), Utils.epsilonAngle);
268 }
269
270
271
272
273
274
275
276 @Test
277 void testVertical() {
278
279
280 OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 1 / 298.257222101, itrf);
281
282
283 NadirPointing nadirAttitudeLaw = new NadirPointing(FramesFactory.getEME2000(), earthShape);
284
285
286 CircularOrbit circ =
287 new CircularOrbit(7178000.0, 1.e-5, 0., FastMath.toRadians(50.), 0.,
288 FastMath.toRadians(90.), PositionAngleType.TRUE,
289 FramesFactory.getEME2000(), date, mu);
290
291
292
293
294 TimeStampedPVCoordinates pvTargetItrf = nadirAttitudeLaw.getTargetPV(circ, date, itrf);
295
296
297 GeodeticPoint geoTarget = earthShape.transform(pvTargetItrf.getPosition(), itrf, date);
298
299
300 double xVert = FastMath.cos(geoTarget.getLongitude())*FastMath.cos(geoTarget.getLatitude());
301 double yVert = FastMath.sin(geoTarget.getLongitude())*FastMath.cos(geoTarget.getLatitude());
302 double zVert = FastMath.sin(geoTarget.getLatitude());
303 Vector3D targetVertical = new Vector3D(xVert, yVert, zVert);
304
305
306 Rotation rotSatEME2000 = nadirAttitudeLaw.getAttitude(circ, date, circ.getFrame()).getRotation();
307
308
309 Vector3D zSatEME2000 = rotSatEME2000.applyInverseTo(Vector3D.PLUS_K);
310 Vector3D zSatItrf = FramesFactory.getEME2000().getStaticTransformTo(itrf, date).transformVector(zSatEME2000);
311
312
313 double angle= Vector3D.angle(zSatItrf, targetVertical);
314 Assertions.assertEquals(0.0, FastMath.sin(angle), Utils.epsilonTest);
315
316 }
317
318
319
320 @Test
321 void testSlidingDerivatives() {
322
323
324 OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 1 / 298.257222101, itrf);
325
326
327 NadirPointing nadirAttitudeLaw = new NadirPointing(FramesFactory.getEME2000(), earthShape);
328
329
330 CircularOrbit circ =
331 new CircularOrbit(7178000.0, 1.e-5, 0., FastMath.toRadians(50.), 0.,
332 FastMath.toRadians(90.), PositionAngleType.TRUE,
333 FramesFactory.getEME2000(), date, mu);
334
335 List<TimeStampedPVCoordinates> sample = new ArrayList<>();
336 for (double dt = -0.1; dt < 0.1; dt += 0.05) {
337 Orbit o = circ.shiftedBy(dt);
338 sample.add(nadirAttitudeLaw.getTargetPV(o, o.getDate(), o.getFrame()));
339 }
340
341
342 final TimeInterpolator<TimeStampedPVCoordinates> interpolator =
343 new TimeStampedPVCoordinatesHermiteInterpolator(sample.size(), CartesianDerivativesFilter.USE_P);
344
345 TimeStampedPVCoordinates reference = interpolator.interpolate(circ.getDate(), sample);
346
347 TimeStampedPVCoordinates target =
348 nadirAttitudeLaw.getTargetPV(circ, circ.getDate(), circ.getFrame());
349
350 Assertions.assertEquals(0.0,
351 Vector3D.distance(reference.getPosition(), target.getPosition()),
352 1.0e-15 * reference.getPosition().getNorm());
353 Assertions.assertEquals(0.0,
354 Vector3D.distance(reference.getVelocity(), target.getVelocity()),
355 3.0e-11 * reference.getVelocity().getNorm());
356 Assertions.assertEquals(0.0,
357 Vector3D.distance(reference.getAcceleration(), target.getAcceleration()),
358 1.3e-5 * reference.getAcceleration().getNorm());
359
360 }
361
362 @Test
363 void testSpin() {
364
365
366 OneAxisEllipsoid earthShape = new OneAxisEllipsoid(6378136.460, 1 / 298.257222101, itrf);
367
368
369 NadirPointing law = new NadirPointing(FramesFactory.getEME2000(), earthShape);
370
371
372 KeplerianOrbit orbit =
373 new KeplerianOrbit(7178000.0, 1.e-4, FastMath.toRadians(50.),
374 FastMath.toRadians(10.), FastMath.toRadians(20.),
375 FastMath.toRadians(30.), PositionAngleType.MEAN,
376 FramesFactory.getEME2000(), date, mu);
377
378 Propagator propagator = new KeplerianPropagator(orbit, law, mu, 2500.0);
379
380 double h = 0.1;
381 SpacecraftState sMinus = propagator.propagate(date.shiftedBy(-h));
382 SpacecraftState s0 = propagator.propagate(date);
383 SpacecraftState sPlus = propagator.propagate(date.shiftedBy(h));
384
385
386 double errorAngleMinus = Rotation.distance(sMinus.shiftedBy(h).getAttitude().getRotation(),
387 s0.getAttitude().getRotation());
388 double evolutionAngleMinus = Rotation.distance(sMinus.getAttitude().getRotation(),
389 s0.getAttitude().getRotation());
390 Assertions.assertEquals(0.0, errorAngleMinus, 5.3e-9 * evolutionAngleMinus);
391 double errorAnglePlus = Rotation.distance(s0.getAttitude().getRotation(),
392 sPlus.shiftedBy(-h).getAttitude().getRotation());
393 double evolutionAnglePlus = Rotation.distance(s0.getAttitude().getRotation(),
394 sPlus.getAttitude().getRotation());
395 Assertions.assertEquals(0.0, errorAnglePlus, 8.1e-9 * evolutionAnglePlus);
396
397 Vector3D spin0 = s0.getAttitude().getSpin();
398 Rotation rM = sMinus.getAttitude().getRotation();
399 Rotation rP = sPlus.getAttitude().getRotation();
400 Vector3D reference = AngularCoordinates.estimateRate(rM, rP, 2 * h);
401 Assertions.assertTrue(Rotation.distance(rM, rP) > 2.0e-4);
402 Assertions.assertEquals(0.0, spin0.subtract(reference).getNorm(), 2.0e-6);
403
404 }
405
406 private <T extends CalculusFieldElement<T>> void checkField(final Field<T> field, final GroundPointing provider,
407 final Orbit orbit, final AbsoluteDate date,
408 final Frame frame)
409 {
410
411 final Attitude attitudeD = provider.getAttitude(orbit, date, frame);
412 final FieldOrbit<T> orbitF = new FieldSpacecraftState<>(field, new SpacecraftState(orbit)).getOrbit();
413 final FieldAbsoluteDate<T> dateF = new FieldAbsoluteDate<>(field, date);
414 final FieldAttitude<T> attitudeF = provider.getAttitude(orbitF, dateF, frame);
415 Assertions.assertEquals(0.0, Rotation.distance(attitudeD.getRotation(), attitudeF.getRotation().toRotation()), 1.0e-15);
416 Assertions.assertEquals(0.0, Vector3D.distance(attitudeD.getSpin(), attitudeF.getSpin().toVector3D()), 2.0e-14);
417 Assertions.assertEquals(0.0, Vector3D.distance(attitudeD.getRotationAcceleration(), attitudeF.getRotationAcceleration().toVector3D()), 4.0e-12);
418
419 final TimeStampedPVCoordinates pvD = provider.getTargetPV(orbit, date, frame);
420 final TimeStampedFieldPVCoordinates<T> pvF = provider.getTargetPV(orbitF, dateF, frame);
421 Assertions.assertEquals(0.0, Vector3D.distance(pvD.getPosition(), pvF.getPosition().toVector3D()), 1.0e-15);
422 Assertions.assertEquals(0.0, Vector3D.distance(pvD.getVelocity(), pvF.getVelocity().toVector3D()), 2.0e-8);
423 Assertions.assertEquals(0.0, Vector3D.distance(pvD.getAcceleration(), pvF.getAcceleration().toVector3D()), 3.0e-5);
424
425 }
426
427 @BeforeEach
428 public void setUp() {
429 try {
430
431 Utils.setDataRoot("regular-data");
432
433
434 date = new AbsoluteDate(new DateComponents(2008, 4, 7),
435 TimeComponents.H00,
436 TimeScalesFactory.getUTC());
437
438
439 mu = 3.9860047e14;
440
441
442 itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
443
444 } catch (OrekitException oe) {
445 Assertions.fail(oe.getMessage());
446 }
447
448 }
449
450 @AfterEach
451 public void tearDown() {
452 date = null;
453 itrf = null;
454 }
455
456 }
457