1 /* Copyright 2002-2026 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.CalculusFieldElement;
20 import org.hipparchus.analysis.polynomials.SmoothStepFactory;
21 import org.orekit.errors.OrekitException;
22 import org.orekit.frames.Frame;
23 import org.orekit.orbits.AbstractFieldOrbitInterpolator;
24 import org.orekit.orbits.FieldCartesianOrbit;
25 import org.orekit.orbits.FieldOrbit;
26 import org.orekit.propagation.analytical.AbstractAnalyticalPropagator;
27 import org.orekit.propagation.analytical.FieldAbstractAnalyticalPropagator;
28 import org.orekit.time.FieldAbsoluteDate;
29 import org.orekit.utils.FieldPVCoordinates;
30
31 import java.util.List;
32
33 /**
34 * Orbit blender.
35 * <p>
36 * Its purpose is to interpolate orbit state between tabulated orbit states using the concept of blending, exposed in :
37 * "Efficient Covariance Interpolation using Blending of Approximate State Error Transitions" by Sergei Tanygin, and applying
38 * it to orbit states instead of covariances.
39 * <p>
40 * It propagates tabulated values to the interpolating time using given analytical propagator and then blend each propagated
41 * states using a smoothstep function. It gives especially good results as explained
42 * <a href="https://orekit.org/doc/technical-notes/Implementation_of_covariance_interpolation_in_Orekit.pdf">here</a>
43 * compared to Hermite interpolation when time steps between tabulated values get significant (In LEO, > 10 mn for
44 * example).
45 *
46 * @param <T> type of field element
47 *
48 * @author Vincent Cucchietti
49 * @see org.hipparchus.analysis.polynomials.SmoothStepFactory
50 * @see org.hipparchus.analysis.polynomials.SmoothStepFactory.FieldSmoothStepFunction
51 * @see OrbitBlender
52 */
53 public class FieldOrbitBlender<T extends CalculusFieldElement<T>> extends AbstractFieldOrbitInterpolator<T> {
54
55 /** Analytical propagator used to propagate tabulated orbits to interpolating time. */
56 private final FieldAbstractAnalyticalPropagator<T> analyticalPropagator;
57
58 /** Blending function. */
59 private final SmoothStepFactory.FieldSmoothStepFunction<T> blendingFunction;
60
61 /**
62 * Default constructor.
63 *
64 * @param blendingFunction
65 * {@link org.hipparchus.analysis.polynomials.SmoothStepFactory.SmoothStepFunction smoothstep function} used for
66 * blending
67 * @param analyticalPropagator analytical propagator used to propagate tabulated orbits to interpolating time
68 * @param outputInertialFrame output inertial frame
69 *
70 * @throws OrekitException if output frame is not inertial
71 */
72 public FieldOrbitBlender(final SmoothStepFactory.FieldSmoothStepFunction<T> blendingFunction,
73 final FieldAbstractAnalyticalPropagator<T> analyticalPropagator,
74 final Frame outputInertialFrame) {
75 super(DEFAULT_INTERPOLATION_POINTS, 0., outputInertialFrame);
76 this.blendingFunction = blendingFunction;
77 this.analyticalPropagator = analyticalPropagator;
78 }
79
80 /** {@inheritDoc} */
81 @Override
82 public FieldOrbit<T> interpolate(final InterpolationData interpolationData) {
83
84 // Get interpolation date
85 final FieldAbsoluteDate<T> interpolationDate = interpolationData.getInterpolationDate();
86
87 // Get first and last entry
88 final List<FieldOrbit<T>> neighborList = interpolationData.getNeighborList();
89 final FieldOrbit<T> previousOrbit = neighborList.getFirst();
90 final FieldOrbit<T> nextOrbit = neighborList.get(1);
91
92 // Propagate orbits
93 final FieldOrbit<T> forwardedOrbit = propagateOrbitAnalytically(previousOrbit, interpolationDate);
94 final FieldOrbit<T> backwardedOrbit = propagateOrbitAnalytically(nextOrbit, interpolationDate);
95
96 // Extract position-velocity-acceleration coordinates
97 final FieldPVCoordinates<T> forwardedPV = forwardedOrbit.getPVCoordinates(getOutputInertialFrame());
98 final FieldPVCoordinates<T> backwardedPV = backwardedOrbit.getPVCoordinates(getOutputInertialFrame());
99
100 // Blend PV coordinates
101 final T timeParameter = getTimeParameter(interpolationDate, previousOrbit.getDate(), nextOrbit.getDate());
102 final T blendingValue = blendingFunction.value(timeParameter);
103
104 final FieldPVCoordinates<T> blendedPV = forwardedPV.blendArithmeticallyWith(backwardedPV, blendingValue);
105
106 // Output new blended instance
107 return new FieldCartesianOrbit<>(blendedPV, getOutputInertialFrame(), interpolationDate, previousOrbit.getMu());
108 }
109
110 /**
111 * Propagate orbit using predefined {@link AbstractAnalyticalPropagator analytical propagator}.
112 *
113 * @param tabulatedOrbit tabulated orbit to propagate
114 * @param propagationDate propagation date
115 *
116 * @return orbit propagated to propagation date
117 */
118 private FieldOrbit<T> propagateOrbitAnalytically(final FieldOrbit<T> tabulatedOrbit,
119 final FieldAbsoluteDate<T> propagationDate) {
120
121 analyticalPropagator.resetInitialState(new FieldSpacecraftState<>(tabulatedOrbit));
122
123 return analyticalPropagator.propagate(propagationDate).getOrbit();
124 }
125 }