Attitude.java
/* Copyright 2002-2013 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.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.apache.commons.math3.util.Pair;
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;
/** 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 = -947817502698754209L;
/** Current date. */
private final AbsoluteDate date;
/** Reference frame. */
private final Frame referenceFrame;
/** Attitude and spin. */
private final AngularCoordinates 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.date = date;
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 attitude rotation between reference frame and satellite frame
* @param spin satellite spin (axis and velocity, in <strong>satellite</strong> frame)
*/
public Attitude(final AbsoluteDate date, final Frame referenceFrame,
final Rotation attitude, final Vector3D spin) {
this(date, referenceFrame, new AngularCoordinates(attitude, spin));
}
/** Estimate spin between two orientations.
* <p>Estimation is based on a simple fixed rate rotation
* during the time interval between the two attitude.</p>
* @param start start orientation
* @param end end orientation
* @param dt time elapsed between the dates of the two orientations
* @return spin allowing to go from start to end orientation
* @deprecated as of 6.0 superseded by {@link
* AngularCoordinates#estimateRate(Rotation, Rotation, double)}
*/
@Deprecated
public static Vector3D estimateSpin(final Rotation start, final Rotation end,
final double dt) {
return AngularCoordinates.estimateRate(start, end, dt);
}
/** 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(date.shiftedBy(dt), 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, date);
return new Attitude(date, newReferenceFrame,
orientation.getRotation().applyTo(t.getRotation()),
orientation.getRotationRate().add(orientation.getRotation().applyTo(t.getRotationRate())));
}
/** Get the date of attitude parameters.
* @return date of the attitude parameters
*/
public AbsoluteDate getDate() {
return date;
}
/** 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 AngularCoordinates 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();
}
/** {@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>
*/
public Attitude interpolate(final AbsoluteDate interpolationDate, final Collection<Attitude> sample) {
final List<Pair<AbsoluteDate, AngularCoordinates>> datedPV =
new ArrayList<Pair<AbsoluteDate, AngularCoordinates>>(sample.size());
for (final Attitude attitude : sample) {
datedPV.add(new Pair<AbsoluteDate, AngularCoordinates>(attitude.getDate(), attitude.getOrientation()));
}
final AngularCoordinates interpolated = AngularCoordinates.interpolate(interpolationDate, true, datedPV);
return new Attitude(interpolationDate, referenceFrame, interpolated);
}
}