1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.general;
18
19 import java.io.BufferedWriter;
20 import java.io.IOException;
21 import java.nio.charset.StandardCharsets;
22 import java.nio.file.Files;
23 import java.nio.file.Paths;
24 import java.util.ArrayList;
25 import java.util.List;
26
27 import org.hipparchus.geometry.euclidean.threed.Rotation;
28 import org.junit.jupiter.api.Assertions;
29 import org.junit.jupiter.api.BeforeEach;
30 import org.junit.jupiter.api.Test;
31 import org.orekit.Utils;
32 import org.orekit.attitudes.Attitude;
33 import org.orekit.attitudes.AttitudeProvider;
34 import org.orekit.attitudes.FrameAlignedProvider;
35 import org.orekit.bodies.CelestialBody;
36 import org.orekit.bodies.CelestialBodyFactory;
37 import org.orekit.data.DataSource;
38 import org.orekit.errors.OrekitIllegalArgumentException;
39 import org.orekit.errors.OrekitMessages;
40 import org.orekit.files.ccsds.definitions.CelestialBodyFrame;
41 import org.orekit.files.ccsds.definitions.FrameFacade;
42 import org.orekit.files.ccsds.definitions.SpacecraftBodyFrame;
43 import org.orekit.files.ccsds.definitions.TimeSystem;
44 import org.orekit.files.ccsds.ndm.ParserBuilder;
45 import org.orekit.files.ccsds.ndm.WriterBuilder;
46 import org.orekit.files.ccsds.ndm.adm.AdmHeader;
47 import org.orekit.files.ccsds.ndm.adm.AttitudeType;
48 import org.orekit.files.ccsds.ndm.adm.aem.AemMetadata;
49 import org.orekit.files.ccsds.ndm.adm.aem.AemSegment;
50 import org.orekit.files.ccsds.ndm.adm.aem.AttitudeWriter;
51 import org.orekit.files.ccsds.utils.FileFormat;
52 import org.orekit.files.general.AttitudeEphemerisFile.AttitudeEphemerisSegment;
53 import org.orekit.files.general.OrekitAttitudeEphemerisFile.OrekitSatelliteAttitudeEphemeris;
54 import org.orekit.frames.Frame;
55 import org.orekit.frames.FramesFactory;
56 import org.orekit.orbits.KeplerianOrbit;
57 import org.orekit.orbits.PositionAngleType;
58 import org.orekit.propagation.SpacecraftState;
59 import org.orekit.propagation.analytical.KeplerianPropagator;
60 import org.orekit.time.AbsoluteDate;
61 import org.orekit.utils.AngularDerivativesFilter;
62 import org.orekit.utils.Constants;
63 import org.orekit.utils.TimeStampedAngularCoordinates;
64
65 public class OrekitAttitudeEphemerisFileTest {
66
67 @BeforeEach
68 public void setUp() throws Exception {
69 Utils.setDataRoot("regular-data");
70 }
71
72 @Test
73 public void testGetSatellites() {
74 final String id1 = "ID1";
75 final String id2 = "ID2";
76 OrekitAttitudeEphemerisFile file = new OrekitAttitudeEphemerisFile();
77 OrekitSatelliteAttitudeEphemeris ephem1 = file.addSatellite(id1);
78 Assertions.assertNotNull(ephem1);
79 OrekitSatelliteAttitudeEphemeris ephem2 = file.addSatellite(id2);
80 Assertions.assertNotNull(ephem2);
81 }
82
83 @Test
84 public void testWritingToAEM() throws IOException {
85 final double quaternionTolerance = 1e-5;
86 final String satId = "SATELLITE1";
87 final double sma = 10000000;
88 final double inc = Math.toRadians(45.0);
89 final double ecc = 0.1;
90 final double raan = 0.0;
91 final double pa = 0.0;
92 final double ta = 0.0;
93 final AbsoluteDate date = new AbsoluteDate();
94 final Frame frame = FramesFactory.getEME2000();
95 final CelestialBody body = CelestialBodyFactory.getEarth();
96 final double mu = body.getGM();
97 KeplerianOrbit initialOrbit = new KeplerianOrbit(sma, ecc, inc, pa, raan, ta, PositionAngleType.TRUE,
98 frame, date, mu);
99
100
101
102 final Rotation refRot = new Rotation(0.72501, -0.64585, 0.018542, -0.23854, false);
103 AttitudeProvider inertialPointing = new FrameAlignedProvider(refRot);
104 KeplerianPropagator propagator = new KeplerianPropagator(initialOrbit, inertialPointing);
105
106 final double propagationDurationSeconds = 1200.0;
107 final double stepSizeSeconds = 60.0;
108 List<SpacecraftState> states = new ArrayList<SpacecraftState>();
109
110 for (double dt = 0.0; dt < propagationDurationSeconds; dt += stepSizeSeconds) {
111 states.add(propagator.propagate(date.shiftedBy(dt)));
112 }
113
114 OrekitAttitudeEphemerisFile ephemerisFile = new OrekitAttitudeEphemerisFile();
115 OrekitSatelliteAttitudeEphemeris satellite = ephemerisFile.addSatellite(satId);
116 satellite.addNewSegment(states,
117 OrekitSatelliteAttitudeEphemeris.DEFAULT_INTERPOLATION_METHOD,
118 OrekitSatelliteAttitudeEphemeris.DEFAULT_INTERPOLATION_SIZE,
119 AngularDerivativesFilter.USE_RR);
120
121
122 Assertions.assertEquals(satId, satellite.getId());
123 Assertions.assertEquals(0.0, states.get(0).getDate().durationFrom(satellite.getStart()), 1.0e-15);
124 Assertions.assertEquals(0.0, states.get(states.size() - 1).getDate().durationFrom(satellite.getStop()), 1.0e-15);
125
126
127 AttitudeEphemerisSegment<TimeStampedAngularCoordinates> segment = satellite.getSegments().get(0);
128 Assertions.assertEquals(OrekitSatelliteAttitudeEphemeris.DEFAULT_INTERPOLATION_METHOD, segment.getInterpolationMethod());
129 Assertions.assertEquals(OrekitSatelliteAttitudeEphemeris.DEFAULT_INTERPOLATION_SIZE, segment.getInterpolationSamples());
130 Assertions.assertEquals(0.0, states.get(0).getDate().durationFrom(segment.getStart()), 1.0e-15);
131 Assertions.assertEquals(0.0, states.get(states.size() - 1).getDate().durationFrom(segment.getStop()), 1.0e-15);
132 Assertions.assertEquals(AngularDerivativesFilter.USE_RR, segment.getAvailableDerivatives());
133
134
135 final Attitude attitude = segment.getAttitudeProvider().getAttitude(initialOrbit, date, frame);
136 Assertions.assertEquals(frame, attitude.getReferenceFrame());
137 Assertions.assertEquals(refRot.getQ0(), attitude.getRotation().getQ0(), quaternionTolerance);
138 Assertions.assertEquals(refRot.getQ1(), attitude.getRotation().getQ1(), quaternionTolerance);
139 Assertions.assertEquals(refRot.getQ2(), attitude.getRotation().getQ2(), quaternionTolerance);
140 Assertions.assertEquals(refRot.getQ3(), attitude.getRotation().getQ3(), quaternionTolerance);
141
142 String tempAem = Files.createTempFile("OrekitAttitudeEphemerisFileTest", ".aem").toString();
143 try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(tempAem), StandardCharsets.UTF_8)) {
144 final AdmHeader header = new AdmHeader();
145 header.setFormatVersion(1.0);
146 new AttitudeWriter(new WriterBuilder().buildAemWriter(),
147 header, dummyMetadata(), FileFormat.KVN, "", Constants.JULIAN_DAY, 60).
148 write(writer, ephemerisFile);
149 }
150
151 AttitudeEphemerisFile<TimeStampedAngularCoordinates, AemSegment> ephemerisFrom =
152 new ParserBuilder().buildAemParser().parseMessage(new DataSource(tempAem));
153 Files.delete(Paths.get(tempAem));
154
155 segment = ephemerisFrom.getSatellites().get(satId).getSegments().get(0);
156 Assertions.assertEquals(states.get(0).getDate(), segment.getStart());
157 Assertions.assertEquals(states.get(states.size() - 1).getDate(), segment.getStop());
158 Assertions.assertEquals(states.size(), segment.getAngularCoordinates().size());
159 for (int i = 0; i < states.size(); i++) {
160 TimeStampedAngularCoordinates expected = states.get(i).getAttitude().getOrientation();
161 TimeStampedAngularCoordinates actual = segment.getAngularCoordinates().get(i);
162 Assertions.assertEquals(expected.getDate(), actual.getDate());
163 Assertions.assertEquals(0.0, Rotation.distance(refRot, actual.getRotation()), quaternionTolerance);
164 }
165
166 }
167
168 @Test
169 public void testNoStates() {
170
171
172 final String satId = "SATELLITE1";
173
174
175 List<SpacecraftState> states = new ArrayList<SpacecraftState>();
176
177
178 OrekitAttitudeEphemerisFile ephemerisFile = new OrekitAttitudeEphemerisFile();
179 OrekitSatelliteAttitudeEphemeris satellite = ephemerisFile.addSatellite(satId);
180
181
182 try {
183 satellite.addNewSegment(states,
184 OrekitSatelliteAttitudeEphemeris.DEFAULT_INTERPOLATION_METHOD,
185 OrekitSatelliteAttitudeEphemeris.DEFAULT_INTERPOLATION_SIZE,
186 AngularDerivativesFilter.USE_RR);
187 } catch (OrekitIllegalArgumentException oiae) {
188 Assertions.assertEquals(OrekitMessages.NULL_ARGUMENT, oiae.getSpecifier());
189 }
190
191
192 }
193
194 @Test
195 public void testNoEnoughDataForInterpolation() {
196
197
198 final String satId = "SATELLITE1";
199 final double sma = 10000000;
200 final double inc = Math.toRadians(45.0);
201 final double ecc = 0.1;
202 final double raan = 0.0;
203 final double pa = 0.0;
204 final double ta = 0.0;
205 final AbsoluteDate date = new AbsoluteDate();
206 final Frame frame = FramesFactory.getEME2000();
207 final CelestialBody body = CelestialBodyFactory.getEarth();
208 final double mu = body.getGM();
209 KeplerianOrbit initialOrbit = new KeplerianOrbit(sma, ecc, inc, pa, raan, ta, PositionAngleType.TRUE,
210 frame, date, mu);
211 SpacecraftState state = new SpacecraftState(initialOrbit);
212
213
214 List<SpacecraftState> states = new ArrayList<SpacecraftState>();
215 states.add(state);
216
217
218 OrekitAttitudeEphemerisFile ephemerisFile = new OrekitAttitudeEphemerisFile();
219 OrekitSatelliteAttitudeEphemeris satellite = ephemerisFile.addSatellite(satId);
220
221
222 try {
223 satellite.addNewSegment(states, "LINEAR", 1, AngularDerivativesFilter.USE_R);
224 } catch (OrekitIllegalArgumentException oiae) {
225 Assertions.assertEquals(OrekitMessages.NOT_ENOUGH_DATA, oiae.getSpecifier());
226 }
227 }
228
229 private AemMetadata dummyMetadata() {
230 AemMetadata metadata = new AemMetadata(4);
231 metadata.setTimeSystem(TimeSystem.TT);
232 metadata.setObjectID("SATELLITE1");
233 metadata.setObjectName("transgalactic");
234 metadata.getEndpoints().setFrameA(new FrameFacade(FramesFactory.getGCRF(), CelestialBodyFrame.GCRF,
235 null, null, "GCRF"));
236 metadata.getEndpoints().setFrameB(new FrameFacade(null, null, null,
237 new SpacecraftBodyFrame(SpacecraftBodyFrame.BaseEquipment.GYRO_FRAME, "1"),
238 "GYRO FRAME 1"));
239 metadata.getEndpoints().setA2b(true);
240 metadata.setStartTime(AbsoluteDate.J2000_EPOCH.shiftedBy(80 * Constants.JULIAN_CENTURY));
241 metadata.setStopTime(metadata.getStartTime().shiftedBy(Constants.JULIAN_YEAR));
242 metadata.setAttitudeType(AttitudeType.QUATERNION_DERIVATIVE);
243 metadata.setIsFirst(true);
244 return metadata;
245 }
246
247 }
248