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 19 import java.io.Serializable; 20 import java.util.Collection; 21 22 import org.apache.commons.math3.analysis.differentiation.DerivativeStructure; 23 import org.apache.commons.math3.analysis.interpolation.HermiteInterpolator; 24 import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; 25 import org.apache.commons.math3.util.Pair; 26 import org.orekit.time.AbsoluteDate; 27 import org.orekit.time.TimeShiftable; 28 29 /** Simple container for Position/Velocity pairs. 30 * <p> 31 * The state can be slightly shifted to close dates. This shift is based on 32 * a simple linear model. It is <em>not</em> intended as a replacement for 33 * proper orbit propagation (it is not even Keplerian!) but should be sufficient 34 * for either small time shifts or coarse accuracy. 35 * </p> 36 * <p> 37 * This class is the angular counterpart to {@link AngularCoordinates}. 38 * </p> 39 * <p>Instances of this class are guaranteed to be immutable.</p> 40 * @author Fabien Maussion 41 * @author Luc Maisonobe 42 */ 43 public class PVCoordinates implements TimeShiftable<PVCoordinates>, Serializable { 44 45 /** Fixed position/velocity at origin (both p and v are zero vectors). */ 46 public static final PVCoordinates ZERO = new PVCoordinates(Vector3D.ZERO, Vector3D.ZERO); 47 48 /** Serializable UID. */ 49 private static final long serialVersionUID = 4157449919684833834L; 50 51 /** The position. */ 52 private final Vector3D position; 53 54 /** The velocity. */ 55 private final Vector3D velocity; 56 57 /** Simple constructor. 58 * <p> Sets the Coordinates to default : (0 0 0) (0 0 0).</p> 59 */ 60 public PVCoordinates() { 61 position = Vector3D.ZERO; 62 velocity = Vector3D.ZERO; 63 } 64 65 /** Builds a PVCoordinates pair. 66 * @param position the position vector (m) 67 * @param velocity the velocity vector (m/s) 68 */ 69 public PVCoordinates(final Vector3D position, final Vector3D velocity) { 70 this.position = position; 71 this.velocity = velocity; 72 } 73 74 /** Multiplicative constructor 75 * <p>Build a PVCoordinates from another one and a scale factor.</p> 76 * <p>The PVCoordinates built will be a * pv</p> 77 * @param a scale factor 78 * @param pv base (unscaled) PVCoordinates 79 */ 80 public PVCoordinates(final double a, final PVCoordinates pv) { 81 position = new Vector3D(a, pv.position); 82 velocity = new Vector3D(a, pv.velocity); 83 } 84 85 /** Subtractive constructor 86 * <p>Build a relative PVCoordinates from a start and an end position.</p> 87 * <p>The PVCoordinates built will be end - start.</p> 88 * @param start Starting PVCoordinates 89 * @param end ending PVCoordinates 90 */ 91 public PVCoordinates(final PVCoordinates start, final PVCoordinates end) { 92 this.position = end.position.subtract(start.position); 93 this.velocity = end.velocity.subtract(start.velocity); 94 } 95 96 /** Linear constructor 97 * <p>Build a PVCoordinates from two other ones and corresponding scale factors.</p> 98 * <p>The PVCoordinates built will be a1 * u1 + a2 * u2</p> 99 * @param a1 first scale factor 100 * @param pv1 first base (unscaled) PVCoordinates 101 * @param a2 second scale factor 102 * @param pv2 second base (unscaled) PVCoordinates 103 */ 104 public PVCoordinates(final double a1, final PVCoordinates pv1, 105 final double a2, final PVCoordinates pv2) { 106 position = new Vector3D(a1, pv1.position, a2, pv2.position); 107 velocity = new Vector3D(a1, pv1.velocity, a2, pv2.velocity); 108 } 109 110 /** Linear constructor 111 * <p>Build a PVCoordinates from three other ones and corresponding scale factors.</p> 112 * <p>The PVCoordinates built will be a1 * u1 + a2 * u2 + a3 * u3</p> 113 * @param a1 first scale factor 114 * @param pv1 first base (unscaled) PVCoordinates 115 * @param a2 second scale factor 116 * @param pv2 second base (unscaled) PVCoordinates 117 * @param a3 third scale factor 118 * @param pv3 third base (unscaled) PVCoordinates 119 */ 120 public PVCoordinates(final double a1, final PVCoordinates pv1, 121 final double a2, final PVCoordinates pv2, 122 final double a3, final PVCoordinates pv3) { 123 position = new Vector3D(a1, pv1.position, a2, pv2.position, a3, pv3.position); 124 velocity = new Vector3D(a1, pv1.velocity, a2, pv2.velocity, a3, pv3.velocity); 125 } 126 127 /** Linear constructor 128 * <p>Build a PVCoordinates from four other ones and corresponding scale factors.</p> 129 * <p>The PVCoordinates built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4</p> 130 * @param a1 first scale factor 131 * @param pv1 first base (unscaled) PVCoordinates 132 * @param a2 second scale factor 133 * @param pv2 second base (unscaled) PVCoordinates 134 * @param a3 third scale factor 135 * @param pv3 third base (unscaled) PVCoordinates 136 * @param a4 fourth scale factor 137 * @param pv4 fourth base (unscaled) PVCoordinates 138 */ 139 public PVCoordinates(final double a1, final PVCoordinates pv1, 140 final double a2, final PVCoordinates pv2, 141 final double a3, final PVCoordinates pv3, 142 final double a4, final PVCoordinates pv4) { 143 position = new Vector3D(a1, pv1.position, a2, pv2.position, a3, pv3.position, a4, pv4.position); 144 velocity = new Vector3D(a1, pv1.velocity, a2, pv2.velocity, a3, pv3.velocity, a4, pv4.velocity); 145 } 146 147 /** Estimate velocity between two positions. 148 * <p>Estimation is based on a simple fixed velocity translation 149 * during the time interval between the two positions.</p> 150 * @param start start position 151 * @param end end position 152 * @param dt time elapsed between the dates of the two positions 153 * @return velocity allowing to go from start to end positions 154 */ 155 public static Vector3D estimateVelocity(final Vector3D start, final Vector3D end, final double dt) { 156 final double scale = 1.0 / dt; 157 return new Vector3D(scale, end, -scale, start); 158 } 159 160 /** Get a time-shifted state. 161 * <p> 162 * The state can be slightly shifted to close dates. This shift is based on 163 * a simple linear model. It is <em>not</em> intended as a replacement for 164 * proper orbit propagation (it is not even Keplerian!) but should be sufficient 165 * for either small time shifts or coarse accuracy. 166 * </p> 167 * @param dt time shift in seconds 168 * @return a new state, shifted with respect to the instance (which is immutable) 169 */ 170 public PVCoordinates shiftedBy(final double dt) { 171 return new PVCoordinates(new Vector3D(1, position, dt, velocity), velocity); 172 } 173 174 /** Interpolate position-velocity. 175 * <p> 176 * The interpolated instance is created by polynomial Hermite interpolation 177 * ensuring velocity remains the exact derivative of position. 178 * </p> 179 * <p> 180 * Note that even if first time derivatives (velocities) 181 * from sample can be ignored, the interpolated instance always includes 182 * interpolated derivatives. This feature can be used explicitly to 183 * compute these derivatives when it would be too complex to compute them 184 * from an analytical formula: just compute a few sample points from the 185 * explicit formula and set the derivatives to zero in these sample points, 186 * then use interpolation to add derivatives consistent with the positions. 187 * </p> 188 * @param date interpolation date 189 * @param useVelocities if true, use sample points velocities, 190 * otherwise ignore them and use only positions 191 * @param sample sample points on which interpolation should be done 192 * @return a new position-velocity, interpolated at specified date 193 */ 194 public static PVCoordinates interpolate(final AbsoluteDate date, final boolean useVelocities, 195 final Collection<Pair<AbsoluteDate, PVCoordinates>> sample) { 196 197 // set up an interpolator taking derivatives into account 198 final HermiteInterpolator interpolator = new HermiteInterpolator(); 199 200 // add sample points 201 if (useVelocities) { 202 // populate sample with position and velocity data 203 for (final Pair<AbsoluteDate, PVCoordinates> datedPV : sample) { 204 final Vector3D position = datedPV.getValue().getPosition(); 205 final Vector3D velocity = datedPV.getValue().getVelocity(); 206 interpolator.addSamplePoint(datedPV.getKey().getDate().durationFrom(date), 207 new double[] { 208 position.getX(), position.getY(), position.getZ() 209 }, new double[] { 210 velocity.getX(), velocity.getY(), velocity.getZ() 211 }); 212 } 213 } else { 214 // populate sample with position data, ignoring velocity 215 for (final Pair<AbsoluteDate, PVCoordinates> datedPV : sample) { 216 final Vector3D position = datedPV.getValue().getPosition(); 217 interpolator.addSamplePoint(datedPV.getKey().getDate().durationFrom(date), 218 new double[] { 219 position.getX(), position.getY(), position.getZ() 220 }); 221 } 222 } 223 224 // interpolate 225 final DerivativeStructure zero = new DerivativeStructure(1, 1, 0, 0.0); 226 final DerivativeStructure[] p = interpolator.value(zero); 227 228 // build a new interpolated instance 229 return new PVCoordinates(new Vector3D(p[0].getValue(), 230 p[1].getValue(), 231 p[2].getValue()), 232 new Vector3D(p[0].getPartialDerivative(1), 233 p[1].getPartialDerivative(1), 234 p[2].getPartialDerivative(1))); 235 236 } 237 238 /** Gets the position. 239 * @return the position vector (m). 240 */ 241 public Vector3D getPosition() { 242 return position; 243 } 244 245 /** Gets the velocity. 246 * @return the velocity vector (m/s). 247 */ 248 public Vector3D getVelocity() { 249 return velocity; 250 } 251 252 /** Gets the momentum. 253 * <p>This vector is the p ⊗ v where p is position, v is velocity 254 * and ⊗ is cross product. To get the real physical angular momentum 255 * you need to multiply this vector by the mass.</p> 256 * <p>The returned vector is recomputed each time this method is called, it 257 * is not cached.</p> 258 * @return a new instance of the momentum vector (m<sup>2</sup>/s). 259 */ 260 public Vector3D getMomentum() { 261 return Vector3D.crossProduct(position, velocity); 262 } 263 264 /** 265 * Get the angular velocity (spin) of this point as seen from the origin. 266 * <p/> 267 * The angular velocity vector is parallel to the {@link #getMomentum() angular 268 * momentum} and is computed by ω = p × v / ||p||<sup>2</sup> 269 * 270 * @return the angular velocity vector 271 * @see <a href="http://en.wikipedia.org/wiki/Angular_velocity">Angular Velocity on 272 * Wikipedia</a> 273 */ 274 public Vector3D getAngularVelocity() { 275 return this.getMomentum().scalarMultiply(1.0 / this.getPosition().getNormSq()); 276 } 277 278 /** Get the opposite of the instance. 279 * @return a new position-velocity which is opposite to the instance 280 */ 281 public PVCoordinates negate() { 282 return new PVCoordinates(position.negate(), velocity.negate()); 283 } 284 285 /** Return a string representation of this position/velocity pair. 286 * @return string representation of this position/velocity pair 287 */ 288 public String toString() { 289 final String comma = ", "; 290 return new StringBuffer().append('{').append("P("). 291 append(position.getX()).append(comma). 292 append(position.getY()).append(comma). 293 append(position.getZ()).append("), V("). 294 append(velocity.getX()).append(comma). 295 append(velocity.getY()).append(comma). 296 append(velocity.getZ()).append(")}").toString(); 297 } 298 299 }