LinearKeplerianCovarianceMapper.java

  1. /* Copyright 2022-2025 Romain Serra
  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. import org.hipparchus.analysis.differentiation.Gradient;
  19. import org.hipparchus.analysis.differentiation.GradientField;
  20. import org.hipparchus.linear.MatrixUtils;
  21. import org.hipparchus.linear.RealMatrix;
  22. import org.hipparchus.util.MathArrays;
  23. import org.orekit.frames.LOF;
  24. import org.orekit.frames.LOFType;
  25. import org.orekit.orbits.FieldOrbit;
  26. import org.orekit.orbits.Orbit;
  27. import org.orekit.orbits.OrbitType;
  28. import org.orekit.orbits.PositionAngleBased;
  29. import org.orekit.orbits.PositionAngleType;
  30. import org.orekit.utils.DerivativeStateUtils;

  31. /**
  32.  * Package private class to map orbital covariance using linearized Keplerian motion
  33.  * (with non-Keplerian correction from derivatives if available).
  34.  * The linearization uses the same coordinates as the ones for which the covariance coefficients are defined.
  35.  *
  36.  * @author Romain Serra
  37.  * @since 13.1
  38.  */
  39. class LinearKeplerianCovarianceMapper {

  40.     /** Default local orbital frame to use. */
  41.     private static final LOF DEFAULT_LOF = LOFType.QSW;

  42.     /** Reference orbit. */
  43.     private final Orbit orbit;

  44.     /** Reference orbital covariance. */
  45.     private final StateCovariance stateCovariance;

  46.     /** Converted covariance (from reference) using the same characteristics than the reference orbit. */
  47.     private final StateCovariance convertedCovariance;

  48.     /**
  49.      * Constructor.
  50.      * @param orbit initial orbit
  51.      * @param stateCovariance initial orbital covariance
  52.      */
  53.     LinearKeplerianCovarianceMapper(final Orbit orbit, final StateCovariance stateCovariance) {
  54.         this.orbit = orbit;
  55.         this.stateCovariance = stateCovariance;
  56.         this.convertedCovariance = changeCovarianceBefore();
  57.     }

  58.     /**
  59.      * Maps the orbital covariance to the target orbit based on Keplerian linearization.
  60.      * The coordinates and frame are kept the same as the reference covariance.
  61.      * @param targetOrbit target orbit
  62.      * @return mapped covariance
  63.      */
  64.     StateCovariance map(final Orbit targetOrbit) {
  65.         final PositionAngleType positionAngleType = findPositionAngleType();
  66.         final StateCovariance shiftedCovariance = shiftCovariance(orbit, convertedCovariance, targetOrbit,
  67.                 positionAngleType);
  68.         return changeCovarianceAfter(shiftedCovariance, targetOrbit, positionAngleType);
  69.     }

  70.     /**
  71.      * Convert the initial orbital covariance in the same coordinates and frame than the initial orbit.
  72.      * @return covariance
  73.      */
  74.     private StateCovariance changeCovarianceBefore() {
  75.         final PositionAngleType positionAngleType = findPositionAngleType();
  76.         final StateCovariance intermediateCovariance = stateCovariance.changeCovarianceFrame(orbit, orbit.getFrame());
  77.         return intermediateCovariance.changeCovarianceType(orbit, orbit.getType(), positionAngleType);
  78.     }

  79.     /**
  80.      * Extract the position angle type from the initial orbit.
  81.      * @return position angle type
  82.      */
  83.     private PositionAngleType findPositionAngleType() {
  84.         if (orbit instanceof PositionAngleBased<?>) {
  85.             final PositionAngleBased<?> positionAngleBased = (PositionAngleBased<?>) orbit;
  86.             return positionAngleBased.getCachedPositionAngleType();
  87.         } else {
  88.             // Cartesian
  89.             return null;
  90.         }
  91.     }

  92.     /**
  93.      * Shift orbital covariance according to linearized Keplerian motion, with corrections if non-Keplerian derivatives are present.
  94.      * @param orbit reference orbit
  95.      * @param convertedCovariance covariance to shift
  96.      * @param nextOrbit target orbit
  97.      * @param positionAngleType position angle type to use
  98.      * @return shifted covariance
  99.      */
  100.     private static StateCovariance shiftCovariance(final Orbit orbit, final StateCovariance convertedCovariance,
  101.                                                    final Orbit nextOrbit, final PositionAngleType positionAngleType) {
  102.         final RealMatrix initialCovarianceMatrix = convertedCovariance.getMatrix();
  103.         final GradientField gradientField = GradientField.getField(6);
  104.         final FieldOrbit<Gradient> fieldOrbit = DerivativeStateUtils.buildOrbitGradient(gradientField, orbit);
  105.         final FieldOrbit<Gradient> shiftedFieldOrbit = fieldOrbit.shiftedBy(nextOrbit.durationFrom(orbit));
  106.         final Gradient[] orbitalArray = MathArrays.buildArray(gradientField, 6);
  107.         shiftedFieldOrbit.getType().mapOrbitToArray(shiftedFieldOrbit, positionAngleType, orbitalArray, null);
  108.         final RealMatrix stateTransitionMatrix = MatrixUtils.createRealMatrix(6, 6);
  109.         for (int i = 0; i < orbitalArray.length; i++) {
  110.             stateTransitionMatrix.setRow(i, orbitalArray[i].getGradient());
  111.         }
  112.         final RealMatrix covarianceMatrix = stateTransitionMatrix.multiply(initialCovarianceMatrix
  113.                 .multiplyTransposed(stateTransitionMatrix));
  114.         return new StateCovariance(covarianceMatrix, nextOrbit.getDate(), nextOrbit.getFrame(),
  115.                 nextOrbit.getType(), positionAngleType);
  116.     }

  117.     /**
  118.      * Convert an orbital covariance to the same coordinates and frame than the initial, reference one.
  119.      * @param covarianceToConvert covariance to convert
  120.      * @param nextOrbit target orbit
  121.      * @param positionAngleType position angle type to use
  122.      * @return converted covariance
  123.      */
  124.     private StateCovariance changeCovarianceAfter(final StateCovariance covarianceToConvert, final Orbit nextOrbit,
  125.                                                   final PositionAngleType positionAngleType) {
  126.         final Orbit propagatedOrbit = orbit.shiftedBy(nextOrbit.durationFrom(orbit));
  127.         final LOF lof = stateCovariance.getLOF() == null ? DEFAULT_LOF : stateCovariance.getLOF();
  128.         final StateCovariance cartesianCovarianceInFrame = covarianceToConvert.changeCovarianceType(propagatedOrbit,
  129.                 OrbitType.CARTESIAN, positionAngleType);
  130.         final StateCovariance covarianceInLof = cartesianCovarianceInFrame.changeCovarianceFrame(propagatedOrbit, lof);
  131.         if (stateCovariance.getLOF() != null) {
  132.             return covarianceInLof;
  133.         } else {
  134.             // convert back from an arbitrary LOF to reduce approximation
  135.             final StateCovariance covariance = covarianceInLof.changeCovarianceFrame(nextOrbit, nextOrbit.getFrame());
  136.             if (stateCovariance.getOrbitType() != OrbitType.CARTESIAN) {
  137.                 return covariance.changeCovarianceType(propagatedOrbit, stateCovariance.getOrbitType(), positionAngleType);
  138.             } else {
  139.                 return covariance;
  140.             }
  141.         }
  142.     }
  143. }