FieldPVCoordinates.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.RealFieldElement;
  21. import org.apache.commons.math3.analysis.interpolation.FieldHermiteInterpolator;
  22. import org.apache.commons.math3.geometry.euclidean.threed.FieldVector3D;
  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, using {@link RealFieldElement}.
  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 FieldAngularCoordinates}.
  35.  * </p>
  36.  * <p>Instances of this class are guaranteed to be immutable.</p>
  37.  * @param <T> the type of the field elements
  38.  * @author Luc Maisonobe
  39.  * @since 6.0
  40.  * @see PVCoordinates
  41.  */
  42. public class FieldPVCoordinates<T extends RealFieldElement<T>>
  43.     implements TimeShiftable<FieldPVCoordinates<T>>, Serializable {

  44.     /** Serializable UID. */
  45.     private static final long serialVersionUID = 20130222L;

  46.     /** The position. */
  47.     private final FieldVector3D<T> position;

  48.     /** The velocity. */
  49.     private final FieldVector3D<T> velocity;

  50.     /** Builds a PVCoordinates pair.
  51.      * @param position the position vector (m)
  52.      * @param velocity the velocity vector (m/s)
  53.      */
  54.     public FieldPVCoordinates(final FieldVector3D<T> position, final FieldVector3D<T> velocity) {
  55.         this.position = position;
  56.         this.velocity = velocity;
  57.     }

  58.     /** Multiplicative constructor
  59.      * <p>Build a PVCoordinates from another one and a scale factor.</p>
  60.      * <p>The PVCoordinates built will be a * pv</p>
  61.      * @param a scale factor
  62.      * @param pv base (unscaled) PVCoordinates
  63.      */
  64.     public FieldPVCoordinates(final double a, final FieldPVCoordinates<T> pv) {
  65.         position = new FieldVector3D<T>(a, pv.position);
  66.         velocity = new FieldVector3D<T>(a, pv.velocity);
  67.     }

  68.     /** Multiplicative constructor
  69.      * <p>Build a PVCoordinates from another one and a scale factor.</p>
  70.      * <p>The PVCoordinates built will be a * pv</p>
  71.      * @param a scale factor
  72.      * @param pv base (unscaled) PVCoordinates
  73.      */
  74.     public FieldPVCoordinates(final T a, final FieldPVCoordinates<T> pv) {
  75.         position = new FieldVector3D<T>(a, pv.position);
  76.         velocity = new FieldVector3D<T>(a, pv.velocity);
  77.     }

  78.     /** Multiplicative constructor
  79.      * <p>Build a PVCoordinates from another one and a scale factor.</p>
  80.      * <p>The PVCoordinates built will be a * pv</p>
  81.      * @param a scale factor
  82.      * @param pv base (unscaled) PVCoordinates
  83.      */
  84.     public FieldPVCoordinates(final T a, final PVCoordinates pv) {
  85.         position = new FieldVector3D<T>(a, pv.getPosition());
  86.         velocity = new FieldVector3D<T>(a, pv.getVelocity());
  87.     }

  88.     /** Subtractive constructor
  89.      * <p>Build a relative PVCoordinates from a start and an end position.</p>
  90.      * <p>The PVCoordinates built will be end - start.</p>
  91.      * @param start Starting PVCoordinates
  92.      * @param end ending PVCoordinates
  93.      */
  94.     public FieldPVCoordinates(final FieldPVCoordinates<T> start, final FieldPVCoordinates<T> end) {
  95.         this.position = end.position.subtract(start.position);
  96.         this.velocity = end.velocity.subtract(start.velocity);
  97.     }

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

  111.     /** Linear constructor
  112.      * <p>Build a PVCoordinates from two other ones and corresponding scale factors.</p>
  113.      * <p>The PVCoordinates built will be a1 * u1 + a2 * u2</p>
  114.      * @param a1 first scale factor
  115.      * @param pv1 first base (unscaled) PVCoordinates
  116.      * @param a2 second scale factor
  117.      * @param pv2 second base (unscaled) PVCoordinates
  118.      */
  119.     public FieldPVCoordinates(final T a1, final FieldPVCoordinates<T> pv1,
  120.                            final T a2, final FieldPVCoordinates<T> pv2) {
  121.         position = new FieldVector3D<T>(a1, pv1.position, a2, pv2.position);
  122.         velocity = new FieldVector3D<T>(a1, pv1.velocity, a2, pv2.velocity);
  123.     }

  124.     /** Linear constructor
  125.      * <p>Build a PVCoordinates from two other ones and corresponding scale factors.</p>
  126.      * <p>The PVCoordinates built will be a1 * u1 + a2 * u2</p>
  127.      * @param a1 first scale factor
  128.      * @param pv1 first base (unscaled) PVCoordinates
  129.      * @param a2 second scale factor
  130.      * @param pv2 second base (unscaled) PVCoordinates
  131.      */
  132.     public FieldPVCoordinates(final T a1, final PVCoordinates pv1,
  133.                            final T a2, final PVCoordinates pv2) {
  134.         position = new FieldVector3D<T>(a1, pv1.getPosition(), a2, pv2.getPosition());
  135.         velocity = new FieldVector3D<T>(a1, pv1.getVelocity(), a2, pv2.getVelocity());
  136.     }

  137.     /** Linear constructor
  138.      * <p>Build a PVCoordinates from three other ones and corresponding scale factors.</p>
  139.      * <p>The PVCoordinates built will be a1 * u1 + a2 * u2 + a3 * u3</p>
  140.      * @param a1 first scale factor
  141.      * @param pv1 first base (unscaled) PVCoordinates
  142.      * @param a2 second scale factor
  143.      * @param pv2 second base (unscaled) PVCoordinates
  144.      * @param a3 third scale factor
  145.      * @param pv3 third base (unscaled) PVCoordinates
  146.      */
  147.     public FieldPVCoordinates(final double a1, final FieldPVCoordinates<T> pv1,
  148.                            final double a2, final FieldPVCoordinates<T> pv2,
  149.                            final double a3, final FieldPVCoordinates<T> pv3) {
  150.         position = new FieldVector3D<T>(a1, pv1.position, a2, pv2.position, a3, pv3.position);
  151.         velocity = new FieldVector3D<T>(a1, pv1.velocity, a2, pv2.velocity, a3, pv3.velocity);
  152.     }

  153.     /** Linear constructor
  154.      * <p>Build a PVCoordinates from three other ones and corresponding scale factors.</p>
  155.      * <p>The PVCoordinates built will be a1 * u1 + a2 * u2 + a3 * u3</p>
  156.      * @param a1 first scale factor
  157.      * @param pv1 first base (unscaled) PVCoordinates
  158.      * @param a2 second scale factor
  159.      * @param pv2 second base (unscaled) PVCoordinates
  160.      * @param a3 third scale factor
  161.      * @param pv3 third base (unscaled) PVCoordinates
  162.      */
  163.     public FieldPVCoordinates(final T a1, final FieldPVCoordinates<T> pv1,
  164.                            final T a2, final FieldPVCoordinates<T> pv2,
  165.                            final T a3, final FieldPVCoordinates<T> pv3) {
  166.         position = new FieldVector3D<T>(a1, pv1.position, a2, pv2.position, a3, pv3.position);
  167.         velocity = new FieldVector3D<T>(a1, pv1.velocity, a2, pv2.velocity, a3, pv3.velocity);
  168.     }

  169.     /** Linear constructor
  170.      * <p>Build a PVCoordinates from three other ones and corresponding scale factors.</p>
  171.      * <p>The PVCoordinates built will be a1 * u1 + a2 * u2 + a3 * u3</p>
  172.      * @param a1 first scale factor
  173.      * @param pv1 first base (unscaled) PVCoordinates
  174.      * @param a2 second scale factor
  175.      * @param pv2 second base (unscaled) PVCoordinates
  176.      * @param a3 third scale factor
  177.      * @param pv3 third base (unscaled) PVCoordinates
  178.      */
  179.     public FieldPVCoordinates(final T a1, final PVCoordinates pv1,
  180.                            final T a2, final PVCoordinates pv2,
  181.                            final T a3, final PVCoordinates pv3) {
  182.         position = new FieldVector3D<T>(a1, pv1.getPosition(), a2, pv2.getPosition(), a3, pv3.getPosition());
  183.         velocity = new FieldVector3D<T>(a1, pv1.getVelocity(), a2, pv2.getVelocity(), a3, pv3.getVelocity());
  184.     }

  185.     /** Linear constructor
  186.      * <p>Build a PVCoordinates from four other ones and corresponding scale factors.</p>
  187.      * <p>The PVCoordinates built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4</p>
  188.      * @param a1 first scale factor
  189.      * @param pv1 first base (unscaled) PVCoordinates
  190.      * @param a2 second scale factor
  191.      * @param pv2 second base (unscaled) PVCoordinates
  192.      * @param a3 third scale factor
  193.      * @param pv3 third base (unscaled) PVCoordinates
  194.      * @param a4 fourth scale factor
  195.      * @param pv4 fourth base (unscaled) PVCoordinates
  196.      */
  197.     public FieldPVCoordinates(final double a1, final FieldPVCoordinates<T> pv1,
  198.                            final double a2, final FieldPVCoordinates<T> pv2,
  199.                            final double a3, final FieldPVCoordinates<T> pv3,
  200.                            final double a4, final FieldPVCoordinates<T> pv4) {
  201.         position = new FieldVector3D<T>(a1, pv1.position, a2, pv2.position, a3, pv3.position, a4, pv4.position);
  202.         velocity = new FieldVector3D<T>(a1, pv1.velocity, a2, pv2.velocity, a3, pv3.velocity, a4, pv4.velocity);
  203.     }

  204.     /** Linear constructor
  205.      * <p>Build a PVCoordinates from four other ones and corresponding scale factors.</p>
  206.      * <p>The PVCoordinates built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4</p>
  207.      * @param a1 first scale factor
  208.      * @param pv1 first base (unscaled) PVCoordinates
  209.      * @param a2 second scale factor
  210.      * @param pv2 second base (unscaled) PVCoordinates
  211.      * @param a3 third scale factor
  212.      * @param pv3 third base (unscaled) PVCoordinates
  213.      * @param a4 fourth scale factor
  214.      * @param pv4 fourth base (unscaled) PVCoordinates
  215.      */
  216.     public FieldPVCoordinates(final T a1, final FieldPVCoordinates<T> pv1,
  217.                            final T a2, final FieldPVCoordinates<T> pv2,
  218.                            final T a3, final FieldPVCoordinates<T> pv3,
  219.                            final T a4, final FieldPVCoordinates<T> pv4) {
  220.         position = new FieldVector3D<T>(a1, pv1.position, a2, pv2.position, a3, pv3.position, a4, pv4.position);
  221.         velocity = new FieldVector3D<T>(a1, pv1.velocity, a2, pv2.velocity, a3, pv3.velocity, a4, pv4.velocity);
  222.     }

  223.     /** Linear constructor
  224.      * <p>Build a PVCoordinates from four other ones and corresponding scale factors.</p>
  225.      * <p>The PVCoordinates built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4</p>
  226.      * @param a1 first scale factor
  227.      * @param pv1 first base (unscaled) PVCoordinates
  228.      * @param a2 second scale factor
  229.      * @param pv2 second base (unscaled) PVCoordinates
  230.      * @param a3 third scale factor
  231.      * @param pv3 third base (unscaled) PVCoordinates
  232.      * @param a4 fourth scale factor
  233.      * @param pv4 fourth base (unscaled) PVCoordinates
  234.      */
  235.     public FieldPVCoordinates(final T a1, final PVCoordinates pv1,
  236.                            final T a2, final PVCoordinates pv2,
  237.                            final T a3, final PVCoordinates pv3,
  238.                            final T a4, final PVCoordinates pv4) {
  239.         position = new FieldVector3D<T>(a1, pv1.getPosition(), a2, pv2.getPosition(),
  240.                                   a3, pv3.getPosition(), a4, pv4.getPosition());
  241.         velocity = new FieldVector3D<T>(a1, pv1.getVelocity(), a2, pv2.getVelocity(),
  242.                                   a3, pv3.getVelocity(), a4, pv4.getVelocity());
  243.     }

  244.     /** Estimate velocity between two positions.
  245.      * <p>Estimation is based on a simple fixed velocity translation
  246.      * during the time interval between the two positions.</p>
  247.      * @param start start position
  248.      * @param end end position
  249.      * @param dt time elapsed between the dates of the two positions
  250.      * @param <T> the type of the field elements
  251.      * @return velocity allowing to go from start to end positions
  252.      */
  253.     public static <T extends RealFieldElement<T>> FieldVector3D<T> estimateVelocity(final FieldVector3D<T> start,
  254.                                                                                     final FieldVector3D<T> end,
  255.                                                                                     final double dt) {
  256.         final double scale = 1.0 / dt;
  257.         return new FieldVector3D<T>(scale, end, -scale, start);
  258.     }

  259.     /** Get a time-shifted state.
  260.      * <p>
  261.      * The state can be slightly shifted to close dates. This shift is based on
  262.      * a simple linear model. It is <em>not</em> intended as a replacement for
  263.      * proper orbit propagation (it is not even Keplerian!) but should be sufficient
  264.      * for either small time shifts or coarse accuracy.
  265.      * </p>
  266.      * @param dt time shift in seconds
  267.      * @return a new state, shifted with respect to the instance (which is immutable)
  268.      */
  269.     public FieldPVCoordinates<T> shiftedBy(final double dt) {
  270.         return new FieldPVCoordinates<T>(new FieldVector3D<T>(1, position, dt, velocity), velocity);
  271.     }

  272.     /** Interpolate position-velocity.
  273.      * <p>
  274.      * The interpolated instance is created by polynomial Hermite interpolation
  275.      * ensuring velocity remains the exact derivative of position.
  276.      * </p>
  277.      * <p>
  278.      * Note that even if first time derivatives (velocities)
  279.      * from sample can be ignored, the interpolated instance always includes
  280.      * interpolated derivatives. This feature can be used explicitly to
  281.      * compute these derivatives when it would be too complex to compute them
  282.      * from an analytical formula: just compute a few sample points from the
  283.      * explicit formula and set the derivatives to zero in these sample points,
  284.      * then use interpolation to add derivatives consistent with the positions.
  285.      * </p>
  286.      * @param date interpolation date
  287.      * @param useVelocities if true, use sample points velocities,
  288.      * otherwise ignore them and use only positions
  289.      * @param sample sample points on which interpolation should be done
  290.      * @param <T> the type of the field elements
  291.      * @return a new position-velocity, interpolated at specified date
  292.      */
  293.     @SuppressWarnings("unchecked")
  294.     public static <T extends RealFieldElement<T>> FieldPVCoordinates<T> interpolate(final AbsoluteDate date,
  295.                                                                                     final boolean useVelocities,
  296.                                                                                     final Collection<Pair<AbsoluteDate, FieldPVCoordinates<T>>> sample) {

  297.         // get field properties
  298.         final T prototype = sample.iterator().next().getValue().getPosition().getX();
  299.         final T zero      = prototype.getField().getZero();

  300.         // set up an interpolator
  301.         final FieldHermiteInterpolator<T> interpolator = new FieldHermiteInterpolator<T>();

  302.         // add sample points
  303.         if (useVelocities) {
  304.             // populate sample with position and velocity data
  305.             for (final Pair<AbsoluteDate, FieldPVCoordinates<T>> datedPV : sample) {
  306.                 interpolator.addSamplePoint(zero.add(datedPV.getKey().getDate().durationFrom(date)),
  307.                                             datedPV.getValue().getPosition().toArray(),
  308.                                             datedPV.getValue().getVelocity().toArray());
  309.             }
  310.         } else {
  311.             // populate sample with position data, ignoring velocity
  312.             for (final Pair<AbsoluteDate, FieldPVCoordinates<T>> datedPV : sample) {
  313.                 interpolator.addSamplePoint(zero.add(datedPV.getKey().getDate().durationFrom(date)),
  314.                                             datedPV.getValue().getPosition().toArray());
  315.             }
  316.         }

  317.         // interpolate
  318.         final T[][] p = interpolator.derivatives(zero, 1);

  319.         // build a new interpolated instance
  320.         return new FieldPVCoordinates<T>(new FieldVector3D<T>(p[0]),
  321.                                          new FieldVector3D<T>(p[1]));

  322.     }

  323.     /** Gets the position.
  324.      * @return the position vector (m).
  325.      */
  326.     public FieldVector3D<T> getPosition() {
  327.         return position;
  328.     }

  329.     /** Gets the velocity.
  330.      * @return the velocity vector (m/s).
  331.      */
  332.     public FieldVector3D<T> getVelocity() {
  333.         return velocity;
  334.     }

  335.     /** Gets the momentum.
  336.      * <p>This vector is the p &otimes; v where p is position, v is velocity
  337.      * and &otimes; is cross product. To get the real physical angular momentum
  338.      * you need to multiply this vector by the mass.</p>
  339.      * <p>The returned vector is recomputed each time this method is called, it
  340.      * is not cached.</p>
  341.      * @return a new instance of the momentum vector (m<sup>2</sup>/s).
  342.      */
  343.     public FieldVector3D<T> getMomentum() {
  344.         return FieldVector3D.crossProduct(position, velocity);
  345.     }

  346.     /**
  347.      * Get the angular velocity (spin) of this point as seen from the origin.
  348.      * <p/>
  349.      * The angular velocity vector is parallel to the {@link #getMomentum() angular
  350.      * momentum} and is computed by &omega; = p &times; v / ||p||<sup>2</sup>
  351.      *
  352.      * @return the angular velocity vector
  353.      * @see <a href="http://en.wikipedia.org/wiki/Angular_velocity">Angular Velocity on
  354.      *      Wikipedia</a>
  355.      */
  356.     public FieldVector3D<T> getAngularVelocity() {
  357.         return this.getMomentum().scalarMultiply(
  358.                 this.getPosition().getNormSq().reciprocal());
  359.     }

  360.     /** Get the opposite of the instance.
  361.      * @return a new position-velocity which is opposite to the instance
  362.      */
  363.     public FieldPVCoordinates<T> negate() {
  364.         return new FieldPVCoordinates<T>(position.negate(), velocity.negate());
  365.     }

  366.     /** Convert to a constant position-velocity without derivatives.
  367.      * @return a constant position-velocity
  368.      */
  369.     public PVCoordinates toPVCoordinates() {
  370.         return new PVCoordinates(position.toVector3D(), velocity.toVector3D());
  371.     }

  372.     /** Return a string representation of this position/velocity pair.
  373.      * @return string representation of this position/velocity pair
  374.      */
  375.     public String toString() {
  376.         final String comma = ", ";
  377.         return new StringBuffer().append('{').append("P(").
  378.                                   append(position.getX().getReal()).append(comma).
  379.                                   append(position.getY().getReal()).append(comma).
  380.                                   append(position.getZ().getReal()).append("), V(").
  381.                                   append(velocity.getX().getReal()).append(comma).
  382.                                   append(velocity.getY().getReal()).append(comma).
  383.                                   append(velocity.getZ().getReal()).append(")}").toString();
  384.     }

  385. }