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.propagation.covariance;
18
19 import org.hipparchus.linear.RealMatrix;
20 import org.orekit.frames.Frame;
21 import org.orekit.orbits.Orbit;
22 import org.orekit.orbits.OrbitType;
23 import org.orekit.orbits.PositionAngleType;
24 import org.orekit.propagation.AdditionalDataProvider;
25 import org.orekit.propagation.MatricesHarvester;
26 import org.orekit.propagation.Propagator;
27 import org.orekit.propagation.SpacecraftState;
28 import org.orekit.time.AbsoluteDate;
29
30 /**
31 * Additional state provider for state covariance matrix.
32 * <p>
33 * This additional state provider allows computing a propagated covariance matrix based on a user defined input state
34 * covariance matrix. The computation of the propagated covariance matrix uses the State Transition Matrix between the
35 * propagated spacecraft state and the initial state. As a result, the user must define the name
36 * {@link #stmName of the provider for the State Transition Matrix}. The STM is assumed to be the identity at the
37 * covariance epoch, if it is not, results will not be consistent.
38 * <p>
39 * As the State Transition Matrix and the input state covariance matrix can be expressed in different orbit types, the
40 * user must specify both orbit types when building the covariance provider. In addition, the position angle used in
41 * both matrices must also be specified.
42 * <p>
43 * In order to add this additional state provider to an orbit propagator, user must use the
44 * {@link Propagator#addAdditionalDataProvider(AdditionalDataProvider)} method.
45 * <p>
46 * For a given propagated spacecraft {@code state}, the propagated state covariance matrix is accessible through the
47 * method {@link #getStateCovariance(SpacecraftState)}
48 * <p>
49 * The provider must be initialized with the same epoch as the reference covariance. This means either that the very first
50 * propagation must start from this date or the {@link #init(SpacecraftState, AbsoluteDate)} (SpacecraftState)
51 * must be called manually once before use. Failure to do so will result in an {@link NullPointerException}.
52 *
53 * @author Bryan Cazabonne
54 * @author Vincent Cucchietti
55 * @since 11.3
56 */
57 public class StateCovarianceMatrixProvider implements AdditionalDataProvider<RealMatrix> {
58
59 /** Dimension of the state. */
60 private static final int ORBITAL_STATE_DIMENSION = 6;
61
62 /** Name of the state for State Transition Matrix. */
63 private final String stmName;
64
65 /** Matrix harvester to access the State Transition Matrix. */
66 private final MatricesHarvester harvester;
67
68 /** Name of the additional state. */
69 private final String additionalName;
70
71 /** Orbit type used for the State Transition Matrix. */
72 private final OrbitType stmOrbitType;
73
74 /** Position angle used for State Transition Matrix. */
75 private final PositionAngleType stmAngleType;
76
77 /** Orbit type for the covariance matrix. */
78 private final OrbitType covOrbitType;
79
80 /** Position angle used for the covariance matrix. */
81 private final PositionAngleType covAngleType;
82
83 /** Reference state covariance. */
84 private final StateCovariance covRef;
85
86 /** State covariance matrix adapted for STM. */
87 private RealMatrix covMatrixRef;
88
89 /**
90 * Constructor.
91 *
92 * @param additionalName name of the additional state
93 * @param stmName name of the state for State Transition Matrix
94 * @param harvester matrix harvester as returned by
95 * {@code propagator.setupMatricesComputation(stmName, null, null)}
96 * @param covRef reference state covariance
97 */
98 public StateCovarianceMatrixProvider(final String additionalName, final String stmName,
99 final MatricesHarvester harvester, final StateCovariance covRef) {
100 // Initialize fields
101 this.additionalName = additionalName;
102 this.stmName = stmName;
103 this.harvester = harvester;
104 this.covRef = covRef;
105 this.covOrbitType = covRef.getOrbitType();
106 this.covAngleType = covRef.getPositionAngleType();
107 this.stmOrbitType = harvester.getOrbitType();
108 this.stmAngleType = harvester.getPositionAngleType();
109 }
110
111 /** {@inheritDoc} */
112 @Override
113 public String getName() {
114 return additionalName;
115 }
116
117 /** {@inheritDoc} */
118 @Override
119 public void init(final SpacecraftState initialState, final AbsoluteDate target) {
120 if (initialState.getDate().isEqualTo(covRef.getDate())) {
121 // Convert the initial state covariance in the same orbit type and frame as the STM
122 final Orbit initialOrbit = initialState.getOrbit();
123 StateCovariance covariance = covRef.changeCovarianceFrame(initialOrbit, initialState.getFrame());
124 covariance = covariance.changeCovarianceType(initialOrbit, stmOrbitType, stmAngleType);
125 covMatrixRef = covariance.getMatrix();
126 }
127 }
128
129 /**
130 * {@inheritDoc}
131 * <p>
132 * The covariance matrix can be computed only if the State Transition Matrix state is available.
133 * </p>
134 */
135 @Override
136 public boolean yields(final SpacecraftState state) {
137 return !state.hasAdditionalData(stmName);
138 }
139
140 /** {@inheritDoc} */
141 @Override
142 public RealMatrix getAdditionalData(final SpacecraftState state) {
143
144 // State transition matrix for the input state
145 final int inclusiveSize = ORBITAL_STATE_DIMENSION - 1;
146 final RealMatrix dYdY0 = harvester.getStateTransitionMatrix(state).getSubMatrix(0, inclusiveSize, 0, inclusiveSize);
147
148 // Compute the propagated covariance matrix
149 RealMatrix propCov = dYdY0.multiply(covMatrixRef.multiplyTransposed(dYdY0));
150 final StateCovariance propagated = new StateCovariance(propCov, state.getDate(), state.getFrame(), stmOrbitType, stmAngleType);
151
152 // Update to the user defined type
153 propCov = propagated.changeCovarianceType(state.getOrbit(), covOrbitType, covAngleType).getMatrix();
154
155 // Return the propagated covariance matrix
156 return propCov;
157
158 }
159
160 /**
161 * Get the orbit type in which the covariance matrix is expressed.
162 *
163 * @return the orbit type
164 */
165 public OrbitType getCovarianceOrbitType() {
166 return covOrbitType;
167 }
168
169 /**
170 * Get the state covariance in the same frame/local orbital frame, orbit type and position angle as the reference
171 * covariance.
172 *
173 * @param state spacecraft state to which the covariance matrix should correspond
174 * @return the state covariance
175 * @see #getStateCovariance(SpacecraftState, Frame)
176 * @see #getStateCovariance(SpacecraftState, OrbitType, PositionAngleType)
177 */
178 public StateCovariance getStateCovariance(final SpacecraftState state) {
179
180 // Get the current propagated covariance
181 final RealMatrix covarianceMatrix = getAdditionalData(state);
182
183 // Create associated state covariance
184 final StateCovariance covariance =
185 new StateCovariance(covarianceMatrix, state.getDate(), state.getFrame(), covOrbitType, covAngleType);
186
187 // Return the state covariance in same frame/lof as reference covariance
188 if (covRef.getLOF() == null) {
189 return covariance;
190 }
191 else {
192 return covariance.changeCovarianceFrame(state.getOrbit(), covRef.getLOF());
193 }
194
195 }
196
197 /**
198 * Get the state covariance expressed in a given frame.
199 * <p>
200 * The output covariance matrix is expressed in the same orbit type as {@link #getCovarianceOrbitType()}.
201 *
202 * @param state spacecraft state to which the covariance matrix should correspond
203 * @param frame output frame for which the output covariance matrix must be expressed (must be inertial)
204 * @return the state covariance expressed in <code>frame</code>
205 * @see #getStateCovariance(SpacecraftState)
206 * @see #getStateCovariance(SpacecraftState, OrbitType, PositionAngleType)
207 */
208 public StateCovariance getStateCovariance(final SpacecraftState state, final Frame frame) {
209 // Return the converted covariance
210 return getStateCovariance(state).changeCovarianceFrame(state.getOrbit(), frame);
211 }
212
213 /**
214 * Get the state covariance expressed in a given orbit type.
215 *
216 * @param state spacecraft state to which the covariance matrix should correspond
217 * @param orbitType output orbit type
218 * @param angleType output position angle (not used if orbitType equals {@code CARTESIAN})
219 * @return the state covariance in <code>orbitType</code> and <code>angleType</code>
220 * @see #getStateCovariance(SpacecraftState)
221 * @see #getStateCovariance(SpacecraftState, Frame)
222 */
223 public StateCovariance getStateCovariance(final SpacecraftState state, final OrbitType orbitType,
224 final PositionAngleType angleType) {
225 // Return the converted covariance
226 return getStateCovariance(state).changeCovarianceType(state.getOrbit(), orbitType, angleType);
227 }
228 }