1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.attitudes;
18
19
20 import java.util.ArrayList;
21 import java.util.List;
22
23 import org.hipparchus.Field;
24 import org.hipparchus.CalculusFieldElement;
25 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
26 import org.hipparchus.geometry.euclidean.threed.Rotation;
27 import org.hipparchus.geometry.euclidean.threed.RotationOrder;
28 import org.hipparchus.geometry.euclidean.threed.Vector3D;
29 import org.hipparchus.ode.events.Action;
30 import org.hipparchus.ode.nonstiff.AdaptiveStepsizeIntegrator;
31 import org.hipparchus.ode.nonstiff.DormandPrince853Integrator;
32 import org.hipparchus.util.Decimal64Field;
33 import org.hipparchus.util.FastMath;
34 import org.junit.Assert;
35 import org.junit.Before;
36 import org.junit.Test;
37 import org.orekit.Utils;
38 import org.orekit.bodies.CelestialBodyFactory;
39 import org.orekit.bodies.GeodeticPoint;
40 import org.orekit.bodies.OneAxisEllipsoid;
41 import org.orekit.errors.OrekitException;
42 import org.orekit.errors.OrekitMessages;
43 import org.orekit.forces.gravity.HolmesFeatherstoneAttractionModel;
44 import org.orekit.forces.gravity.potential.GravityFieldFactory;
45 import org.orekit.forces.gravity.potential.ICGEMFormatReader;
46 import org.orekit.frames.FramesFactory;
47 import org.orekit.frames.LOFType;
48 import org.orekit.frames.TopocentricFrame;
49 import org.orekit.orbits.FieldKeplerianOrbit;
50 import org.orekit.orbits.FieldOrbit;
51 import org.orekit.orbits.KeplerianOrbit;
52 import org.orekit.orbits.Orbit;
53 import org.orekit.propagation.FieldPropagator;
54 import org.orekit.propagation.FieldSpacecraftState;
55 import org.orekit.propagation.Propagator;
56 import org.orekit.propagation.SpacecraftState;
57 import org.orekit.propagation.analytical.EcksteinHechlerPropagator;
58 import org.orekit.propagation.analytical.FieldEcksteinHechlerPropagator;
59 import org.orekit.propagation.analytical.KeplerianPropagator;
60 import org.orekit.propagation.events.DateDetector;
61 import org.orekit.propagation.events.EclipseDetector;
62 import org.orekit.propagation.events.ElevationDetector;
63 import org.orekit.propagation.events.EventDetector;
64 import org.orekit.propagation.events.EventsLogger;
65 import org.orekit.propagation.events.handlers.ContinueOnEvent;
66 import org.orekit.propagation.numerical.NumericalPropagator;
67 import org.orekit.propagation.sampling.FieldOrekitFixedStepHandler;
68 import org.orekit.propagation.sampling.OrekitFixedStepHandler;
69 import org.orekit.time.AbsoluteDate;
70 import org.orekit.time.FieldAbsoluteDate;
71 import org.orekit.time.TimeScalesFactory;
72 import org.orekit.utils.AngularDerivativesFilter;
73 import org.orekit.utils.Constants;
74 import org.orekit.utils.FieldPVCoordinates;
75 import org.orekit.utils.IERSConventions;
76 import org.orekit.utils.PVCoordinates;
77 import org.orekit.utils.PVCoordinatesProvider;
78
79 public class AttitudesSequenceTest {
80
81 private AbsoluteDate lastChange;
82 private boolean inEclipse;
83
84 @Test
85 public void testDayNightSwitch() {
86
87 final AbsoluteDate initialDate = new AbsoluteDate(2004, 01, 01, 23, 30, 00.000, TimeScalesFactory.getUTC());
88 final Vector3D position = new Vector3D(-6142438.668, 3492467.560, -25767.25680);
89 final Vector3D velocity = new Vector3D(505.8479685, 942.7809215, 7435.922231);
90 final Orbit initialOrbit = new KeplerianOrbit(new PVCoordinates(position, velocity),
91 FramesFactory.getEME2000(), initialDate,
92 Constants.EIGEN5C_EARTH_MU);
93
94 final
95
96
97 EventsLogger logger = new EventsLogger();
98 final AttitudesSequence attitudesSequence = new AttitudesSequence();
99 final AttitudeProvider dayObservationLaw = new LofOffset(initialOrbit.getFrame(), LOFType.LVLH_CCSDS,
100 RotationOrder.XYZ, FastMath.toRadians(20), FastMath.toRadians(40), 0);
101 final AttitudeProvider nightRestingLaw = new LofOffset(initialOrbit.getFrame(), LOFType.LVLH_CCSDS);
102 final PVCoordinatesProvider sun = CelestialBodyFactory.getSun();
103 final EclipseDetector ed =
104 new EclipseDetector(sun, 696000000.,
105 new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
106 0.0,
107 FramesFactory.getGTOD(IERSConventions.IERS_2010, true))).
108 withHandler(new ContinueOnEvent<EclipseDetector>() {
109 public Action eventOccurred(final SpacecraftState s, final EclipseDetector d, final boolean increasing) {
110 setInEclipse(s.getDate(), !increasing);
111 return Action.RESET_STATE;
112 }
113 });
114 final EventDetector monitored = logger.monitorDetector(ed);
115 final Handler dayToNightHandler = new Handler(dayObservationLaw, nightRestingLaw);
116 final Handler nightToDayHandler = new Handler(nightRestingLaw, dayObservationLaw);
117 attitudesSequence.addSwitchingCondition(dayObservationLaw, nightRestingLaw,
118 monitored, false, true, 300.0,
119 AngularDerivativesFilter.USE_RRA, dayToNightHandler);
120 attitudesSequence.addSwitchingCondition(nightRestingLaw, dayObservationLaw,
121 monitored, true, false, 300.0,
122 AngularDerivativesFilter.USE_RRA, nightToDayHandler);
123 SpacecraftState initialState = new SpacecraftState(initialOrbit);
124 initialState = initialState.addAdditionalState("fortyTwo", 42.0);
125 if (ed.g(initialState) >= 0) {
126
127 setInEclipse(initialDate, false);
128 attitudesSequence.resetActiveProvider(dayObservationLaw);
129 } else {
130
131 setInEclipse(initialDate, true);
132 attitudesSequence.resetActiveProvider(nightRestingLaw);
133 }
134
135
136 final Propagator propagator = new EcksteinHechlerPropagator(initialOrbit, attitudesSequence,
137 Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS,
138 Constants.EIGEN5C_EARTH_MU, Constants.EIGEN5C_EARTH_C20,
139 Constants.EIGEN5C_EARTH_C30, Constants.EIGEN5C_EARTH_C40,
140 Constants.EIGEN5C_EARTH_C50, Constants.EIGEN5C_EARTH_C60);
141
142
143 attitudesSequence.registerSwitchEvents(propagator);
144
145 propagator.setStepHandler(60.0, new OrekitFixedStepHandler() {
146 public void handleStep(SpacecraftState currentState) {
147
148
149 final Vector3D earth = currentState.toTransform().transformPosition(Vector3D.ZERO);
150 final double pointingOffset = Vector3D.angle(earth, Vector3D.PLUS_K);
151
152
153
154 final double eclipseAngle = ed.g(currentState);
155
156 if (currentState.getDate().durationFrom(lastChange) > 300) {
157 if (inEclipse) {
158 Assert.assertTrue(eclipseAngle <= 0);
159 Assert.assertEquals(0.0, pointingOffset, 1.0e-6);
160 } else {
161 Assert.assertTrue(eclipseAngle >= 0);
162 Assert.assertEquals(0.767215, pointingOffset, 1.0e-6);
163 }
164 } else {
165
166 Assert.assertTrue(pointingOffset + " " + (0.767215 - pointingOffset),
167 pointingOffset <= 0.7672155);
168 }
169 }
170 });
171
172
173 propagator.propagate(initialDate.shiftedBy(12600.));
174
175
176
177
178 Assert.assertEquals(8, logger.getLoggedEvents().size());
179
180
181 Assert.assertEquals(2, dayToNightHandler.dates.size());
182 Assert.assertEquals(2, nightToDayHandler.dates.size());
183
184 }
185
186 @Test
187 public void testDayNightSwitchField() {
188 doTestDayNightSwitchField(Decimal64Field.getInstance());
189 }
190
191 private <T extends CalculusFieldElement<T>> void doTestDayNightSwitchField(final Field<T> field)
192 {
193
194
195 final FieldAbsoluteDate<T> initialDate = new FieldAbsoluteDate<>(field, 2004, 01, 01, 23, 30, 00.000, TimeScalesFactory.getUTC());
196 final FieldVector3D<T> position = new FieldVector3D<>(field,
197 new Vector3D(-6142438.668, 3492467.560, -25767.25680));
198 final FieldVector3D<T> velocity = new FieldVector3D<>(field,
199 new Vector3D(505.8479685, 942.7809215, 7435.922231));
200 final FieldOrbit<T> initialOrbit = new FieldKeplerianOrbit<>(new FieldPVCoordinates<>(position, velocity),
201 FramesFactory.getEME2000(), initialDate,
202 field.getZero().add(Constants.EIGEN5C_EARTH_MU));
203
204
205 EventsLogger logger = new EventsLogger();
206 final AttitudesSequence attitudesSequence = new AttitudesSequence();
207 final AttitudeProvider dayObservationLaw = new LofOffset(initialOrbit.getFrame(), LOFType.LVLH_CCSDS,
208 RotationOrder.XYZ, FastMath.toRadians(20), FastMath.toRadians(40), 0);
209 final AttitudeProvider nightRestingLaw = new LofOffset(initialOrbit.getFrame(), LOFType.LVLH_CCSDS);
210 final PVCoordinatesProvider sun = CelestialBodyFactory.getSun();
211 final EclipseDetector ed =
212 new EclipseDetector(sun, 696000000.,
213 new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
214 0.0,
215 FramesFactory.getGTOD(IERSConventions.IERS_2010, true))).
216 withHandler(new ContinueOnEvent<EclipseDetector>() {
217 int count = 0;
218 public Action eventOccurred(final SpacecraftState s,
219 final EclipseDetector d,
220 final boolean increasing) {
221 setInEclipse(s.getDate(), !increasing);
222 if (count++ == 7) {
223 return Action.STOP;
224 } else {
225 switch (count % 3) {
226 case 0 :
227 return Action.CONTINUE;
228 case 1 :
229 return Action.RESET_DERIVATIVES;
230 default :
231 return Action.RESET_STATE;
232 }
233 }
234 }
235 });
236 final EventDetector monitored = logger.monitorDetector(ed);
237 final Handler dayToNightHandler = new Handler(dayObservationLaw, nightRestingLaw);
238 final Handler nightToDayHandler = new Handler(nightRestingLaw, dayObservationLaw);
239 attitudesSequence.addSwitchingCondition(dayObservationLaw, nightRestingLaw,
240 monitored, false, true, 300.0,
241 AngularDerivativesFilter.USE_RRA, dayToNightHandler);
242 attitudesSequence.addSwitchingCondition(nightRestingLaw, dayObservationLaw,
243 monitored, true, false, 300.0,
244 AngularDerivativesFilter.USE_RRA, nightToDayHandler);
245 FieldSpacecraftState<T> initialState = new FieldSpacecraftState<>(initialOrbit);
246 initialState = initialState.addAdditionalState("fortyTwo", field.getZero().add(42.0));
247 if (ed.g(initialState.toSpacecraftState()) >= 0) {
248
249 setInEclipse(initialDate.toAbsoluteDate(), false);
250 attitudesSequence.resetActiveProvider(dayObservationLaw);
251 } else {
252
253 setInEclipse(initialDate.toAbsoluteDate(), true);
254 attitudesSequence.resetActiveProvider(nightRestingLaw);
255 }
256
257
258 final FieldPropagator<T> propagator = new FieldEcksteinHechlerPropagator<T>(initialOrbit, attitudesSequence,
259 Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS,
260 field.getZero().add(Constants.EIGEN5C_EARTH_MU),
261 Constants.EIGEN5C_EARTH_C20,
262 Constants.EIGEN5C_EARTH_C30, Constants.EIGEN5C_EARTH_C40,
263 Constants.EIGEN5C_EARTH_C50, Constants.EIGEN5C_EARTH_C60);
264
265
266 attitudesSequence.registerSwitchEvents(field, propagator);
267
268 propagator.setStepHandler(field.getZero().add(60.0), new FieldOrekitFixedStepHandler<T>() {
269 public void handleStep(FieldSpacecraftState<T> currentState) {
270
271
272 final FieldVector3D<T> earth = currentState.toTransform().transformPosition(Vector3D.ZERO);
273 final T pointingOffset = FieldVector3D.angle(earth, Vector3D.PLUS_K);
274
275
276
277 final double eclipseAngle = ed.g(currentState.toSpacecraftState());
278
279 if (currentState.getDate().durationFrom(lastChange).getReal() > 300) {
280 if (inEclipse) {
281 Assert.assertTrue(eclipseAngle <= 0);
282 Assert.assertEquals(0.0, pointingOffset.getReal(), 1.0e-6);
283 } else {
284 Assert.assertTrue(eclipseAngle >= 0);
285 Assert.assertEquals(0.767215, pointingOffset.getReal(), 1.0e-6);
286 }
287 } else {
288
289 Assert.assertTrue(pointingOffset.getReal() + " " + (0.767215 - pointingOffset.getReal()),
290 pointingOffset.getReal() <= 0.7672155);
291 }
292 }
293 });
294
295
296 propagator.propagate(initialDate.shiftedBy(12600.));
297
298
299
300
301 Assert.assertEquals(8, logger.getLoggedEvents().size());
302
303
304 Assert.assertEquals(2, dayToNightHandler.dates.size());
305 Assert.assertEquals(2, nightToDayHandler.dates.size());
306
307 }
308
309 @Test
310 public void testBackwardPropagation() {
311
312
313 final AbsoluteDate initialDate = new AbsoluteDate(2004, 01, 01, 23, 30, 00.000, TimeScalesFactory.getUTC());
314 final Vector3D position = new Vector3D(-6142438.668, 3492467.560, -25767.25680);
315 final Vector3D velocity = new Vector3D(505.8479685, 942.7809215, 7435.922231);
316 final Orbit initialOrbit = new KeplerianOrbit(new PVCoordinates(position, velocity),
317 FramesFactory.getEME2000(), initialDate,
318 Constants.EIGEN5C_EARTH_MU);
319
320 final AttitudesSequence attitudesSequence = new AttitudesSequence();
321 final AttitudeProvider past = new InertialProvider(Rotation.IDENTITY);
322 final AttitudeProvider current = new InertialProvider(Rotation.IDENTITY);
323 final AttitudeProvider future = new InertialProvider(Rotation.IDENTITY);
324 final Handler handler = new Handler(current, past);
325 attitudesSequence.addSwitchingCondition(past, current,
326 new DateDetector(initialDate.shiftedBy(-500.0)),
327 true, false, 10.0, AngularDerivativesFilter.USE_R, handler);
328 attitudesSequence.addSwitchingCondition(current, future,
329 new DateDetector(initialDate.shiftedBy(+500.0)),
330 true, false, 10.0, AngularDerivativesFilter.USE_R, null);
331 attitudesSequence.resetActiveProvider(current);
332
333 SpacecraftState initialState = new SpacecraftState(initialOrbit);
334 initialState = initialState.addAdditionalState("fortyTwo", 42.0);
335 final Propagator propagator = new EcksteinHechlerPropagator(initialOrbit, attitudesSequence,
336 Constants.EIGEN5C_EARTH_EQUATORIAL_RADIUS,
337 Constants.EIGEN5C_EARTH_MU, Constants.EIGEN5C_EARTH_C20,
338 Constants.EIGEN5C_EARTH_C30, Constants.EIGEN5C_EARTH_C40,
339 Constants.EIGEN5C_EARTH_C50, Constants.EIGEN5C_EARTH_C60);
340 propagator.resetInitialState(initialState);
341 Assert.assertEquals(42.0, propagator.getInitialState().getAdditionalState("fortyTwo")[0], 1.0e-10);
342
343
344 attitudesSequence.registerSwitchEvents(propagator);
345
346 SpacecraftState finalState = propagator.propagate(initialDate.shiftedBy(-10000.0));
347 Assert.assertEquals(42.0, finalState.getAdditionalState("fortyTwo")[0], 1.0e-10);
348 Assert.assertEquals(1, handler.dates.size());
349 Assert.assertEquals(-500.0, handler.dates.get(0).durationFrom(initialDate), 1.0e-3);
350 Assert.assertEquals(-490.0, finalState.getDate().durationFrom(initialDate), 1.0e-3);
351
352 }
353
354 @Test
355 public void testTooShortTransition() {
356 double threshold = 1.5;
357 double transitionTime = 0.5;
358 try {
359 new AttitudesSequence().addSwitchingCondition(new InertialProvider(Rotation.IDENTITY),
360 new InertialProvider(Rotation.IDENTITY),
361 new DateDetector(1000.0, threshold,
362 AbsoluteDate.J2000_EPOCH),
363 true, false, transitionTime,
364 AngularDerivativesFilter.USE_R, null);
365 Assert.fail("an exception should have been thrown");
366 } catch (OrekitException oe) {
367 Assert.assertEquals(OrekitMessages.TOO_SHORT_TRANSITION_TIME_FOR_ATTITUDES_SWITCH,
368 oe.getSpecifier());
369 Assert.assertEquals(transitionTime, ((Double) oe.getParts()[0]).doubleValue(), 1.0e-10);
370 Assert.assertEquals(threshold, ((Double) oe.getParts()[1]).doubleValue(), 1.0e-10);
371 }
372 }
373
374 @Test
375 public void testOutOfSyncCalls() {
376
377 final AbsoluteDate initialDate = new AbsoluteDate(2004, 01, 01, 23, 30, 00.000, TimeScalesFactory.getUTC());
378 final Vector3D position = new Vector3D(-6142438.668, 3492467.560, -25767.25680);
379 final Vector3D velocity = new Vector3D(505.8479685, 942.7809215, 7435.922231);
380 final Orbit initialOrbit = new KeplerianOrbit(new PVCoordinates(position, velocity),
381 FramesFactory.getEME2000(), initialDate,
382 Constants.EIGEN5C_EARTH_MU);
383
384 final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
385 Constants.WGS84_EARTH_FLATTENING,
386 FramesFactory.getITRF(IERSConventions.IERS_2010, true));
387 final TopocentricFrame volgograd = new TopocentricFrame(earth,
388 new GeodeticPoint(FastMath.toRadians(48.7),
389 FastMath.toRadians(44.5),
390 24.0),
391 "Волгоград");
392 final AttitudesSequence attitudesSequence = new AttitudesSequence();
393 final double transitionTime = 250.0;
394 final AttitudeProvider nadirPointing = new NadirPointing(initialOrbit.getFrame(), earth);
395 final AttitudeProvider targetPointing = new TargetPointing(initialOrbit.getFrame(), volgograd.getPoint(), earth);
396 final ElevationDetector eventDetector = new ElevationDetector(volgograd).
397 withConstantElevation(FastMath.toRadians(5.0)).
398 withHandler(new ContinueOnEvent<>());
399 final Handler nadirToTarget = new Handler(nadirPointing, targetPointing);
400 attitudesSequence.addSwitchingCondition(nadirPointing, targetPointing, eventDetector,
401 true, false, transitionTime, AngularDerivativesFilter.USE_RR,
402 nadirToTarget);
403 final Handler targetToNadir = new Handler(targetPointing, nadirPointing);
404 attitudesSequence.addSwitchingCondition(targetPointing, nadirPointing, eventDetector,
405 false, true, transitionTime, AngularDerivativesFilter.USE_RR,
406 targetToNadir);
407 final double[][] tolerance = NumericalPropagator.tolerances(10.0, initialOrbit, initialOrbit.getType());
408 final AdaptiveStepsizeIntegrator integrator = new DormandPrince853Integrator(0.001, 300.0, tolerance[0], tolerance[1]);
409 final NumericalPropagator propagator = new NumericalPropagator(integrator);
410 GravityFieldFactory.addPotentialCoefficientsReader(new ICGEMFormatReader("g007_eigen_05c_coef", false));
411 propagator.addForceModel(new HolmesFeatherstoneAttractionModel(earth.getBodyFrame(),
412 GravityFieldFactory.getNormalizedProvider(8, 8)));
413 propagator.setInitialState(new SpacecraftState(initialOrbit,
414 nadirPointing.getAttitude(initialOrbit,
415 initialOrbit.getDate(),
416 initialOrbit.getFrame())));
417 propagator.setAttitudeProvider(attitudesSequence);
418 attitudesSequence.registerSwitchEvents(propagator);
419 propagator.setStepHandler(10, state -> {
420
421 Attitude nadirAttitude = nadirPointing.getAttitude(state.getOrbit(), state.getDate(), state.getFrame());
422 Attitude targetAttitude = targetPointing.getAttitude(state.getOrbit(), state.getDate(), state.getFrame());
423 Attitude stateAttitude = state.getAttitude();
424
425 if (nadirToTarget.dates.isEmpty() || state.getDate().durationFrom(nadirToTarget.dates.get(0)) < 0) {
426
427 checkEqualAttitudes(nadirAttitude, stateAttitude);
428 } else if (state.getDate().durationFrom(nadirToTarget.dates.get(0)) <= transitionTime) {
429
430 checkBetweenAttitudes(nadirAttitude, targetAttitude, stateAttitude);
431 } else if (targetToNadir.dates.isEmpty() || state.getDate().durationFrom(targetToNadir.dates.get(0)) < 0) {
432
433 checkEqualAttitudes(targetAttitude, stateAttitude);
434 } else if (state.getDate().durationFrom(targetToNadir.dates.get(0)) <= transitionTime) {
435
436 checkBetweenAttitudes(targetAttitude, nadirAttitude, stateAttitude);
437 } else {
438
439 checkEqualAttitudes(nadirAttitude, stateAttitude);
440 }
441
442 });
443 propagator.propagate(initialDate.shiftedBy(6000));
444
445 }
446
447
448
449
450 @Test
451 public void testResetDuringTransitionForward() {
452
453 final AbsoluteDate initialDate = new AbsoluteDate(2004, 01, 01, 23, 30, 00.000, TimeScalesFactory.getUTC());
454 final Vector3D position = new Vector3D(-6142438.668, 3492467.560, -25767.25680);
455 final Vector3D velocity = new Vector3D(505.8479685, 942.7809215, 7435.922231);
456 final Orbit initialOrbit = new KeplerianOrbit(new PVCoordinates(position, velocity),
457 FramesFactory.getEME2000(), initialDate,
458 Constants.EIGEN5C_EARTH_MU);
459
460 final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
461 Constants.WGS84_EARTH_FLATTENING,
462 FramesFactory.getITRF(IERSConventions.IERS_2010, true));
463 final TopocentricFrame volgograd = new TopocentricFrame(earth,
464 new GeodeticPoint(FastMath.toRadians(48.7),
465 FastMath.toRadians(44.5),
466 24.0),
467 "Волгоград");
468 final AttitudesSequence attitudesSequence = new AttitudesSequence();
469 final double transitionTime = 250.0;
470 final AttitudeProvider nadirPointing = new NadirPointing(initialOrbit.getFrame(), earth);
471 final AttitudeProvider targetPointing = new TargetPointing(initialOrbit.getFrame(), volgograd.getPoint(), earth);
472 final ElevationDetector eventDetector = new ElevationDetector(volgograd).
473 withConstantElevation(FastMath.toRadians(5.0)).
474 withHandler(new ContinueOnEvent<>());
475 final List<AbsoluteDate> nadirToTarget = new ArrayList<>();
476 attitudesSequence.addSwitchingCondition(nadirPointing, targetPointing, eventDetector,
477 true, false, transitionTime, AngularDerivativesFilter.USE_RR,
478 (previous, next, state) -> nadirToTarget.add(state.getDate()));
479 final double[][] tolerance = NumericalPropagator.tolerances(10.0, initialOrbit, initialOrbit.getType());
480 final AdaptiveStepsizeIntegrator integrator = new DormandPrince853Integrator(0.001, 300.0, tolerance[0], tolerance[1]);
481 final NumericalPropagator propagator = new NumericalPropagator(integrator);
482 GravityFieldFactory.addPotentialCoefficientsReader(new ICGEMFormatReader("g007_eigen_05c_coef", false));
483 propagator.addForceModel(new HolmesFeatherstoneAttractionModel(earth.getBodyFrame(),
484 GravityFieldFactory.getNormalizedProvider(8, 8)));
485 propagator.setInitialState(new SpacecraftState(initialOrbit,
486 nadirPointing.getAttitude(initialOrbit,
487 initialOrbit.getDate(),
488 initialOrbit.getFrame())));
489 propagator.setAttitudeProvider(attitudesSequence);
490 attitudesSequence.registerSwitchEvents(propagator);
491 propagator.propagate(initialDate.shiftedBy(6000));
492
493
494
495
496 final AbsoluteDate midTransition = nadirToTarget.get(0).shiftedBy(0.5 * transitionTime);
497 SpacecraftState state = propagator.propagate(midTransition.shiftedBy(-60), midTransition);
498 Rotation nadirR = nadirPointing.getAttitude(state.getOrbit(), state.getDate(), state.getFrame()).getRotation();
499 Rotation targetR = targetPointing.getAttitude(state.getOrbit(), state.getDate(), state.getFrame()).getRotation();
500 final double reorientationAngle = Rotation.distance(nadirR, targetR);
501 Assert.assertEquals(0.5 * reorientationAngle,
502 Rotation.distance(state.getAttitude().getRotation(), nadirR),
503 0.03 * reorientationAngle);
504
505
506
507
508
509 final AbsoluteDate afterTransition = midTransition.shiftedBy(transitionTime);
510 state = propagator.propagate(midTransition, afterTransition);
511 targetR = targetPointing.getAttitude(state.getOrbit(), state.getDate(), state.getFrame()).getRotation();
512
513 Assert.assertEquals(targetR.getQ0(),
514 state.getAttitude().getRotation().getQ0(),
515 1.0e-16);
516 Assert.assertEquals(targetR.getQ1(),
517 state.getAttitude().getRotation().getQ1(),
518 1.0e-16);
519 Assert.assertEquals(targetR.getQ2(),
520 state.getAttitude().getRotation().getQ2(),
521 1.0e-16);
522 Assert.assertEquals(targetR.getQ3(),
523 state.getAttitude().getRotation().getQ3(),
524 1.0e-16);
525 }
526
527 @Test
528 public void testResetDuringTransitionBackward() {
529
530 final AbsoluteDate initialDate = new AbsoluteDate(2004, 01, 01, 23, 30, 00.000, TimeScalesFactory.getUTC());
531 final Vector3D position = new Vector3D(-6142438.668, 3492467.560, -25767.25680);
532 final Vector3D velocity = new Vector3D(505.8479685, 942.7809215, 7435.922231);
533 final Orbit initialOrbit = new KeplerianOrbit(new PVCoordinates(position, velocity),
534 FramesFactory.getEME2000(), initialDate,
535 Constants.EIGEN5C_EARTH_MU);
536
537 final OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
538 Constants.WGS84_EARTH_FLATTENING,
539 FramesFactory.getITRF(IERSConventions.IERS_2010, true));
540 final TopocentricFrame volgograd = new TopocentricFrame(earth,
541 new GeodeticPoint(FastMath.toRadians(48.7),
542 FastMath.toRadians(44.5),
543 24.0),
544 "Волгоград");
545 final AttitudesSequence attitudesSequence = new AttitudesSequence();
546 final double transitionTime = 250.0;
547 final AttitudeProvider nadirPointing = new NadirPointing(initialOrbit.getFrame(), earth);
548 final AttitudeProvider targetPointing = new TargetPointing(initialOrbit.getFrame(), volgograd.getPoint(), earth);
549 final ElevationDetector eventDetector = new ElevationDetector(volgograd).
550 withConstantElevation(FastMath.toRadians(5.0)).
551 withHandler(new ContinueOnEvent<>());
552 final List<AbsoluteDate> nadirToTarget = new ArrayList<>();
553 attitudesSequence.addSwitchingCondition(nadirPointing, targetPointing, eventDetector,
554 true, false, transitionTime, AngularDerivativesFilter.USE_RR,
555 (previous, next, state) -> nadirToTarget.add(state.getDate()));
556 final double[][] tolerance = NumericalPropagator.tolerances(10.0, initialOrbit, initialOrbit.getType());
557 final AdaptiveStepsizeIntegrator integrator = new DormandPrince853Integrator(0.001, 300.0, tolerance[0], tolerance[1]);
558 final NumericalPropagator propagator = new NumericalPropagator(integrator);
559 GravityFieldFactory.addPotentialCoefficientsReader(new ICGEMFormatReader("g007_eigen_05c_coef", false));
560 propagator.addForceModel(new HolmesFeatherstoneAttractionModel(earth.getBodyFrame(),
561 GravityFieldFactory.getNormalizedProvider(8, 8)));
562 propagator.setInitialState(new SpacecraftState(initialOrbit,
563 nadirPointing.getAttitude(initialOrbit,
564 initialOrbit.getDate(),
565 initialOrbit.getFrame())));
566 propagator.setAttitudeProvider(attitudesSequence);
567 attitudesSequence.registerSwitchEvents(propagator);
568 propagator.propagate(initialDate.shiftedBy(6000));
569
570
571
572 final AbsoluteDate midTransition = nadirToTarget.get(0).shiftedBy(0.5 * transitionTime);
573 SpacecraftState state = propagator.propagate(midTransition.shiftedBy(+60), midTransition);
574 Rotation nadirR = nadirPointing.getAttitude(state.getOrbit(), state.getDate(), state.getFrame()).getRotation();
575 Rotation targetR = targetPointing.getAttitude(state.getOrbit(), state.getDate(), state.getFrame()).getRotation();
576 final double reorientationAngle = Rotation.distance(nadirR, targetR);
577 Assert.assertEquals(0.5 * reorientationAngle,
578 Rotation.distance(state.getAttitude().getRotation(), targetR),
579 0.03 * reorientationAngle);
580
581
582 }
583
584
585
586
587 @Test
588 public void testAnalyticalPropagatorTransition() {
589
590 final AbsoluteDate initialDate = new AbsoluteDate(2017, 03, 27, 0, 0, 00.000, TimeScalesFactory.getUTC());
591 final Vector3D position = new Vector3D(-39098981.4866597, -15784239.3610601, 78908.2289853595);
592 final Vector3D velocity = new Vector3D(1151.00321021175, -2851.14864755189, -2.02133248357321);
593 final Orbit initialOrbit = new KeplerianOrbit(new PVCoordinates(position, velocity),
594 FramesFactory.getGCRF(), initialDate,
595 Constants.WGS84_EARTH_MU);
596
597
598 final AttitudeProvider before = new InertialProvider(new Rotation(0, 0, 0, 1, false));
599 final AttitudeProvider current = new InertialProvider(Rotation.IDENTITY);
600 final AttitudeProvider after = new InertialProvider(new Rotation(0, 0, 0, -1, false));
601
602
603 final AbsoluteDate forwardSwitchDate = initialDate.shiftedBy(600);
604 final AbsoluteDate backwardSwitchDate = initialDate.shiftedBy(-600);
605 final DateDetector forwardSwitchDetector = new DateDetector(forwardSwitchDate).withHandler(new ContinueOnEvent<DateDetector>());
606 final DateDetector backwardSwitchDetector = new DateDetector(backwardSwitchDate).withHandler(new ContinueOnEvent<DateDetector>());
607
608
609 final AttitudesSequence attitudeSequence = new AttitudesSequence();
610 attitudeSequence.resetActiveProvider(current);
611 attitudeSequence.addSwitchingCondition(before, current, backwardSwitchDetector, true, true, 60, AngularDerivativesFilter.USE_RR, null);
612 attitudeSequence.addSwitchingCondition(current, after, forwardSwitchDetector, true, true, 60, AngularDerivativesFilter.USE_RR, null);
613
614
615 Propagator propagator = new KeplerianPropagator(initialOrbit);
616 propagator.setAttitudeProvider(attitudeSequence);
617 attitudeSequence.registerSwitchEvents(propagator);
618
619 SpacecraftState stateAfter = propagator.propagate(initialDate, initialDate.shiftedBy(1200));
620 SpacecraftState stateBefore = propagator.propagate(initialDate, initialDate.shiftedBy(-1200));
621
622
623 Assert.assertEquals(1200, stateAfter.getDate().durationFrom(initialDate), 1.0E-3);
624 Assert.assertEquals(-1200, stateBefore.getDate().durationFrom(initialDate), 1.0E-3);
625
626
627 Assert.assertEquals(before.getAttitude(stateBefore.getOrbit(), stateBefore.getDate(), stateBefore.getFrame()).getRotation().getQ0(),
628 stateBefore.getAttitude().getRotation().getQ0(),
629 1.0E-16);
630 Assert.assertEquals(before.getAttitude(stateBefore.getOrbit(), stateBefore.getDate(), stateBefore.getFrame()).getRotation().getQ1(),
631 stateBefore.getAttitude().getRotation().getQ1(),
632 1.0E-16);
633 Assert.assertEquals(before.getAttitude(stateBefore.getOrbit(), stateBefore.getDate(), stateBefore.getFrame()).getRotation().getQ2(),
634 stateBefore.getAttitude().getRotation().getQ2(),
635 1.0E-16);
636 Assert.assertEquals(before.getAttitude(stateBefore.getOrbit(), stateBefore.getDate(), stateBefore.getFrame()).getRotation().getQ3(),
637 stateBefore.getAttitude().getRotation().getQ3(),
638 1.0E-16);
639
640 Assert.assertEquals(after.getAttitude(stateAfter.getOrbit(), stateAfter.getDate(), stateAfter.getFrame()).getRotation().getQ0(),
641 stateAfter.getAttitude().getRotation().getQ0(),
642 1.0E-16);
643 Assert.assertEquals(after.getAttitude(stateAfter.getOrbit(), stateAfter.getDate(), stateAfter.getFrame()).getRotation().getQ1(),
644 stateAfter.getAttitude().getRotation().getQ1(),
645 1.0E-16);
646 Assert.assertEquals(after.getAttitude(stateAfter.getOrbit(), stateAfter.getDate(), stateAfter.getFrame()).getRotation().getQ2(),
647 stateAfter.getAttitude().getRotation().getQ2(),
648 1.0E-16);
649 Assert.assertEquals(after.getAttitude(stateAfter.getOrbit(), stateAfter.getDate(), stateAfter.getFrame()).getRotation().getQ3(),
650 stateAfter.getAttitude().getRotation().getQ3(),
651 1.0E-16);
652 }
653
654 private static class Handler implements AttitudesSequence.SwitchHandler {
655
656 private AttitudeProvider expectedPrevious;
657 private AttitudeProvider expectedNext;
658 private List<AbsoluteDate> dates;
659
660 public Handler(final AttitudeProvider expectedPrevious, final AttitudeProvider expectedNext) {
661 this.expectedPrevious = expectedPrevious;
662 this.expectedNext = expectedNext;
663 this.dates = new ArrayList<AbsoluteDate>();
664 }
665
666 @Override
667 public void switchOccurred(AttitudeProvider previous, AttitudeProvider next,
668 SpacecraftState state) {
669 Assert.assertTrue(previous == expectedPrevious);
670 Assert.assertTrue(next == expectedNext);
671 dates.add(state.getDate());
672 }
673
674 }
675
676 private void setInEclipse(AbsoluteDate lastChange, boolean inEclipse) {
677 this.lastChange = lastChange;
678 this.inEclipse = inEclipse;
679 }
680
681 private void checkEqualAttitudes(final Attitude expected, final Attitude tested) {
682 Assert.assertEquals(0.0,
683 Rotation.distance(expected.getRotation(), tested.getRotation()),
684 1.0e-14);
685 Assert.assertEquals(0.0,
686 Vector3D.distance(expected.getSpin(), tested.getSpin()),
687 1.0e-11);
688 Assert.assertEquals(0.0,
689 Vector3D.distance(expected.getRotationAcceleration(), tested.getRotationAcceleration()),
690 1.0e-9);
691 }
692
693 private void checkBetweenAttitudes(final Attitude limit1, final Attitude limit2, final Attitude tested) {
694 final Rotation r1 = limit1.getRotation();
695 final Rotation r2 = limit2.getRotation();
696 final Rotation t = tested.getRotation();
697 final double reorientationAngle = Rotation.distance(r1, r2);
698 Assert.assertTrue(Rotation.distance(t, r1) < reorientationAngle);
699 Assert.assertTrue(Rotation.distance(t, r2) < reorientationAngle);
700 }
701
702 @Before
703 public void setUp() {
704 Utils.setDataRoot("regular-data:potential");
705 }
706
707 }
708