SP3CoordinateHermiteInterpolator.java

  1. /* Copyright 2022-2025 Luc Maisonobe
  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.files.sp3;

  18. import java.util.stream.Stream;

  19. import org.hipparchus.analysis.interpolation.HermiteInterpolator;
  20. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  21. import org.orekit.time.AbsoluteDate;
  22. import org.orekit.time.AbstractTimeInterpolator;

  23. /** Interpolator for {@link SP3Coordinate SP3 coordinates}.
  24.  * <p>
  25.  * As this implementation of interpolation is polynomial, it should be used only with small number of interpolation points
  26.  * (about 10-20 points) in order to avoid <a href="http://en.wikipedia.org/wiki/Runge%27s_phenomenon">Runge's phenomenon</a>
  27.  * and numerical problems (including NaN appearing).
  28.  * </p>
  29.  * <p>
  30.  * If some clock or clock rate are present in the SP3 files as default values (999999.999999), then they
  31.  * are replaced by {@code Double.NaN} during parsing, so the interpolation will exhibit NaNs, but the
  32.  * positions will be properly interpolated.
  33.  * </p>
  34.  *
  35.  * @author Luc Maisonobe
  36.  * @see HermiteInterpolator
  37.  * @see SP3Coordinate
  38.  * @since 12.0
  39.  */
  40. public class SP3CoordinateHermiteInterpolator extends AbstractTimeInterpolator<SP3Coordinate> {

  41.     /** Flag for using velocity and clock rate. */
  42.     private final boolean useRates;

  43.     /**
  44.      * Constructor.
  45.      * <p>
  46.      * As this implementation of interpolation is polynomial, it should be used only with small number of interpolation
  47.      * points (about 10-20 points) in order to avoid <a href="http://en.wikipedia.org/wiki/Runge%27s_phenomenon">Runge's
  48.      * phenomenon</a> and numerical problems (including NaN appearing).
  49.      * </p>
  50.      *
  51.      * @param interpolationPoints number of interpolation points
  52.      * @param extrapolationThreshold extrapolation threshold beyond which the propagation will fail
  53.      * @param useRates if true, use velocity and clock rates for interpolation
  54.      */
  55.     public SP3CoordinateHermiteInterpolator(final int interpolationPoints,
  56.                                             final double extrapolationThreshold,
  57.                                             final boolean useRates) {
  58.         super(interpolationPoints, extrapolationThreshold);
  59.         this.useRates = useRates;
  60.     }

  61.     /**
  62.      * {@inheritDoc}
  63.      * <p>
  64.      * The interpolated instance is created by polynomial Hermite interpolation ensuring velocity remains the exact
  65.      * derivative of position.
  66.      * <p>
  67.      * Note that even if first time derivatives (velocities) from sample can be ignored, the interpolated instance always
  68.      * includes interpolated derivatives. This feature can be used explicitly to compute these derivatives when it would be
  69.      * too complex to compute them from an analytical formula: just compute a few sample points from the explicit formula and
  70.      * set the derivatives to zero in these sample points, then use interpolation to add derivatives consistent with the
  71.      * positions.
  72.      */
  73.     @Override
  74.     protected SP3Coordinate interpolate(final InterpolationData interpolationData) {

  75.         // Get date
  76.         final AbsoluteDate date = interpolationData.getInterpolationDate();

  77.         // Convert sample to stream
  78.         final Stream<SP3Coordinate> sample = interpolationData.getNeighborList().stream();

  79.         // Set up an interpolator taking derivatives into account
  80.         final HermiteInterpolator interpolator = new HermiteInterpolator();

  81.         // Add sample points
  82.         if (useRates) {
  83.             // populate sample with position, clock, velocity and clock rate data
  84.             sample.forEach(c -> interpolator.addSamplePoint(c.getDate().durationFrom(date),
  85.                                         new double[] {
  86.                                             c.getPosition().getX(),
  87.                                             c.getPosition().getY(),
  88.                                             c.getPosition().getZ(),
  89.                                             c.getClockCorrection(),
  90.                                         },
  91.                                         new double[] {
  92.                                             c.getVelocity().getX(),
  93.                                             c.getVelocity().getY(),
  94.                                             c.getVelocity().getZ(),
  95.                                             c.getClockRateChange(),
  96.                                         }));
  97.         } else {
  98.             // populate sample with position and clock data, ignoring velocity and clock rate
  99.             sample.forEach(c -> interpolator.addSamplePoint(c.getDate().durationFrom(date),
  100.                                         new double[] {
  101.                                             c.getPosition().getX(),
  102.                                             c.getPosition().getY(),
  103.                                             c.getPosition().getZ(),
  104.                                             c.getClockCorrection(),
  105.                                         }));
  106.         }

  107.         // Interpolate
  108.         final double[][] interpolated = interpolator.derivatives(0.0, 1);

  109.         // Build a new interpolated instance
  110.         return new SP3Coordinate(date,
  111.                                  new Vector3D(interpolated[0][0], interpolated[0][1], interpolated[0][2]), null,
  112.                                  new Vector3D(interpolated[1][0], interpolated[1][1], interpolated[1][2]), null,
  113.                                  interpolated[0][3], Double.NaN,
  114.                                  interpolated[1][3], Double.NaN,
  115.                                  false, false, false, false);

  116.     }

  117. }