1   /* Copyright 2002-2021 CS GROUP
2    * Licensed to CS GROUP (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.util.List;
20  import java.util.stream.Collectors;
21  import java.util.stream.Stream;
22  
23  import org.hipparchus.Field;
24  import org.hipparchus.CalculusFieldElement;
25  import org.hipparchus.geometry.euclidean.threed.FieldRotation;
26  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
27  import org.hipparchus.geometry.euclidean.threed.Rotation;
28  import org.hipparchus.geometry.euclidean.threed.RotationConvention;
29  import org.hipparchus.geometry.euclidean.threed.Vector3D;
30  import org.orekit.frames.Frame;
31  import org.orekit.frames.Transform;
32  import org.orekit.time.FieldAbsoluteDate;
33  import org.orekit.time.FieldTimeInterpolable;
34  import org.orekit.time.FieldTimeShiftable;
35  import org.orekit.time.FieldTimeStamped;
36  import org.orekit.utils.AngularDerivativesFilter;
37  import org.orekit.utils.FieldAngularCoordinates;
38  import org.orekit.utils.TimeStampedFieldAngularCoordinates;
39  
40  
41  /** This class handles attitude definition at a given date.
42  
43   * <p>This class represents the rotation between a reference frame and
44   * the satellite frame, as well as the spin of the satellite (axis and
45   * rotation rate).</p>
46   * <p>
47   * The state can be slightly shifted to close dates. This shift is based on
48   * a linear extrapolation for attitude taking the spin rate into account.
49   * It is <em>not</em> intended as a replacement for proper attitude propagation
50   * but should be sufficient for either small time shifts or coarse accuracy.
51   * </p>
52   * <p>The instance <code>Attitude</code> is guaranteed to be immutable.</p>
53   * @see     org.orekit.orbits.Orbit
54   * @see AttitudeProvider
55   * @author V&eacute;ronique Pommier-Maurussane
56   */
57  
58  public class FieldAttitude<T extends CalculusFieldElement<T>>
59      implements FieldTimeStamped<T>, FieldTimeShiftable<FieldAttitude<T>, T>, FieldTimeInterpolable<FieldAttitude<T>, T> {
60  
61  
62      /** Reference frame. */
63      private final Frame referenceFrame;
64  
65       /** Attitude and spin.  */
66      private final TimeStampedFieldAngularCoordinates<T> 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 FieldAttitude(final Frame referenceFrame, final TimeStampedFieldAngularCoordinates<T> 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 FieldAttitude(final FieldAbsoluteDate<T> date, final Frame referenceFrame,
85                           final FieldAngularCoordinates<T> orientation) {
86          this(referenceFrame,
87               new TimeStampedFieldAngularCoordinates<>(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 FieldAttitude(final FieldAbsoluteDate<T> date, final Frame referenceFrame,
101                          final FieldRotation<T> attitude, final FieldVector3D<T> spin, final FieldVector3D<T> acceleration) {
102         this(referenceFrame, new TimeStampedFieldAngularCoordinates<>(date, attitude, spin, acceleration));
103     }
104 
105     /** Creates a new instance.
106      * @param date date at which attitude is defined
107      * @param referenceFrame reference frame from which attitude is defined
108      * @param attitude rotation between reference frame and satellite frame
109      * @param spin satellite spin (axis and velocity, in <strong>satellite</strong> frame)
110      * @param acceleration satellite rotation acceleration (in <strong>satellite</strong> frame)
111      * @param field field used by default
112      */
113     public FieldAttitude(final FieldAbsoluteDate<T> date, final Frame referenceFrame,
114                          final Rotation attitude, final Vector3D spin, final Vector3D acceleration, final Field<T> field) {
115         this(referenceFrame, new TimeStampedFieldAngularCoordinates<>(date,
116                                                                       new FieldRotation<>(field, attitude),
117                                                                       new FieldVector3D<>(field, spin),
118                                                                       new FieldVector3D<>(field, acceleration)));
119     }
120 
121     /** Builds an instance for a regular {@link Attitude}.
122      * @param field fields to which the elements belong
123      * @param attitude attitude to convert
124      */
125     public FieldAttitude(final Field<T> field, final Attitude attitude) {
126         this(attitude.getReferenceFrame(), new TimeStampedFieldAngularCoordinates<>(field, attitude.getOrientation()));
127     }
128 
129     /** Get a time-shifted attitude.
130      * <p>
131      * The state can be slightly shifted to close dates. This shift is based on
132      * a linear extrapolation for attitude taking the spin rate into account.
133      * It is <em>not</em> intended as a replacement for proper attitude propagation
134      * but should be sufficient for either small time shifts or coarse accuracy.
135      * </p>
136      * @param dt time shift in seconds
137      * @return a new attitude, shifted with respect to the instance (which is immutable)
138      */
139     public FieldAttitude<T> shiftedBy(final double dt) {
140         return new FieldAttitude<>(referenceFrame, orientation.shiftedBy(dt));
141     }
142 
143     /** Get a time-shifted attitude.
144      * <p>
145      * The state can be slightly shifted to close dates. This shift is based on
146      * a linear extrapolation for attitude taking the spin rate into account.
147      * It is <em>not</em> intended as a replacement for proper attitude propagation
148      * but should be sufficient for either small time shifts or coarse accuracy.
149      * </p>
150      * @param dt time shift in seconds
151      * @return a new attitude, shifted with respect to the instance (which is immutable)
152      */
153     public FieldAttitude<T> shiftedBy(final T dt) {
154         return new FieldAttitude<>(referenceFrame, orientation.shiftedBy(dt));
155     }
156 
157     /** Get a similar attitude with a specific reference frame.
158      * <p>
159      * If the instance reference frame is already the specified one, the instance
160      * itself is returned without any object creation. Otherwise, a new instance
161      * will be created with the specified reference frame. In this case, the
162      * required intermediate rotation and spin between the specified and the
163      * original reference frame will be inserted.
164      * </p>
165      * @param newReferenceFrame desired reference frame for attitude
166      * @return an attitude that has the same orientation and motion as the instance,
167      * but guaranteed to have the specified reference frame
168      */
169     public FieldAttitude<T> withReferenceFrame(final Frame newReferenceFrame) {
170 
171         if (newReferenceFrame == referenceFrame) {
172             // simple case, the instance is already compliant
173             return this;
174         }
175 
176         // we have to take an intermediate rotation into account
177         final Transform t = newReferenceFrame.getTransformTo(referenceFrame, orientation.getDate().toAbsoluteDate());
178         return new FieldAttitude<>(orientation.getDate(), newReferenceFrame,
179                                    orientation.getRotation().compose(t.getRotation(), RotationConvention.VECTOR_OPERATOR),
180                                    orientation.getRotationRate().add(orientation.getRotation().applyTo(t.getRotationRate())),
181                                    orientation.getRotationAcceleration().add(orientation.getRotation().applyTo(t.getRotationAcceleration())));
182 
183     }
184 
185     /** Get the date of attitude parameters.
186      * @return date of the attitude parameters
187      */
188     public FieldAbsoluteDate<T> getDate() {
189         return orientation.getDate();
190     }
191 
192     /** Get the reference frame.
193      * @return referenceFrame reference frame from which attitude is defined.
194      */
195     public Frame getReferenceFrame() {
196         return referenceFrame;
197     }
198 
199     /** Get the complete orientation including spin.
200      * @return complete orientation including spin
201      * @see #getRotation()
202      * @see #getSpin()
203      */
204     public TimeStampedFieldAngularCoordinates<T> getOrientation() {
205         return orientation;
206     }
207 
208     /** Get the attitude rotation.
209      * @return attitude satellite rotation from reference frame.
210      * @see #getOrientation()
211      * @see #getSpin()
212      */
213     public FieldRotation<T> getRotation() {
214         return orientation.getRotation();
215     }
216 
217     /** Get the satellite spin.
218      * <p>The spin vector is defined in <strong>satellite</strong> frame.</p>
219      * @return spin satellite spin (axis and velocity).
220      * @see #getOrientation()
221      * @see #getRotation()
222      */
223     public FieldVector3D<T> getSpin() {
224         return orientation.getRotationRate();
225     }
226 
227     /** Get the satellite rotation acceleration.
228      * <p>The rotation acceleration. vector is defined in <strong>satellite</strong> frame.</p>
229      * @return rotation acceleration
230      * @see #getOrientation()
231      * @see #getRotation()
232      */
233     public FieldVector3D<T> getRotationAcceleration() {
234         return orientation.getRotationAcceleration();
235     }
236 
237     /** Get an interpolated instance.
238      * <p>
239      * The interpolated instance is created by polynomial Hermite interpolation
240      * on Rodrigues vector ensuring rotation rate remains the exact derivative of rotation.
241      * </p>
242      * <p>
243      * As this implementation of interpolation is polynomial, it should be used only
244      * with small samples (about 10-20 points) in order to avoid <a
245      * href="http://en.wikipedia.org/wiki/Runge%27s_phenomenon">Runge's phenomenon</a>
246      * and numerical problems (including NaN appearing).
247      * </p>
248      * @param interpolationDate interpolation date
249      * @param sample sample points on which interpolation should be done
250      * @return a new instance, interpolated at specified date
251      */
252     public FieldAttitude<T> interpolate(final FieldAbsoluteDate<T> interpolationDate,
253                                         final Stream<FieldAttitude<T>> sample) {
254         final List<TimeStampedFieldAngularCoordinates<T>> datedPV =
255                 sample.map(attitude -> attitude.orientation).collect(Collectors.toList());
256         final TimeStampedFieldAngularCoordinates<T> interpolated =
257                 TimeStampedFieldAngularCoordinates.interpolate(interpolationDate, AngularDerivativesFilter.USE_RR, datedPV);
258         return new FieldAttitude<>(referenceFrame, interpolated);
259     }
260     /**
261      * Converts to an Attitude instance.
262      * @return Attitude with same properties
263      */
264     public Attitude toAttitude() {
265         return new Attitude(orientation.getDate().toAbsoluteDate(), referenceFrame, orientation.toAngularCoordinates());
266     }
267 
268 }