- /* Copyright 2002-2024 CS GROUP
- * 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.analytical;
- import java.io.Serializable;
- import org.hipparchus.analysis.differentiation.UnivariateDerivative2;
- import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
- import org.hipparchus.geometry.euclidean.threed.Vector3D;
- import org.hipparchus.linear.RealMatrix;
- import org.hipparchus.util.FastMath;
- import org.hipparchus.util.MathUtils;
- import org.hipparchus.util.SinCos;
- import org.orekit.attitudes.AttitudeProvider;
- import org.orekit.attitudes.FrameAlignedProvider;
- import org.orekit.errors.OrekitException;
- import org.orekit.errors.OrekitMessages;
- import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider;
- import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider.UnnormalizedSphericalHarmonics;
- import org.orekit.orbits.CartesianOrbit;
- import org.orekit.orbits.CircularOrbit;
- import org.orekit.orbits.Orbit;
- import org.orekit.orbits.OrbitType;
- import org.orekit.orbits.PositionAngleType;
- import org.orekit.propagation.AbstractMatricesHarvester;
- import org.orekit.propagation.PropagationType;
- import org.orekit.propagation.SpacecraftState;
- import org.orekit.time.AbsoluteDate;
- import org.orekit.utils.DoubleArrayDictionary;
- import org.orekit.utils.TimeSpanMap;
- import org.orekit.utils.TimeStampedPVCoordinates;
- /** This class propagates a {@link org.orekit.propagation.SpacecraftState}
- * using the analytical Eckstein-Hechler model.
- * <p>The Eckstein-Hechler model is suited for near circular orbits
- * (e < 0.1, with poor accuracy between 0.005 and 0.1) and inclination
- * neither equatorial (direct or retrograde) nor critical (direct or
- * retrograde).</p>
- * <p>
- * Note that before version 7.0, there was a large inconsistency in the generated
- * orbits, and it was fixed as of version 7.0 of Orekit, with a visible side effect.
- * The problems is that if the circular parameters produced by the Eckstein-Hechler
- * model are used to build an orbit considered to be osculating, the velocity deduced
- * from this orbit was <em>inconsistent with the position evolution</em>! The reason is
- * that the model includes non-Keplerian effects but it does not include a corresponding
- * circular/Cartesian conversion. As a consequence, all subsequent computation involving
- * velocity were wrong. This includes attitude modes like yaw compensation and Doppler
- * effect. As this effect was considered serious enough and as accurate velocities were
- * considered important, the propagator now generates {@link CartesianOrbit Cartesian
- * orbits} which are built in a special way to ensure consistency throughout propagation.
- * A side effect is that if circular parameters are rebuilt by user from these propagated
- * Cartesian orbit, the circular parameters will generally <em>not</em> match the initial
- * orbit (differences in semi-major axis can exceed 120 m). The position however <em>will</em>
- * match to sub-micrometer level, and this position will be identical to the positions
- * that were generated by previous versions (in other words, the internals of the models
- * have not been changed, only the output parameters have been changed). The correctness
- * of the initialization has been assessed and is good, as it allows the subsequent orbit
- * to remain close to a numerical reference orbit.
- * </p>
- * <p>
- * If users need a more definitive initialization of an Eckstein-Hechler propagator, they
- * should consider using a {@link org.orekit.propagation.conversion.PropagatorConverter
- * propagator converter} to initialize their Eckstein-Hechler propagator using a complete
- * sample instead of just a single initial orbit.
- * </p>
- * @see Orbit
- * @author Guylaine Prat
- */
- public class EcksteinHechlerPropagator extends AbstractAnalyticalPropagator {
- /** Default convergence threshold for mean parameters conversion. */
- private static final double EPSILON_DEFAULT = 1.0e-11;
- /** Default value for maxIterations. */
- private static final int MAX_ITERATIONS_DEFAULT = 100;
- /** Initial Eckstein-Hechler model. */
- private EHModel initialModel;
- /** All models. */
- private transient TimeSpanMap<EHModel> models;
- /** Reference radius of the central body attraction model (m). */
- private double referenceRadius;
- /** Central attraction coefficient (m³/s²). */
- private double mu;
- /** Un-normalized zonal coefficients. */
- private double[] ck0;
- /** Build a propagator from orbit and potential provider.
- * <p>Mass and attitude provider are set to unspecified non-null arbitrary values.</p>
- *
- * <p>Using this constructor, an initial osculating orbit is considered.</p>
- *
- * @param initialOrbit initial orbit
- * @param provider for un-normalized zonal coefficients
- * @see #EcksteinHechlerPropagator(Orbit, AttitudeProvider,
- * UnnormalizedSphericalHarmonicsProvider)
- * @see #EcksteinHechlerPropagator(Orbit, UnnormalizedSphericalHarmonicsProvider,
- * PropagationType)
- */
- public EcksteinHechlerPropagator(final Orbit initialOrbit,
- final UnnormalizedSphericalHarmonicsProvider provider) {
- this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
- DEFAULT_MASS, provider, provider.onDate(initialOrbit.getDate()));
- }
- /**
- * Private helper constructor.
- * <p>Using this constructor, an initial osculating orbit is considered.</p>
- * @param initialOrbit initial orbit
- * @param attitude attitude provider
- * @param mass spacecraft mass
- * @param provider for un-normalized zonal coefficients
- * @param harmonics {@code provider.onDate(initialOrbit.getDate())}
- * @see #EcksteinHechlerPropagator(Orbit, AttitudeProvider, double,
- * UnnormalizedSphericalHarmonicsProvider,
- * UnnormalizedSphericalHarmonicsProvider.UnnormalizedSphericalHarmonics,
- * PropagationType)
- */
- public EcksteinHechlerPropagator(final Orbit initialOrbit,
- final AttitudeProvider attitude,
- final double mass,
- final UnnormalizedSphericalHarmonicsProvider provider,
- final UnnormalizedSphericalHarmonics harmonics) {
- this(initialOrbit, attitude, mass, provider.getAe(), provider.getMu(),
- harmonics.getUnnormalizedCnm(2, 0),
- harmonics.getUnnormalizedCnm(3, 0),
- harmonics.getUnnormalizedCnm(4, 0),
- harmonics.getUnnormalizedCnm(5, 0),
- harmonics.getUnnormalizedCnm(6, 0));
- }
- /** Build a propagator from orbit and potential.
- * <p>Mass and attitude provider are set to unspecified non-null arbitrary values.</p>
- * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
- * are related to both the normalized coefficients
- * <span style="text-decoration: overline">C</span><sub>n,0</sub>
- * and the J<sub>n</sub> one as follows:</p>
- *
- * <p> C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
- * <span style="text-decoration: overline">C</span><sub>n,0</sub>
- *
- * <p> C<sub>n,0</sub> = -J<sub>n</sub>
- *
- * <p>Using this constructor, an initial osculating orbit is considered.</p>
- *
- * @param initialOrbit initial orbit
- * @param referenceRadius reference radius of the Earth for the potential model (m)
- * @param mu central attraction coefficient (m³/s²)
- * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
- * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
- * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
- * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
- * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
- * @see org.orekit.utils.Constants
- * @see #EcksteinHechlerPropagator(Orbit, AttitudeProvider, double, double, double,
- * double, double, double, double, double)
- */
- public EcksteinHechlerPropagator(final Orbit initialOrbit,
- final double referenceRadius, final double mu,
- final double c20, final double c30, final double c40,
- final double c50, final double c60) {
- this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
- DEFAULT_MASS, referenceRadius, mu, c20, c30, c40, c50, c60);
- }
- /** Build a propagator from orbit, mass and potential provider.
- * <p>Attitude law is set to an unspecified non-null arbitrary value.</p>
- *
- * <p>Using this constructor, an initial osculating orbit is considered.</p>
- *
- * @param initialOrbit initial orbit
- * @param mass spacecraft mass
- * @param provider for un-normalized zonal coefficients
- * @see #EcksteinHechlerPropagator(Orbit, AttitudeProvider, double,
- * UnnormalizedSphericalHarmonicsProvider)
- */
- public EcksteinHechlerPropagator(final Orbit initialOrbit, final double mass,
- final UnnormalizedSphericalHarmonicsProvider provider) {
- this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
- mass, provider, provider.onDate(initialOrbit.getDate()));
- }
- /** Build a propagator from orbit, mass and potential.
- * <p>Attitude law is set to an unspecified non-null arbitrary value.</p>
- * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
- * are related to both the normalized coefficients
- * <span style="text-decoration: overline">C</span><sub>n,0</sub>
- * and the J<sub>n</sub> one as follows:</p>
- *
- * <p> C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
- * <span style="text-decoration: overline">C</span><sub>n,0</sub>
- *
- * <p> C<sub>n,0</sub> = -J<sub>n</sub>
- *
- * <p>Using this constructor, an initial osculating orbit is considered.</p>
- *
- * @param initialOrbit initial orbit
- * @param mass spacecraft mass
- * @param referenceRadius reference radius of the Earth for the potential model (m)
- * @param mu central attraction coefficient (m³/s²)
- * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
- * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
- * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
- * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
- * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
- * @see #EcksteinHechlerPropagator(Orbit, AttitudeProvider, double, double, double,
- * double, double, double, double, double)
- */
- public EcksteinHechlerPropagator(final Orbit initialOrbit, final double mass,
- final double referenceRadius, final double mu,
- final double c20, final double c30, final double c40,
- final double c50, final double c60) {
- this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
- mass, referenceRadius, mu, c20, c30, c40, c50, c60);
- }
- /** Build a propagator from orbit, attitude provider and potential provider.
- * <p>Mass is set to an unspecified non-null arbitrary value.</p>
- * <p>Using this constructor, an initial osculating orbit is considered.</p>
- * @param initialOrbit initial orbit
- * @param attitudeProv attitude provider
- * @param provider for un-normalized zonal coefficients
- */
- public EcksteinHechlerPropagator(final Orbit initialOrbit,
- final AttitudeProvider attitudeProv,
- final UnnormalizedSphericalHarmonicsProvider provider) {
- this(initialOrbit, attitudeProv, DEFAULT_MASS, provider, provider.onDate(initialOrbit.getDate()));
- }
- /** Build a propagator from orbit, attitude provider and potential.
- * <p>Mass is set to an unspecified non-null arbitrary value.</p>
- * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
- * are related to both the normalized coefficients
- * <span style="text-decoration: overline">C</span><sub>n,0</sub>
- * and the J<sub>n</sub> one as follows:</p>
- *
- * <p> C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
- * <span style="text-decoration: overline">C</span><sub>n,0</sub>
- *
- * <p> C<sub>n,0</sub> = -J<sub>n</sub>
- *
- * <p>Using this constructor, an initial osculating orbit is considered.</p>
- *
- * @param initialOrbit initial orbit
- * @param attitudeProv attitude provider
- * @param referenceRadius reference radius of the Earth for the potential model (m)
- * @param mu central attraction coefficient (m³/s²)
- * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
- * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
- * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
- * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
- * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
- */
- public EcksteinHechlerPropagator(final Orbit initialOrbit,
- final AttitudeProvider attitudeProv,
- final double referenceRadius, final double mu,
- final double c20, final double c30, final double c40,
- final double c50, final double c60) {
- this(initialOrbit, attitudeProv, DEFAULT_MASS, referenceRadius, mu, c20, c30, c40, c50, c60);
- }
- /** Build a propagator from orbit, attitude provider, mass and potential provider.
- * <p>Using this constructor, an initial osculating orbit is considered.</p>
- * @param initialOrbit initial orbit
- * @param attitudeProv attitude provider
- * @param mass spacecraft mass
- * @param provider for un-normalized zonal coefficients
- * @see #EcksteinHechlerPropagator(Orbit, AttitudeProvider, double,
- * UnnormalizedSphericalHarmonicsProvider, PropagationType)
- */
- public EcksteinHechlerPropagator(final Orbit initialOrbit,
- final AttitudeProvider attitudeProv,
- final double mass,
- final UnnormalizedSphericalHarmonicsProvider provider) {
- this(initialOrbit, attitudeProv, mass, provider, provider.onDate(initialOrbit.getDate()));
- }
- /** Build a propagator from orbit, attitude provider, mass and potential.
- * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
- * are related to both the normalized coefficients
- * <span style="text-decoration: overline">C</span><sub>n,0</sub>
- * and the J<sub>n</sub> one as follows:</p>
- *
- * <p> C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
- * <span style="text-decoration: overline">C</span><sub>n,0</sub>
- *
- * <p> C<sub>n,0</sub> = -J<sub>n</sub>
- *
- * <p>Using this constructor, an initial osculating orbit is considered.</p>
- *
- * @param initialOrbit initial orbit
- * @param attitudeProv attitude provider
- * @param mass spacecraft mass
- * @param referenceRadius reference radius of the Earth for the potential model (m)
- * @param mu central attraction coefficient (m³/s²)
- * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
- * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
- * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
- * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
- * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
- * @see #EcksteinHechlerPropagator(Orbit, AttitudeProvider, double, double, double,
- * double, double, double, double, double, PropagationType)
- */
- public EcksteinHechlerPropagator(final Orbit initialOrbit,
- final AttitudeProvider attitudeProv,
- final double mass,
- final double referenceRadius, final double mu,
- final double c20, final double c30, final double c40,
- final double c50, final double c60) {
- this(initialOrbit, attitudeProv, mass, referenceRadius, mu, c20, c30, c40, c50, c60,
- PropagationType.OSCULATING);
- }
- /** Build a propagator from orbit and potential provider.
- * <p>Mass and attitude provider are set to unspecified non-null arbitrary values.</p>
- *
- * <p>Using this constructor, it is possible to define the initial orbit as
- * a mean Eckstein-Hechler orbit or an osculating one.</p>
- *
- * @param initialOrbit initial orbit
- * @param provider for un-normalized zonal coefficients
- * @param initialType initial orbit type (mean Eckstein-Hechler orbit or osculating orbit)
- * @since 10.2
- */
- public EcksteinHechlerPropagator(final Orbit initialOrbit,
- final UnnormalizedSphericalHarmonicsProvider provider,
- final PropagationType initialType) {
- this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
- DEFAULT_MASS, provider, provider.onDate(initialOrbit.getDate()), initialType);
- }
- /** Build a propagator from orbit, attitude provider, mass and potential provider.
- * <p>Using this constructor, it is possible to define the initial orbit as
- * a mean Eckstein-Hechler orbit or an osculating one.</p>
- * @param initialOrbit initial orbit
- * @param attitudeProv attitude provider
- * @param mass spacecraft mass
- * @param provider for un-normalized zonal coefficients
- * @param initialType initial orbit type (mean Eckstein-Hechler orbit or osculating orbit)
- * @since 10.2
- */
- public EcksteinHechlerPropagator(final Orbit initialOrbit,
- final AttitudeProvider attitudeProv,
- final double mass,
- final UnnormalizedSphericalHarmonicsProvider provider,
- final PropagationType initialType) {
- this(initialOrbit, attitudeProv, mass, provider, provider.onDate(initialOrbit.getDate()), initialType);
- }
- /**
- * Private helper constructor.
- * <p>Using this constructor, it is possible to define the initial orbit as
- * a mean Eckstein-Hechler orbit or an osculating one.</p>
- * @param initialOrbit initial orbit
- * @param attitude attitude provider
- * @param mass spacecraft mass
- * @param provider for un-normalized zonal coefficients
- * @param harmonics {@code provider.onDate(initialOrbit.getDate())}
- * @param initialType initial orbit type (mean Eckstein-Hechler orbit or osculating orbit)
- * @since 10.2
- */
- public EcksteinHechlerPropagator(final Orbit initialOrbit,
- final AttitudeProvider attitude,
- final double mass,
- final UnnormalizedSphericalHarmonicsProvider provider,
- final UnnormalizedSphericalHarmonics harmonics,
- final PropagationType initialType) {
- this(initialOrbit, attitude, mass, provider.getAe(), provider.getMu(),
- harmonics.getUnnormalizedCnm(2, 0),
- harmonics.getUnnormalizedCnm(3, 0),
- harmonics.getUnnormalizedCnm(4, 0),
- harmonics.getUnnormalizedCnm(5, 0),
- harmonics.getUnnormalizedCnm(6, 0),
- initialType);
- }
- /** Build a propagator from orbit, attitude provider, mass and potential.
- * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
- * are related to both the normalized coefficients
- * <span style="text-decoration: overline">C</span><sub>n,0</sub>
- * and the J<sub>n</sub> one as follows:</p>
- *
- * <p> C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
- * <span style="text-decoration: overline">C</span><sub>n,0</sub>
- *
- * <p> C<sub>n,0</sub> = -J<sub>n</sub>
- *
- * <p>Using this constructor, it is possible to define the initial orbit as
- * a mean Eckstein-Hechler orbit or an osculating one.</p>
- *
- * @param initialOrbit initial orbit
- * @param attitudeProv attitude provider
- * @param mass spacecraft mass
- * @param referenceRadius reference radius of the Earth for the potential model (m)
- * @param mu central attraction coefficient (m³/s²)
- * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
- * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
- * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
- * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
- * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
- * @param initialType initial orbit type (mean Eckstein-Hechler orbit or osculating orbit)
- * @since 10.2
- */
- public EcksteinHechlerPropagator(final Orbit initialOrbit,
- final AttitudeProvider attitudeProv,
- final double mass,
- final double referenceRadius, final double mu,
- final double c20, final double c30, final double c40,
- final double c50, final double c60,
- final PropagationType initialType) {
- this(initialOrbit, attitudeProv, mass, referenceRadius, mu,
- c20, c30, c40, c50, c60, initialType, EPSILON_DEFAULT, MAX_ITERATIONS_DEFAULT);
- }
- /** Build a propagator from orbit, attitude provider, mass and potential.
- * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
- * are related to both the normalized coefficients
- * <span style="text-decoration: overline">C</span><sub>n,0</sub>
- * and the J<sub>n</sub> one as follows:</p>
- *
- * <p> C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
- * <span style="text-decoration: overline">C</span><sub>n,0</sub>
- *
- * <p> C<sub>n,0</sub> = -J<sub>n</sub>
- *
- * <p>Using this constructor, it is possible to define the initial orbit as
- * a mean Eckstein-Hechler orbit or an osculating one.</p>
- *
- * @param initialOrbit initial orbit
- * @param attitudeProv attitude provider
- * @param mass spacecraft mass
- * @param referenceRadius reference radius of the Earth for the potential model (m)
- * @param mu central attraction coefficient (m³/s²)
- * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
- * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
- * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
- * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
- * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
- * @param epsilon convergence threshold for mean parameters conversion
- * @param maxIterations maximum iterations for mean parameters conversion
- * @param initialType initial orbit type (mean Eckstein-Hechler orbit or osculating orbit)
- * @since 11.2
- */
- public EcksteinHechlerPropagator(final Orbit initialOrbit,
- final AttitudeProvider attitudeProv,
- final double mass,
- final double referenceRadius, final double mu,
- final double c20, final double c30, final double c40,
- final double c50, final double c60,
- final PropagationType initialType,
- final double epsilon, final int maxIterations) {
- super(attitudeProv);
- // store model coefficients
- this.referenceRadius = referenceRadius;
- this.mu = mu;
- this.ck0 = new double[] {
- 0.0, 0.0, c20, c30, c40, c50, c60
- };
- // compute mean parameters if needed
- // transform into circular adapted parameters used by the Eckstein-Hechler model
- resetInitialState(new SpacecraftState(initialOrbit,
- attitudeProv.getAttitude(initialOrbit,
- initialOrbit.getDate(),
- initialOrbit.getFrame()),
- mass),
- initialType, epsilon, maxIterations);
- }
- /** Conversion from osculating to mean orbit.
- * <p>
- * Compute mean orbit <b>in a Eckstein-Hechler sense</b>, corresponding to the
- * osculating SpacecraftState in input.
- * </p>
- * <p>
- * Since the osculating orbit is obtained with the computation of
- * short-periodic variation, the resulting output will depend on
- * the gravity field parameterized in input.
- * </p>
- * <p>
- * The computation is done through a fixed-point iteration process.
- * </p>
- * @param osculating osculating orbit to convert
- * @param provider for un-normalized zonal coefficients
- * @param harmonics {@code provider.onDate(osculating.getDate())}
- * @return mean orbit in a Eckstein-Hechler sense
- * @since 11.2
- */
- public static CircularOrbit computeMeanOrbit(final Orbit osculating,
- final UnnormalizedSphericalHarmonicsProvider provider,
- final UnnormalizedSphericalHarmonics harmonics) {
- return computeMeanOrbit(osculating, provider, harmonics, EPSILON_DEFAULT, MAX_ITERATIONS_DEFAULT);
- }
- /** Conversion from osculating to mean orbit.
- * <p>
- * Compute mean orbit <b>in a Eckstein-Hechler sense</b>, corresponding to the
- * osculating SpacecraftState in input.
- * </p>
- * <p>
- * Since the osculating orbit is obtained with the computation of
- * short-periodic variation, the resulting output will depend on
- * the gravity field parameterized in input.
- * </p>
- * <p>
- * The computation is done through a fixed-point iteration process.
- * </p>
- * @param osculating osculating orbit to convert
- * @param provider for un-normalized zonal coefficients
- * @param harmonics {@code provider.onDate(osculating.getDate())}
- * @param epsilon convergence threshold for mean parameters conversion
- * @param maxIterations maximum iterations for mean parameters conversion
- * @return mean orbit in a Eckstein-Hechler sense
- * @since 11.2
- */
- public static CircularOrbit computeMeanOrbit(final Orbit osculating,
- final UnnormalizedSphericalHarmonicsProvider provider,
- final UnnormalizedSphericalHarmonics harmonics,
- final double epsilon, final int maxIterations) {
- return computeMeanOrbit(osculating,
- provider.getAe(), provider.getMu(),
- harmonics.getUnnormalizedCnm(2, 0),
- harmonics.getUnnormalizedCnm(3, 0),
- harmonics.getUnnormalizedCnm(4, 0),
- harmonics.getUnnormalizedCnm(5, 0),
- harmonics.getUnnormalizedCnm(6, 0),
- epsilon, maxIterations);
- }
- /** Conversion from osculating to mean orbit.
- * <p>
- * Compute mean orbit <b>in a Eckstein-Hechler sense</b>, corresponding to the
- * osculating SpacecraftState in input.
- * </p>
- * <p>
- * Since the osculating orbit is obtained with the computation of
- * short-periodic variation, the resulting output will depend on
- * the gravity field parameterized in input.
- * </p>
- * <p>
- * The computation is done through a fixed-point iteration process.
- * </p>
- * @param osculating osculating orbit to convert
- * @param referenceRadius reference radius of the Earth for the potential model (m)
- * @param mu central attraction coefficient (m³/s²)
- * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
- * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
- * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
- * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
- * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
- * @param epsilon convergence threshold for mean parameters conversion
- * @param maxIterations maximum iterations for mean parameters conversion
- * @return mean orbit in a Eckstein-Hechler sense
- * @since 11.2
- */
- public static CircularOrbit computeMeanOrbit(final Orbit osculating,
- final double referenceRadius, final double mu,
- final double c20, final double c30, final double c40,
- final double c50, final double c60,
- final double epsilon, final int maxIterations) {
- final EcksteinHechlerPropagator propagator =
- new EcksteinHechlerPropagator(osculating,
- FrameAlignedProvider.of(osculating.getFrame()),
- DEFAULT_MASS,
- referenceRadius, mu, c20, c30, c40, c50, c60,
- PropagationType.OSCULATING, epsilon, maxIterations);
- return propagator.initialModel.mean;
- }
- /** {@inheritDoc}
- * <p>The new initial state to consider
- * must be defined with an osculating orbit.</p>
- * @see #resetInitialState(SpacecraftState, PropagationType)
- */
- public void resetInitialState(final SpacecraftState state) {
- resetInitialState(state, PropagationType.OSCULATING);
- }
- /** Reset the propagator initial state.
- * @param state new initial state to consider
- * @param stateType mean Eckstein-Hechler orbit or osculating orbit
- * @since 10.2
- */
- public void resetInitialState(final SpacecraftState state, final PropagationType stateType) {
- resetInitialState(state, stateType, EPSILON_DEFAULT, MAX_ITERATIONS_DEFAULT);
- }
- /** Reset the propagator initial state.
- * @param state new initial state to consider
- * @param stateType mean Eckstein-Hechler orbit or osculating orbit
- * @param epsilon convergence threshold for mean parameters conversion
- * @param maxIterations maximum iterations for mean parameters conversion
- * @since 11.2
- */
- public void resetInitialState(final SpacecraftState state, final PropagationType stateType,
- final double epsilon, final int maxIterations) {
- super.resetInitialState(state);
- final CircularOrbit circular = (CircularOrbit) OrbitType.CIRCULAR.convertType(state.getOrbit());
- this.initialModel = (stateType == PropagationType.MEAN) ?
- new EHModel(circular, state.getMass(), referenceRadius, mu, ck0) :
- computeMeanParameters(circular, state.getMass(), epsilon, maxIterations);
- this.models = new TimeSpanMap<EHModel>(initialModel);
- }
- /** {@inheritDoc} */
- protected void resetIntermediateState(final SpacecraftState state, final boolean forward) {
- resetIntermediateState(state, forward, EPSILON_DEFAULT, MAX_ITERATIONS_DEFAULT);
- }
- /** Reset an intermediate state.
- * @param state new intermediate state to consider
- * @param forward if true, the intermediate state is valid for
- * propagations after itself
- * @param epsilon convergence threshold for mean parameters conversion
- * @param maxIterations maximum iterations for mean parameters conversion
- * @since 11.2
- */
- protected void resetIntermediateState(final SpacecraftState state, final boolean forward,
- final double epsilon, final int maxIterations) {
- final EHModel newModel = computeMeanParameters((CircularOrbit) OrbitType.CIRCULAR.convertType(state.getOrbit()),
- state.getMass(), epsilon, maxIterations);
- if (forward) {
- models.addValidAfter(newModel, state.getDate(), false);
- } else {
- models.addValidBefore(newModel, state.getDate(), false);
- }
- stateChanged(state);
- }
- /** Compute mean parameters according to the Eckstein-Hechler analytical model.
- * @param osculating osculating orbit
- * @param mass constant mass
- * @param epsilon convergence threshold for mean parameters conversion
- * @param maxIterations maximum iterations for mean parameters conversion
- * @return Eckstein-Hechler mean model
- */
- private EHModel computeMeanParameters(final CircularOrbit osculating, final double mass,
- final double epsilon, final int maxIterations) {
- // sanity check
- if (osculating.getA() < referenceRadius) {
- throw new OrekitException(OrekitMessages.TRAJECTORY_INSIDE_BRILLOUIN_SPHERE,
- osculating.getA());
- }
- // rough initialization of the mean parameters
- EHModel current = new EHModel(osculating, mass, referenceRadius, mu, ck0);
- // threshold for each parameter
- final double thresholdA = epsilon * (1 + FastMath.abs(current.mean.getA()));
- final double thresholdE = epsilon * (1 + current.mean.getE());
- final double thresholdAngles = epsilon * MathUtils.TWO_PI;
- int i = 0;
- while (i++ < maxIterations) {
- // recompute the osculating parameters from the current mean parameters
- final UnivariateDerivative2[] parameters = current.propagateParameters(current.mean.getDate());
- // adapted parameters residuals
- final double deltaA = osculating.getA() - parameters[0].getValue();
- final double deltaEx = osculating.getCircularEx() - parameters[1].getValue();
- final double deltaEy = osculating.getCircularEy() - parameters[2].getValue();
- final double deltaI = osculating.getI() - parameters[3].getValue();
- final double deltaRAAN = MathUtils.normalizeAngle(osculating.getRightAscensionOfAscendingNode() -
- parameters[4].getValue(),
- 0.0);
- final double deltaAlphaM = MathUtils.normalizeAngle(osculating.getAlphaM() - parameters[5].getValue(), 0.0);
- // update mean parameters
- current = new EHModel(new CircularOrbit(current.mean.getA() + deltaA,
- current.mean.getCircularEx() + deltaEx,
- current.mean.getCircularEy() + deltaEy,
- current.mean.getI() + deltaI,
- current.mean.getRightAscensionOfAscendingNode() + deltaRAAN,
- current.mean.getAlphaM() + deltaAlphaM,
- PositionAngleType.MEAN,
- current.mean.getFrame(),
- current.mean.getDate(), mu),
- mass, referenceRadius, mu, ck0);
- // check convergence
- if (FastMath.abs(deltaA) < thresholdA &&
- FastMath.abs(deltaEx) < thresholdE &&
- FastMath.abs(deltaEy) < thresholdE &&
- FastMath.abs(deltaI) < thresholdAngles &&
- FastMath.abs(deltaRAAN) < thresholdAngles &&
- FastMath.abs(deltaAlphaM) < thresholdAngles) {
- return current;
- }
- }
- throw new OrekitException(OrekitMessages.UNABLE_TO_COMPUTE_ECKSTEIN_HECHLER_MEAN_PARAMETERS, i);
- }
- /** {@inheritDoc} */
- public CartesianOrbit propagateOrbit(final AbsoluteDate date) {
- // compute Cartesian parameters, taking derivatives into account
- // to make sure velocity and acceleration are consistent
- final EHModel current = models.get(date);
- return new CartesianOrbit(toCartesian(date, current.propagateParameters(date)),
- current.mean.getFrame(), mu);
- }
- /**
- * Get the central attraction coefficient μ.
- * @return mu central attraction coefficient (m³/s²)
- * @since 11.1
- */
- public double getMu() {
- return mu;
- }
- /**
- * Get the un-normalized zonal coefficients.
- * @return the un-normalized zonal coefficients
- * @since 11.1
- */
- public double[] getCk0() {
- return ck0.clone();
- }
- /**
- * Get the reference radius of the central body attraction model.
- * @return the reference radius in meters
- * @since 11.1
- */
- public double getReferenceRadius() {
- return referenceRadius;
- }
- /** {@inheritDoc} */
- @Override
- protected AbstractMatricesHarvester createHarvester(final String stmName, final RealMatrix initialStm,
- final DoubleArrayDictionary initialJacobianColumns) {
- // Create the harvester
- final EcksteinHechlerHarvester harvester = new EcksteinHechlerHarvester(this, stmName, initialStm, initialJacobianColumns);
- // Update the list of additional state provider
- addAdditionalStateProvider(harvester);
- // Return the configured harvester
- return harvester;
- }
- /** Local class for Eckstein-Hechler model, with fixed mean parameters. */
- private static class EHModel implements Serializable {
- /** Serializable UID. */
- private static final long serialVersionUID = 20160115L;
- /** Mean orbit. */
- private final CircularOrbit mean;
- /** Constant mass. */
- private final double mass;
- // CHECKSTYLE: stop JavadocVariable check
- // preprocessed values
- private final double xnotDot;
- private final double rdpom;
- private final double rdpomp;
- private final double eps1;
- private final double eps2;
- private final double xim;
- private final double ommD;
- private final double rdl;
- private final double aMD;
- private final double kh;
- private final double kl;
- private final double ax1;
- private final double ay1;
- private final double as1;
- private final double ac2;
- private final double axy3;
- private final double as3;
- private final double ac4;
- private final double as5;
- private final double ac6;
- private final double ex1;
- private final double exx2;
- private final double exy2;
- private final double ex3;
- private final double ex4;
- private final double ey1;
- private final double eyx2;
- private final double eyy2;
- private final double ey3;
- private final double ey4;
- private final double rx1;
- private final double ry1;
- private final double r2;
- private final double r3;
- private final double rl;
- private final double iy1;
- private final double ix1;
- private final double i2;
- private final double i3;
- private final double ih;
- private final double lx1;
- private final double ly1;
- private final double l2;
- private final double l3;
- private final double ll;
- // CHECKSTYLE: resume JavadocVariable check
- /** Create a model for specified mean orbit.
- * @param mean mean orbit
- * @param mass constant mass
- * @param referenceRadius reference radius of the central body attraction model (m)
- * @param mu central attraction coefficient (m³/s²)
- * @param ck0 un-normalized zonal coefficients
- */
- EHModel(final CircularOrbit mean, final double mass,
- final double referenceRadius, final double mu, final double[] ck0) {
- this.mean = mean;
- this.mass = mass;
- // preliminary processing
- double q = referenceRadius / mean.getA();
- double ql = q * q;
- final double g2 = ck0[2] * ql;
- ql *= q;
- final double g3 = ck0[3] * ql;
- ql *= q;
- final double g4 = ck0[4] * ql;
- ql *= q;
- final double g5 = ck0[5] * ql;
- ql *= q;
- final double g6 = ck0[6] * ql;
- final SinCos sc = FastMath.sinCos(mean.getI());
- final double cosI1 = sc.cos();
- final double sinI1 = sc.sin();
- final double sinI2 = sinI1 * sinI1;
- final double sinI4 = sinI2 * sinI2;
- final double sinI6 = sinI2 * sinI4;
- if (sinI2 < 1.0e-10) {
- throw new OrekitException(OrekitMessages.ALMOST_EQUATORIAL_ORBIT,
- FastMath.toDegrees(mean.getI()));
- }
- if (FastMath.abs(sinI2 - 4.0 / 5.0) < 1.0e-3) {
- throw new OrekitException(OrekitMessages.ALMOST_CRITICALLY_INCLINED_ORBIT,
- FastMath.toDegrees(mean.getI()));
- }
- if (mean.getE() > 0.1) {
- // if 0.005 < e < 0.1 no error is triggered, but accuracy is poor
- throw new OrekitException(OrekitMessages.TOO_LARGE_ECCENTRICITY_FOR_PROPAGATION_MODEL,
- mean.getE());
- }
- xnotDot = FastMath.sqrt(mu / mean.getA()) / mean.getA();
- rdpom = -0.75 * g2 * (4.0 - 5.0 * sinI2);
- rdpomp = 7.5 * g4 * (1.0 - 31.0 / 8.0 * sinI2 + 49.0 / 16.0 * sinI4) -
- 13.125 * g6 * (1.0 - 8.0 * sinI2 + 129.0 / 8.0 * sinI4 - 297.0 / 32.0 * sinI6);
- q = 3.0 / (32.0 * rdpom);
- eps1 = q * g4 * sinI2 * (30.0 - 35.0 * sinI2) -
- 175.0 * q * g6 * sinI2 * (1.0 - 3.0 * sinI2 + 2.0625 * sinI4);
- q = 3.0 * sinI1 / (8.0 * rdpom);
- eps2 = q * g3 * (4.0 - 5.0 * sinI2) - q * g5 * (10.0 - 35.0 * sinI2 + 26.25 * sinI4);
- xim = mean.getI();
- ommD = cosI1 * (1.50 * g2 - 2.25 * g2 * g2 * (2.5 - 19.0 / 6.0 * sinI2) +
- 0.9375 * g4 * (7.0 * sinI2 - 4.0) +
- 3.28125 * g6 * (2.0 - 9.0 * sinI2 + 8.25 * sinI4));
- rdl = 1.0 - 1.50 * g2 * (3.0 - 4.0 * sinI2);
- aMD = rdl +
- 2.25 * g2 * g2 * (9.0 - 263.0 / 12.0 * sinI2 + 341.0 / 24.0 * sinI4) +
- 15.0 / 16.0 * g4 * (8.0 - 31.0 * sinI2 + 24.5 * sinI4) +
- 105.0 / 32.0 * g6 * (-10.0 / 3.0 + 25.0 * sinI2 - 48.75 * sinI4 + 27.5 * sinI6);
- final double qq = -1.5 * g2 / rdl;
- final double qA = 0.75 * g2 * g2 * sinI2;
- final double qB = 0.25 * g4 * sinI2;
- final double qC = 105.0 / 16.0 * g6 * sinI2;
- final double qD = -0.75 * g3 * sinI1;
- final double qE = 3.75 * g5 * sinI1;
- kh = 0.375 / rdpom;
- kl = kh / sinI1;
- ax1 = qq * (2.0 - 3.5 * sinI2);
- ay1 = qq * (2.0 - 2.5 * sinI2);
- as1 = qD * (4.0 - 5.0 * sinI2) +
- qE * (2.625 * sinI4 - 3.5 * sinI2 + 1.0);
- ac2 = qq * sinI2 +
- qA * 7.0 * (2.0 - 3.0 * sinI2) +
- qB * (15.0 - 17.5 * sinI2) +
- qC * (3.0 * sinI2 - 1.0 - 33.0 / 16.0 * sinI4);
- axy3 = qq * 3.5 * sinI2;
- as3 = qD * 5.0 / 3.0 * sinI2 +
- qE * 7.0 / 6.0 * sinI2 * (1.0 - 1.125 * sinI2);
- ac4 = qA * sinI2 +
- qB * 4.375 * sinI2 +
- qC * 0.75 * (1.1 * sinI4 - sinI2);
- as5 = qE * 21.0 / 80.0 * sinI4;
- ac6 = qC * -11.0 / 80.0 * sinI4;
- ex1 = qq * (1.0 - 1.25 * sinI2);
- exx2 = qq * 0.5 * (3.0 - 5.0 * sinI2);
- exy2 = qq * (2.0 - 1.5 * sinI2);
- ex3 = qq * 7.0 / 12.0 * sinI2;
- ex4 = qq * 17.0 / 8.0 * sinI2;
- ey1 = qq * (1.0 - 1.75 * sinI2);
- eyx2 = qq * (1.0 - 3.0 * sinI2);
- eyy2 = qq * (2.0 * sinI2 - 1.5);
- ey3 = qq * 7.0 / 12.0 * sinI2;
- ey4 = qq * 17.0 / 8.0 * sinI2;
- q = -qq * cosI1;
- rx1 = 3.5 * q;
- ry1 = -2.5 * q;
- r2 = -0.5 * q;
- r3 = 7.0 / 6.0 * q;
- rl = g3 * cosI1 * (4.0 - 15.0 * sinI2) -
- 2.5 * g5 * cosI1 * (4.0 - 42.0 * sinI2 + 52.5 * sinI4);
- q = 0.5 * qq * sinI1 * cosI1;
- iy1 = q;
- ix1 = -q;
- i2 = q;
- i3 = q * 7.0 / 3.0;
- ih = -g3 * cosI1 * (4.0 - 5.0 * sinI2) +
- 2.5 * g5 * cosI1 * (4.0 - 14.0 * sinI2 + 10.5 * sinI4);
- lx1 = qq * (7.0 - 77.0 / 8.0 * sinI2);
- ly1 = qq * (55.0 / 8.0 * sinI2 - 7.50);
- l2 = qq * (1.25 * sinI2 - 0.5);
- l3 = qq * (77.0 / 24.0 * sinI2 - 7.0 / 6.0);
- ll = g3 * (53.0 * sinI2 - 4.0 - 57.5 * sinI4) +
- 2.5 * g5 * (4.0 - 96.0 * sinI2 + 269.5 * sinI4 - 183.75 * sinI6);
- }
- /** Extrapolate an orbit up to a specific target date.
- * @param date target date for the orbit
- * @return propagated parameters
- */
- public UnivariateDerivative2[] propagateParameters(final AbsoluteDate date) {
- // Keplerian evolution
- final UnivariateDerivative2 dt = new UnivariateDerivative2(date.durationFrom(mean.getDate()), 1.0, 0.0);
- final UnivariateDerivative2 xnot = dt.multiply(xnotDot);
- // secular effects
- // eccentricity
- final UnivariateDerivative2 x = xnot.multiply(rdpom + rdpomp);
- final UnivariateDerivative2 cx = x.cos();
- final UnivariateDerivative2 sx = x.sin();
- final UnivariateDerivative2 exm = cx.multiply(mean.getCircularEx()).
- add(sx.multiply(eps2 - (1.0 - eps1) * mean.getCircularEy()));
- final UnivariateDerivative2 eym = sx.multiply((1.0 + eps1) * mean.getCircularEx()).
- add(cx.multiply(mean.getCircularEy() - eps2)).
- add(eps2);
- // no secular effect on inclination
- // right ascension of ascending node
- final UnivariateDerivative2 omm = new UnivariateDerivative2(MathUtils.normalizeAngle(mean.getRightAscensionOfAscendingNode() + ommD * xnot.getValue(),
- FastMath.PI),
- ommD * xnotDot,
- 0.0);
- // latitude argument
- final UnivariateDerivative2 xlm = new UnivariateDerivative2(MathUtils.normalizeAngle(mean.getAlphaM() + aMD * xnot.getValue(),
- FastMath.PI),
- aMD * xnotDot,
- 0.0);
- // periodical terms
- final UnivariateDerivative2 cl1 = xlm.cos();
- final UnivariateDerivative2 sl1 = xlm.sin();
- final UnivariateDerivative2 cl2 = cl1.multiply(cl1).subtract(sl1.multiply(sl1));
- final UnivariateDerivative2 sl2 = cl1.multiply(sl1).add(sl1.multiply(cl1));
- final UnivariateDerivative2 cl3 = cl2.multiply(cl1).subtract(sl2.multiply(sl1));
- final UnivariateDerivative2 sl3 = cl2.multiply(sl1).add(sl2.multiply(cl1));
- final UnivariateDerivative2 cl4 = cl3.multiply(cl1).subtract(sl3.multiply(sl1));
- final UnivariateDerivative2 sl4 = cl3.multiply(sl1).add(sl3.multiply(cl1));
- final UnivariateDerivative2 cl5 = cl4.multiply(cl1).subtract(sl4.multiply(sl1));
- final UnivariateDerivative2 sl5 = cl4.multiply(sl1).add(sl4.multiply(cl1));
- final UnivariateDerivative2 cl6 = cl5.multiply(cl1).subtract(sl5.multiply(sl1));
- final UnivariateDerivative2 qh = eym.subtract(eps2).multiply(kh);
- final UnivariateDerivative2 ql = exm.multiply(kl);
- final UnivariateDerivative2 exmCl1 = exm.multiply(cl1);
- final UnivariateDerivative2 exmSl1 = exm.multiply(sl1);
- final UnivariateDerivative2 eymCl1 = eym.multiply(cl1);
- final UnivariateDerivative2 eymSl1 = eym.multiply(sl1);
- final UnivariateDerivative2 exmCl2 = exm.multiply(cl2);
- final UnivariateDerivative2 exmSl2 = exm.multiply(sl2);
- final UnivariateDerivative2 eymCl2 = eym.multiply(cl2);
- final UnivariateDerivative2 eymSl2 = eym.multiply(sl2);
- final UnivariateDerivative2 exmCl3 = exm.multiply(cl3);
- final UnivariateDerivative2 exmSl3 = exm.multiply(sl3);
- final UnivariateDerivative2 eymCl3 = eym.multiply(cl3);
- final UnivariateDerivative2 eymSl3 = eym.multiply(sl3);
- final UnivariateDerivative2 exmCl4 = exm.multiply(cl4);
- final UnivariateDerivative2 exmSl4 = exm.multiply(sl4);
- final UnivariateDerivative2 eymCl4 = eym.multiply(cl4);
- final UnivariateDerivative2 eymSl4 = eym.multiply(sl4);
- // semi major axis
- final UnivariateDerivative2 rda = exmCl1.multiply(ax1).
- add(eymSl1.multiply(ay1)).
- add(sl1.multiply(as1)).
- add(cl2.multiply(ac2)).
- add(exmCl3.add(eymSl3).multiply(axy3)).
- add(sl3.multiply(as3)).
- add(cl4.multiply(ac4)).
- add(sl5.multiply(as5)).
- add(cl6.multiply(ac6));
- // eccentricity
- final UnivariateDerivative2 rdex = cl1.multiply(ex1).
- add(exmCl2.multiply(exx2)).
- add(eymSl2.multiply(exy2)).
- add(cl3.multiply(ex3)).
- add(exmCl4.add(eymSl4).multiply(ex4));
- final UnivariateDerivative2 rdey = sl1.multiply(ey1).
- add(exmSl2.multiply(eyx2)).
- add(eymCl2.multiply(eyy2)).
- add(sl3.multiply(ey3)).
- add(exmSl4.subtract(eymCl4).multiply(ey4));
- // ascending node
- final UnivariateDerivative2 rdom = exmSl1.multiply(rx1).
- add(eymCl1.multiply(ry1)).
- add(sl2.multiply(r2)).
- add(eymCl3.subtract(exmSl3).multiply(r3)).
- add(ql.multiply(rl));
- // inclination
- final UnivariateDerivative2 rdxi = eymSl1.multiply(iy1).
- add(exmCl1.multiply(ix1)).
- add(cl2.multiply(i2)).
- add(exmCl3.add(eymSl3).multiply(i3)).
- add(qh.multiply(ih));
- // latitude argument
- final UnivariateDerivative2 rdxl = exmSl1.multiply(lx1).
- add(eymCl1.multiply(ly1)).
- add(sl2.multiply(l2)).
- add(exmSl3.subtract(eymCl3).multiply(l3)).
- add(ql.multiply(ll));
- // osculating parameters
- return new UnivariateDerivative2[] {
- rda.add(1.0).multiply(mean.getA()),
- rdex.add(exm),
- rdey.add(eym),
- rdxi.add(xim),
- rdom.add(omm),
- rdxl.add(xlm)
- };
- }
- }
- /** Convert circular parameters <em>with derivatives</em> to Cartesian coordinates.
- * @param date date of the orbital parameters
- * @param parameters circular parameters (a, ex, ey, i, raan, alphaM)
- * @return Cartesian coordinates consistent with values and derivatives
- */
- private TimeStampedPVCoordinates toCartesian(final AbsoluteDate date, final UnivariateDerivative2[] parameters) {
- // evaluate coordinates in the orbit canonical reference frame
- final UnivariateDerivative2 cosOmega = parameters[4].cos();
- final UnivariateDerivative2 sinOmega = parameters[4].sin();
- final UnivariateDerivative2 cosI = parameters[3].cos();
- final UnivariateDerivative2 sinI = parameters[3].sin();
- final UnivariateDerivative2 alphaE = meanToEccentric(parameters[5], parameters[1], parameters[2]);
- final UnivariateDerivative2 cosAE = alphaE.cos();
- final UnivariateDerivative2 sinAE = alphaE.sin();
- final UnivariateDerivative2 ex2 = parameters[1].square();
- final UnivariateDerivative2 ey2 = parameters[2].square();
- final UnivariateDerivative2 exy = parameters[1].multiply(parameters[2]);
- final UnivariateDerivative2 q = ex2.add(ey2).subtract(1).negate().sqrt();
- final UnivariateDerivative2 beta = q.add(1).reciprocal();
- final UnivariateDerivative2 bx2 = beta.multiply(ex2);
- final UnivariateDerivative2 by2 = beta.multiply(ey2);
- final UnivariateDerivative2 bxy = beta.multiply(exy);
- final UnivariateDerivative2 u = bxy.multiply(sinAE).subtract(parameters[1].add(by2.subtract(1).multiply(cosAE)));
- final UnivariateDerivative2 v = bxy.multiply(cosAE).subtract(parameters[2].add(bx2.subtract(1).multiply(sinAE)));
- final UnivariateDerivative2 x = parameters[0].multiply(u);
- final UnivariateDerivative2 y = parameters[0].multiply(v);
- // canonical orbit reference frame
- final FieldVector3D<UnivariateDerivative2> p =
- new FieldVector3D<>(x.multiply(cosOmega).subtract(y.multiply(cosI.multiply(sinOmega))),
- x.multiply(sinOmega).add(y.multiply(cosI.multiply(cosOmega))),
- y.multiply(sinI));
- // dispatch derivatives
- final Vector3D p0 = new Vector3D(p.getX().getValue(),
- p.getY().getValue(),
- p.getZ().getValue());
- final Vector3D p1 = new Vector3D(p.getX().getFirstDerivative(),
- p.getY().getFirstDerivative(),
- p.getZ().getFirstDerivative());
- final Vector3D p2 = new Vector3D(p.getX().getSecondDerivative(),
- p.getY().getSecondDerivative(),
- p.getZ().getSecondDerivative());
- return new TimeStampedPVCoordinates(date, p0, p1, p2);
- }
- /** Computes the eccentric latitude argument from the mean latitude argument.
- * @param alphaM = M + Ω mean latitude argument (rad)
- * @param ex e cos(Ω), first component of circular eccentricity vector
- * @param ey e sin(Ω), second component of circular eccentricity vector
- * @return the eccentric latitude argument.
- */
- private UnivariateDerivative2 meanToEccentric(final UnivariateDerivative2 alphaM,
- final UnivariateDerivative2 ex,
- final UnivariateDerivative2 ey) {
- // Generalization of Kepler equation to circular parameters
- // with alphaE = PA + E and
- // alphaM = PA + M = alphaE - ex.sin(alphaE) + ey.cos(alphaE)
- UnivariateDerivative2 alphaE = alphaM;
- UnivariateDerivative2 shift = alphaM.getField().getZero();
- UnivariateDerivative2 alphaEMalphaM = alphaM.getField().getZero();
- UnivariateDerivative2 cosAlphaE = alphaE.cos();
- UnivariateDerivative2 sinAlphaE = alphaE.sin();
- int iter = 0;
- do {
- final UnivariateDerivative2 f2 = ex.multiply(sinAlphaE).subtract(ey.multiply(cosAlphaE));
- final UnivariateDerivative2 f1 = alphaM.getField().getOne().subtract(ex.multiply(cosAlphaE)).subtract(ey.multiply(sinAlphaE));
- final UnivariateDerivative2 f0 = alphaEMalphaM.subtract(f2);
- final UnivariateDerivative2 f12 = f1.multiply(2);
- shift = f0.multiply(f12).divide(f1.multiply(f12).subtract(f0.multiply(f2)));
- alphaEMalphaM = alphaEMalphaM.subtract(shift);
- alphaE = alphaM.add(alphaEMalphaM);
- cosAlphaE = alphaE.cos();
- sinAlphaE = alphaE.sin();
- } while (++iter < 50 && FastMath.abs(shift.getValue()) > 1.0e-12);
- return alphaE;
- }
- /** {@inheritDoc} */
- protected double getMass(final AbsoluteDate date) {
- return models.get(date).mass;
- }
- }