ImpulseManeuver.java

  1. /* Copyright 2002-2018 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.forces.maneuvers;

  18. import java.util.Map;

  19. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  20. import org.hipparchus.util.FastMath;
  21. import org.orekit.attitudes.Attitude;
  22. import org.orekit.attitudes.AttitudeProvider;
  23. import org.orekit.errors.OrekitException;
  24. import org.orekit.orbits.CartesianOrbit;
  25. import org.orekit.propagation.SpacecraftState;
  26. import org.orekit.propagation.events.AbstractDetector;
  27. import org.orekit.propagation.events.EventDetector;
  28. import org.orekit.propagation.events.handlers.EventHandler;
  29. import org.orekit.time.AbsoluteDate;
  30. import org.orekit.utils.Constants;
  31. import org.orekit.utils.PVCoordinates;

  32. /** Impulse maneuver model.
  33.  * <p>This class implements an impulse maneuver as a discrete event
  34.  * that can be provided to any {@link org.orekit.propagation.Propagator
  35.  * Propagator}.</p>
  36.  * <p>The maneuver is triggered when an underlying event generates a
  37.  * {@link org.orekit.propagation.events.handlers.EventHandler.Action#STOP STOP} event,
  38.  * in which case this class will generate a {@link
  39.  * org.orekit.propagation.events.handlers.EventHandler.Action#RESET_STATE RESET_STATE}
  40.  * event (the stop event from the underlying object is therefore filtered out).
  41.  * In the simple cases, the underlying event detector may be a basic
  42.  * {@link org.orekit.propagation.events.DateDetector date event}, but it
  43.  * can also be a more elaborate {@link
  44.  * org.orekit.propagation.events.ApsideDetector apside event} for apogee
  45.  * maneuvers for example.</p>
  46.  * <p>The maneuver is defined by a single velocity increment in satellite
  47.  * frame. The current attitude of the spacecraft, defined by the current
  48.  * spacecraft state, will be used to compute the velocity direction in
  49.  * inertial frame. A typical case for tangential maneuvers is to use a
  50.  * {@link org.orekit.attitudes.LofOffset LOF aligned} attitude provider for state propagation and a
  51.  * velocity increment along the +X satellite axis.</p>
  52.  * <p>Beware that the triggering event detector must behave properly both
  53.  * before and after maneuver. If for example a node detector is used to trigger
  54.  * an inclination maneuver and the maneuver change the orbit to an equatorial one,
  55.  * the node detector will fail just after the maneuver, being unable to find a
  56.  * node on an equatorial orbit! This is a real case that has been encountered
  57.  * during validation ...</p>
  58.  * @see org.orekit.propagation.Propagator#addEventDetector(EventDetector)
  59.  * @param <T> class type for the generic version
  60.  * @author Luc Maisonobe
  61.  */
  62. public class ImpulseManeuver<T extends EventDetector> extends AbstractDetector<ImpulseManeuver<T>> {

  63.     /** Serializable UID. */
  64.     private static final long serialVersionUID = 20131118L;

  65.     /** The attitude to override during the maneuver, if set. */
  66.     private final AttitudeProvider attitudeOverride;

  67.     /** Triggering event. */
  68.     private final T trigger;

  69.     /** Velocity increment in satellite frame. */
  70.     private final Vector3D deltaVSat;

  71.     /** Specific impulse. */
  72.     private final double isp;

  73.     /** Engine exhaust velocity. */
  74.     private final double vExhaust;

  75.     /** Indicator for forward propagation. */
  76.     private boolean forward;

  77.     /** Build a new instance.
  78.      * @param trigger triggering event
  79.      * @param deltaVSat velocity increment in satellite frame
  80.      * @param isp engine specific impulse (s)
  81.      */
  82.     public ImpulseManeuver(final T trigger, final Vector3D deltaVSat, final double isp) {
  83.         this(trigger.getMaxCheckInterval(), trigger.getThreshold(),
  84.              trigger.getMaxIterationCount(), new Handler<T>(),
  85.              trigger, null, deltaVSat, isp);
  86.     }


  87.     /** Build a new instance.
  88.      * @param trigger triggering event
  89.      * @param attitudeOverride the attitude provider to use for the maneuver
  90.      * @param deltaVSat velocity increment in satellite frame
  91.      * @param isp engine specific impulse (s)
  92.      */
  93.     public ImpulseManeuver(final T trigger, final AttitudeProvider attitudeOverride, final Vector3D deltaVSat, final double isp) {
  94.         this(trigger.getMaxCheckInterval(), trigger.getThreshold(),
  95.              trigger.getMaxIterationCount(), new Handler<T>(),
  96.              trigger, attitudeOverride, deltaVSat, isp);
  97.     }

  98.     /** Private constructor with full parameters.
  99.      * <p>
  100.      * This constructor is private as users are expected to use the builder
  101.      * API with the various {@code withXxx()} methods to set up the instance
  102.      * in a readable manner without using a huge amount of parameters.
  103.      * </p>
  104.      * @param maxCheck maximum checking interval (s)
  105.      * @param threshold convergence threshold (s)
  106.      * @param maxIter maximum number of iterations in the event time search
  107.      * @param handler event handler to call at event occurrences
  108.      * @param trigger triggering event
  109.      * @param attitudeOverride the attitude provider to use for the maneuver
  110.      * @param deltaVSat velocity increment in satellite frame
  111.      * @param isp engine specific impulse (s)
  112.      * @since 6.1
  113.      */
  114.     private ImpulseManeuver(final double maxCheck, final double threshold,
  115.                             final int maxIter, final EventHandler<? super ImpulseManeuver<T>> handler,
  116.                             final T trigger, final AttitudeProvider attitudeOverride, final Vector3D deltaVSat,
  117.                             final double isp) {
  118.         super(maxCheck, threshold, maxIter, handler);
  119.         this.attitudeOverride = attitudeOverride;
  120.         this.trigger   = trigger;
  121.         this.deltaVSat = deltaVSat;
  122.         this.isp       = isp;
  123.         this.vExhaust  = Constants.G0_STANDARD_GRAVITY * isp;
  124.     }

  125.     /** {@inheritDoc} */
  126.     @Override
  127.     protected ImpulseManeuver<T> create(final double newMaxCheck, final double newThreshold,
  128.                                         final int newMaxIter, final EventHandler<? super ImpulseManeuver<T>> newHandler) {
  129.         return new ImpulseManeuver<T>(newMaxCheck, newThreshold, newMaxIter, newHandler,
  130.                                       trigger, attitudeOverride, deltaVSat, isp);
  131.     }

  132.     /** {@inheritDoc} */
  133.     public void init(final SpacecraftState s0, final AbsoluteDate t) {
  134.         forward = t.durationFrom(s0.getDate()) >= 0;
  135.     }

  136.     /** {@inheritDoc} */
  137.     public double g(final SpacecraftState s) throws OrekitException {
  138.         return trigger.g(s);
  139.     }

  140.     /**
  141.      * Get the Attitude Provider to use during maneuver.
  142.      * @return the attitude provider
  143.      */
  144.     public AttitudeProvider getAttitudeOverride() {
  145.         return attitudeOverride;
  146.     }

  147.     /** Get the triggering event.
  148.      * @return triggering event
  149.      */
  150.     public T getTrigger() {
  151.         return trigger;
  152.     }

  153.     /** Get the velocity increment in satellite frame.
  154.     * @return velocity increment in satellite frame
  155.     */
  156.     public Vector3D getDeltaVSat() {
  157.         return deltaVSat;
  158.     }

  159.     /** Get the specific impulse.
  160.     * @return specific impulse
  161.     */
  162.     public double getIsp() {
  163.         return isp;
  164.     }

  165.     /** Local handler.
  166.      * @param <T> class type for the generic version
  167.      */
  168.     private static class Handler<T extends EventDetector> implements EventHandler<ImpulseManeuver<T>> {

  169.         /** {@inheritDoc} */
  170.         public EventHandler.Action eventOccurred(final SpacecraftState s, final ImpulseManeuver<T> im,
  171.                                                  final boolean increasing)
  172.             throws OrekitException {

  173.             // filter underlying event
  174.             final EventHandler.Action underlyingAction = im.trigger.eventOccurred(s, increasing);

  175.             return (underlyingAction == Action.STOP) ? Action.RESET_STATE : Action.CONTINUE;

  176.         }

  177.         /** {@inheritDoc} */
  178.         @Override
  179.         public SpacecraftState resetState(final ImpulseManeuver<T> im, final SpacecraftState oldState)
  180.             throws OrekitException {

  181.             final AbsoluteDate date = oldState.getDate();
  182.             final AttitudeProvider override = im.getAttitudeOverride();
  183.             final Attitude attitude;

  184.             if (override == null) {
  185.                 attitude = oldState.getAttitude();
  186.             } else {
  187.                 attitude = override.getAttitude(oldState.getOrbit(), date, oldState.getFrame());
  188.             }

  189.             // convert velocity increment in inertial frame
  190.             final Vector3D deltaV = attitude.getRotation().applyInverseTo(im.deltaVSat);
  191.             final double sign     = im.forward ? +1 : -1;

  192.             // apply increment to position/velocity
  193.             final PVCoordinates oldPV = oldState.getPVCoordinates();
  194.             final PVCoordinates newPV =
  195.                             new PVCoordinates(oldPV.getPosition(),
  196.                                               new Vector3D(1, oldPV.getVelocity(), sign, deltaV));
  197.             final CartesianOrbit newOrbit =
  198.                     new CartesianOrbit(newPV, oldState.getFrame(), date, oldState.getMu());

  199.             // compute new mass
  200.             final double newMass = oldState.getMass() * FastMath.exp(-sign * deltaV.getNorm() / im.vExhaust);

  201.             // pack everything in a new state
  202.             SpacecraftState newState = new SpacecraftState(oldState.getOrbit().getType().convertType(newOrbit),
  203.                                                            attitude, newMass);
  204.             for (final Map.Entry<String, double[]> entry : oldState.getAdditionalStates().entrySet()) {
  205.                 newState = newState.addAdditionalState(entry.getKey(), entry.getValue());
  206.             }
  207.             return newState;


  208.         }

  209.     }

  210. }