PVCoordinates.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.utils;

  18. import java.io.Serializable;
  19. import java.util.Collection;

  20. import org.apache.commons.math3.analysis.differentiation.DerivativeStructure;
  21. import org.apache.commons.math3.analysis.interpolation.HermiteInterpolator;
  22. import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
  23. import org.apache.commons.math3.util.Pair;
  24. import org.orekit.time.AbsoluteDate;
  25. import org.orekit.time.TimeShiftable;

  26. /** Simple container for Position/Velocity pairs.
  27.  * <p>
  28.  * The state can be slightly shifted to close dates. This shift is based on
  29.  * a simple linear model. It is <em>not</em> intended as a replacement for
  30.  * proper orbit propagation (it is not even Keplerian!) but should be sufficient
  31.  * for either small time shifts or coarse accuracy.
  32.  * </p>
  33.  * <p>
  34.  * This class is the angular counterpart to {@link AngularCoordinates}.
  35.  * </p>
  36.  * <p>Instances of this class are guaranteed to be immutable.</p>
  37.  * @author Fabien Maussion
  38.  * @author Luc Maisonobe
  39.  */
  40. public class PVCoordinates implements TimeShiftable<PVCoordinates>, Serializable {

  41.     /** Fixed position/velocity at origin (both p and v are zero vectors). */
  42.     public static final PVCoordinates ZERO = new PVCoordinates(Vector3D.ZERO, Vector3D.ZERO);

  43.     /** Serializable UID. */
  44.     private static final long serialVersionUID = 4157449919684833834L;

  45.     /** The position. */
  46.     private final Vector3D position;

  47.     /** The velocity. */
  48.     private final Vector3D velocity;

  49.     /** Simple constructor.
  50.      * <p> Sets the Coordinates to default : (0 0 0) (0 0 0).</p>
  51.      */
  52.     public PVCoordinates() {
  53.         position = Vector3D.ZERO;
  54.         velocity = Vector3D.ZERO;
  55.     }

  56.     /** Builds a PVCoordinates pair.
  57.      * @param position the position vector (m)
  58.      * @param velocity the velocity vector (m/s)
  59.      */
  60.     public PVCoordinates(final Vector3D position, final Vector3D velocity) {
  61.         this.position = position;
  62.         this.velocity = velocity;
  63.     }

  64.     /** Multiplicative constructor
  65.      * <p>Build a PVCoordinates from another one and a scale factor.</p>
  66.      * <p>The PVCoordinates built will be a * pv</p>
  67.      * @param a scale factor
  68.      * @param pv base (unscaled) PVCoordinates
  69.      */
  70.     public PVCoordinates(final double a, final PVCoordinates pv) {
  71.         position = new Vector3D(a, pv.position);
  72.         velocity = new Vector3D(a, pv.velocity);
  73.     }

  74.     /** Subtractive constructor
  75.      * <p>Build a relative PVCoordinates from a start and an end position.</p>
  76.      * <p>The PVCoordinates built will be end - start.</p>
  77.      * @param start Starting PVCoordinates
  78.      * @param end ending PVCoordinates
  79.      */
  80.     public PVCoordinates(final PVCoordinates start, final PVCoordinates end) {
  81.         this.position = end.position.subtract(start.position);
  82.         this.velocity = end.velocity.subtract(start.velocity);
  83.     }

  84.     /** Linear constructor
  85.      * <p>Build a PVCoordinates from two other ones and corresponding scale factors.</p>
  86.      * <p>The PVCoordinates built will be a1 * u1 + a2 * u2</p>
  87.      * @param a1 first scale factor
  88.      * @param pv1 first base (unscaled) PVCoordinates
  89.      * @param a2 second scale factor
  90.      * @param pv2 second base (unscaled) PVCoordinates
  91.      */
  92.     public PVCoordinates(final double a1, final PVCoordinates pv1,
  93.                          final double a2, final PVCoordinates pv2) {
  94.         position = new Vector3D(a1, pv1.position, a2, pv2.position);
  95.         velocity = new Vector3D(a1, pv1.velocity, a2, pv2.velocity);
  96.     }

  97.     /** Linear constructor
  98.      * <p>Build a PVCoordinates from three other ones and corresponding scale factors.</p>
  99.      * <p>The PVCoordinates built will be a1 * u1 + a2 * u2 + a3 * u3</p>
  100.      * @param a1 first scale factor
  101.      * @param pv1 first base (unscaled) PVCoordinates
  102.      * @param a2 second scale factor
  103.      * @param pv2 second base (unscaled) PVCoordinates
  104.      * @param a3 third scale factor
  105.      * @param pv3 third base (unscaled) PVCoordinates
  106.      */
  107.     public PVCoordinates(final double a1, final PVCoordinates pv1,
  108.                          final double a2, final PVCoordinates pv2,
  109.                          final double a3, final PVCoordinates pv3) {
  110.         position = new Vector3D(a1, pv1.position, a2, pv2.position, a3, pv3.position);
  111.         velocity = new Vector3D(a1, pv1.velocity, a2, pv2.velocity, a3, pv3.velocity);
  112.     }

  113.     /** Linear constructor
  114.      * <p>Build a PVCoordinates from four other ones and corresponding scale factors.</p>
  115.      * <p>The PVCoordinates built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4</p>
  116.      * @param a1 first scale factor
  117.      * @param pv1 first base (unscaled) PVCoordinates
  118.      * @param a2 second scale factor
  119.      * @param pv2 second base (unscaled) PVCoordinates
  120.      * @param a3 third scale factor
  121.      * @param pv3 third base (unscaled) PVCoordinates
  122.      * @param a4 fourth scale factor
  123.      * @param pv4 fourth base (unscaled) PVCoordinates
  124.      */
  125.     public PVCoordinates(final double a1, final PVCoordinates pv1,
  126.                          final double a2, final PVCoordinates pv2,
  127.                          final double a3, final PVCoordinates pv3,
  128.                          final double a4, final PVCoordinates pv4) {
  129.         position = new Vector3D(a1, pv1.position, a2, pv2.position, a3, pv3.position, a4, pv4.position);
  130.         velocity = new Vector3D(a1, pv1.velocity, a2, pv2.velocity, a3, pv3.velocity, a4, pv4.velocity);
  131.     }

  132.     /** Estimate velocity between two positions.
  133.      * <p>Estimation is based on a simple fixed velocity translation
  134.      * during the time interval between the two positions.</p>
  135.      * @param start start position
  136.      * @param end end position
  137.      * @param dt time elapsed between the dates of the two positions
  138.      * @return velocity allowing to go from start to end positions
  139.      */
  140.     public static Vector3D estimateVelocity(final Vector3D start, final Vector3D end, final double dt) {
  141.         final double scale = 1.0 / dt;
  142.         return new Vector3D(scale, end, -scale, start);
  143.     }

  144.     /** Get a time-shifted state.
  145.      * <p>
  146.      * The state can be slightly shifted to close dates. This shift is based on
  147.      * a simple linear model. It is <em>not</em> intended as a replacement for
  148.      * proper orbit propagation (it is not even Keplerian!) but should be sufficient
  149.      * for either small time shifts or coarse accuracy.
  150.      * </p>
  151.      * @param dt time shift in seconds
  152.      * @return a new state, shifted with respect to the instance (which is immutable)
  153.      */
  154.     public PVCoordinates shiftedBy(final double dt) {
  155.         return new PVCoordinates(new Vector3D(1, position, dt, velocity), velocity);
  156.     }

  157.     /** Interpolate position-velocity.
  158.      * <p>
  159.      * The interpolated instance is created by polynomial Hermite interpolation
  160.      * ensuring velocity remains the exact derivative of position.
  161.      * </p>
  162.      * <p>
  163.      * Note that even if first time derivatives (velocities)
  164.      * from sample can be ignored, the interpolated instance always includes
  165.      * interpolated derivatives. This feature can be used explicitly to
  166.      * compute these derivatives when it would be too complex to compute them
  167.      * from an analytical formula: just compute a few sample points from the
  168.      * explicit formula and set the derivatives to zero in these sample points,
  169.      * then use interpolation to add derivatives consistent with the positions.
  170.      * </p>
  171.      * @param date interpolation date
  172.      * @param useVelocities if true, use sample points velocities,
  173.      * otherwise ignore them and use only positions
  174.      * @param sample sample points on which interpolation should be done
  175.      * @return a new position-velocity, interpolated at specified date
  176.      */
  177.     public static PVCoordinates interpolate(final AbsoluteDate date, final boolean useVelocities,
  178.                                             final Collection<Pair<AbsoluteDate, PVCoordinates>> sample) {

  179.         // set up an interpolator taking derivatives into account
  180.         final HermiteInterpolator interpolator = new HermiteInterpolator();

  181.         // add sample points
  182.         if (useVelocities) {
  183.             // populate sample with position and velocity data
  184.             for (final Pair<AbsoluteDate, PVCoordinates> datedPV : sample) {
  185.                 final Vector3D position = datedPV.getValue().getPosition();
  186.                 final Vector3D velocity = datedPV.getValue().getVelocity();
  187.                 interpolator.addSamplePoint(datedPV.getKey().getDate().durationFrom(date),
  188.                                             new double[] {
  189.                                                 position.getX(), position.getY(), position.getZ()
  190.                                             }, new double[] {
  191.                                                 velocity.getX(), velocity.getY(), velocity.getZ()
  192.                                             });
  193.             }
  194.         } else {
  195.             // populate sample with position data, ignoring velocity
  196.             for (final Pair<AbsoluteDate, PVCoordinates> datedPV : sample) {
  197.                 final Vector3D position = datedPV.getValue().getPosition();
  198.                 interpolator.addSamplePoint(datedPV.getKey().getDate().durationFrom(date),
  199.                                             new double[] {
  200.                                                 position.getX(), position.getY(), position.getZ()
  201.                                             });
  202.             }
  203.         }

  204.         // interpolate
  205.         final DerivativeStructure zero = new DerivativeStructure(1, 1, 0, 0.0);
  206.         final DerivativeStructure[] p  = interpolator.value(zero);

  207.         // build a new interpolated instance
  208.         return new PVCoordinates(new Vector3D(p[0].getValue(),
  209.                                               p[1].getValue(),
  210.                                               p[2].getValue()),
  211.                                  new Vector3D(p[0].getPartialDerivative(1),
  212.                                               p[1].getPartialDerivative(1),
  213.                                               p[2].getPartialDerivative(1)));

  214.     }

  215.     /** Gets the position.
  216.      * @return the position vector (m).
  217.      */
  218.     public Vector3D getPosition() {
  219.         return position;
  220.     }

  221.     /** Gets the velocity.
  222.      * @return the velocity vector (m/s).
  223.      */
  224.     public Vector3D getVelocity() {
  225.         return velocity;
  226.     }

  227.     /** Gets the momentum.
  228.      * <p>This vector is the p &otimes; v where p is position, v is velocity
  229.      * and &otimes; is cross product. To get the real physical angular momentum
  230.      * you need to multiply this vector by the mass.</p>
  231.      * <p>The returned vector is recomputed each time this method is called, it
  232.      * is not cached.</p>
  233.      * @return a new instance of the momentum vector (m<sup>2</sup>/s).
  234.      */
  235.     public Vector3D getMomentum() {
  236.         return Vector3D.crossProduct(position, velocity);
  237.     }

  238.     /**
  239.      * Get the angular velocity (spin) of this point as seen from the origin.
  240.      * <p/>
  241.      * The angular velocity vector is parallel to the {@link #getMomentum() angular
  242.      * momentum} and is computed by &omega; = p &times; v / ||p||<sup>2</sup>
  243.      *
  244.      * @return the angular velocity vector
  245.      * @see <a href="http://en.wikipedia.org/wiki/Angular_velocity">Angular Velocity on
  246.      *      Wikipedia</a>
  247.      */
  248.     public Vector3D getAngularVelocity() {
  249.         return this.getMomentum().scalarMultiply(1.0 / this.getPosition().getNormSq());
  250.     }

  251.     /** Get the opposite of the instance.
  252.      * @return a new position-velocity which is opposite to the instance
  253.      */
  254.     public PVCoordinates negate() {
  255.         return new PVCoordinates(position.negate(), velocity.negate());
  256.     }

  257.     /** Return a string representation of this position/velocity pair.
  258.      * @return string representation of this position/velocity pair
  259.      */
  260.     public String toString() {
  261.         final String comma = ", ";
  262.         return new StringBuffer().append('{').append("P(").
  263.                                   append(position.getX()).append(comma).
  264.                                   append(position.getY()).append(comma).
  265.                                   append(position.getZ()).append("), V(").
  266.                                   append(velocity.getX()).append(comma).
  267.                                   append(velocity.getY()).append(comma).
  268.                                   append(velocity.getZ()).append(")}").toString();
  269.     }

  270. }