Attitude.java
/* Copyright 2002-2018 CS Systèmes d'Information
* Licensed to CS Systèmes d'Information (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.attitudes;
import java.io.Serializable;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.hipparchus.geometry.euclidean.threed.Rotation;
import org.hipparchus.geometry.euclidean.threed.RotationConvention;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.orekit.errors.OrekitException;
import org.orekit.frames.Frame;
import org.orekit.frames.Transform;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeInterpolable;
import org.orekit.time.TimeShiftable;
import org.orekit.time.TimeStamped;
import org.orekit.utils.AngularCoordinates;
import org.orekit.utils.AngularDerivativesFilter;
import org.orekit.utils.TimeStampedAngularCoordinates;
/** This class handles attitude definition at a given date.
* <p>This class represents the rotation between a reference frame and
* the satellite frame, as well as the spin of the satellite (axis and
* rotation rate).</p>
* <p>
* The state can be slightly shifted to close dates. This shift is based on
* a linear extrapolation for attitude taking the spin rate into account.
* It is <em>not</em> intended as a replacement for proper attitude propagation
* but should be sufficient for either small time shifts or coarse accuracy.
* </p>
* <p>The instance <code>Attitude</code> is guaranteed to be immutable.</p>
* @see org.orekit.orbits.Orbit
* @see AttitudeProvider
* @author Véronique Pommier-Maurussane
*/
public class Attitude
implements TimeStamped, TimeShiftable<Attitude>, TimeInterpolable<Attitude>, Serializable {
/** Serializable UID. */
private static final long serialVersionUID = 20140611L;
/** Reference frame. */
private final Frame referenceFrame;
/** Attitude and spin. */
private final TimeStampedAngularCoordinates orientation;
/** Creates a new instance.
* @param referenceFrame reference frame from which attitude is defined
* @param orientation complete orientation between reference frame and satellite frame,
* including rotation rate
*/
public Attitude(final Frame referenceFrame, final TimeStampedAngularCoordinates orientation) {
this.referenceFrame = referenceFrame;
this.orientation = orientation;
}
/** Creates a new instance.
* @param date date at which attitude is defined
* @param referenceFrame reference frame from which attitude is defined
* @param orientation complete orientation between reference frame and satellite frame,
* including rotation rate
*/
public Attitude(final AbsoluteDate date, final Frame referenceFrame,
final AngularCoordinates orientation) {
this(referenceFrame,
new TimeStampedAngularCoordinates(date,
orientation.getRotation(),
orientation.getRotationRate(),
orientation.getRotationAcceleration()));
}
/** Creates a new instance.
* @param date date at which attitude is defined
* @param referenceFrame reference frame from which attitude is defined
* @param attitude rotation between reference frame and satellite frame
* @param spin satellite spin (axis and velocity, in <strong>satellite</strong> frame)
* @param acceleration satellite rotation acceleration (in <strong>satellite</strong> frame)
*/
public Attitude(final AbsoluteDate date, final Frame referenceFrame,
final Rotation attitude, final Vector3D spin, final Vector3D acceleration) {
this(referenceFrame, new TimeStampedAngularCoordinates(date, attitude, spin, acceleration));
}
/** Get a time-shifted attitude.
* <p>
* The state can be slightly shifted to close dates. This shift is based on
* a linear extrapolation for attitude taking the spin rate into account.
* It is <em>not</em> intended as a replacement for proper attitude propagation
* but should be sufficient for either small time shifts or coarse accuracy.
* </p>
* @param dt time shift in seconds
* @return a new attitude, shifted with respect to the instance (which is immutable)
*/
public Attitude shiftedBy(final double dt) {
return new Attitude(referenceFrame, orientation.shiftedBy(dt));
}
/** Get a similar attitude with a specific reference frame.
* <p>
* If the instance reference frame is already the specified one, the instance
* itself is returned without any object creation. Otherwise, a new instance
* will be created with the specified reference frame. In this case, the
* required intermediate rotation and spin between the specified and the
* original reference frame will be inserted.
* </p>
* @param newReferenceFrame desired reference frame for attitude
* @return an attitude that has the same orientation and motion as the instance,
* but guaranteed to have the specified reference frame
* @exception OrekitException if conversion between reference frames fails
*/
public Attitude withReferenceFrame(final Frame newReferenceFrame)
throws OrekitException {
if (newReferenceFrame == referenceFrame) {
// simple case, the instance is already compliant
return this;
}
// we have to take an intermediate rotation into account
final Transform t = newReferenceFrame.getTransformTo(referenceFrame, orientation.getDate());
return new Attitude(orientation.getDate(), newReferenceFrame,
orientation.getRotation().compose(t.getRotation(), RotationConvention.VECTOR_OPERATOR),
orientation.getRotationRate().add(orientation.getRotation().applyTo(t.getRotationRate())),
orientation.getRotationAcceleration().add(orientation.getRotation().applyTo(t.getRotationAcceleration())));
}
/** Get the date of attitude parameters.
* @return date of the attitude parameters
*/
public AbsoluteDate getDate() {
return orientation.getDate();
}
/** Get the reference frame.
* @return referenceFrame reference frame from which attitude is defined.
*/
public Frame getReferenceFrame() {
return referenceFrame;
}
/** Get the complete orientation including spin.
* @return complete orientation including spin
* @see #getRotation()
* @see #getSpin()
*/
public TimeStampedAngularCoordinates getOrientation() {
return orientation;
}
/** Get the attitude rotation.
* @return attitude satellite rotation from reference frame.
* @see #getOrientation()
* @see #getSpin()
*/
public Rotation getRotation() {
return orientation.getRotation();
}
/** Get the satellite spin.
* <p>The spin vector is defined in <strong>satellite</strong> frame.</p>
* @return spin satellite spin (axis and velocity).
* @see #getOrientation()
* @see #getRotation()
*/
public Vector3D getSpin() {
return orientation.getRotationRate();
}
/** Get the satellite rotation acceleration.
* <p>The rotation acceleration. vector is defined in <strong>satellite</strong> frame.</p>
* @return rotation acceleration
* @see #getOrientation()
* @see #getRotation()
*/
public Vector3D getRotationAcceleration() {
return orientation.getRotationAcceleration();
}
/** {@inheritDoc}
* <p>
* The interpolated instance is created by polynomial Hermite interpolation
* on Rodrigues vector ensuring rotation rate remains the exact derivative of rotation.
* </p>
* <p>
* As this implementation of interpolation is polynomial, it should be used only
* with small samples (about 10-20 points) in order to avoid <a
* href="http://en.wikipedia.org/wiki/Runge%27s_phenomenon">Runge's phenomenon</a>
* and numerical problems (including NaN appearing).
* </p>
* @exception OrekitException if the number of point is too small for interpolating
*/
public Attitude interpolate(final AbsoluteDate interpolationDate, final Stream<Attitude> sample)
throws OrekitException {
final List<TimeStampedAngularCoordinates> datedPV =
sample.map(attitude -> attitude.orientation).collect(Collectors.toList());
final TimeStampedAngularCoordinates interpolated =
TimeStampedAngularCoordinates.interpolate(interpolationDate, AngularDerivativesFilter.USE_RR, datedPV);
return new Attitude(referenceFrame, interpolated);
}
}