SP3CoordinateHermiteInterpolator.java

  1. /* Copyright 2023 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.  *
  29.  * @author Luc Maisonobe
  30.  * @see HermiteInterpolator
  31.  * @see SP3Coordinate
  32.  * @since 12.0
  33.  */
  34. public class SP3CoordinateHermiteInterpolator extends AbstractTimeInterpolator<SP3Coordinate> {

  35.     /** Flag for using velocity and clock rate. */
  36.     private final boolean useRates;

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

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

  69.         // Get date
  70.         final AbsoluteDate date = interpolationData.getInterpolationDate();

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

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

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

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

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

  114.     }

  115. }