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 ORBITAL_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 final 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 and frame as the STM
112 final Orbit initialOrbit = initialState.getOrbit();
113 StateCovariance covariance = covInit.changeCovarianceFrame(initialOrbit, initialState.getFrame());
114 covariance = covariance.changeCovarianceType(initialOrbit, stmOrbitType, stmAngleType);
115
116 covMatrixInit = covariance.getMatrix();
117 }
118
119 /**
120 * {@inheritDoc}
121 * <p>
122 * The covariance matrix can be computed only if the State Transition Matrix state is available.
123 * </p>
124 */
125 @Override
126 public boolean yields(final SpacecraftState state) {
127 return !state.hasAdditionalData(stmName);
128 }
129
130 /** {@inheritDoc} */
131 @Override
132 public RealMatrix getAdditionalData(final SpacecraftState state) {
133
134 // State transition matrix for the input state
135 final int inclusiveSize = ORBITAL_STATE_DIMENSION - 1;
136 final RealMatrix dYdY0 = harvester.getStateTransitionMatrix(state).getSubMatrix(0, inclusiveSize, 0, inclusiveSize);
137
138 // Compute the propagated covariance matrix
139 RealMatrix propCov = dYdY0.multiply(covMatrixInit.multiplyTransposed(dYdY0));
140 final StateCovariance propagated = new StateCovariance(propCov, state.getDate(), state.getFrame(), stmOrbitType, stmAngleType);
141
142 // Update to the user defined type
143 propCov = propagated.changeCovarianceType(state.getOrbit(), covOrbitType, covAngleType).getMatrix();
144
145 // Return the propagated covariance matrix
146 return propCov;
147
148 }
149
150 /**
151 * Get the orbit type in which the covariance matrix is expressed.
152 *
153 * @return the orbit type
154 */
155 public OrbitType getCovarianceOrbitType() {
156 return covOrbitType;
157 }
158
159 /**
160 * Get the state covariance in the same frame/local orbital frame, orbit type and position angle as the initial
161 * covariance.
162 *
163 * @param state spacecraft state to which the covariance matrix should correspond
164 * @return the state covariance
165 * @see #getStateCovariance(SpacecraftState, Frame)
166 * @see #getStateCovariance(SpacecraftState, OrbitType, PositionAngleType)
167 */
168 public StateCovariance getStateCovariance(final SpacecraftState state) {
169
170 // Get the current propagated covariance
171 final RealMatrix covarianceMatrix = getAdditionalData(state);
172
173 // Create associated state covariance
174 final StateCovariance covariance =
175 new StateCovariance(covarianceMatrix, state.getDate(), state.getFrame(), covOrbitType, covAngleType);
176
177 // Return the state covariance in same frame/lof as initial covariance
178 if (covInit.getLOF() == null) {
179 return covariance;
180 }
181 else {
182 return covariance.changeCovarianceFrame(state.getOrbit(), covInit.getLOF());
183 }
184
185 }
186
187 /**
188 * Get the state covariance expressed in a given frame.
189 * <p>
190 * The output covariance matrix is expressed in the same orbit type as {@link #getCovarianceOrbitType()}.
191 *
192 * @param state spacecraft state to which the covariance matrix should correspond
193 * @param frame output frame for which the output covariance matrix must be expressed (must be inertial)
194 * @return the state covariance expressed in <code>frame</code>
195 * @see #getStateCovariance(SpacecraftState)
196 * @see #getStateCovariance(SpacecraftState, OrbitType, PositionAngleType)
197 */
198 public StateCovariance getStateCovariance(final SpacecraftState state, final Frame frame) {
199 // Return the converted covariance
200 return getStateCovariance(state).changeCovarianceFrame(state.getOrbit(), frame);
201 }
202
203 /**
204 * Get the state covariance expressed in a given orbit type.
205 *
206 * @param state spacecraft state to which the covariance matrix should correspond
207 * @param orbitType output orbit type
208 * @param angleType output position angle (not used if orbitType equals {@code CARTESIAN})
209 * @return the state covariance in <code>orbitType</code> and <code>angleType</code>
210 * @see #getStateCovariance(SpacecraftState)
211 * @see #getStateCovariance(SpacecraftState, Frame)
212 */
213 public StateCovariance getStateCovariance(final SpacecraftState state, final OrbitType orbitType,
214 final PositionAngleType angleType) {
215 // Return the converted covariance
216 return getStateCovariance(state).changeCovarianceType(state.getOrbit(), orbitType, angleType);
217 }
218 }