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