J2DifferentialEffect.java

  1. /* Copyright 2002-2013 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.propagation.analytical;

  18. import org.apache.commons.math3.util.FastMath;
  19. import org.orekit.errors.OrekitException;
  20. import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider;
  21. import org.orekit.orbits.EquinoctialOrbit;
  22. import org.orekit.orbits.Orbit;
  23. import org.orekit.orbits.OrbitType;
  24. import org.orekit.orbits.PositionAngle;
  25. import org.orekit.propagation.SpacecraftState;
  26. import org.orekit.time.AbsoluteDate;

  27. /** Analytical model for J2 effect.
  28.  * <p>
  29.  * This class computes the differential effect of J2 due to an initial orbit
  30.  * offset. A typical case is when an inclination maneuver changes an orbit
  31.  * inclination at time t<sub>0</sub>. As ascending node drift rate depends on
  32.  * inclination, the change induces a time-dependent change in ascending node
  33.  * for later dates.
  34.  * </p>
  35.  * @see org.orekit.forces.maneuvers.SmallManeuverAnalyticalModel
  36.  * @author Luc Maisonobe
  37.  */
  38. public class J2DifferentialEffect
  39.     implements AdapterPropagator.DifferentialEffect {

  40.     /** Reference date. */
  41.     private final AbsoluteDate referenceDate;

  42.     /** Differential drift on perigee argument. */
  43.     private final double dPaDot;

  44.     /** Differential drift on ascending node. */
  45.     private final double dRaanDot;

  46.     /** Indicator for applying effect before reference date. */
  47.     private final boolean applyBefore;

  48.     /** Simple constructor.
  49.      * <p>
  50.      * The {@code applyBefore} parameter is mainly used when the differential
  51.      * effect is associated with a maneuver. In this case, the parameter must be
  52.      * set to {@code false}.
  53.      * </p>
  54.      * @param original original state at reference date
  55.      * @param directEffect direct effect changing the orbit
  56.      * @param applyBefore if true, effect is applied both before and after
  57.      * reference date, if false it is only applied after reference date
  58.      * @param gravityField gravity field to use
  59.      * @exception OrekitException if gravity field does not contain J2 coefficient
  60.      */
  61.     public J2DifferentialEffect(final SpacecraftState original,
  62.                                 final AdapterPropagator.DifferentialEffect directEffect,
  63.                                 final boolean applyBefore,
  64.                                 final UnnormalizedSphericalHarmonicsProvider gravityField)
  65.         throws OrekitException {
  66.         this(original, directEffect, applyBefore,
  67.              gravityField.getAe(), gravityField.getMu(),
  68.              -gravityField.onDate(original.getDate()).getUnnormalizedCnm(2, 0));
  69.     }

  70.     /** Simple constructor.
  71.          * <p>
  72.          * The {@code applyBefore} parameter is mainly used when the differential
  73.          * effect is associated with a maneuver. In this case, the parameter must be
  74.          * set to {@code false}.
  75.          * </p>
  76.          * @param orbit0 original orbit at reference date
  77.          * @param orbit1 shifted orbit at reference date
  78.          * @param applyBefore if true, effect is applied both before and after
  79.          * reference date, if false it is only applied after reference date
  80.          * @param gravityField gravity field to use
  81.          * @exception OrekitException if gravity field does not contain J2 coefficient
  82.          */
  83.     public J2DifferentialEffect(final Orbit orbit0, final Orbit orbit1, final boolean applyBefore,
  84.                                 final UnnormalizedSphericalHarmonicsProvider gravityField)
  85.         throws OrekitException {
  86.         this(orbit0, orbit1, applyBefore,
  87.              gravityField.getAe(), gravityField.getMu(),
  88.              -gravityField.onDate(orbit0.getDate()).getUnnormalizedCnm(2, 0));
  89.     }

  90.     /** Simple constructor.
  91.      * <p>
  92.      * The {@code applyBefore} parameter is mainly used when the differential
  93.      * effect is associated with a maneuver. In this case, the parameter must be
  94.      * set to {@code false}.
  95.      * </p>
  96.      * @param original original state at reference date
  97.      * @param directEffect direct effect changing the orbit
  98.      * @param applyBefore if true, effect is applied both before and after
  99.      * reference date, if false it is only applied after reference date
  100.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  101.      * @param mu central attraction coefficient (m<sup>3</sup>/s<sup>2</sup>)
  102.      * @param j2 un-normalized zonal coefficient (about +1.08e-3 for Earth)
  103.      * @exception OrekitException if direct effect cannot be applied
  104.      */
  105.     public J2DifferentialEffect(final SpacecraftState original,
  106.                                 final AdapterPropagator.DifferentialEffect directEffect,
  107.                                 final boolean applyBefore,
  108.                                 final double referenceRadius, final double mu, final double j2)
  109.         throws OrekitException {
  110.         this(original.getOrbit(),
  111.              directEffect.apply(original.shiftedBy(0.001)).getOrbit().shiftedBy(-0.001),
  112.              applyBefore, referenceRadius, mu, j2);
  113.     }

  114.     /** Simple constructor.
  115.      * <p>
  116.      * The {@code applyBefore} parameter is mainly used when the differential
  117.      * effect is associated with a maneuver. In this case, the parameter must be
  118.      * set to {@code false}.
  119.      * </p>
  120.      * @param orbit0 original orbit at reference date
  121.      * @param orbit1 shifted orbit at reference date
  122.      * @param applyBefore if true, effect is applied both before and after
  123.      * reference date, if false it is only applied after reference date
  124.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  125.      * @param mu central attraction coefficient (m<sup>3</sup>/s<sup>2</sup>)
  126.      * @param j2 un-normalized zonal coefficient (about +1.08e-3 for Earth)
  127.      */
  128.     public J2DifferentialEffect(final Orbit orbit0, final Orbit orbit1, final boolean applyBefore,
  129.                                 final double referenceRadius, final double mu, final double j2) {

  130.         this.referenceDate = orbit0.getDate();
  131.         this.applyBefore   = applyBefore;

  132.         // extract useful parameters
  133.         final double a0 = orbit0.getA();
  134.         final double e0 = orbit0.getE();
  135.         final double i0 = orbit0.getI();
  136.         final double a1 = orbit1.getA();
  137.         final double e1 = orbit1.getE();
  138.         final double i1 = orbit1.getI();

  139.         // compute reference drifts
  140.         final double oMe2       = 1 - e0 * e0;
  141.         final double ratio      = referenceRadius / (a0 * oMe2);
  142.         final double cosI       = FastMath.cos(i0);
  143.         final double sinI       = FastMath.sin(i0);
  144.         final double n          = FastMath.sqrt(mu / a0) / a0;
  145.         final double c          = ratio * ratio * n * j2;
  146.         final double refPaDot   =  0.75 * c * (4 - 5 * sinI * sinI);
  147.         final double refRaanDot = -1.5  * c * cosI;

  148.         // differential model on perigee argument drift
  149.         final double dPaDotDa = -3.5 * refPaDot / a0;
  150.         final double dPaDotDe = 4 * refPaDot * e0 / oMe2;
  151.         final double dPaDotDi = -7.5 * c * sinI * cosI;
  152.         dPaDot = dPaDotDa * (a1 - a0) + dPaDotDe * (e1 - e0) + dPaDotDi * (i1 - i0);

  153.         // differential model on ascending node drift
  154.         final double dRaanDotDa = -3.5 * refRaanDot / a0;
  155.         final double dRaanDotDe = 4 * refRaanDot * e0 / oMe2;
  156.         final double dRaanDotDi = -refRaanDot * FastMath.tan(i0);
  157.         dRaanDot = dRaanDotDa * (a1 - a0) + dRaanDotDe * (e1 - e0) + dRaanDotDi * (i1 - i0);

  158.     }

  159.     /** Compute the effect of the maneuver on an orbit.
  160.      * @param orbit1 original orbit at t<sub>1</sub>, without maneuver
  161.      * @return orbit at t<sub>1</sub>, taking the maneuver
  162.      * into account if t<sub>1</sub> &gt; t<sub>0</sub>
  163.      * @see #apply(SpacecraftState)
  164.      */
  165.     public Orbit apply(final Orbit orbit1) {

  166.         if (orbit1.getDate().compareTo(referenceDate) <= 0 && !applyBefore) {
  167.             // the orbit change has not occurred yet, don't change anything
  168.             return orbit1;
  169.         }

  170.         return updateOrbit(orbit1);

  171.     }

  172.     /** {@inheritDoc} */
  173.     public SpacecraftState apply(final SpacecraftState state1) {

  174.         if (state1.getDate().compareTo(referenceDate) <= 0 && !applyBefore) {
  175.             // the orbit change has not occurred yet, don't change anything
  176.             return state1;
  177.         }

  178.         return new SpacecraftState(updateOrbit(state1.getOrbit()),
  179.                                    state1.getAttitude(), state1.getMass());

  180.     }

  181.     /** Compute the differential effect of J2 on an orbit.
  182.      * @param orbit1 original orbit at t<sub>1</sub>, without differential J2
  183.      * @return orbit at t<sub>1</sub>, always taking the effect into account
  184.      */
  185.     private Orbit updateOrbit(final Orbit orbit1) {

  186.         // convert current orbital state to equinoctial elements
  187.         final EquinoctialOrbit original =
  188.                 (EquinoctialOrbit) OrbitType.EQUINOCTIAL.convertType(orbit1);

  189.         // compute differential effect
  190.         final AbsoluteDate date = original.getDate();
  191.         final double dt         = date.durationFrom(referenceDate);
  192.         final double dPaRaan    = (dPaDot + dRaanDot) * dt;
  193.         final double cPaRaan    = FastMath.cos(dPaRaan);
  194.         final double sPaRaan    = FastMath.sin(dPaRaan);
  195.         final double dRaan      = dRaanDot * dt;
  196.         final double cRaan      = FastMath.cos(dRaan);
  197.         final double sRaan      = FastMath.sin(dRaan);

  198.         final double ex         = original.getEquinoctialEx() * cPaRaan -
  199.                                   original.getEquinoctialEy() * sPaRaan;
  200.         final double ey         = original.getEquinoctialEx() * sPaRaan +
  201.                                   original.getEquinoctialEy() * cPaRaan;
  202.         final double hx         = original.getHx() * cRaan - original.getHy() * sRaan;
  203.         final double hy         = original.getHx() * sRaan + original.getHy() * cRaan;
  204.         final double lambda     = original.getLv() + dPaRaan;

  205.         // build updated orbit
  206.         final EquinoctialOrbit updated =
  207.                 new EquinoctialOrbit(original.getA(), ex, ey, hx, hy, lambda, PositionAngle.TRUE,
  208.                                      original.getFrame(), date, original.getMu());

  209.         // convert to required type
  210.         return orbit1.getType().convertType(updated);

  211.     }

  212. }