1 /* Copyright 2022-2026 Luc Maisonobe
2 * Licensed to CS GROUP (CS) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * CS licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.orekit.files.ccsds.ndm.adm.acm;
19
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.List;
23
24 import org.hipparchus.geometry.euclidean.threed.RotationOrder;
25 import org.orekit.errors.OrekitException;
26 import org.orekit.errors.OrekitMessages;
27 import org.orekit.files.ccsds.definitions.AdMethodType;
28 import org.orekit.files.ccsds.definitions.CcsdsFrameMapper;
29 import org.orekit.files.ccsds.ndm.adm.AttitudeEndpoints;
30 import org.orekit.files.ccsds.section.CommentsContainer;
31 import org.orekit.frames.Frame;
32
33 /** Attitude determination data.
34 * <p>
35 * Beware that the Orekit getters and setters all rely on SI units. The parsers
36 * and writers take care of converting these SI units into CCSDS mandatory units.
37 * The {@link org.orekit.utils.units.Unit Unit} class provides useful
38 * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and
39 * {@link org.orekit.utils.units.Unit#toSI(double) toSI} methods in case the callers
40 * already use CCSDS units instead of the API SI units. The general-purpose
41 * {@link org.orekit.utils.units.Unit Unit} class (without an 's') and the
42 * CCSDS-specific {@link org.orekit.files.ccsds.definitions.Units Units} class
43 * (with an 's') also provide some predefined units. These predefined units and the
44 * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and
45 * {@link org.orekit.utils.units.Unit#toSI(double) toSI} conversion methods are indeed
46 * what the parsers and writers use for the conversions.
47 * </p>
48 * @author Luc Maisonobe
49 * @since 12.0
50 */
51 public class AttitudeDetermination extends CommentsContainer {
52
53 /** Endpoints (i.e. frames A, B and their relationship). */
54 private final AttitudeEndpoints endpoints;
55
56 /** Identification number. */
57 private String id;
58
59 /** Identification of previous orbit determination. */
60 private String prevId;
61
62 /** Attitude determination method. */
63 private AdMethodType method;
64
65 /** Source of attitude estimate. */
66 private String source;
67
68 /** Rotation order for Euler angles. */
69 private RotationOrder eulerRotSeq;
70
71 /** Number of states for {@link AdMethodType#EKF}, {@link AdMethodType#BATCH} or {@link AdMethodType#FILTER_SMOOTHER}. */
72 private int nbStates;
73
74 /** Attitude states. */
75 private AttitudeElementsType attitudeStates;
76
77 /** Type of attitude error state. */
78 private AttitudeCovarianceType covarianceType;
79
80 /** Attitude rate states. */
81 private RateElementsType rateStates;
82
83 /** Rate random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}. */
84 private double sigmaU;
85
86 /** Angle random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}. */
87 private double sigmaV;
88
89 /** Process noise standard deviation if {@link #rateStates} is {@link RateElementsType#ANGVEL}. */
90 private double rateProcessNoiseStdDev;
91
92 /** Sensors used. */
93 private final List<AttitudeDeterminationSensor> sensorsUsed;
94
95 /**
96 * Simple constructor.
97 *
98 * @param frameMapper for creating a {@link Frame}.
99 * @since 13.1.5
100 */
101 public AttitudeDetermination(final CcsdsFrameMapper frameMapper) {
102 endpoints = new AttitudeEndpoints(frameMapper);
103 sensorsUsed = new ArrayList<>();
104 nbStates = -1;
105 }
106
107 /** {@inheritDoc} */
108 @Override
109 public void validate(final double version) {
110 super.validate(version);
111 checkNotNull(attitudeStates, AttitudeDeterminationKey.ATTITUDE_STATES.name());
112 endpoints.checkExternalFrame(AttitudeDeterminationKey.REF_FRAME_A,
113 AttitudeDeterminationKey.REF_FRAME_B);
114
115 // check sensors in increasing number
116 for (int number = 1; number <= sensorsUsed.size(); ++number) {
117 final AttitudeDeterminationSensor sensor = findSensor(number);
118 if (sensor != null) {
119 sensor.validate(version);
120 } else {
121 // no sensor has the expected index
122 throw new OrekitException(OrekitMessages.CCSDS_MISSING_SENSOR_INDEX, number);
123 }
124
125 }
126
127 }
128
129 /** Find sensor by number.
130 * @param number number of the sensor
131 * @return sensor with specified number, or null if not found
132 */
133 private AttitudeDeterminationSensor findSensor(final int number) {
134 for (final AttitudeDeterminationSensor sensor : sensorsUsed) {
135 if (sensor.getSensorNumber() == number) {
136 return sensor;
137 }
138 }
139 return null;
140 }
141
142 /** Get the endpoints (i.e. frames A, B and their relationship).
143 * @return endpoints
144 */
145 public AttitudeEndpoints getEndpoints() {
146 return endpoints;
147 }
148
149 /** Get identification number.
150 * @return identification number
151 */
152 public String getId() {
153 return id;
154 }
155
156 /** Set identification number.
157 * @param id identification number
158 */
159 public void setId(final String id) {
160 this.id = id;
161 }
162
163 /** Get identification of previous orbit determination.
164 * @return identification of previous orbit determination
165 */
166 public String getPrevId() {
167 return prevId;
168 }
169
170 /** Set identification of previous orbit determination.
171 * @param prevId identification of previous orbit determination
172 */
173 public void setPrevId(final String prevId) {
174 this.prevId = prevId;
175 }
176
177 /** Get attitude determination method.
178 * @return attitude determination method
179 */
180 public AdMethodType getMethod() {
181 return method;
182 }
183
184 /** Set attitude determination method.
185 * @param method attitude determination method
186 */
187 public void setMethod(final AdMethodType method) {
188 this.method = method;
189 }
190
191 /** Get source of attitude estimate.
192 * @return source of attitude estimate
193 */
194 public String getSource() {
195 return source;
196 }
197
198 /** Set source of attitude estimate.
199 * @param source source of attitude estimate
200 */
201 public void setSource(final String source) {
202 this.source = source;
203 }
204
205 /** Get the rotation order for Euler angles.
206 * @return rotation order for Euler angles
207 */
208 public RotationOrder getEulerRotSeq() {
209 return eulerRotSeq;
210 }
211
212 /** Set the rotation order for Euler angles.
213 * @param eulerRotSeq rotation order for Euler angles
214 */
215 public void setEulerRotSeq(final RotationOrder eulerRotSeq) {
216 this.eulerRotSeq = eulerRotSeq;
217 }
218
219 /** Get number of states for {@link AdMethodType#EKF}, {@link AdMethodType#BATCH} or {@link AdMethodType#FILTER_SMOOTHER}.
220 * @return number of states
221 */
222 public int getNbStates() {
223 return nbStates;
224 }
225
226 /** Set number of states for {@link AdMethodType#EKF}, {@link AdMethodType#BATCH} or {@link AdMethodType#FILTER_SMOOTHER}.
227 * @param nbStates number of states
228 */
229 public void setNbStates(final int nbStates) {
230 this.nbStates = nbStates;
231 }
232
233 /** Get attitude states.
234 * @return attitude states
235 */
236 public AttitudeElementsType getAttitudeStates() {
237 return attitudeStates;
238 }
239
240 /** Set attitude states.
241 * @param attitudeStates attitude states
242 */
243 public void setAttitudeStates(final AttitudeElementsType attitudeStates) {
244 this.attitudeStates = attitudeStates;
245 }
246
247 /** Get type of attitude error state.
248 * @return type of attitude error state
249 */
250 public AttitudeCovarianceType getCovarianceType() {
251 return covarianceType;
252 }
253
254 /** Set type of attitude error state.
255 * @param covarianceType type of attitude error state
256 */
257 public void setCovarianceType(final AttitudeCovarianceType covarianceType) {
258 this.covarianceType = covarianceType;
259 }
260
261 /** Get attitude rate states.
262 * @return attitude rate states
263 */
264 public RateElementsType getRateStates() {
265 return rateStates;
266 }
267
268 /** Set attitude rate states.
269 * @param rateStates attitude rate states
270 */
271 public void setRateStates(final RateElementsType rateStates) {
272 this.rateStates = rateStates;
273 }
274
275 /** Get rate random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}.
276 * @return rate random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}
277 */
278 public double getSigmaU() {
279 return sigmaU;
280 }
281
282 /** Set rate random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}.
283 * @param sigmaU rate random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}
284 */
285 public void setSigmaU(final double sigmaU) {
286 this.sigmaU = sigmaU;
287 }
288
289 /** Get angle random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}.
290 * @return angle random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}
291 */
292 public double getSigmaV() {
293 return sigmaV;
294 }
295
296 /** Set angle random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}.
297 * @param sigmaV angle random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}
298 */
299 public void setSigmaV(final double sigmaV) {
300 this.sigmaV = sigmaV;
301 }
302
303 /** Get process noise standard deviation if {@link #rateStates} is {@link RateElementsType#ANGVEL}.
304 * @return process noise standard deviation if {@link #rateStates} is {@link RateElementsType#ANGVEL}
305 */
306 public double getRateProcessNoiseStdDev() {
307 return rateProcessNoiseStdDev;
308 }
309
310 /** Set process noise standard deviation if {@link #rateStates} is {@link RateElementsType#ANGVEL}.
311 * @param rateProcessNoiseStdDev process noise standard deviation if {@link #rateStates} is {@link RateElementsType#ANGVEL}
312 */
313 public void setRateProcessNoiseStdDev(final double rateProcessNoiseStdDev) {
314 this.rateProcessNoiseStdDev = rateProcessNoiseStdDev;
315 }
316
317 /** Get sensors used.
318 * @return sensors used
319 */
320 public List<AttitudeDeterminationSensor> getSensorsUsed() {
321 return Collections.unmodifiableList(sensorsUsed);
322 }
323
324 /** Add a sensor used.
325 * @param sensor sensor to add
326 */
327 public void addSensor(final AttitudeDeterminationSensor sensor) {
328 for (final AttitudeDeterminationSensor existing : sensorsUsed) {
329 if (sensor.getSensorNumber() == existing.getSensorNumber()) {
330 throw new OrekitException(OrekitMessages.CCSDS_SENSOR_INDEX_ALREADY_USED, sensor.getSensorNumber());
331 }
332 }
333 sensorsUsed.add(sensor);
334 }
335
336 }