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 }