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.attitudes; 18 19 import java.io.Serializable; 20 import java.util.List; 21 import java.util.stream.Collectors; 22 import java.util.stream.Stream; 23 24 import org.hipparchus.geometry.euclidean.threed.Rotation; 25 import org.hipparchus.geometry.euclidean.threed.RotationConvention; 26 import org.hipparchus.geometry.euclidean.threed.Vector3D; 27 import org.orekit.errors.OrekitException; 28 import org.orekit.frames.Frame; 29 import org.orekit.frames.Transform; 30 import org.orekit.time.AbsoluteDate; 31 import org.orekit.time.TimeInterpolable; 32 import org.orekit.time.TimeShiftable; 33 import org.orekit.time.TimeStamped; 34 import org.orekit.utils.AngularCoordinates; 35 import org.orekit.utils.AngularDerivativesFilter; 36 import org.orekit.utils.TimeStampedAngularCoordinates; 37 38 39 /** This class handles attitude definition at a given date. 40 41 * <p>This class represents the rotation between a reference frame and 42 * the satellite frame, as well as the spin of the satellite (axis and 43 * rotation rate).</p> 44 * <p> 45 * The state can be slightly shifted to close dates. This shift is based on 46 * a linear extrapolation for attitude taking the spin rate into account. 47 * It is <em>not</em> intended as a replacement for proper attitude propagation 48 * but should be sufficient for either small time shifts or coarse accuracy. 49 * </p> 50 * <p>The instance <code>Attitude</code> is guaranteed to be immutable.</p> 51 * @see org.orekit.orbits.Orbit 52 * @see AttitudeProvider 53 * @author Véronique Pommier-Maurussane 54 */ 55 56 public class Attitude 57 implements TimeStamped, TimeShiftable<Attitude>, TimeInterpolable<Attitude>, Serializable { 58 59 /** Serializable UID. */ 60 private static final long serialVersionUID = 20140611L; 61 62 /** Reference frame. */ 63 private final Frame referenceFrame; 64 65 /** Attitude and spin. */ 66 private final TimeStampedAngularCoordinates orientation; 67 68 /** Creates a new instance. 69 * @param referenceFrame reference frame from which attitude is defined 70 * @param orientation complete orientation between reference frame and satellite frame, 71 * including rotation rate 72 */ 73 public Attitude(final Frame referenceFrame, final TimeStampedAngularCoordinates orientation) { 74 this.referenceFrame = referenceFrame; 75 this.orientation = orientation; 76 } 77 78 /** Creates a new instance. 79 * @param date date at which attitude is defined 80 * @param referenceFrame reference frame from which attitude is defined 81 * @param orientation complete orientation between reference frame and satellite frame, 82 * including rotation rate 83 */ 84 public Attitude(final AbsoluteDate date, final Frame referenceFrame, 85 final AngularCoordinates orientation) { 86 this(referenceFrame, 87 new TimeStampedAngularCoordinates(date, 88 orientation.getRotation(), 89 orientation.getRotationRate(), 90 orientation.getRotationAcceleration())); 91 } 92 93 /** Creates a new instance. 94 * @param date date at which attitude is defined 95 * @param referenceFrame reference frame from which attitude is defined 96 * @param attitude rotation between reference frame and satellite frame 97 * @param spin satellite spin (axis and velocity, in <strong>satellite</strong> frame) 98 * @param acceleration satellite rotation acceleration (in <strong>satellite</strong> frame) 99 */ 100 public Attitude(final AbsoluteDate date, final Frame referenceFrame, 101 final Rotation attitude, final Vector3D spin, final Vector3D acceleration) { 102 this(referenceFrame, new TimeStampedAngularCoordinates(date, attitude, spin, acceleration)); 103 } 104 105 /** Get a time-shifted attitude. 106 * <p> 107 * The state can be slightly shifted to close dates. This shift is based on 108 * a linear extrapolation for attitude taking the spin rate into account. 109 * It is <em>not</em> intended as a replacement for proper attitude propagation 110 * but should be sufficient for either small time shifts or coarse accuracy. 111 * </p> 112 * @param dt time shift in seconds 113 * @return a new attitude, shifted with respect to the instance (which is immutable) 114 */ 115 public Attitude shiftedBy(final double dt) { 116 return new Attitude(referenceFrame, orientation.shiftedBy(dt)); 117 } 118 119 /** Get a similar attitude with a specific reference frame. 120 * <p> 121 * If the instance reference frame is already the specified one, the instance 122 * itself is returned without any object creation. Otherwise, a new instance 123 * will be created with the specified reference frame. In this case, the 124 * required intermediate rotation and spin between the specified and the 125 * original reference frame will be inserted. 126 * </p> 127 * @param newReferenceFrame desired reference frame for attitude 128 * @return an attitude that has the same orientation and motion as the instance, 129 * but guaranteed to have the specified reference frame 130 * @exception OrekitException if conversion between reference frames fails 131 */ 132 public Attitude withReferenceFrame(final Frame newReferenceFrame) 133 throws OrekitException { 134 135 if (newReferenceFrame == referenceFrame) { 136 // simple case, the instance is already compliant 137 return this; 138 } 139 140 // we have to take an intermediate rotation into account 141 final Transform t = newReferenceFrame.getTransformTo(referenceFrame, orientation.getDate()); 142 return new Attitude(orientation.getDate(), newReferenceFrame, 143 orientation.getRotation().compose(t.getRotation(), RotationConvention.VECTOR_OPERATOR), 144 orientation.getRotationRate().add(orientation.getRotation().applyTo(t.getRotationRate())), 145 orientation.getRotationAcceleration().add(orientation.getRotation().applyTo(t.getRotationAcceleration()))); 146 147 } 148 149 /** Get the date of attitude parameters. 150 * @return date of the attitude parameters 151 */ 152 public AbsoluteDate getDate() { 153 return orientation.getDate(); 154 } 155 156 /** Get the reference frame. 157 * @return referenceFrame reference frame from which attitude is defined. 158 */ 159 public Frame getReferenceFrame() { 160 return referenceFrame; 161 } 162 163 /** Get the complete orientation including spin. 164 * @return complete orientation including spin 165 * @see #getRotation() 166 * @see #getSpin() 167 */ 168 public TimeStampedAngularCoordinates getOrientation() { 169 return orientation; 170 } 171 172 /** Get the attitude rotation. 173 * @return attitude satellite rotation from reference frame. 174 * @see #getOrientation() 175 * @see #getSpin() 176 */ 177 public Rotation getRotation() { 178 return orientation.getRotation(); 179 } 180 181 /** Get the satellite spin. 182 * <p>The spin vector is defined in <strong>satellite</strong> frame.</p> 183 * @return spin satellite spin (axis and velocity). 184 * @see #getOrientation() 185 * @see #getRotation() 186 */ 187 public Vector3D getSpin() { 188 return orientation.getRotationRate(); 189 } 190 191 /** Get the satellite rotation acceleration. 192 * <p>The rotation acceleration. vector is defined in <strong>satellite</strong> frame.</p> 193 * @return rotation acceleration 194 * @see #getOrientation() 195 * @see #getRotation() 196 */ 197 public Vector3D getRotationAcceleration() { 198 return orientation.getRotationAcceleration(); 199 } 200 201 /** {@inheritDoc} 202 * <p> 203 * The interpolated instance is created by polynomial Hermite interpolation 204 * on Rodrigues vector ensuring rotation rate remains the exact derivative of rotation. 205 * </p> 206 * <p> 207 * As this implementation of interpolation is polynomial, it should be used only 208 * with small samples (about 10-20 points) in order to avoid <a 209 * href="http://en.wikipedia.org/wiki/Runge%27s_phenomenon">Runge's phenomenon</a> 210 * and numerical problems (including NaN appearing). 211 * </p> 212 * @exception OrekitException if the number of point is too small for interpolating 213 */ 214 public Attitude interpolate(final AbsoluteDate interpolationDate, final Stream<Attitude> sample) 215 throws OrekitException { 216 final List<TimeStampedAngularCoordinates> datedPV = 217 sample.map(attitude -> attitude.orientation).collect(Collectors.toList()); 218 final TimeStampedAngularCoordinates interpolated = 219 TimeStampedAngularCoordinates.interpolate(interpolationDate, AngularDerivativesFilter.USE_RR, datedPV); 220 return new Attitude(referenceFrame, interpolated); 221 } 222 223 }