FieldCircularOrbit.java
- /* Copyright 2002-2025 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.orbits;
- import org.hipparchus.CalculusFieldElement;
- import org.hipparchus.Field;
- import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative1;
- import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
- import org.hipparchus.util.FastMath;
- import org.hipparchus.util.FieldSinCos;
- import org.hipparchus.util.MathArrays;
- import org.orekit.errors.OrekitIllegalArgumentException;
- import org.orekit.errors.OrekitInternalError;
- import org.orekit.errors.OrekitMessages;
- import org.orekit.frames.FieldKinematicTransform;
- import org.orekit.frames.Frame;
- import org.orekit.time.FieldAbsoluteDate;
- import org.orekit.utils.FieldPVCoordinates;
- import org.orekit.utils.TimeStampedFieldPVCoordinates;
- /**
- * This class handles circular orbital parameters.
- * <p>
- * The parameters used internally are the circular elements which can be
- * related to Keplerian elements as follows:
- * <ul>
- * <li>a</li>
- * <li>e<sub>x</sub> = e cos(ω)</li>
- * <li>e<sub>y</sub> = e sin(ω)</li>
- * <li>i</li>
- * <li>Ω</li>
- * <li>α<sub>v</sub> = v + ω</li>
- * </ul>
- * where Ω stands for the Right Ascension of the Ascending Node and
- * α<sub>v</sub> stands for the true latitude argument
- * <p>
- * The conversion equations from and to Keplerian elements given above hold only
- * when both sides are unambiguously defined, i.e. when orbit is neither equatorial
- * nor circular. When orbit is circular (but not equatorial), the circular
- * parameters are still unambiguously defined whereas some Keplerian elements
- * (more precisely ω and Ω) become ambiguous. When orbit is equatorial,
- * neither the Keplerian nor the circular parameters can be defined unambiguously.
- * {@link EquinoctialOrbit equinoctial orbits} is the recommended way to represent
- * orbits.
- * </p>
- * <p>
- * The instance <code>CircularOrbit</code> is guaranteed to be immutable.
- * </p>
- * @see Orbit
- * @see KeplerianOrbit
- * @see CartesianOrbit
- * @see EquinoctialOrbit
- * @author Luc Maisonobe
- * @author Fabien Maussion
- * @author Véronique Pommier-Maurussane
- * @since 9.0
- * @param <T> type of the field elements
- */
- public class FieldCircularOrbit<T extends CalculusFieldElement<T>> extends FieldOrbit<T>
- implements PositionAngleBased<FieldCircularOrbit<T>> {
- /** Semi-major axis (m). */
- private final T a;
- /** First component of the circular eccentricity vector. */
- private final T ex;
- /** Second component of the circular eccentricity vector. */
- private final T ey;
- /** Inclination (rad). */
- private final T i;
- /** Right Ascension of Ascending Node (rad). */
- private final T raan;
- /** Cached latitude argument (rad). */
- private final T cachedAlpha;
- /** Type of cached position angle (latitude argument). */
- private final PositionAngleType cachedPositionAngleType;
- /** Semi-major axis derivative (m/s). */
- private final T aDot;
- /** First component of the circular eccentricity vector derivative. */
- private final T exDot;
- /** Second component of the circular eccentricity vector derivative. */
- private final T eyDot;
- /** Inclination derivative (rad/s). */
- private final T iDot;
- /** Right Ascension of Ascending Node derivative (rad/s). */
- private final T raanDot;
- /** True latitude argument derivative (rad/s). */
- private final T cachedAlphaDot;
- /** Partial Cartesian coordinates (position and velocity are valid, acceleration may be missing). */
- private FieldPVCoordinates<T> partialPV;
- /** Creates a new instance.
- * @param a semi-major axis (m)
- * @param ex e cos(ω), first component of circular eccentricity vector
- * @param ey e sin(ω), second component of circular eccentricity vector
- * @param i inclination (rad)
- * @param raan right ascension of ascending node (Ω, rad)
- * @param alpha an + ω, mean, eccentric or true latitude argument (rad)
- * @param type type of latitude argument
- * @param cachedPositionAngleType type of cached latitude argument
- * @param frame the frame in which are defined the parameters
- * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
- * @param date date of the orbital parameters
- * @param mu central attraction coefficient (m³/s²)
- * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or
- * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame}
- * @since 12.1
- */
- public FieldCircularOrbit(final T a, final T ex, final T ey, final T i, final T raan,
- final T alpha, final PositionAngleType type,
- final PositionAngleType cachedPositionAngleType,
- final Frame frame, final FieldAbsoluteDate<T> date, final T mu)
- throws IllegalArgumentException {
- this(a, ex, ey, i, raan, alpha,
- a.getField().getZero(), a.getField().getZero(), a.getField().getZero(), a.getField().getZero(), a.getField().getZero(),
- computeKeplerianAlphaDot(type, a, ex, ey, mu, alpha, type), type, cachedPositionAngleType, frame, date, mu);
- }
- /** Creates a new instance without derivatives and with cached position angle same as value inputted.
- * @param a semi-major axis (m)
- * @param ex e cos(ω), first component of circular eccentricity vector
- * @param ey e sin(ω), second component of circular eccentricity vector
- * @param i inclination (rad)
- * @param raan right ascension of ascending node (Ω, rad)
- * @param alpha an + ω, mean, eccentric or true latitude argument (rad)
- * @param type type of latitude argument
- * @param frame the frame in which are defined the parameters
- * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
- * @param date date of the orbital parameters
- * @param mu central attraction coefficient (m³/s²)
- * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or
- * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame}
- */
- public FieldCircularOrbit(final T a, final T ex, final T ey, final T i, final T raan,
- final T alpha, final PositionAngleType type,
- final Frame frame, final FieldAbsoluteDate<T> date, final T mu)
- throws IllegalArgumentException {
- this(a, ex, ey, i, raan, alpha, type, type, frame, date, mu);
- }
- /** Creates a new instance.
- * @param a semi-major axis (m)
- * @param ex e cos(ω), first component of circular eccentricity vector
- * @param ey e sin(ω), second component of circular eccentricity vector
- * @param i inclination (rad)
- * @param raan right ascension of ascending node (Ω, rad)
- * @param alpha an + ω, mean, eccentric or true latitude argument (rad)
- * @param aDot semi-major axis derivative (m/s)
- * @param exDot d(e cos(ω))/dt, first component of circular eccentricity vector derivative
- * @param eyDot d(e sin(ω))/dt, second component of circular eccentricity vector derivative
- * @param iDot inclination derivative(rad/s)
- * @param raanDot right ascension of ascending node derivative (rad/s)
- * @param alphaDot d(an + ω), mean, eccentric or true latitude argument derivative (rad/s)
- * @param type type of latitude argument
- * @param frame the frame in which are defined the parameters
- * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
- * @param date date of the orbital parameters
- * @param mu central attraction coefficient (m³/s²)
- * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or
- * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame}
- */
- public FieldCircularOrbit(final T a, final T ex, final T ey,
- final T i, final T raan, final T alpha,
- final T aDot, final T exDot, final T eyDot,
- final T iDot, final T raanDot, final T alphaDot, final PositionAngleType type,
- final Frame frame, final FieldAbsoluteDate<T> date, final T mu)
- throws IllegalArgumentException {
- this(a, ex, ey, i, raan, alpha, aDot, exDot, eyDot, iDot, raanDot, alphaDot, type, type, frame, date, mu);
- }
- /** Creates a new instance.
- * @param a semi-major axis (m)
- * @param ex e cos(ω), first component of circular eccentricity vector
- * @param ey e sin(ω), second component of circular eccentricity vector
- * @param i inclination (rad)
- * @param raan right ascension of ascending node (Ω, rad)
- * @param alpha an + ω, mean, eccentric or true latitude argument (rad)
- * @param aDot semi-major axis derivative (m/s)
- * @param exDot d(e cos(ω))/dt, first component of circular eccentricity vector derivative
- * @param eyDot d(e sin(ω))/dt, second component of circular eccentricity vector derivative
- * @param iDot inclination derivative(rad/s)
- * @param raanDot right ascension of ascending node derivative (rad/s)
- * @param alphaDot d(an + ω), mean, eccentric or true latitude argument derivative (rad/s)
- * @param type type of latitude argument
- * @param cachedPositionAngleType type of cached latitude argument
- * @param frame the frame in which are defined the parameters
- * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
- * @param date date of the orbital parameters
- * @param mu central attraction coefficient (m³/s²)
- * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or
- * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame}
- * @since 12.1
- */
- public FieldCircularOrbit(final T a, final T ex, final T ey,
- final T i, final T raan, final T alpha,
- final T aDot, final T exDot, final T eyDot,
- final T iDot, final T raanDot, final T alphaDot,
- final PositionAngleType type, final PositionAngleType cachedPositionAngleType,
- final Frame frame, final FieldAbsoluteDate<T> date, final T mu)
- throws IllegalArgumentException {
- super(frame, date, mu);
- if (ex.getReal() * ex.getReal() + ey.getReal() * ey.getReal() >= 1.0) {
- throw new OrekitIllegalArgumentException(OrekitMessages.HYPERBOLIC_ORBIT_NOT_HANDLED_AS,
- getClass().getName());
- }
- this.a = a;
- this.aDot = aDot;
- this.ex = ex;
- this.exDot = exDot;
- this.ey = ey;
- this.eyDot = eyDot;
- this.i = i;
- this.iDot = iDot;
- this.raan = raan;
- this.raanDot = raanDot;
- this.cachedPositionAngleType = cachedPositionAngleType;
- final FieldUnivariateDerivative1<T> alphaUD = initializeCachedAlpha(alpha, alphaDot, type);
- this.cachedAlpha = alphaUD.getValue();
- this.cachedAlphaDot = alphaUD.getFirstDerivative();
- partialPV = null;
- }
- /** Constructor from Cartesian parameters.
- *
- * <p> The acceleration provided in {@code FieldPVCoordinates} is accessible using
- * {@link #getPVCoordinates()} and {@link #getPVCoordinates(Frame)}. All other methods
- * use {@code mu} and the position to compute the acceleration, including
- * {@link #shiftedBy(CalculusFieldElement)} and {@link #getPVCoordinates(FieldAbsoluteDate, Frame)}.
- *
- * @param pvCoordinates the {@link FieldPVCoordinates} in inertial frame
- * @param frame the frame in which are defined the {@link FieldPVCoordinates}
- * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
- * @param mu central attraction coefficient (m³/s²)
- * @exception IllegalArgumentException if frame is not a {@link
- * Frame#isPseudoInertial pseudo-inertial frame}
- */
- public FieldCircularOrbit(final TimeStampedFieldPVCoordinates<T> pvCoordinates,
- final Frame frame, final T mu)
- throws IllegalArgumentException {
- super(pvCoordinates, frame, mu);
- this.cachedPositionAngleType = PositionAngleType.TRUE;
- // compute semi-major axis
- final FieldVector3D<T> pvP = pvCoordinates.getPosition();
- final FieldVector3D<T> pvV = pvCoordinates.getVelocity();
- final FieldVector3D<T> pvA = pvCoordinates.getAcceleration();
- final T r2 = pvP.getNormSq();
- final T r = r2.sqrt();
- final T V2 = pvV.getNormSq();
- final T rV2OnMu = r.multiply(V2).divide(mu);
- a = r.divide(rV2OnMu.negate().add(2));
- if (!isElliptical()) {
- throw new OrekitIllegalArgumentException(OrekitMessages.HYPERBOLIC_ORBIT_NOT_HANDLED_AS,
- getClass().getName());
- }
- // compute inclination
- final FieldVector3D<T> momentum = pvCoordinates.getMomentum();
- final FieldVector3D<T> plusK = FieldVector3D.getPlusK(r.getField());
- i = FieldVector3D.angle(momentum, plusK);
- // compute right ascension of ascending node
- final FieldVector3D<T> node = FieldVector3D.crossProduct(plusK, momentum);
- raan = node.getY().atan2(node.getX());
- // 2D-coordinates in the canonical frame
- final FieldSinCos<T> scRaan = FastMath.sinCos(raan);
- final FieldSinCos<T> scI = FastMath.sinCos(i);
- final T xP = pvP.getX();
- final T yP = pvP.getY();
- final T zP = pvP.getZ();
- final T x2 = (xP.multiply(scRaan.cos()).add(yP .multiply(scRaan.sin()))).divide(a);
- final T y2 = (yP.multiply(scRaan.cos()).subtract(xP.multiply(scRaan.sin()))).multiply(scI.cos()).add(zP.multiply(scI.sin())).divide(a);
- // compute eccentricity vector
- final T eSE = FieldVector3D.dotProduct(pvP, pvV).divide(a.multiply(mu).sqrt());
- final T eCE = rV2OnMu.subtract(1);
- final T e2 = eCE.multiply(eCE).add(eSE.multiply(eSE));
- final T f = eCE.subtract(e2);
- final T g = eSE.multiply(e2.negate().add(1).sqrt());
- final T aOnR = a.divide(r);
- final T a2OnR2 = aOnR.square();
- ex = a2OnR2.multiply(f.multiply(x2).add(g.multiply(y2)));
- ey = a2OnR2.multiply(f.multiply(y2).subtract(g.multiply(x2)));
- // compute latitude argument
- final T beta = (ex.multiply(ex).add(ey.multiply(ey)).negate().add(1)).sqrt().add(1).reciprocal();
- cachedAlpha = FieldCircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, y2.add(ey).add(eSE.multiply(beta).multiply(ex)).atan2(x2.add(ex).subtract(eSE.multiply(beta).multiply(ey)))
- );
- partialPV = pvCoordinates;
- if (hasNonKeplerianAcceleration(pvCoordinates, mu)) {
- // we have a relevant acceleration, we can compute derivatives
- final T[][] jacobian = MathArrays.buildArray(a.getField(), 6, 6);
- getJacobianWrtCartesian(PositionAngleType.MEAN, jacobian);
- final FieldVector3D<T> keplerianAcceleration = new FieldVector3D<>(r.multiply(r2).reciprocal().multiply(mu.negate()), pvP);
- final FieldVector3D<T> nonKeplerianAcceleration = pvA.subtract(keplerianAcceleration);
- final T aX = nonKeplerianAcceleration.getX();
- final T aY = nonKeplerianAcceleration.getY();
- final T aZ = nonKeplerianAcceleration.getZ();
- aDot = jacobian[0][3].multiply(aX).add(jacobian[0][4].multiply(aY)).add(jacobian[0][5].multiply(aZ));
- exDot = jacobian[1][3].multiply(aX).add(jacobian[1][4].multiply(aY)).add(jacobian[1][5].multiply(aZ));
- eyDot = jacobian[2][3].multiply(aX).add(jacobian[2][4].multiply(aY)).add(jacobian[2][5].multiply(aZ));
- iDot = jacobian[3][3].multiply(aX).add(jacobian[3][4].multiply(aY)).add(jacobian[3][5].multiply(aZ));
- raanDot = jacobian[4][3].multiply(aX).add(jacobian[4][4].multiply(aY)).add(jacobian[4][5].multiply(aZ));
- // in order to compute true anomaly derivative, we must compute
- // mean anomaly derivative including Keplerian motion and convert to true anomaly
- final T alphaMDot = getKeplerianMeanMotion().
- add(jacobian[5][3].multiply(aX)).add(jacobian[5][4].multiply(aY)).add(jacobian[5][5].multiply(aZ));
- final FieldUnivariateDerivative1<T> exUD = new FieldUnivariateDerivative1<>(ex, exDot);
- final FieldUnivariateDerivative1<T> eyUD = new FieldUnivariateDerivative1<>(ey, eyDot);
- final FieldUnivariateDerivative1<T> alphaMUD = new FieldUnivariateDerivative1<>(getAlphaM(), alphaMDot);
- final FieldUnivariateDerivative1<T> alphavUD = FieldCircularLatitudeArgumentUtility.meanToTrue(exUD, eyUD, alphaMUD);
- cachedAlphaDot = alphavUD.getFirstDerivative();
- } else {
- // acceleration is either almost zero or NaN,
- // we assume acceleration was not known
- // we don't set up derivatives
- aDot = getZero();
- exDot = getZero();
- eyDot = getZero();
- iDot = getZero();
- raanDot = getZero();
- cachedAlphaDot = computeKeplerianAlphaDot(cachedPositionAngleType, a, ex, ey, mu, cachedAlpha, cachedPositionAngleType);
- }
- }
- /** Constructor from Cartesian parameters.
- *
- * <p> The acceleration provided in {@code FieldPVCoordinates} is accessible using
- * {@link #getPVCoordinates()} and {@link #getPVCoordinates(Frame)}. All other methods
- * use {@code mu} and the position to compute the acceleration, including
- * {@link #shiftedBy(CalculusFieldElement)} and {@link #getPVCoordinates(FieldAbsoluteDate, Frame)}.
- *
- * @param PVCoordinates the {@link FieldPVCoordinates} in inertial frame
- * @param frame the frame in which are defined the {@link FieldPVCoordinates}
- * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
- * @param date date of the orbital parameters
- * @param mu central attraction coefficient (m³/s²)
- * @exception IllegalArgumentException if frame is not a {@link
- * Frame#isPseudoInertial pseudo-inertial frame}
- */
- public FieldCircularOrbit(final FieldPVCoordinates<T> PVCoordinates, final Frame frame,
- final FieldAbsoluteDate<T> date, final T mu)
- throws IllegalArgumentException {
- this(new TimeStampedFieldPVCoordinates<>(date, PVCoordinates), frame, mu);
- }
- /** Constructor from any kind of orbital parameters.
- * @param op orbital parameters to copy
- */
- public FieldCircularOrbit(final FieldOrbit<T> op) {
- super(op.getFrame(), op.getDate(), op.getMu());
- a = op.getA();
- i = op.getI();
- final T hx = op.getHx();
- final T hy = op.getHy();
- final T h2 = hx.square().add(hy.square());
- final T h = h2.sqrt();
- raan = hy.atan2(hx);
- final FieldSinCos<T> scRaan = FastMath.sinCos(raan);
- final T cosRaan = h.getReal() == 0 ? scRaan.cos() : hx.divide(h);
- final T sinRaan = h.getReal() == 0 ? scRaan.sin() : hy.divide(h);
- final T equiEx = op.getEquinoctialEx();
- final T equiEy = op.getEquinoctialEy();
- ex = equiEx.multiply(cosRaan).add(equiEy.multiply(sinRaan));
- ey = equiEy.multiply(cosRaan).subtract(equiEx.multiply(sinRaan));
- cachedPositionAngleType = PositionAngleType.TRUE;
- cachedAlpha = op.getLv().subtract(raan);
- if (op.hasNonKeplerianAcceleration()) {
- aDot = op.getADot();
- final T hxDot = op.getHxDot();
- final T hyDot = op.getHyDot();
- iDot = cosRaan.multiply(hxDot).add(sinRaan.multiply(hyDot)).multiply(2).divide(h2.add(1));
- raanDot = hx.multiply(hyDot).subtract(hy.multiply(hxDot)).divide(h2);
- final T equiExDot = op.getEquinoctialExDot();
- final T equiEyDot = op.getEquinoctialEyDot();
- exDot = equiExDot.add(equiEy.multiply(raanDot)).multiply(cosRaan).
- add(equiEyDot.subtract(equiEx.multiply(raanDot)).multiply(sinRaan));
- eyDot = equiEyDot.subtract(equiEx.multiply(raanDot)).multiply(cosRaan).
- subtract(equiExDot.add(equiEy.multiply(raanDot)).multiply(sinRaan));
- cachedAlphaDot = op.getLvDot().subtract(raanDot);
- } else {
- aDot = getZero();
- exDot = getZero();
- eyDot = getZero();
- iDot = getZero();
- raanDot = getZero();
- cachedAlphaDot = computeKeplerianAlphaDot(cachedPositionAngleType, a, ex, ey, op.getMu(), cachedAlpha, cachedPositionAngleType);
- }
- partialPV = null;
- }
- /** Constructor from Field and CircularOrbit.
- * <p>Build a FieldCircularOrbit from non-Field CircularOrbit.</p>
- * @param field CalculusField to base object on
- * @param op non-field orbit with only "constant" terms
- * @since 12.0
- */
- public FieldCircularOrbit(final Field<T> field, final CircularOrbit op) {
- super(op.getFrame(), new FieldAbsoluteDate<>(field, op.getDate()), field.getZero().newInstance(op.getMu()));
- a = getZero().newInstance(op.getA());
- i = getZero().newInstance(op.getI());
- raan = getZero().newInstance(op.getRightAscensionOfAscendingNode());
- ex = getZero().newInstance(op.getCircularEx());
- ey = getZero().newInstance(op.getCircularEy());
- cachedPositionAngleType = op.getCachedPositionAngleType();
- cachedAlpha = getZero().newInstance(op.getAlpha(cachedPositionAngleType));
- aDot = getZero().newInstance(op.getADot());
- iDot = getZero().newInstance(op.getIDot());
- raanDot = getZero().newInstance(op.getRightAscensionOfAscendingNodeDot());
- exDot = getZero().newInstance(op.getCircularExDot());
- eyDot = getZero().newInstance(op.getCircularEyDot());
- cachedAlphaDot = getZero().newInstance(op.getAlphaDot(cachedPositionAngleType));
- partialPV = null;
- }
- /** Constructor from Field and Orbit.
- * <p>Build a FieldCircularOrbit from any non-Field Orbit.</p>
- * @param field CalculusField to base object on
- * @param op non-field orbit with only "constant" terms
- * @since 12.0
- */
- public FieldCircularOrbit(final Field<T> field, final Orbit op) {
- this(field, (CircularOrbit) OrbitType.CIRCULAR.convertType(op));
- }
- /** {@inheritDoc} */
- @Override
- public OrbitType getType() {
- return OrbitType.CIRCULAR;
- }
- /** {@inheritDoc} */
- @Override
- public T getA() {
- return a;
- }
- /** {@inheritDoc} */
- @Override
- public T getADot() {
- return aDot;
- }
- /** {@inheritDoc} */
- @Override
- public T getEquinoctialEx() {
- final FieldSinCos<T> sc = FastMath.sinCos(raan);
- return ex.multiply(sc.cos()).subtract(ey.multiply(sc.sin()));
- }
- /** {@inheritDoc} */
- @Override
- public T getEquinoctialExDot() {
- if (!hasNonKeplerianRates()) {
- return getZero();
- }
- final FieldSinCos<T> sc = FastMath.sinCos(raan);
- return exDot.subtract(ey.multiply(raanDot)).multiply(sc.cos()).
- subtract(eyDot.add(ex.multiply(raanDot)).multiply(sc.sin()));
- }
- /** {@inheritDoc} */
- @Override
- public T getEquinoctialEy() {
- final FieldSinCos<T> sc = FastMath.sinCos(raan);
- return ey.multiply(sc.cos()).add(ex.multiply(sc.sin()));
- }
- /** {@inheritDoc} */
- @Override
- public T getEquinoctialEyDot() {
- if (!hasNonKeplerianRates()) {
- return getZero();
- }
- final FieldSinCos<T> sc = FastMath.sinCos(raan);
- return eyDot.add(ex.multiply(raanDot)).multiply(sc.cos()).
- add(exDot.subtract(ey.multiply(raanDot)).multiply(sc.sin()));
- }
- /** Get the first component of the circular eccentricity vector.
- * @return ex = e cos(ω), first component of the circular eccentricity vector
- */
- public T getCircularEx() {
- return ex;
- }
- /** Get the first component of the circular eccentricity vector derivative.
- * @return d(ex)/dt = d(e cos(ω))/dt, first component of the circular eccentricity vector derivative
- */
- public T getCircularExDot() {
- return exDot;
- }
- /** Get the second component of the circular eccentricity vector.
- * @return ey = e sin(ω), second component of the circular eccentricity vector
- */
- public T getCircularEy() {
- return ey;
- }
- /** Get the second component of the circular eccentricity vector derivative.
- * @return d(ey)/dt = d(e sin(ω))/dt, second component of the circular eccentricity vector derivative
- */
- public T getCircularEyDot() {
- return eyDot;
- }
- /** {@inheritDoc} */
- @Override
- public T getHx() {
- // Check for equatorial retrograde orbit
- if (FastMath.abs(i.subtract(i.getPi()).getReal()) < 1.0e-10) {
- return getZero().add(Double.NaN);
- }
- return raan.cos().multiply(i.divide(2).tan());
- }
- /** {@inheritDoc} */
- @Override
- public T getHxDot() {
- // Check for equatorial retrograde orbit
- if (FastMath.abs(i.subtract(i.getPi()).getReal()) < 1.0e-10) {
- return getZero().add(Double.NaN);
- }
- if (!hasNonKeplerianRates()) {
- return getZero();
- }
- final FieldSinCos<T> sc = FastMath.sinCos(raan);
- final T tan = i.multiply(0.5).tan();
- return sc.cos().multiply(0.5).multiply(tan.multiply(tan).add(1)).multiply(iDot).
- subtract(sc.sin().multiply(tan).multiply(raanDot));
- }
- /** {@inheritDoc} */
- @Override
- public T getHy() {
- // Check for equatorial retrograde orbit
- if (FastMath.abs(i.subtract(i.getPi()).getReal()) < 1.0e-10) {
- return getZero().add(Double.NaN);
- }
- return raan.sin().multiply(i.divide(2).tan());
- }
- /** {@inheritDoc} */
- @Override
- public T getHyDot() {
- // Check for equatorial retrograde orbit
- if (FastMath.abs(i.subtract(i.getPi()).getReal()) < 1.0e-10) {
- return getZero().add(Double.NaN);
- }
- if (!hasNonKeplerianRates()) {
- return getZero();
- }
- final FieldSinCos<T> sc = FastMath.sinCos(raan);
- final T tan = i.multiply(0.5).tan();
- return sc.sin().multiply(0.5).multiply(tan.multiply(tan).add(1)).multiply(iDot).
- add(sc.cos().multiply(tan).multiply(raanDot));
- }
- /** Get the true latitude argument.
- * @return v + ω true latitude argument (rad)
- */
- public T getAlphaV() {
- switch (cachedPositionAngleType) {
- case TRUE:
- return cachedAlpha;
- case ECCENTRIC:
- return FieldCircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, cachedAlpha);
- case MEAN:
- return FieldCircularLatitudeArgumentUtility.meanToTrue(ex, ey, cachedAlpha);
- default:
- throw new OrekitInternalError(null);
- }
- }
- /** Get the true latitude argument derivative.
- * @return d(v + ω)/dt true latitude argument derivative (rad/s)
- */
- public T getAlphaVDot() {
- switch (cachedPositionAngleType) {
- case ECCENTRIC:
- final FieldUnivariateDerivative1<T> alphaEUD = new FieldUnivariateDerivative1<>(cachedAlpha, cachedAlphaDot);
- final FieldUnivariateDerivative1<T> exUD = new FieldUnivariateDerivative1<>(ex, exDot);
- final FieldUnivariateDerivative1<T> eyUD = new FieldUnivariateDerivative1<>(ey, eyDot);
- final FieldUnivariateDerivative1<T> alphaVUD = FieldCircularLatitudeArgumentUtility.eccentricToTrue(exUD, eyUD,
- alphaEUD);
- return alphaVUD.getFirstDerivative();
- case TRUE:
- return cachedAlphaDot;
- case MEAN:
- final FieldUnivariateDerivative1<T> alphaMUD = new FieldUnivariateDerivative1<>(cachedAlpha, cachedAlphaDot);
- final FieldUnivariateDerivative1<T> exUD2 = new FieldUnivariateDerivative1<>(ex, exDot);
- final FieldUnivariateDerivative1<T> eyUD2 = new FieldUnivariateDerivative1<>(ey, eyDot);
- final FieldUnivariateDerivative1<T> alphaVUD2 = FieldCircularLatitudeArgumentUtility.meanToTrue(exUD2,
- eyUD2, alphaMUD);
- return alphaVUD2.getFirstDerivative();
- default:
- throw new OrekitInternalError(null);
- }
- }
- /** Get the eccentric latitude argument.
- * @return E + ω eccentric latitude argument (rad)
- */
- public T getAlphaE() {
- switch (cachedPositionAngleType) {
- case TRUE:
- return FieldCircularLatitudeArgumentUtility.trueToEccentric(ex, ey, cachedAlpha);
- case ECCENTRIC:
- return cachedAlpha;
- case MEAN:
- return FieldCircularLatitudeArgumentUtility.meanToEccentric(ex, ey, cachedAlpha);
- default:
- throw new OrekitInternalError(null);
- }
- }
- /** Get the eccentric latitude argument derivative.
- * @return d(E + ω)/dt eccentric latitude argument derivative (rad/s)
- */
- public T getAlphaEDot() {
- switch (cachedPositionAngleType) {
- case TRUE:
- final FieldUnivariateDerivative1<T> alphaVUD = new FieldUnivariateDerivative1<>(cachedAlpha, cachedAlphaDot);
- final FieldUnivariateDerivative1<T> exUD = new FieldUnivariateDerivative1<>(ex, exDot);
- final FieldUnivariateDerivative1<T> eyUD = new FieldUnivariateDerivative1<>(ey, eyDot);
- final FieldUnivariateDerivative1<T> alphaEUD = FieldCircularLatitudeArgumentUtility.trueToEccentric(exUD, eyUD,
- alphaVUD);
- return alphaEUD.getFirstDerivative();
- case ECCENTRIC:
- return cachedAlphaDot;
- case MEAN:
- final FieldUnivariateDerivative1<T> alphaMUD = new FieldUnivariateDerivative1<>(cachedAlpha, cachedAlphaDot);
- final FieldUnivariateDerivative1<T> exUD2 = new FieldUnivariateDerivative1<>(ex, exDot);
- final FieldUnivariateDerivative1<T> eyUD2 = new FieldUnivariateDerivative1<>(ey, eyDot);
- final FieldUnivariateDerivative1<T> alphaVUD2 = FieldCircularLatitudeArgumentUtility.meanToEccentric(exUD2,
- eyUD2, alphaMUD);
- return alphaVUD2.getFirstDerivative();
- default:
- throw new OrekitInternalError(null);
- }
- }
- /** Get the mean latitude argument.
- * @return M + ω mean latitude argument (rad)
- */
- public T getAlphaM() {
- switch (cachedPositionAngleType) {
- case TRUE:
- return FieldCircularLatitudeArgumentUtility.trueToMean(ex, ey, cachedAlpha);
- case MEAN:
- return cachedAlpha;
- case ECCENTRIC:
- return FieldCircularLatitudeArgumentUtility.eccentricToMean(ex, ey, cachedAlpha);
- default:
- throw new OrekitInternalError(null);
- }
- }
- /** Get the mean latitude argument derivative.
- * @return d(M + ω)/dt mean latitude argument derivative (rad/s)
- */
- public T getAlphaMDot() {
- switch (cachedPositionAngleType) {
- case TRUE:
- final FieldUnivariateDerivative1<T> alphaVUD = new FieldUnivariateDerivative1<>(cachedAlpha, cachedAlphaDot);
- final FieldUnivariateDerivative1<T> exUD = new FieldUnivariateDerivative1<>(ex, exDot);
- final FieldUnivariateDerivative1<T> eyUD = new FieldUnivariateDerivative1<>(ey, eyDot);
- final FieldUnivariateDerivative1<T> alphaMUD = FieldCircularLatitudeArgumentUtility.trueToMean(exUD, eyUD,
- alphaVUD);
- return alphaMUD.getFirstDerivative();
- case MEAN:
- return cachedAlphaDot;
- case ECCENTRIC:
- final FieldUnivariateDerivative1<T> alphaEUD = new FieldUnivariateDerivative1<>(cachedAlpha, cachedAlphaDot);
- final FieldUnivariateDerivative1<T> exUD2 = new FieldUnivariateDerivative1<>(ex, exDot);
- final FieldUnivariateDerivative1<T> eyUD2 = new FieldUnivariateDerivative1<>(ey, eyDot);
- final FieldUnivariateDerivative1<T> alphaMUD2 = FieldCircularLatitudeArgumentUtility.eccentricToMean(exUD2,
- eyUD2, alphaEUD);
- return alphaMUD2.getFirstDerivative();
- default:
- throw new OrekitInternalError(null);
- }
- }
- /** Get the latitude argument.
- * @param type type of the angle
- * @return latitude argument (rad)
- */
- public T getAlpha(final PositionAngleType type) {
- return (type == PositionAngleType.MEAN) ? getAlphaM() :
- ((type == PositionAngleType.ECCENTRIC) ? getAlphaE() :
- getAlphaV());
- }
- /** Get the latitude argument derivative.
- * @param type type of the angle
- * @return latitude argument derivative (rad/s)
- */
- public T getAlphaDot(final PositionAngleType type) {
- return (type == PositionAngleType.MEAN) ? getAlphaMDot() :
- ((type == PositionAngleType.ECCENTRIC) ? getAlphaEDot() :
- getAlphaVDot());
- }
- /** {@inheritDoc} */
- @Override
- public T getE() {
- return ex.multiply(ex).add(ey.multiply(ey)).sqrt();
- }
- /** {@inheritDoc} */
- @Override
- public T getEDot() {
- return ex.multiply(exDot).add(ey.multiply(eyDot)).divide(getE());
- }
- /** {@inheritDoc} */
- @Override
- public T getI() {
- return i;
- }
- /** {@inheritDoc} */
- @Override
- public T getIDot() {
- return iDot;
- }
- /** Get the right ascension of the ascending node.
- * @return right ascension of the ascending node (rad)
- */
- public T getRightAscensionOfAscendingNode() {
- return raan;
- }
- /** Get the right ascension of the ascending node derivative.
- * @return right ascension of the ascending node derivative (rad/s)
- */
- public T getRightAscensionOfAscendingNodeDot() {
- return raanDot;
- }
- /** {@inheritDoc} */
- @Override
- public T getLv() {
- return getAlphaV().add(raan);
- }
- /** {@inheritDoc} */
- @Override
- public T getLvDot() {
- return getAlphaVDot().add(raanDot);
- }
- /** {@inheritDoc} */
- @Override
- public T getLE() {
- return getAlphaE().add(raan);
- }
- /** {@inheritDoc} */
- @Override
- public T getLEDot() {
- return getAlphaEDot().add(raanDot);
- }
- /** {@inheritDoc} */
- @Override
- public T getLM() {
- return getAlphaM().add(raan);
- }
- /** {@inheritDoc} */
- @Override
- public T getLMDot() {
- return getAlphaMDot().add(raanDot);
- }
- /** {@inheritDoc} */
- @Override
- public boolean hasNonKeplerianAcceleration() {
- return aDot.getReal() != 0. || exDot.getReal() != 0 || iDot.getReal() != 0. || eyDot.getReal() != 0. || raanDot.getReal() != 0. ||
- FastMath.abs(cachedAlphaDot.subtract(computeKeplerianAlphaDot(cachedPositionAngleType, a, ex, ey, getMu(), cachedAlpha, cachedPositionAngleType)).getReal()) > TOLERANCE_POSITION_ANGLE_RATE;
- }
- /** Compute position and velocity but not acceleration.
- */
- private void computePVWithoutA() {
- if (partialPV != null) {
- // already computed
- return;
- }
- // get equinoctial parameters
- final T equEx = getEquinoctialEx();
- final T equEy = getEquinoctialEy();
- final T hx = getHx();
- final T hy = getHy();
- final T lE = getLE();
- // inclination-related intermediate parameters
- final T hx2 = hx.multiply(hx);
- final T hy2 = hy.multiply(hy);
- final T factH = (hx2.add(1).add(hy2)).reciprocal();
- // reference axes defining the orbital plane
- final T ux = (hx2.add(1).subtract(hy2)).multiply(factH);
- final T uy = hx.multiply(2).multiply(hy).multiply(factH);
- final T uz = hy.multiply(-2).multiply(factH);
- final T vx = uy;
- final T vy = (hy2.subtract(hx2).add(1)).multiply(factH);
- final T vz = hx.multiply(factH).multiply(2);
- // eccentricity-related intermediate parameters
- final T exey = equEx.multiply(equEy);
- final T ex2 = equEx.square();
- final T ey2 = equEy.square();
- final T e2 = ex2.add(ey2);
- final T eta = e2.negate().add(1).sqrt().add(1);
- final T beta = eta.reciprocal();
- // eccentric latitude argument
- final FieldSinCos<T> scLe = FastMath.sinCos(lE);
- final T cLe = scLe.cos();
- final T sLe = scLe.sin();
- final T exCeyS = equEx.multiply(cLe).add(equEy.multiply(sLe));
- // coordinates of position and velocity in the orbital plane
- final T x = a.multiply(beta.negate().multiply(ey2).add(1).multiply(cLe).add(beta.multiply(exey).multiply(sLe)).subtract(equEx));
- final T y = a.multiply(beta.negate().multiply(ex2).add(1).multiply(sLe).add(beta.multiply(exey).multiply(cLe)).subtract(equEy));
- final T factor = getOne().add(getMu()).divide(a).sqrt().divide(exCeyS.negate().add(1));
- final T xdot = factor.multiply( beta.multiply(equEy).multiply(exCeyS).subtract(sLe ));
- final T ydot = factor.multiply( cLe.subtract(beta.multiply(equEx).multiply(exCeyS)));
- final FieldVector3D<T> position = new FieldVector3D<>(x.multiply(ux).add(y.multiply(vx)),
- x.multiply(uy).add(y.multiply(vy)),
- x.multiply(uz).add(y.multiply(vz)));
- final FieldVector3D<T> velocity = new FieldVector3D<>(xdot.multiply(ux).add(ydot.multiply(vx)),
- xdot.multiply(uy).add(ydot.multiply(vy)),
- xdot.multiply(uz).add(ydot.multiply(vz)));
- partialPV = new FieldPVCoordinates<>(position, velocity);
- }
- /** Initialize cached alpha with rate.
- * @param alpha input alpha
- * @param alphaDot rate of input alpha
- * @param inputType position angle type passed as input
- * @return alpha to cache with rate
- * @since 12.1
- */
- private FieldUnivariateDerivative1<T> initializeCachedAlpha(final T alpha, final T alphaDot,
- final PositionAngleType inputType) {
- if (cachedPositionAngleType == inputType) {
- return new FieldUnivariateDerivative1<>(alpha, alphaDot);
- } else {
- final FieldUnivariateDerivative1<T> exUD = new FieldUnivariateDerivative1<>(ex, exDot);
- final FieldUnivariateDerivative1<T> eyUD = new FieldUnivariateDerivative1<>(ey, eyDot);
- final FieldUnivariateDerivative1<T> alphaUD = new FieldUnivariateDerivative1<>(alpha, alphaDot);
- switch (cachedPositionAngleType) {
- case ECCENTRIC:
- if (inputType == PositionAngleType.MEAN) {
- return FieldCircularLatitudeArgumentUtility.meanToEccentric(exUD, eyUD, alphaUD);
- } else {
- return FieldCircularLatitudeArgumentUtility.trueToEccentric(exUD, eyUD, alphaUD);
- }
- case TRUE:
- if (inputType == PositionAngleType.MEAN) {
- return FieldCircularLatitudeArgumentUtility.meanToTrue(exUD, eyUD, alphaUD);
- } else {
- return FieldCircularLatitudeArgumentUtility.eccentricToTrue(exUD, eyUD, alphaUD);
- }
- case MEAN:
- if (inputType == PositionAngleType.TRUE) {
- return FieldCircularLatitudeArgumentUtility.trueToMean(exUD, eyUD, alphaUD);
- } else {
- return FieldCircularLatitudeArgumentUtility.eccentricToMean(exUD, eyUD, alphaUD);
- }
- default:
- throw new OrekitInternalError(null);
- }
- }
- }
- /** Compute non-Keplerian part of the acceleration from first time derivatives.
- * @return non-Keplerian part of the acceleration
- */
- private FieldVector3D<T> nonKeplerianAcceleration() {
- final T[][] dCdP = MathArrays.buildArray(a.getField(), 6, 6);
- getJacobianWrtParameters(PositionAngleType.MEAN, dCdP);
- final T nonKeplerianMeanMotion = getAlphaMDot().subtract(getKeplerianMeanMotion());
- final T nonKeplerianAx = dCdP[3][0].multiply(aDot).
- add(dCdP[3][1].multiply(exDot)).
- add(dCdP[3][2].multiply(eyDot)).
- add(dCdP[3][3].multiply(iDot)).
- add(dCdP[3][4].multiply(raanDot)).
- add(dCdP[3][5].multiply(nonKeplerianMeanMotion));
- final T nonKeplerianAy = dCdP[4][0].multiply(aDot).
- add(dCdP[4][1].multiply(exDot)).
- add(dCdP[4][2].multiply(eyDot)).
- add(dCdP[4][3].multiply(iDot)).
- add(dCdP[4][4].multiply(raanDot)).
- add(dCdP[4][5].multiply(nonKeplerianMeanMotion));
- final T nonKeplerianAz = dCdP[5][0].multiply(aDot).
- add(dCdP[5][1].multiply(exDot)).
- add(dCdP[5][2].multiply(eyDot)).
- add(dCdP[5][3].multiply(iDot)).
- add(dCdP[5][4].multiply(raanDot)).
- add(dCdP[5][5].multiply(nonKeplerianMeanMotion));
- return new FieldVector3D<>(nonKeplerianAx, nonKeplerianAy, nonKeplerianAz);
- }
- /** {@inheritDoc} */
- @Override
- protected FieldVector3D<T> initPosition() {
- // get equinoctial parameters
- final T equEx = getEquinoctialEx();
- final T equEy = getEquinoctialEy();
- final T hx = getHx();
- final T hy = getHy();
- final T lE = getLE();
- // inclination-related intermediate parameters
- final T hx2 = hx.multiply(hx);
- final T hy2 = hy.multiply(hy);
- final T factH = (hx2.add(1).add(hy2)).reciprocal();
- // reference axes defining the orbital plane
- final T ux = (hx2.add(1).subtract(hy2)).multiply(factH);
- final T uy = hx.multiply(2).multiply(hy).multiply(factH);
- final T uz = hy.multiply(-2).multiply(factH);
- final T vx = uy;
- final T vy = (hy2.subtract(hx2).add(1)).multiply(factH);
- final T vz = hx.multiply(factH).multiply(2);
- // eccentricity-related intermediate parameters
- final T exey = equEx.multiply(equEy);
- final T ex2 = equEx.square();
- final T ey2 = equEy.square();
- final T e2 = ex2.add(ey2);
- final T eta = e2.negate().add(1).sqrt().add(1);
- final T beta = eta.reciprocal();
- // eccentric latitude argument
- final FieldSinCos<T> scLe = FastMath.sinCos(lE);
- final T cLe = scLe.cos();
- final T sLe = scLe.sin();
- // coordinates of position and velocity in the orbital plane
- final T x = a.multiply(beta.negate().multiply(ey2).add(1).multiply(cLe).add(beta.multiply(exey).multiply(sLe)).subtract(equEx));
- final T y = a.multiply(beta.negate().multiply(ex2).add(1).multiply(sLe).add(beta.multiply(exey).multiply(cLe)).subtract(equEy));
- return new FieldVector3D<>(x.multiply(ux).add(y.multiply(vx)),
- x.multiply(uy).add(y.multiply(vy)),
- x.multiply(uz).add(y.multiply(vz)));
- }
- /** {@inheritDoc} */
- @Override
- protected TimeStampedFieldPVCoordinates<T> initPVCoordinates() {
- // position and velocity
- computePVWithoutA();
- // acceleration
- final T r2 = partialPV.getPosition().getNormSq();
- final FieldVector3D<T> keplerianAcceleration = new FieldVector3D<>(r2.multiply(r2.sqrt()).reciprocal().multiply(getMu().negate()),
- partialPV.getPosition());
- final FieldVector3D<T> acceleration = hasNonKeplerianRates() ?
- keplerianAcceleration.add(nonKeplerianAcceleration()) :
- keplerianAcceleration;
- return new TimeStampedFieldPVCoordinates<>(getDate(), partialPV.getPosition(), partialPV.getVelocity(), acceleration);
- }
- /** {@inheritDoc} */
- @Override
- public FieldCircularOrbit<T> inFrame(final Frame inertialFrame) {
- final FieldPVCoordinates<T> fieldPVCoordinates;
- if (hasNonKeplerianAcceleration()) {
- fieldPVCoordinates = getPVCoordinates(inertialFrame);
- } else {
- final FieldKinematicTransform<T> transform = getFrame().getKinematicTransformTo(inertialFrame, getDate());
- fieldPVCoordinates = transform.transformOnlyPV(getPVCoordinates());
- }
- final FieldCircularOrbit<T> fieldOrbit = new FieldCircularOrbit<>(fieldPVCoordinates, inertialFrame, getDate(), getMu());
- if (fieldOrbit.getCachedPositionAngleType() == getCachedPositionAngleType()) {
- return fieldOrbit;
- } else {
- return fieldOrbit.withCachedPositionAngleType(getCachedPositionAngleType());
- }
- }
- /** {@inheritDoc} */
- @Override
- public FieldCircularOrbit<T> withCachedPositionAngleType(final PositionAngleType positionAngleType) {
- return new FieldCircularOrbit<>(a, ex, ey, i, raan, getAlpha(positionAngleType), aDot, exDot, eyDot, iDot, raanDot,
- getAlphaDot(positionAngleType), positionAngleType, getFrame(), getDate(), getMu());
- }
- /** {@inheritDoc} */
- @Override
- public FieldCircularOrbit<T> shiftedBy(final double dt) {
- return shiftedBy(getZero().newInstance(dt));
- }
- /** {@inheritDoc} */
- @Override
- public FieldCircularOrbit<T> shiftedBy(final T dt) {
- // use Keplerian-only motion
- final FieldCircularOrbit<T> keplerianShifted = new FieldCircularOrbit<>(a, ex, ey, i, raan,
- getAlphaM().add(getKeplerianMeanMotion().multiply(dt)),
- PositionAngleType.MEAN, cachedPositionAngleType, getFrame(),
- getDate().shiftedBy(dt), getMu());
- if (hasNonKeplerianRates()) {
- // extract non-Keplerian acceleration from first time derivatives
- final FieldVector3D<T> nonKeplerianAcceleration = nonKeplerianAcceleration();
- // add quadratic effect of non-Keplerian acceleration to Keplerian-only shift
- keplerianShifted.computePVWithoutA();
- final FieldVector3D<T> fixedP = new FieldVector3D<>(getOne(), keplerianShifted.partialPV.getPosition(),
- dt.square().multiply(0.5), nonKeplerianAcceleration);
- final T fixedR2 = fixedP.getNormSq();
- final T fixedR = fixedR2.sqrt();
- final FieldVector3D<T> fixedV = new FieldVector3D<>(getOne(), keplerianShifted.partialPV.getVelocity(),
- dt, nonKeplerianAcceleration);
- final FieldVector3D<T> fixedA = new FieldVector3D<>(fixedR2.multiply(fixedR).reciprocal().multiply(getMu().negate()),
- keplerianShifted.partialPV.getPosition(),
- getOne(), nonKeplerianAcceleration);
- // build a new orbit, taking non-Keplerian acceleration into account
- return new FieldCircularOrbit<>(new TimeStampedFieldPVCoordinates<>(keplerianShifted.getDate(),
- fixedP, fixedV, fixedA),
- keplerianShifted.getFrame(), keplerianShifted.getMu());
- } else {
- // Keplerian-only motion is all we can do
- return keplerianShifted;
- }
- }
- /** {@inheritDoc} */
- @Override
- protected T[][] computeJacobianMeanWrtCartesian() {
- final T[][] jacobian = MathArrays.buildArray(getOne().getField(), 6, 6);
- // compute various intermediate parameters
- computePVWithoutA();
- final FieldVector3D<T> position = partialPV.getPosition();
- final FieldVector3D<T> velocity = partialPV.getVelocity();
- final T x = position.getX();
- final T y = position.getY();
- final T z = position.getZ();
- final T vx = velocity.getX();
- final T vy = velocity.getY();
- final T vz = velocity.getZ();
- final T pv = FieldVector3D.dotProduct(position, velocity);
- final T r2 = position.getNormSq();
- final T r = r2.sqrt();
- final T v2 = velocity.getNormSq();
- final T mu = getMu();
- final T oOsqrtMuA = getOne().divide(a.multiply(mu).sqrt());
- final T rOa = r.divide(a);
- final T aOr = a.divide(r);
- final T aOr2 = a.divide(r2);
- final T a2 = a.square();
- final T ex2 = ex.square();
- final T ey2 = ey.square();
- final T e2 = ex2.add(ey2);
- final T epsilon = e2.negate().add(1.0).sqrt();
- final T beta = epsilon.add(1).reciprocal();
- final T eCosE = rOa.negate().add(1);
- final T eSinE = pv.multiply(oOsqrtMuA);
- final FieldSinCos<T> scI = FastMath.sinCos(i);
- final FieldSinCos<T> scRaan = FastMath.sinCos(raan);
- final T cosI = scI.cos();
- final T sinI = scI.sin();
- final T cosRaan = scRaan.cos();
- final T sinRaan = scRaan.sin();
- // da
- fillHalfRow(aOr.multiply(2.0).multiply(aOr2), position, jacobian[0], 0);
- fillHalfRow(a2.multiply(mu.divide(2.).reciprocal()), velocity, jacobian[0], 3);
- // differentials of the normalized momentum
- final FieldVector3D<T> danP = new FieldVector3D<>(v2, position, pv.negate(), velocity);
- final FieldVector3D<T> danV = new FieldVector3D<>(r2, velocity, pv.negate(), position);
- final T recip = partialPV.getMomentum().getNorm().reciprocal();
- final T recip2 = recip.multiply(recip);
- final T recip2N = recip2.negate();
- final FieldVector3D<T> dwXP = new FieldVector3D<>(recip,
- new FieldVector3D<>(getZero(), vz, vy.negate()),
- recip2N.multiply(sinRaan).multiply(sinI),
- danP);
- final FieldVector3D<T> dwYP = new FieldVector3D<>(recip,
- new FieldVector3D<>(vz.negate(), getZero(), vx),
- recip2.multiply(cosRaan).multiply(sinI),
- danP);
- final FieldVector3D<T> dwZP = new FieldVector3D<>(recip,
- new FieldVector3D<>(vy, vx.negate(), getZero()),
- recip2N.multiply(cosI),
- danP);
- final FieldVector3D<T> dwXV = new FieldVector3D<>(recip,
- new FieldVector3D<>(getZero(), z.negate(), y),
- recip2N.multiply(sinRaan).multiply(sinI),
- danV);
- final FieldVector3D<T> dwYV = new FieldVector3D<>(recip,
- new FieldVector3D<>(z, getZero(), x.negate()),
- recip2.multiply(cosRaan).multiply(sinI),
- danV);
- final FieldVector3D<T> dwZV = new FieldVector3D<>(recip,
- new FieldVector3D<>(y.negate(), x, getZero()),
- recip2N.multiply(cosI),
- danV);
- // di
- fillHalfRow(sinRaan.multiply(cosI), dwXP, cosRaan.negate().multiply(cosI), dwYP, sinI.negate(), dwZP, jacobian[3], 0);
- fillHalfRow(sinRaan.multiply(cosI), dwXV, cosRaan.negate().multiply(cosI), dwYV, sinI.negate(), dwZV, jacobian[3], 3);
- // dRaan
- fillHalfRow(sinRaan.divide(sinI), dwYP, cosRaan.divide(sinI), dwXP, jacobian[4], 0);
- fillHalfRow(sinRaan.divide(sinI), dwYV, cosRaan.divide(sinI), dwXV, jacobian[4], 3);
- // orbital frame: (p, q, w) p along ascending node, w along momentum
- // the coordinates of the spacecraft in this frame are: (u, v, 0)
- final T u = x.multiply(cosRaan).add(y.multiply(sinRaan));
- final T cv = x.negate().multiply(sinRaan).add(y.multiply(cosRaan));
- final T v = cv.multiply(cosI).add(z.multiply(sinI));
- // du
- final FieldVector3D<T> duP = new FieldVector3D<>(cv.multiply(cosRaan).divide(sinI), dwXP,
- cv.multiply(sinRaan).divide(sinI), dwYP,
- getOne(), new FieldVector3D<>(cosRaan, sinRaan, getZero()));
- final FieldVector3D<T> duV = new FieldVector3D<>(cv.multiply(cosRaan).divide(sinI), dwXV,
- cv.multiply(sinRaan).divide(sinI), dwYV);
- // dv
- final FieldVector3D<T> dvP = new FieldVector3D<>(u.negate().multiply(cosRaan).multiply(cosI).divide(sinI).add(sinRaan.multiply(z)), dwXP,
- u.negate().multiply(sinRaan).multiply(cosI).divide(sinI).subtract(cosRaan.multiply(z)), dwYP,
- cv, dwZP,
- getOne(), new FieldVector3D<>(sinRaan.negate().multiply(cosI), cosRaan.multiply(cosI), sinI));
- final FieldVector3D<T> dvV = new FieldVector3D<>(u.negate().multiply(cosRaan).multiply(cosI).divide(sinI).add(sinRaan.multiply(z)), dwXV,
- u.negate().multiply(sinRaan).multiply(cosI).divide(sinI).subtract(cosRaan.multiply(z)), dwYV,
- cv, dwZV);
- final FieldVector3D<T> dc1P = new FieldVector3D<>(aOr2.multiply(eSinE.multiply(eSinE).multiply(2).add(1).subtract(eCosE)).divide(r2), position,
- aOr2.multiply(-2).multiply(eSinE).multiply(oOsqrtMuA), velocity);
- final FieldVector3D<T> dc1V = new FieldVector3D<>(aOr2.multiply(-2).multiply(eSinE).multiply(oOsqrtMuA), position,
- getZero().newInstance(2).divide(mu), velocity);
- final FieldVector3D<T> dc2P = new FieldVector3D<>(aOr2.multiply(eSinE).multiply(eSinE.multiply(eSinE).subtract(e2.negate().add(1))).divide(r2.multiply(epsilon)), position,
- aOr2.multiply(e2.negate().add(1).subtract(eSinE.multiply(eSinE))).multiply(oOsqrtMuA).divide(epsilon), velocity);
- final FieldVector3D<T> dc2V = new FieldVector3D<>(aOr2.multiply(e2.negate().add(1).subtract(eSinE.multiply(eSinE))).multiply(oOsqrtMuA).divide(epsilon), position,
- eSinE.divide(epsilon.multiply(mu)), velocity);
- final T cof1 = aOr2.multiply(eCosE.subtract(e2));
- final T cof2 = aOr2.multiply(epsilon).multiply(eSinE);
- final FieldVector3D<T> dexP = new FieldVector3D<>(u, dc1P, v, dc2P, cof1, duP, cof2, dvP);
- final FieldVector3D<T> dexV = new FieldVector3D<>(u, dc1V, v, dc2V, cof1, duV, cof2, dvV);
- final FieldVector3D<T> deyP = new FieldVector3D<>(v, dc1P, u.negate(), dc2P, cof1, dvP, cof2.negate(), duP);
- final FieldVector3D<T> deyV = new FieldVector3D<>(v, dc1V, u.negate(), dc2V, cof1, dvV, cof2.negate(), duV);
- fillHalfRow(getOne(), dexP, jacobian[1], 0);
- fillHalfRow(getOne(), dexV, jacobian[1], 3);
- fillHalfRow(getOne(), deyP, jacobian[2], 0);
- fillHalfRow(getOne(), deyV, jacobian[2], 3);
- final T cle = u.divide(a).add(ex).subtract(eSinE.multiply(beta).multiply(ey));
- final T sle = v.divide(a).add(ey).add(eSinE.multiply(beta).multiply(ex));
- final T m1 = beta.multiply(eCosE);
- final T m2 = m1.multiply(eCosE).negate().add(1);
- final T m3 = (u.multiply(ey).subtract(v.multiply(ex))).add(eSinE.multiply(beta).multiply(u.multiply(ex).add(v.multiply(ey))));
- final T m4 = sle.negate().add(cle.multiply(eSinE).multiply(beta));
- final T m5 = cle.add(sle.multiply(eSinE).multiply(beta));
- final T kk = m3.multiply(2).divide(r).add(aOr.multiply(eSinE)).add(m1.multiply(eSinE).multiply(m1.add(1).subtract(aOr.add(1).multiply(m2))).divide(epsilon)).divide(r2);
- final T jj = (m1.multiply(m2).divide(epsilon).subtract(1)).multiply(oOsqrtMuA);
- fillHalfRow(kk, position,
- jj, velocity,
- m4, dexP,
- m5, deyP,
- sle.negate().divide(a), duP,
- cle.divide(a), dvP,
- jacobian[5], 0);
- final T ll = (m1.multiply(m2).divide(epsilon ).subtract(1)).multiply(oOsqrtMuA);
- final T mm = m3.multiply(2).add(eSinE.multiply(a)).add(m1.multiply(eSinE).multiply(r).multiply(eCosE.multiply(beta).multiply(2).subtract(aOr.multiply(m2))).divide(epsilon)).divide(mu);
- fillHalfRow(ll, position,
- mm, velocity,
- m4, dexV,
- m5, deyV,
- sle.negate().divide(a), duV,
- cle.divide(a), dvV,
- jacobian[5], 3);
- return jacobian;
- }
- /** {@inheritDoc} */
- @Override
- protected T[][] computeJacobianEccentricWrtCartesian() {
- // start by computing the Jacobian with mean angle
- final T[][] jacobian = computeJacobianMeanWrtCartesian();
- // Differentiating the Kepler equation aM = aE - ex sin aE + ey cos aE leads to:
- // daM = (1 - ex cos aE - ey sin aE) dE - sin aE dex + cos aE dey
- // which is inverted and rewritten as:
- // daE = a/r daM + sin aE a/r dex - cos aE a/r dey
- final T alphaE = getAlphaE();
- final FieldSinCos<T> scAe = FastMath.sinCos(alphaE);
- final T cosAe = scAe.cos();
- final T sinAe = scAe.sin();
- final T aOr = getOne().divide(getOne().subtract(ex.multiply(cosAe)).subtract(ey.multiply(sinAe)));
- // update longitude row
- final T[] rowEx = jacobian[1];
- final T[] rowEy = jacobian[2];
- final T[] rowL = jacobian[5];
- for (int j = 0; j < 6; ++j) {
- // rowL[j] = aOr * ( rowL[j] + sinAe * rowEx[j] - cosAe * rowEy[j]);
- rowL[j] = aOr.multiply(rowL[j].add(sinAe.multiply(rowEx[j])).subtract( cosAe.multiply(rowEy[j])));
- }
- jacobian[5] = rowL;
- return jacobian;
- }
- /** {@inheritDoc} */
- @Override
- protected T[][] computeJacobianTrueWrtCartesian() {
- // start by computing the Jacobian with eccentric angle
- final T[][] jacobian = computeJacobianEccentricWrtCartesian();
- // Differentiating the eccentric latitude equation
- // tan((aV - aE)/2) = [ex sin aE - ey cos aE] / [sqrt(1-ex^2-ey^2) + 1 - ex cos aE - ey sin aE]
- // leads to
- // cT (daV - daE) = cE daE + cX dex + cY dey
- // with
- // cT = [d^2 + (ex sin aE - ey cos aE)^2] / 2
- // d = 1 + sqrt(1-ex^2-ey^2) - ex cos aE - ey sin aE
- // cE = (ex cos aE + ey sin aE) (sqrt(1-ex^2-ey^2) + 1) - ex^2 - ey^2
- // cX = sin aE (sqrt(1-ex^2-ey^2) + 1) - ey + ex (ex sin aE - ey cos aE) / sqrt(1-ex^2-ey^2)
- // cY = -cos aE (sqrt(1-ex^2-ey^2) + 1) + ex + ey (ex sin aE - ey cos aE) / sqrt(1-ex^2-ey^2)
- // which can be solved to find the differential of the true latitude
- // daV = (cT + cE) / cT daE + cX / cT deX + cY / cT deX
- final T alphaE = getAlphaE();
- final FieldSinCos<T> scAe = FastMath.sinCos(alphaE);
- final T cosAe = scAe.cos();
- final T sinAe = scAe.sin();
- final T eSinE = ex.multiply(sinAe).subtract(ey.multiply(cosAe));
- final T ecosE = ex.multiply(cosAe).add(ey.multiply(sinAe));
- final T e2 = ex.multiply(ex).add(ey.multiply(ey));
- final T epsilon = (getOne().subtract(e2)).sqrt();
- final T onePeps = getOne().add(epsilon);
- final T d = onePeps.subtract(ecosE);
- final T cT = (d.multiply(d).add(eSinE.multiply(eSinE))).divide(2);
- final T cE = ecosE.multiply(onePeps).subtract(e2);
- final T cX = ex.multiply(eSinE).divide(epsilon).subtract(ey).add(sinAe.multiply(onePeps));
- final T cY = ey.multiply(eSinE).divide(epsilon).add(ex).subtract(cosAe.multiply(onePeps));
- final T factorLe = (cT.add(cE)).divide(cT);
- final T factorEx = cX.divide(cT);
- final T factorEy = cY.divide(cT);
- // update latitude row
- final T[] rowEx = jacobian[1];
- final T[] rowEy = jacobian[2];
- final T[] rowA = jacobian[5];
- for (int j = 0; j < 6; ++j) {
- rowA[j] = factorLe.multiply(rowA[j]).add(factorEx.multiply(rowEx[j])).add(factorEy.multiply(rowEy[j]));
- }
- return jacobian;
- }
- /** {@inheritDoc} */
- @Override
- public void addKeplerContribution(final PositionAngleType type, final T gm, final T[] pDot) {
- pDot[5] = pDot[5].add(computeKeplerianAlphaDot(type, a, ex, ey, gm, cachedAlpha, cachedPositionAngleType));
- }
- /**
- * Compute rate of argument of latitude.
- * @param type position angle type of rate
- * @param a semi major axis
- * @param ex ex
- * @param ey ey
- * @param mu mu
- * @param alpha argument of latitude
- * @param cachedType position angle type of passed alpha
- * @param <T> field type
- * @return first-order time derivative for alpha
- * @since 12.2
- */
- private static <T extends CalculusFieldElement<T>> T computeKeplerianAlphaDot(final PositionAngleType type, final T a,
- final T ex, final T ey, final T mu,
- final T alpha, final PositionAngleType cachedType) {
- final T n = a.reciprocal().multiply(mu).sqrt().divide(a);
- if (type == PositionAngleType.MEAN) {
- return n;
- }
- final FieldSinCos<T> sc;
- final T ksi;
- if (type == PositionAngleType.ECCENTRIC) {
- sc = FastMath.sinCos(FieldCircularLatitudeArgumentUtility.convertAlpha(cachedType, alpha, ex, ey, type));
- ksi = ((ex.multiply(sc.cos())).add(ey.multiply(sc.sin()))).negate().add(1).reciprocal();
- return n.multiply(ksi);
- } else { // TRUE
- sc = FastMath.sinCos(FieldCircularLatitudeArgumentUtility.convertAlpha(cachedType, alpha, ex, ey, type));
- final T one = n.getField().getOne();
- final T oMe2 = one.subtract(ex.square()).subtract(ey.square());
- ksi = one.add(ex.multiply(sc.cos())).add(ey.multiply(sc.sin()));
- return n.multiply(ksi.square()).divide(oMe2.multiply(oMe2.sqrt()));
- }
- }
- /** Returns a string representation of this Orbit object.
- * @return a string representation of this object
- */
- public String toString() {
- return new StringBuilder().append("circular parameters: ").append('{').
- append("a: ").append(a.getReal()).
- append(", ex: ").append(ex.getReal()).append(", ey: ").append(ey.getReal()).
- append(", i: ").append(FastMath.toDegrees(i.getReal())).
- append(", raan: ").append(FastMath.toDegrees(raan.getReal())).
- append(", alphaV: ").append(FastMath.toDegrees(getAlphaV().getReal())).
- append(";}").toString();
- }
- /** {@inheritDoc} */
- @Override
- public PositionAngleType getCachedPositionAngleType() {
- return cachedPositionAngleType;
- }
- /** {@inheritDoc} */
- @Override
- public boolean hasNonKeplerianRates() {
- return hasNonKeplerianAcceleration();
- }
- /** {@inheritDoc} */
- @Override
- public FieldCircularOrbit<T> withKeplerianRates() {
- return new FieldCircularOrbit<>(getA(), getCircularEx(), getCircularEy(),
- getI(), getRightAscensionOfAscendingNode(), cachedAlpha,
- cachedPositionAngleType, getFrame(), getDate(), getMu());
- }
- /** {@inheritDoc} */
- @Override
- public CircularOrbit toOrbit() {
- final double cachedPositionAngle = cachedAlpha.getReal();
- return new CircularOrbit(a.getReal(), ex.getReal(), ey.getReal(),
- i.getReal(), raan.getReal(), cachedPositionAngle,
- aDot.getReal(), exDot.getReal(), eyDot.getReal(),
- iDot.getReal(), raanDot.getReal(), cachedAlphaDot.getReal(),
- cachedPositionAngleType, getFrame(),
- getDate().toAbsoluteDate(), getMu().getReal());
- }
- }