LinearKeplerianCovarianceMapper.java
- /* Copyright 2022-2025 Romain Serra
- * Licensed to CS GROUP (CS) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * CS licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.orekit.propagation;
- import org.hipparchus.analysis.differentiation.Gradient;
- import org.hipparchus.analysis.differentiation.GradientField;
- import org.hipparchus.linear.MatrixUtils;
- import org.hipparchus.linear.RealMatrix;
- import org.hipparchus.util.MathArrays;
- import org.orekit.frames.LOF;
- import org.orekit.frames.LOFType;
- import org.orekit.orbits.FieldOrbit;
- import org.orekit.orbits.Orbit;
- import org.orekit.orbits.OrbitType;
- import org.orekit.orbits.PositionAngleBased;
- import org.orekit.orbits.PositionAngleType;
- import org.orekit.utils.DerivativeStateUtils;
- /**
- * Package private class to map orbital covariance using linearized Keplerian motion
- * (with non-Keplerian correction from derivatives if available).
- * The linearization uses the same coordinates as the ones for which the covariance coefficients are defined.
- *
- * @author Romain Serra
- * @since 13.1
- */
- class LinearKeplerianCovarianceMapper {
- /** Default local orbital frame to use. */
- private static final LOF DEFAULT_LOF = LOFType.QSW;
- /** Reference orbit. */
- private final Orbit orbit;
- /** Reference orbital covariance. */
- private final StateCovariance stateCovariance;
- /** Converted covariance (from reference) using the same characteristics than the reference orbit. */
- private final StateCovariance convertedCovariance;
- /**
- * Constructor.
- * @param orbit initial orbit
- * @param stateCovariance initial orbital covariance
- */
- LinearKeplerianCovarianceMapper(final Orbit orbit, final StateCovariance stateCovariance) {
- this.orbit = orbit;
- this.stateCovariance = stateCovariance;
- this.convertedCovariance = changeCovarianceBefore();
- }
- /**
- * Maps the orbital covariance to the target orbit based on Keplerian linearization.
- * The coordinates and frame are kept the same as the reference covariance.
- * @param targetOrbit target orbit
- * @return mapped covariance
- */
- StateCovariance map(final Orbit targetOrbit) {
- final PositionAngleType positionAngleType = findPositionAngleType();
- final StateCovariance shiftedCovariance = shiftCovariance(orbit, convertedCovariance, targetOrbit,
- positionAngleType);
- return changeCovarianceAfter(shiftedCovariance, targetOrbit, positionAngleType);
- }
- /**
- * Convert the initial orbital covariance in the same coordinates and frame than the initial orbit.
- * @return covariance
- */
- private StateCovariance changeCovarianceBefore() {
- final PositionAngleType positionAngleType = findPositionAngleType();
- final StateCovariance intermediateCovariance = stateCovariance.changeCovarianceFrame(orbit, orbit.getFrame());
- return intermediateCovariance.changeCovarianceType(orbit, orbit.getType(), positionAngleType);
- }
- /**
- * Extract the position angle type from the initial orbit.
- * @return position angle type
- */
- private PositionAngleType findPositionAngleType() {
- if (orbit instanceof PositionAngleBased<?>) {
- final PositionAngleBased<?> positionAngleBased = (PositionAngleBased<?>) orbit;
- return positionAngleBased.getCachedPositionAngleType();
- } else {
- // Cartesian
- return null;
- }
- }
- /**
- * Shift orbital covariance according to linearized Keplerian motion, with corrections if non-Keplerian derivatives are present.
- * @param orbit reference orbit
- * @param convertedCovariance covariance to shift
- * @param nextOrbit target orbit
- * @param positionAngleType position angle type to use
- * @return shifted covariance
- */
- private static StateCovariance shiftCovariance(final Orbit orbit, final StateCovariance convertedCovariance,
- final Orbit nextOrbit, final PositionAngleType positionAngleType) {
- final RealMatrix initialCovarianceMatrix = convertedCovariance.getMatrix();
- final GradientField gradientField = GradientField.getField(6);
- final FieldOrbit<Gradient> fieldOrbit = DerivativeStateUtils.buildOrbitGradient(gradientField, orbit);
- final FieldOrbit<Gradient> shiftedFieldOrbit = fieldOrbit.shiftedBy(nextOrbit.durationFrom(orbit));
- final Gradient[] orbitalArray = MathArrays.buildArray(gradientField, 6);
- shiftedFieldOrbit.getType().mapOrbitToArray(shiftedFieldOrbit, positionAngleType, orbitalArray, null);
- final RealMatrix stateTransitionMatrix = MatrixUtils.createRealMatrix(6, 6);
- for (int i = 0; i < orbitalArray.length; i++) {
- stateTransitionMatrix.setRow(i, orbitalArray[i].getGradient());
- }
- final RealMatrix covarianceMatrix = stateTransitionMatrix.multiply(initialCovarianceMatrix
- .multiplyTransposed(stateTransitionMatrix));
- return new StateCovariance(covarianceMatrix, nextOrbit.getDate(), nextOrbit.getFrame(),
- nextOrbit.getType(), positionAngleType);
- }
- /**
- * Convert an orbital covariance to the same coordinates and frame than the initial, reference one.
- * @param covarianceToConvert covariance to convert
- * @param nextOrbit target orbit
- * @param positionAngleType position angle type to use
- * @return converted covariance
- */
- private StateCovariance changeCovarianceAfter(final StateCovariance covarianceToConvert, final Orbit nextOrbit,
- final PositionAngleType positionAngleType) {
- final Orbit propagatedOrbit = orbit.shiftedBy(nextOrbit.durationFrom(orbit));
- final LOF lof = stateCovariance.getLOF() == null ? DEFAULT_LOF : stateCovariance.getLOF();
- final StateCovariance cartesianCovarianceInFrame = covarianceToConvert.changeCovarianceType(propagatedOrbit,
- OrbitType.CARTESIAN, positionAngleType);
- final StateCovariance covarianceInLof = cartesianCovarianceInFrame.changeCovarianceFrame(propagatedOrbit, lof);
- if (stateCovariance.getLOF() != null) {
- return covarianceInLof;
- } else {
- // convert back from an arbitrary LOF to reduce approximation
- final StateCovariance covariance = covarianceInLof.changeCovarianceFrame(nextOrbit, nextOrbit.getFrame());
- if (stateCovariance.getOrbitType() != OrbitType.CARTESIAN) {
- return covariance.changeCovarianceType(propagatedOrbit, stateCovariance.getOrbitType(), positionAngleType);
- } else {
- return covariance;
- }
- }
- }
- }