1 /* Copyright 2002-2026 CS GROUP
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 package org.orekit.files.ccsds.ndm.adm.apm;
18
19 import java.util.Optional;
20
21 import org.orekit.annotation.Nullable;
22 import org.orekit.errors.OrekitException;
23 import org.orekit.errors.OrekitMessages;
24 import org.orekit.files.ccsds.definitions.CcsdsFrameMapper;
25 import org.orekit.files.ccsds.ndm.adm.AttitudeEndpoints;
26 import org.orekit.files.ccsds.section.CommentsContainer;
27 import org.orekit.frames.Frame;
28
29 /**
30 * Container for Attitude Parameter Message data lines.
31 * <p>
32 * Beware that the Orekit getters and setters all rely on SI units. The parsers
33 * and writers take care of converting these SI units into CCSDS mandatory units.
34 * The {@link org.orekit.utils.units.Unit Unit} class provides useful
35 * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and
36 * {@link org.orekit.utils.units.Unit#toSI(double) toSI} methods in case the callers
37 * already use CCSDS units instead of the API SI units. The general-purpose
38 * {@link org.orekit.utils.units.Unit Unit} class (without an 's') and the
39 * CCSDS-specific {@link org.orekit.files.ccsds.definitions.Units Units} class
40 * (with an 's') also provide some predefined units. These predefined units and the
41 * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and
42 * {@link org.orekit.utils.units.Unit#toSI(double) toSI} conversion methods are indeed
43 * what the parsers and writers use for the conversions.
44 * </p>
45 * @author Bryan Cazabonne
46 * @since 10.2
47 */
48 public class SpinStabilized extends CommentsContainer {
49
50 /** Endpoints (i.e. frames A, B and their relationship). */
51 private final AttitudeEndpoints endpoints;
52
53 /** Right ascension of spin axis vector (rad). */
54 private double spinAlpha;
55
56 /** Declination of the spin axis vector (rad). */
57 private double spinDelta;
58
59 /** Phase of the satellite about the spin axis (rad). */
60 private double spinAngle;
61
62 /** Angular velocity of satellite around spin axis (rad/s). */
63 private double spinAngleVel;
64
65 /** Nutation angle of spin axis (rad). */
66 @Nullable
67 private Double nutation;
68
69 /** Body nutation period of the spin axis (s). */
70 @Nullable
71 private Double nutationPer;
72
73 /** Inertial nutation phase (rad). */
74 @Nullable
75 private Double nutationPhase;
76
77 /** Right ascension of angular momentum vector (rad).
78 * @since 12.0
79 */
80 @Nullable
81 private Double momentumAlpha;
82
83 /** Declination of the angular momentum vector (rad).
84 * @since 12.0
85 */
86 @Nullable
87 private Double momentumDelta;
88
89 /** Angular velocity of spin vector around the angular momentum vector (rad/s).
90 * @since 12.0
91 */
92 @Nullable
93 private Double nutationVel;
94
95 /**
96 * Simple constructor.
97 *
98 * @param frameMapper for creating a {@link Frame}.
99 * @since 13.1.5
100 */
101 public SpinStabilized(final CcsdsFrameMapper frameMapper) {
102 endpoints = new AttitudeEndpoints(frameMapper);
103 spinAlpha = Double.NaN;
104 spinDelta = Double.NaN;
105 spinAngle = Double.NaN;
106 spinAngleVel = Double.NaN;
107 }
108
109 /** {@inheritDoc} */
110 @Override
111 public void validate(final double version) {
112 super.validate(version);
113 endpoints.checkMandatoryEntriesExceptExternalFrame(version,
114 SpinStabilizedKey.SPIN_FRAME_A,
115 SpinStabilizedKey.SPIN_FRAME_B,
116 SpinStabilizedKey.SPIN_DIR);
117 endpoints.checkExternalFrame(SpinStabilizedKey.SPIN_FRAME_A, SpinStabilizedKey.SPIN_FRAME_B);
118 checkNotNaN(spinAlpha, SpinStabilizedKey.SPIN_ALPHA.name());
119 checkNotNaN(spinDelta, SpinStabilizedKey.SPIN_DELTA.name());
120 checkNotNaN(spinAngle, SpinStabilizedKey.SPIN_ANGLE.name());
121 checkNotNaN(spinAngleVel, SpinStabilizedKey.SPIN_ANGLE_VEL.name());
122 if (getNutation().isEmpty() || getNutationPeriod().isEmpty() || getNutationPhase().isEmpty()) {
123 // if at least one is empty, all must be empty
124 if (!(getNutation().isEmpty() && getNutationPeriod().isEmpty() && getNutationPhase().isEmpty())) {
125 throw new OrekitException(OrekitMessages.UNINITIALIZED_VALUE_FOR_KEY, "NUTATION*");
126 }
127 }
128 if (getMomentumAlpha().isEmpty() || getMomentumDelta().isEmpty() || getNutationVel().isEmpty()) {
129 // if at least one is empty, all must be empty
130 if (!(getMomentumAlpha().isEmpty() && getMomentumDelta().isEmpty() && getNutationVel().isEmpty())) {
131 throw new OrekitException(OrekitMessages.UNINITIALIZED_VALUE_FOR_KEY, "MOMENTUM*/NUTATION_VEL");
132 }
133 }
134 }
135
136 /** Get the endpoints (i.e. frames A, B and their relationship).
137 * @return endpoints
138 */
139 public AttitudeEndpoints getEndpoints() {
140 return endpoints;
141 }
142
143 /**
144 * Get the right ascension of spin axis vector (rad).
145 * @return the right ascension of spin axis vector
146 */
147 public double getSpinAlpha() {
148 return spinAlpha;
149 }
150
151 /**
152 * Set the right ascension of spin axis vector (rad).
153 * @param spinAlpha value to be set
154 */
155 public void setSpinAlpha(final double spinAlpha) {
156 refuseFurtherComments();
157 this.spinAlpha = spinAlpha;
158 }
159
160 /**
161 * Get the declination of the spin axis vector (rad).
162 * @return the declination of the spin axis vector (rad).
163 */
164 public double getSpinDelta() {
165 return spinDelta;
166 }
167
168 /**
169 * Set the declination of the spin axis vector (rad).
170 * @param spinDelta value to be set
171 */
172 public void setSpinDelta(final double spinDelta) {
173 refuseFurtherComments();
174 this.spinDelta = spinDelta;
175 }
176
177 /**
178 * Get the phase of the satellite about the spin axis (rad).
179 * @return the phase of the satellite about the spin axis
180 */
181 public double getSpinAngle() {
182 return spinAngle;
183 }
184
185 /**
186 * Set the phase of the satellite about the spin axis (rad).
187 * @param spinAngle value to be set
188 */
189 public void setSpinAngle(final double spinAngle) {
190 refuseFurtherComments();
191 this.spinAngle = spinAngle;
192 }
193
194 /**
195 * Get the angular velocity of satellite around spin axis (rad/s).
196 * @return the angular velocity of satellite around spin axis
197 */
198 public double getSpinAngleVel() {
199 return spinAngleVel;
200 }
201
202 /**
203 * Set the angular velocity of satellite around spin axis (rad/s).
204 * @param spinAngleVel value to be set
205 */
206 public void setSpinAngleVel(final double spinAngleVel) {
207 refuseFurtherComments();
208 this.spinAngleVel = spinAngleVel;
209 }
210
211 /**
212 * Get the nutation angle of spin axis (rad).
213 * @return the nutation angle of spin axis
214 */
215 public Optional<Double> getNutation() {
216 return Optional.ofNullable(nutation);
217 }
218
219 /**
220 * Set the nutation angle of spin axis (rad).
221 * @param nutation the nutation angle to be set
222 */
223 public void setNutation(final double nutation) {
224 refuseFurtherComments();
225 this.nutation = nutation;
226 }
227
228 /**
229 * Get the body nutation period of the spin axis (s).
230 * @return the body nutation period of the spin axis
231 */
232 public Optional<Double> getNutationPeriod() {
233 return Optional.ofNullable(nutationPer);
234 }
235
236 /**
237 * Set the body nutation period of the spin axis (s).
238 * @param period the nutation period to be set
239 */
240 public void setNutationPeriod(final double period) {
241 refuseFurtherComments();
242 this.nutationPer = period;
243 }
244
245 /**
246 * Get the inertial nutation phase (rad).
247 * @return the inertial nutation phase
248 */
249 public Optional<Double> getNutationPhase() {
250 return Optional.ofNullable(nutationPhase);
251 }
252
253 /**
254 * Set the inertial nutation phase (rad).
255 * @param nutationPhase the nutation phase to be set
256 */
257 public void setNutationPhase(final double nutationPhase) {
258 refuseFurtherComments();
259 this.nutationPhase = nutationPhase;
260 }
261
262 /**
263 * Get the right ascension of angular momentum vector (rad).
264 * @return the right ascension of angular momentum vector
265 * @since 12.0
266 */
267 public Optional<Double> getMomentumAlpha() {
268 return Optional.ofNullable(momentumAlpha);
269 }
270
271 /**
272 * Set the right ascension of angular momentum vector (rad).
273 * @param momentumAlpha value to be set
274 * @since 12.0
275 */
276 public void setMomentumAlpha(final double momentumAlpha) {
277 refuseFurtherComments();
278 this.momentumAlpha = momentumAlpha;
279 }
280
281 /**
282 * Get the declination of the angular momentum vector (rad).
283 * @return the declination of the angular momentum vector (rad).
284 * @since 12.0
285 */
286 public Optional<Double> getMomentumDelta() {
287 return Optional.ofNullable(momentumDelta);
288 }
289
290 /**
291 * Set the declination of the angular momentum vector (rad).
292 * @param momentumDelta value to be set
293 * @since 12.0
294 */
295 public void setMomentumDelta(final double momentumDelta) {
296 refuseFurtherComments();
297 this.momentumDelta = momentumDelta;
298 }
299
300 /**
301 * Get the angular velocity of spin vector around angular momentum vector.
302 * @return angular velocity of spin vector around angular momentum vector (rad/s)
303 * @since 12.0
304 */
305 public Optional<Double> getNutationVel() {
306 return Optional.ofNullable(nutationVel);
307 }
308
309 /**
310 * Set the angular velocity of spin vector around angular momentum vector.
311 * @param nutationVel angular velocity of spin vector around angular momentum vector (rad/s)
312 * @since 12.0
313 */
314 public void setNutationVel(final double nutationVel) {
315 refuseFurtherComments();
316 this.nutationVel = nutationVel;
317 }
318
319 /** Check if the logical block includes nutation.
320 * @return true if logical block includes nutation
321 * @since 12.0
322 */
323 public boolean hasNutation() {
324 return getNutation().isPresent() && getNutationPeriod().isPresent() && getNutationPhase().isPresent();
325 }
326
327 /** Check if the logical block includes momentum.
328 * @return true if logical block includes momentum
329 * @since 12.0
330 */
331 public boolean hasMomentum() {
332 return getMomentumAlpha().isPresent() && getMomentumDelta().isPresent() && getNutationVel().isPresent();
333 }
334
335 }