1   /* Copyright 2002-2025 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.propagation.analytical.tle.generation;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.util.FastMath;
21  import org.hipparchus.util.MathUtils;
22  import org.orekit.orbits.FieldKeplerianOrbit;
23  import org.orekit.orbits.KeplerianOrbit;
24  import org.orekit.propagation.analytical.tle.FieldTLE;
25  import org.orekit.propagation.analytical.tle.TLE;
26  import org.orekit.time.AbsoluteDate;
27  import org.orekit.time.FieldAbsoluteDate;
28  import org.orekit.time.TimeScale;
29  
30  /**
31   * Utility class for TLE generation algorithm.
32   * @author Bryan Cazabonne
33   * @author Thomas Paulet
34   * @author Mark Rutten
35   */
36  public final class TleGenerationUtil {
37  
38      /** Private constructor.
39       * <p>This class is a utility class, it should neither have a public
40       * nor a default constructor. This private constructor prevents
41       * the compiler from generating one automatically.</p>
42       */
43      private TleGenerationUtil() {
44      }
45  
46      /**
47       * Builds a new TLE from Keplerian parameters and a template for TLE data.
48       * @param keplerianOrbit the Keplerian parameters to build the TLE from
49       * @param templateTLE TLE used to get object identification
50       * @param bStar TLE B* parameter
51       * @param utc UTC scale
52       * @return TLE with template identification and new orbital parameters
53       */
54      public static TLE newTLE(final KeplerianOrbit keplerianOrbit, final TLE templateTLE,
55                               final double bStar, final TimeScale utc) {
56  
57          // Keplerian parameters
58          final double meanMotion  = keplerianOrbit.getKeplerianMeanMotion();
59          final double e           = keplerianOrbit.getE();
60          final double i           = keplerianOrbit.getI();
61          final double raan        = keplerianOrbit.getRightAscensionOfAscendingNode();
62          final double pa          = keplerianOrbit.getPerigeeArgument();
63          final double meanAnomaly = keplerianOrbit.getMeanAnomaly();
64  
65          // TLE epoch is state epoch
66          final AbsoluteDate epoch = keplerianOrbit.getDate();
67  
68          // Identification
69          final int satelliteNumber = templateTLE.getSatelliteNumber();
70          final char classification = templateTLE.getClassification();
71          final int launchYear      = templateTLE.getLaunchYear();
72          final int launchNumber    = templateTLE.getLaunchNumber();
73          final String launchPiece  = templateTLE.getLaunchPiece();
74          final int ephemerisType   = templateTLE.getEphemerisType();
75          final int elementNumber   = templateTLE.getElementNumber();
76  
77          // Updates revolutionNumberAtEpoch
78          final int revolutionNumberAtEpoch = templateTLE.getRevolutionNumberAtEpoch();
79          final double dt = epoch.durationFrom(templateTLE.getDate());
80          final int newRevolutionNumberAtEpoch = (int) (revolutionNumberAtEpoch + FastMath.floor((MathUtils.normalizeAngle(meanAnomaly, FastMath.PI) + dt * meanMotion) / (MathUtils.TWO_PI)));
81  
82          // Gets Mean Motion derivatives
83          final double meanMotionFirstDerivative  = templateTLE.getMeanMotionFirstDerivative();
84          final double meanMotionSecondDerivative = templateTLE.getMeanMotionSecondDerivative();
85  
86          // Returns the new TLE
87          return new TLE(satelliteNumber, classification, launchYear, launchNumber, launchPiece, ephemerisType,
88                         elementNumber, epoch, meanMotion, meanMotionFirstDerivative, meanMotionSecondDerivative,
89                         e, i, pa, raan, meanAnomaly, newRevolutionNumberAtEpoch, bStar, utc);
90  
91      }
92  
93      /**
94       * Builds a new TLE from Keplerian parameters and a template for TLE data.
95       * @param keplerianOrbit the Keplerian parameters to build the TLE from
96       * @param templateTLE TLE used to get object identification
97       * @param bStar TLE B* parameter
98       * @param utc UTC scale
99       * @param <T> type of the element
100      * @return TLE with template identification and new orbital parameters
101      */
102     public static <T extends CalculusFieldElement<T>> FieldTLE<T> newTLE(final FieldKeplerianOrbit<T> keplerianOrbit,
103                                                                          final FieldTLE<T> templateTLE, final T bStar,
104                                                                          final TimeScale utc) {
105 
106         // Keplerian parameters
107         final T meanMotion  = keplerianOrbit.getKeplerianMeanMotion();
108         final T e           = keplerianOrbit.getE();
109         final T i           = keplerianOrbit.getI();
110         final T raan        = keplerianOrbit.getRightAscensionOfAscendingNode();
111         final T pa          = keplerianOrbit.getPerigeeArgument();
112         final T meanAnomaly = keplerianOrbit.getMeanAnomaly();
113 
114         // TLE epoch is state epoch
115         final FieldAbsoluteDate<T> epoch = keplerianOrbit.getDate();
116 
117         // Identification
118         final int satelliteNumber = templateTLE.getSatelliteNumber();
119         final char classification = templateTLE.getClassification();
120         final int launchYear      = templateTLE.getLaunchYear();
121         final int launchNumber    = templateTLE.getLaunchNumber();
122         final String launchPiece  = templateTLE.getLaunchPiece();
123         final int ephemerisType   = templateTLE.getEphemerisType();
124         final int elementNumber   = templateTLE.getElementNumber();
125 
126         // Updates revolutionNumberAtEpoch
127         final int revolutionNumberAtEpoch = templateTLE.getRevolutionNumberAtEpoch();
128         final T dt = epoch.durationFrom(templateTLE.getDate());
129         final int newRevolutionNumberAtEpoch = (int) ((int) revolutionNumberAtEpoch + FastMath.floor(MathUtils.normalizeAngle(meanAnomaly, e.getPi()).add(dt.multiply(meanMotion)).divide(MathUtils.TWO_PI)).getReal());
130 
131         // Gets Mean Motion derivatives
132         final T meanMotionFirstDerivative  = templateTLE.getMeanMotionFirstDerivative();
133         final T meanMotionSecondDerivative = templateTLE.getMeanMotionSecondDerivative();
134 
135         // Returns the new TLE
136         return new FieldTLE<>(satelliteNumber, classification, launchYear, launchNumber, launchPiece, ephemerisType,
137                               elementNumber, epoch, meanMotion, meanMotionFirstDerivative, meanMotionSecondDerivative,
138                               e, i, pa, raan, meanAnomaly, newRevolutionNumberAtEpoch, bStar.getReal(), utc);
139 
140     }
141 
142 }