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