1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.forces;
18
19 import org.hipparchus.CalculusFieldElement;
20 import org.hipparchus.Field;
21 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
22 import org.hipparchus.geometry.euclidean.threed.Rotation;
23 import org.hipparchus.geometry.euclidean.threed.Vector3D;
24 import org.hipparchus.util.Binary64;
25 import org.hipparchus.util.Binary64Field;
26 import org.hipparchus.util.FastMath;
27 import org.junit.jupiter.api.Assertions;
28 import org.junit.jupiter.api.BeforeEach;
29 import org.junit.jupiter.api.Test;
30 import org.orekit.Utils;
31 import org.orekit.attitudes.Attitude;
32 import org.orekit.attitudes.LofOffset;
33 import org.orekit.bodies.CelestialBody;
34 import org.orekit.bodies.CelestialBodyFactory;
35 import org.orekit.errors.OrekitException;
36 import org.orekit.frames.Frame;
37 import org.orekit.frames.FramesFactory;
38 import org.orekit.frames.LOFType;
39 import org.orekit.orbits.CartesianOrbit;
40 import org.orekit.orbits.CircularOrbit;
41 import org.orekit.orbits.Orbit;
42 import org.orekit.orbits.PositionAngleType;
43 import org.orekit.propagation.FieldSpacecraftState;
44 import org.orekit.propagation.Propagator;
45 import org.orekit.propagation.SpacecraftState;
46 import org.orekit.propagation.analytical.EcksteinHechlerPropagator;
47 import org.orekit.time.AbsoluteDate;
48 import org.orekit.time.DateComponents;
49 import org.orekit.time.FieldAbsoluteDate;
50 import org.orekit.time.TimeComponents;
51 import org.orekit.time.TimeScalesFactory;
52 import org.orekit.utils.Constants;
53 import org.orekit.utils.ExtendedPositionProvider;
54 import org.orekit.utils.TimeStampedAngularCoordinates;
55 import org.orekit.utils.TimeStampedPVCoordinates;
56
57 public class PointingPanelTest {
58
59 @Test
60 void testBestPointing() {
61
62 AbsoluteDate initialDate = propagator.getInitialState().getDate();
63 CelestialBody sun = CelestialBodyFactory.getSun();
64 PointingPanel solarArray = new PointingPanel(Vector3D.PLUS_J, sun, 20.0, 0.0, 0.0, 0.0, 0.0);
65 for (double dt = 0; dt < 4000; dt += 60) {
66
67 SpacecraftState state = propagator.propagate(initialDate.shiftedBy(dt));
68
69 Vector3D sunInert = sun.getPosition(initialDate, state.getFrame());
70 Vector3D momentum = state.getPVCoordinates().getMomentum();
71 double sunElevation = FastMath.PI / 2 - Vector3D.angle(sunInert, momentum);
72 Assertions.assertEquals(15.1, FastMath.toDegrees(sunElevation), 0.1);
73
74 Vector3D n = solarArray.getNormal(state);
75 Assertions.assertEquals(0.0, n.getY(), 1.0e-10);
76
77
78 Vector3D sunSat = state.getAttitude().getRotation().applyTo(sunInert);
79 double misAlignment = Vector3D.angle(sunSat, n);
80 Assertions.assertEquals(sunElevation, misAlignment, 1.0e-3);
81
82 }
83 }
84
85 @Test
86 void testNormalOptimalRotationDouble() {
87 AbsoluteDate initialDate = propagator.getInitialState().getDate();
88 CelestialBody sun = CelestialBodyFactory.getSun();
89 final Panel absorbingSolarArray = new PointingPanel(Vector3D.PLUS_J, sun, 20.0, 0.0, 0.0, 1.0, 0.0);
90 for (double dt = 0; dt < 4000; dt += 60) {
91 AbsoluteDate date = initialDate.shiftedBy(dt);
92 SpacecraftState state = propagator.propagate(date);
93 Vector3D normal = absorbingSolarArray.getNormal(state);
94 Assertions.assertEquals(0, Vector3D.dotProduct(normal, Vector3D.PLUS_J), 1.0e-16);
95 }
96 }
97
98 @Test
99 void testNormalOptimalRotationField() {
100 AbsoluteDate initialDate = propagator.getInitialState().getDate();
101 CelestialBody sun = CelestialBodyFactory.getSun();
102 final Panel absorbingSolarArray = new PointingPanel(Vector3D.PLUS_J, sun, 20.0, 0.0, 0.0, 1.0, 0.0);
103 Field<Binary64> field = Binary64Field.getInstance();
104 for (double dt = 0; dt < 4000; dt += 60) {
105 AbsoluteDate date = initialDate.shiftedBy(dt);
106 FieldSpacecraftState<Binary64> fState = new FieldSpacecraftState<>(field, propagator.propagate(date));
107 FieldVector3D<Binary64> normal = absorbingSolarArray.getNormal(fState);
108 Assertions.assertEquals(0, FieldVector3D.dotProduct(normal, Vector3D.PLUS_J).getReal(), 1.0e-16);
109 }
110 }
111
112 void testNormalSunAlignedDouble() {
113 ExtendedPositionProvider ep = new ExtendedPositionProvider() {
114
115 @Override
116 public Vector3D getPosition(AbsoluteDate date, Frame frame) {
117 return new Vector3D(0, 1e6, 0);
118 }
119
120 @Override
121 public <T extends CalculusFieldElement<T>> FieldVector3D<T> getPosition(FieldAbsoluteDate<T> date,
122 Frame frame) {
123
124 return null;
125 }
126 };
127 final Panel panel = new PointingPanel(Vector3D.PLUS_J, ep, 20.0, 0.0, 0.0, 1.0, 0.0);
128 final Orbit orbit = new CartesianOrbit(new TimeStampedPVCoordinates(AbsoluteDate.J2000_EPOCH,
129 Vector3D.ZERO,
130 Vector3D.ZERO,
131 Vector3D.ZERO),
132 FramesFactory.getEME2000(), Constants.EIGEN5C_EARTH_MU);
133 final Attitude attitude = new Attitude(FramesFactory.getEME2000(),
134 new TimeStampedAngularCoordinates(AbsoluteDate.J2000_EPOCH,
135 Rotation.IDENTITY,
136 Vector3D.ZERO,
137 Vector3D.ZERO));
138 final SpacecraftState state = new SpacecraftState(orbit, attitude, 1000.0);
139 Vector3D normal = panel.getNormal(state);
140 Assertions.assertEquals(0, Vector3D.dotProduct(normal, Vector3D.PLUS_J), 1.0e-16);
141 }
142
143 @Test
144 void testNormalSunAlignedField() {
145 ExtendedPositionProvider ep = new ExtendedPositionProvider() {
146
147 @Override
148 public TimeStampedPVCoordinates getPVCoordinates(AbsoluteDate date, Frame frame) {
149
150 return null;
151 }
152
153 @Override
154 public <T extends CalculusFieldElement<T>> FieldVector3D<T>
155 getPosition(FieldAbsoluteDate<T> date, Frame frame) {
156 return new FieldVector3D<>(date.getField(), new Vector3D(0, 1e6, 0));
157 }
158 };
159 final Panel panel = new PointingPanel(Vector3D.PLUS_J, ep, 20.0, 0.0, 0.0, 1.0, 0.0);
160 final Orbit orbit = new CartesianOrbit(new TimeStampedPVCoordinates(AbsoluteDate.J2000_EPOCH,
161 Vector3D.ZERO,
162 Vector3D.ZERO,
163 Vector3D.ZERO),
164 FramesFactory.getEME2000(), Constants.EIGEN5C_EARTH_MU);
165 final Attitude attitude = new Attitude(FramesFactory.getEME2000(),
166 new TimeStampedAngularCoordinates(AbsoluteDate.J2000_EPOCH,
167 Rotation.IDENTITY,
168 Vector3D.ZERO,
169 Vector3D.ZERO));
170 final SpacecraftState state = new SpacecraftState(orbit, attitude, 1000.0);
171 Field<Binary64> field = Binary64Field.getInstance();
172 FieldVector3D<Binary64> normal = panel.getNormal(new FieldSpacecraftState<>(field, state));
173 Assertions.assertEquals(0, FieldVector3D.dotProduct(normal, Vector3D.PLUS_J).getReal(), 1.0e-16);
174 }
175
176 @BeforeEach
177 public void setUp() {
178 try {
179 Utils.setDataRoot("regular-data");
180 mu = 3.9860047e14;
181 double ae = 6.378137e6;
182 double c20 = -1.08263e-3;
183 double c30 = 2.54e-6;
184 double c40 = 1.62e-6;
185 double c50 = 2.3e-7;
186 double c60 = -5.5e-7;
187
188 AbsoluteDate date = new AbsoluteDate(new DateComponents(1970, 7, 1),
189 new TimeComponents(13, 59, 27.816),
190 TimeScalesFactory.getUTC());
191
192
193
194 Orbit circ =
195 new CircularOrbit(7178000.0, 0.5e-4, -0.5e-4, FastMath.toRadians(50.), FastMath.toRadians(280),
196 FastMath.toRadians(10.0), PositionAngleType.MEAN,
197 FramesFactory.getEME2000(), date, mu);
198 propagator =
199 new EcksteinHechlerPropagator(circ,
200 new LofOffset(circ.getFrame(), LOFType.LVLH_CCSDS),
201 ae, mu, c20, c30, c40, c50, c60);
202 } catch (OrekitException oe) {
203 Assertions.fail(oe.getLocalizedMessage());
204 }
205 }
206
207 private double mu;
208 private Propagator propagator;
209
210 }