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
18 package org.orekit.files.ccsds.ndm.odm.omm;
19
20 import java.util.Optional;
21
22 import org.orekit.annotation.Nullable;
23 import org.orekit.files.ccsds.section.CommentsContainer;
24
25 /** Container for TLE data.
26 * <p>
27 * Beware that the Orekit getters and setters all rely on SI units. The parsers
28 * and writers take care of converting these SI units into CCSDS mandatory units.
29 * The {@link org.orekit.utils.units.Unit Unit} class provides useful
30 * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and
31 * {@link org.orekit.utils.units.Unit#toSI(double) toSI} methods in case the callers
32 * already use CCSDS units instead of the API SI units. The general-purpose
33 * {@link org.orekit.utils.units.Unit Unit} class (without an 's') and the
34 * CCSDS-specific {@link org.orekit.files.ccsds.definitions.Units Units} class
35 * (with an 's') also provide some predefined units. These predefined units and the
36 * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and
37 * {@link org.orekit.utils.units.Unit#toSI(double) toSI} conversion methods are indeed
38 * what the parsers and writers use for the conversions.
39 * </p>
40 * @author sports
41 * @since 6.1
42 */
43 public class OmmTle extends CommentsContainer {
44
45 /** Constant for EPHEMERIS_TYPE SGP.
46 * @since 12.0
47 */
48 public static final int EPHEMERIS_TYPE_SGP = 0;
49
50 /** Constant for EPHEMERIS_TYPE SGP4.
51 * @since 12.0
52 */
53 public static final int EPHEMERIS_TYPE_SGP4 = 2;
54
55 /** Constant for EPHEMERIS_TYPE PPT3.
56 * @since 12.0
57 */
58 public static final int EPHEMERIS_TYPE_PPT3 = 3;
59
60 /** Constant for EPHEMERIS_TYPE SGP4-XP.
61 * @since 12.0
62 */
63 public static final int EPHEMERIS_TYPE_SGP4_XP = 4;
64
65 /** Constant for EPHEMERIS_TYPE Special Perturbations.
66 * @since 12.0
67 */
68 public static final int EPHEMERIS_TYPE_SPECIAL_PERTURBATIONS = 6;
69
70 /** Ephemeris Type, only required if MEAN_ELEMENT_THEORY = SGP/SGP4. Some sources suggest the coding for
71 * the EPHEMERIS_TYPE keyword: 0 = SGP, 2 = SGP4, 3 = PPT3, 4 = SGP4-XP, 6 = Special Perturbations. Default value = 0.
72 */
73 private int ephemerisType;
74
75 /** Classification Type, only required if MEAN_ELEMENT_THEORY = SGP/SGP4. Some sources suggest the
76 * following coding for the CLASSIFICATION_TYPE keyword: U = unclassified, S = secret. Default value = U.
77 */
78 private char classificationType;
79
80 /** NORAD Catalog Number ("Satellite Number"), an integer of up to nine digits. */
81 private int noradID;
82
83 /** Element set number for this satellite, only required if MEAN_ELEMENT_THEORY = SGP/SGP4.
84 * Normally incremented sequentially, but may be out of sync if it is generated from a backup source.
85 * Used to distinguish different TLEs, and therefore only meaningful if TLE based data is being exchanged. */
86 private int elementSetNo;
87
88 /** Revolution Number, only required if MEAN_ELEMENT_THEORY = SGP/SGP4. */
89 private int revAtEpoch;
90
91 /** SGP/SGP4 drag-like coefficient (in units 1/[Earth radii]), only required if MEAN_ELEMENT_THEORY = SGP/SGP4. */
92 @Nullable
93 private Double bStar;
94
95 /** SGP4-XP drag-like coefficient (in m²/kg), only required if MEAN_ELEMENT_THEORY = SGP4-XP.
96 * @since 12.0
97 */
98 @Nullable
99 private Double bTerm;
100
101 /** First Time Derivative of the Mean Motion, only required if MEAN_ELEMENT_THEORY = SGP. */
102 @Nullable
103 private Double meanMotionDot;
104
105 /** Second Time Derivative of Mean Motion, only required if MEAN_ELEMENT_THEORY = SGP. */
106 @Nullable
107 private Double meanMotionDotDot;
108
109 /** SGP4-XP solar radiation pressure-like coefficient Aγ/m (in m²/kg), only required if MEAN_ELEMENT_THEORY = SGP4-XP.
110 * @since 12.0
111 */
112 @Nullable
113 private Double agOm;
114
115 /** Create an empty data set.
116 */
117 public OmmTle() {
118 ephemerisType = EPHEMERIS_TYPE_SGP;
119 classificationType = 'U';
120 noradID = -1;
121 elementSetNo = -1;
122 revAtEpoch = -1;
123 }
124
125 /** {@inheritDoc} */
126 @Override
127 public void validate(final double version) {
128 super.validate(version);
129
130 checkNotNegative(noradID, OmmTleKey.NORAD_CAT_ID.name());
131 checkNotNegative(elementSetNo, OmmTleKey.ELEMENT_SET_NO.name());
132 checkNotNegative(revAtEpoch, OmmTleKey.REV_AT_EPOCH.name());
133
134 if (ephemerisType == EPHEMERIS_TYPE_SGP4) {
135 checkNotNaN(getBStar().orElse(Double.NaN), OmmTleKey.BSTAR.name());
136 } else if (ephemerisType == EPHEMERIS_TYPE_SGP4_XP) {
137 checkNotNaN(getBTerm().orElse(Double.NaN), OmmTleKey.BTERM.name());
138 }
139
140 if (ephemerisType == EPHEMERIS_TYPE_SGP || ephemerisType == EPHEMERIS_TYPE_PPT3) {
141 checkNotNaN(getMeanMotionDot().orElse(Double.NaN), OmmTleKey.MEAN_MOTION_DOT.name());
142 }
143
144 if (ephemerisType == EPHEMERIS_TYPE_SGP || ephemerisType == EPHEMERIS_TYPE_PPT3) {
145 checkNotNaN(getMeanMotionDotDot().orElse(Double.NaN), OmmTleKey.MEAN_MOTION_DDOT.name());
146 } else if (ephemerisType == EPHEMERIS_TYPE_SGP4_XP) {
147 checkNotNaN(getAGoM().orElse(Double.NaN), OmmTleKey.AGOM.name());
148 }
149
150 }
151
152 /** Get the ephemeris type.
153 * @return the ephemerisType
154 */
155 public int getEphemerisType() {
156 return ephemerisType;
157 }
158
159 /** Set the ephemeris type.
160 * @param ephemerisType the ephemeris type to be set
161 */
162 public void setEphemerisType(final int ephemerisType) {
163 refuseFurtherComments();
164 this.ephemerisType = ephemerisType;
165 }
166
167 /** Get the classification type.
168 * @return the classificationType
169 */
170 public char getClassificationType() {
171 return classificationType;
172 }
173
174 /** Set the classification type.
175 * @param classificationType the classification type to be set
176 */
177 public void setClassificationType(final char classificationType) {
178 refuseFurtherComments();
179 this.classificationType = classificationType;
180 }
181
182 /** Get the NORAD Catalog Number ("Satellite Number").
183 * @return the NORAD Catalog Number
184 */
185 public int getNoradID() {
186 return noradID;
187 }
188
189 /** Set the NORAD Catalog Number ("Satellite Number").
190 * @param noradID the element set number to be set
191 */
192 public void setNoradID(final int noradID) {
193 refuseFurtherComments();
194 this.noradID = noradID;
195 }
196
197 /** Get the element set number for this satellite.
198 * @return the element set number for this satellite
199 */
200 public int getElementSetNumber() {
201 return elementSetNo;
202 }
203
204 /** Set the element set number for this satellite.
205 * @param elementSetNo the element set number to be set
206 */
207 public void setElementSetNo(final int elementSetNo) {
208 refuseFurtherComments();
209 this.elementSetNo = elementSetNo;
210 }
211
212 /** Get the revolution rumber.
213 * @return the revolution rumber
214 */
215 public int getRevAtEpoch() {
216 return revAtEpoch;
217 }
218
219 /** Set the revolution rumber.
220 * @param revAtEpoch the Revolution Number to be set
221 */
222 public void setRevAtEpoch(final int revAtEpoch) {
223 refuseFurtherComments();
224 this.revAtEpoch = revAtEpoch;
225 }
226
227 /** Get the SGP/SGP4 drag-like coefficient.
228 * @return the SGP/SGP4 drag-like coefficient
229 */
230 public Optional<Double> getBStar() {
231 return Optional.ofNullable(bStar);
232 }
233
234 /** Set the SGP/SGP4 drag-like coefficient.
235 * @param bstar the SGP/SGP4 drag-like coefficient to be set
236 */
237 public void setBStar(final double bstar) {
238 refuseFurtherComments();
239 this.bStar = bstar;
240 }
241
242 /** Get the SGP4-XP drag-like coefficient.
243 * @return the SGP4-XP drag-like coefficient
244 * @since 12.0
245 */
246 public Optional<Double> getBTerm() {
247 return Optional.ofNullable(bTerm);
248 }
249
250 /** Set the SGP4-XP drag-like coefficient.
251 * @param bterm the SGP4-XP drag-like coefficient to be set
252 * @since 12.0
253 */
254 public void setBTerm(final double bterm) {
255 refuseFurtherComments();
256 this.bTerm = bterm;
257 }
258
259 /** Get the first time derivative of the mean motion.
260 * @return the first time derivative of the mean motion
261 */
262 public Optional<Double> getMeanMotionDot() {
263 return Optional.ofNullable(meanMotionDot);
264 }
265
266 /** Set the first time derivative of the mean motion.
267 * @param meanMotionDot the first time derivative of the mean motion to be set
268 */
269 public void setMeanMotionDot(final double meanMotionDot) {
270 refuseFurtherComments();
271 this.meanMotionDot = meanMotionDot;
272 }
273
274 /** Get the second time derivative of the mean motion.
275 * @return the second time derivative of the mean motion
276 */
277 public Optional<Double> getMeanMotionDotDot() {
278 return Optional.ofNullable(meanMotionDotDot);
279 }
280
281 /** Set the second time derivative of the mean motion.
282 * @param meanMotionDotDot the second time derivative of the mean motion to be set
283 */
284 public void setMeanMotionDotDot(final double meanMotionDotDot) {
285 refuseFurtherComments();
286 this.meanMotionDotDot = meanMotionDotDot;
287 }
288
289 /** Get the SGP4-XP solar radiation pressure-like coefficient Aγ/m.
290 * @return the SGP4-XP solar radiation pressure-like coefficient Aγ/m
291 * @since 12.0
292 */
293 public Optional<Double> getAGoM() {
294 return Optional.ofNullable(agOm);
295 }
296
297 /** Set the SGP4-XP solar radiation pressure-like coefficient Aγ/m.
298 * @param agom the SGP4-XP solar radiation pressure-like coefficient Aγ/m to be set
299 * @since 12.0
300 */
301 public void setAGoM(final double agom) {
302 refuseFurtherComments();
303 this.agOm = agom;
304 }
305
306 }