Commit 4b2926af authored by Luc Maisonobe's avatar Luc Maisonobe

Merge branch 'gnss-attitude' into develop

parents 659137ab 4296a0b0
......@@ -18,18 +18,15 @@ package org.orekit.bodies;
import java.io.Serializable;
import org.hipparchus.RealFieldElement;
import org.orekit.errors.OrekitException;
import org.orekit.frames.Frame;
import org.orekit.time.FieldAbsoluteDate;
import org.orekit.utils.PVCoordinatesProvider;
import org.orekit.utils.TimeStampedFieldPVCoordinates;
import org.orekit.utils.ExtendedPVCoordinatesProvider;
/** Interface for celestial bodies like Sun, Moon or solar system planets.
* @author Luc Maisonobe
* @see CelestialBodyFactory
*/
public interface CelestialBody extends Serializable, PVCoordinatesProvider {
public interface CelestialBody extends Serializable, ExtendedPVCoordinatesProvider {
/** Get an inertially oriented, body centered frame.
* <p>The frame is always bound to the body center, and its axes have a
......@@ -59,19 +56,4 @@ public interface CelestialBody extends Serializable, PVCoordinatesProvider {
*/
double getGM();
/**
* Get the {@link TimeStampedFieldPVCoordinates} of the body in the selected frame.
*
* @param date current date
* @param frame the frame where to define the position
* @param <T> type fo the field elements
* @return time-stamped position/velocity of the body (m and m/s)
* @throws OrekitException if position cannot be computed in given frame
* @see #getPVCoordinates(org.orekit.time.AbsoluteDate, Frame)
*/
<T extends RealFieldElement<T>> TimeStampedFieldPVCoordinates<T> getPVCoordinates(
FieldAbsoluteDate<T> date,
Frame frame)
throws OrekitException;
}
......@@ -23,9 +23,12 @@ import org.orekit.errors.OrekitException;
import org.orekit.frames.Frame;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.FieldAbsoluteDate;
import org.orekit.utils.ExtendedPVCoordinatesProvider;
import org.orekit.utils.FieldPVCoordinatesProvider;
import org.orekit.utils.PVCoordinatesProvider;
import org.orekit.utils.TimeStampedAngularCoordinates;
import org.orekit.utils.TimeStampedFieldAngularCoordinates;
import org.orekit.utils.TimeStampedFieldPVCoordinates;
import org.orekit.utils.TimeStampedPVCoordinates;
/**
......@@ -46,7 +49,7 @@ public abstract class AbstractGNSSAttitudeProvider implements GNSSAttitudeProvid
private final AbsoluteDate validityEnd;
/** Provider for Sun position. */
private final PVCoordinatesProvider sun;
private final ExtendedPVCoordinatesProvider sun;
/** Inertial frame where velocity are computed. */
private final Frame inertialFrame;
......@@ -59,7 +62,7 @@ public abstract class AbstractGNSSAttitudeProvider implements GNSSAttitudeProvid
*/
protected AbstractGNSSAttitudeProvider(final AbsoluteDate validityStart,
final AbsoluteDate validityEnd,
final PVCoordinatesProvider sun,
final ExtendedPVCoordinatesProvider sun,
final Frame inertialFrame) {
this.validityStart = validityStart;
this.validityEnd = validityEnd;
......@@ -104,8 +107,17 @@ public abstract class AbstractGNSSAttitudeProvider implements GNSSAttitudeProvid
final FieldAbsoluteDate<T> date,
final Frame frame)
throws OrekitException {
// TODO
return null;
// Sun/spacecraft geometry
// computed in inertial frame so orbital plane (which depends on spacecraft velocity) is correct
final TimeStampedFieldPVCoordinates<T> sunPV = sun.getPVCoordinates(date, inertialFrame);
final TimeStampedFieldPVCoordinates<T> svPV = pvProv.getPVCoordinates(date, inertialFrame);
// compute yaw correction
final TimeStampedFieldAngularCoordinates<T> corrected = correctedYaw(new GNSSFieldAttitudeContext<>(sunPV, svPV));
return new FieldAttitude<>(inertialFrame, corrected).withReferenceFrame(frame);
}
/** Compute GNSS attitude with midnight/noon yaw turn correction.
......@@ -116,4 +128,14 @@ public abstract class AbstractGNSSAttitudeProvider implements GNSSAttitudeProvid
protected abstract TimeStampedAngularCoordinates correctedYaw(GNSSAttitudeContext context)
throws OrekitException;
/** Compute GNSS attitude with midnight/noon yaw turn correction.
* @param context context data for attitude computation
* @param <T> type of the field elements
* @return corrected yaw, using inertial frame as the reference
* @exception OrekitException if yaw corrected attitude cannot be computed
*/
protected abstract <T extends RealFieldElement<T>> TimeStampedFieldAngularCoordinates<T>
correctedYaw(GNSSFieldAttitudeContext<T> context)
throws OrekitException;
}
......@@ -16,11 +16,13 @@
*/
package org.orekit.gnss.attitude;
import org.hipparchus.RealFieldElement;
import org.orekit.errors.OrekitException;
import org.orekit.frames.Frame;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.PVCoordinatesProvider;
import org.orekit.utils.ExtendedPVCoordinatesProvider;
import org.orekit.utils.TimeStampedAngularCoordinates;
import org.orekit.utils.TimeStampedFieldAngularCoordinates;
/**
* Attitude providers for Beidou geostationary orbit navigation satellites.
......@@ -39,7 +41,7 @@ public class BeidouGeo extends AbstractGNSSAttitudeProvider {
* @param inertialFrame inertial frame where velocity are computed
*/
public BeidouGeo(final AbsoluteDate validityStart, final AbsoluteDate validityEnd,
final PVCoordinatesProvider sun, final Frame inertialFrame) {
final ExtendedPVCoordinatesProvider sun, final Frame inertialFrame) {
super(validityStart, validityEnd, sun, inertialFrame);
}
......@@ -53,4 +55,14 @@ public class BeidouGeo extends AbstractGNSSAttitudeProvider {
}
/** {@inheritDoc} */
@Override
protected <T extends RealFieldElement<T>> TimeStampedFieldAngularCoordinates<T> correctedYaw(final GNSSFieldAttitudeContext<T> context)
throws OrekitException {
// geostationary Beidou spacecraft are always in Orbit Normal (ON) yaw
return context.orbitNormalYaw();
}
}
......@@ -16,12 +16,14 @@
*/
package org.orekit.gnss.attitude;
import org.hipparchus.RealFieldElement;
import org.hipparchus.util.FastMath;
import org.orekit.errors.OrekitException;
import org.orekit.frames.Frame;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.PVCoordinatesProvider;
import org.orekit.utils.ExtendedPVCoordinatesProvider;
import org.orekit.utils.TimeStampedAngularCoordinates;
import org.orekit.utils.TimeStampedFieldAngularCoordinates;
/**
* Attitude providers for Beidou inclined geosynchronous orbit navigation satellites.
......@@ -43,7 +45,7 @@ public class BeidouIGSO extends AbstractGNSSAttitudeProvider {
* @param inertialFrame inertial frame where velocity are computed
*/
public BeidouIGSO(final AbsoluteDate validityStart, final AbsoluteDate validityEnd,
final PVCoordinatesProvider sun, final Frame inertialFrame) {
final ExtendedPVCoordinatesProvider sun, final Frame inertialFrame) {
super(validityStart, validityEnd, sun, inertialFrame);
}
......@@ -62,4 +64,19 @@ public class BeidouIGSO extends AbstractGNSSAttitudeProvider {
}
/** {@inheritDoc} */
@Override
protected <T extends RealFieldElement<T>> TimeStampedFieldAngularCoordinates<T> correctedYaw(final GNSSFieldAttitudeContext<T> context)
throws OrekitException {
if (FastMath.abs(context.getBeta()).getReal() < 2 * BETA_0) {
// when Sun is close to orbital plane, attitude is in Orbit Normal (ON) yaw
return context.orbitNormalYaw();
}
// in nominal yaw mode
return context.getNominalYaw();
}
}
......@@ -16,12 +16,14 @@
*/
package org.orekit.gnss.attitude;
import org.hipparchus.RealFieldElement;
import org.hipparchus.util.FastMath;
import org.orekit.errors.OrekitException;
import org.orekit.frames.Frame;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.PVCoordinatesProvider;
import org.orekit.utils.ExtendedPVCoordinatesProvider;
import org.orekit.utils.TimeStampedAngularCoordinates;
import org.orekit.utils.TimeStampedFieldAngularCoordinates;
/**
* Attitude providers for Beidou Medium Earth Orbit navigation satellites.
......@@ -43,7 +45,7 @@ public class BeidouMeo extends AbstractGNSSAttitudeProvider {
* @param inertialFrame inertial frame where velocity are computed
*/
public BeidouMeo(final AbsoluteDate validityStart, final AbsoluteDate validityEnd,
final PVCoordinatesProvider sun, final Frame inertialFrame) {
final ExtendedPVCoordinatesProvider sun, final Frame inertialFrame) {
super(validityStart, validityEnd, sun, inertialFrame);
}
......@@ -62,4 +64,19 @@ public class BeidouMeo extends AbstractGNSSAttitudeProvider {
}
/** {@inheritDoc} */
@Override
protected <T extends RealFieldElement<T>> TimeStampedFieldAngularCoordinates<T> correctedYaw(final GNSSFieldAttitudeContext<T> context)
throws OrekitException {
if (FastMath.abs(context.getBeta()).getReal() < 2 * BETA_0) {
// when Sun is close to orbital plane, attitude is in Orbit Normal (ON) yaw
return context.orbitNormalYaw();
}
// in nominal yaw mode
return context.getNominalYaw();
}
}
......@@ -130,9 +130,7 @@ class GNSSAttitudeContext implements TimeStamped {
1.0e-9);
this.nominalYawDS = nominalYaw.toDerivativeStructureRotation(ORDER);
// TODO: the Kouba model assumes perfectly circular orbit, it should really be:
this.muRate = svPV.getAngularVelocity().getNorm();
//this.muRate = svPV.getVelocity().getNorm() / svPV.getPosition().getNorm();
}
......@@ -297,9 +295,7 @@ class GNSSAttitudeContext implements TimeStamped {
* @return angle projected into orbital plane, always positive
*/
private DerivativeStructure inOrbitPlaneAbsoluteAngle(final DerivativeStructure angle) {
// TODO: the Kouba model assumes planar right-angle triangle resolution, it should really be:
return FastMath.acos(FastMath.cos(angle).divide(FastMath.cos(beta)));
//return angle.multiply(angle).subtract(beta.multiply(beta)).sqrt();
}
/** Project a spacecraft/Sun angle into orbital plane.
......@@ -313,9 +309,7 @@ class GNSSAttitudeContext implements TimeStamped {
* @return angle projected into orbital plane, always positive
*/
public double inOrbitPlaneAbsoluteAngle(final double angle) {
// TODO: the Kouba model assumes planar right-angle triangle resolution, it should really be:
return FastMath.acos(FastMath.cos(angle) / FastMath.cos(beta.getReal()));
//return FastMath.sqrt(angle * angle - beta.getReal() * beta.getReal());
}
/** Compute yaw.
......
/* 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.gnss.attitude;
import org.hipparchus.Field;
import org.hipparchus.RealFieldElement;
import org.hipparchus.analysis.differentiation.FDSFactory;
import org.hipparchus.analysis.differentiation.FieldDerivativeStructure;
import org.hipparchus.geometry.euclidean.threed.FieldRotation;
import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
import org.hipparchus.geometry.euclidean.threed.RotationConvention;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.hipparchus.util.FastMath;
import org.orekit.errors.OrekitException;
import org.orekit.frames.FieldTransform;
import org.orekit.frames.LOFType;
import org.orekit.time.FieldAbsoluteDate;
import org.orekit.time.FieldTimeStamped;
import org.orekit.utils.FieldPVCoordinates;
import org.orekit.utils.PVCoordinates;
import org.orekit.utils.TimeStampedFieldAngularCoordinates;
import org.orekit.utils.TimeStampedFieldPVCoordinates;
/**
* Boilerplate computations for GNSS attitude.
*
* <p>
* This class is intended to hold throw-away data pertaining to <em>one</em> call
* to {@link GNSSAttitudeProvider#getAttitude(org.orekit.utils.FieldPVCoordinatesProvider,
* org.orekit.time.FieldAbsoluteDate, org.orekit.frames.Frame)) getAttitude}. It allows
* the various {@link GNSSAttitudeProvider} implementations to be immutable as they
* do not store any state, and hence to be thread-safe, reentrant and naturally
* serializable (so for example ephemeris built from them are also serializable).
* </p>
*
* @author Luc Maisonobe
* @since 9.2
*/
class GNSSFieldAttitudeContext<T extends RealFieldElement<T>> implements FieldTimeStamped<T> {
/** Constant Y axis. */
private static final PVCoordinates PLUS_Y =
new PVCoordinates(Vector3D.PLUS_J, Vector3D.ZERO, Vector3D.ZERO);
/** Constant Z axis. */
private static final PVCoordinates MINUS_Z =
new PVCoordinates(Vector3D.MINUS_K, Vector3D.ZERO, Vector3D.ZERO);
/** Limit value below which we shoud use replace beta by betaIni. */
private static final double BETA_SIGN_CHANGE_PROTECTION = FastMath.toRadians(0.07);
/** Derivation order. */
private static final int ORDER = 2;
/** Constant Y axis. */
private final FieldPVCoordinates<T> plusY;
/** Constant Z axis. */
private final FieldPVCoordinates<T> minusZ;
/** Spacecraft position-velocity in inertial frame. */
private final TimeStampedFieldPVCoordinates<T> svPV;
/** Spacecraft position-velocity in inertial frame. */
private final FieldPVCoordinates<FieldDerivativeStructure<T>> svPVDS;
/** Angle between Sun and orbital plane. */
private final FieldDerivativeStructure<T> beta;
/** Cosine of the angle between spacecraft and Sun direction. */
private final FieldDerivativeStructure<T> svbCos;
/** Nominal yaw. */
private final TimeStampedFieldAngularCoordinates<T> nominalYaw;
/** Nominal yaw. */
private final FieldRotation<FieldDerivativeStructure<T>> nominalYawDS;
/** Spacecraft angular velocity. */
private T muRate;
/** Limit cosine for the midnight turn. */
private double cNight;
/** Limit cosine for the noon turn. */
private double cNoon;
/** Relative orbit angle to turn center. */
private FieldDerivativeStructure<T> delta;
/** Half span of the turn region, as an angle in orbit plane. */
private T halfSpan;
/** Turn start date. */
private FieldAbsoluteDate<T> turnStart;
/** Turn end date. */
private FieldAbsoluteDate<T> turnEnd;
/** Simple constructor.
* @param sunPV Sun position-velocity in inertial frame
* @param svPV spacecraft position-velocity in inertial frame
* @exception OrekitException if yaw cannot be corrected
*/
GNSSFieldAttitudeContext(final TimeStampedFieldPVCoordinates<T> sunPV, final TimeStampedFieldPVCoordinates<T> svPV)
throws OrekitException {
final Field<T> field = sunPV.getDate().getField();
plusY = new FieldPVCoordinates<>(field, PLUS_Y);
minusZ = new FieldPVCoordinates<>(field, MINUS_Z);
final FieldPVCoordinates<FieldDerivativeStructure<T>> sunPVDS = sunPV.toDerivativeStructurePV(ORDER);
this.svPV = svPV;
this.svPVDS = svPV.toDerivativeStructurePV(ORDER);
this.svbCos = FieldVector3D.dotProduct(sunPVDS.getPosition(), svPVDS.getPosition()).
divide(sunPVDS.getPosition().getNorm().
multiply(svPVDS.getPosition().getNorm()));
this.beta = FieldVector3D.angle(sunPVDS.getPosition(), svPVDS.getMomentum()).
negate().
add(0.5 * FastMath.PI);
// nominal yaw steering
this.nominalYaw =
new TimeStampedFieldAngularCoordinates<>(svPV.getDate(),
svPV.normalize(),
sunPV.crossProduct(svPV).normalize(),
minusZ,
plusY,
1.0e-9);
this.nominalYawDS = nominalYaw.toDerivativeStructureRotation(ORDER);
this.muRate = svPV.getAngularVelocity().getNorm();
}
/** {@inheritDoc} */
@Override
public FieldAbsoluteDate<T> getDate() {
return svPV.getDate();
}
/** Get the cosine of the angle between spacecraft and Sun direction.
* @return cosine of the angle between spacecraft and Sun direction.
*/
public T getSVBcos() {
return svbCos.getValue();
}
/** Get the angle between Sun and orbital plane.
* @return angle between Sun and orbital plane
* @see #getBetaDS()
* @see #getSecuredBeta(TurnTimeRange)
*/
public T getBeta() {
return beta.getValue();
}
/** Get the angle between Sun and orbital plane.
* @return angle between Sun and orbital plane
* @see #getBeta()
* @see #getSecuredBeta(TurnTimeRange)
*/
public FieldDerivativeStructure<T> getBetaDS() {
return beta;
}
/** Get a Sun elevation angle that does not change sign within the turn.
* <p>
* This method either returns the current beta or replaces it with the
* value at turn start, so the sign remains constant throughout the
* turn. As of 9.2, it is only useful for GPS and Glonass.
* </p>
* @return secured Sun elevation angle
* @see #getBeta()
* @see #getBetaDS()
*/
public T getSecuredBeta() {
return FastMath.abs(beta.getReal()) < BETA_SIGN_CHANGE_PROTECTION ?
beta.taylor(timeSinceTurnStart(getDate()).negate()) :
getBeta();
}
/** Get the nominal yaw.
* @return nominal yaw
*/
public TimeStampedFieldAngularCoordinates<T> getNominalYaw() {
return nominalYaw;
}
/** Compute nominal yaw angle.
* @return nominal yaw angle
*/
public T yawAngle() {
final FieldVector3D<T> xSat = nominalYaw.getRotation().revert().applyTo(Vector3D.PLUS_I);
return FastMath.copySign(FieldVector3D.angle(svPV.getVelocity(), xSat), -beta.getReal());
}
/** Compute nominal yaw angle.
* @return nominal yaw angle
*/
public FieldDerivativeStructure<T> yawAngleDS() {
final FieldVector3D<FieldDerivativeStructure<T>> xSat = nominalYawDS.revert().applyTo(Vector3D.PLUS_I);
final FDSFactory<T> factory = xSat.getX().getFactory();
final FieldVector3D<T> v = svPV.getVelocity();
final FieldVector3D<FieldDerivativeStructure<T>> vDS = new FieldVector3D<>(factory.constant(v.getX()),
factory.constant(v.getY()),
factory.constant(v.getZ()));
return FieldVector3D.angle(vDS, xSat).copySign(beta.getValue().negate());
}
/** Set up the midnight/noon turn region.
* @param cosNight limit cosine for the midnight turn
* @param cosNoon limit cosine for the noon turn
* @return true if spacecraft is in the midnight/noon turn region
*/
public boolean setUpTurnRegion(final double cosNight, final double cosNoon) {
this.cNight = cosNight;
this.cNoon = cosNoon;
if (svbCos.getValue().getReal() < cNight) {
// in eclipse turn mode
final FieldDerivativeStructure<T> absDelta = inOrbitPlaneAbsoluteAngle(svbCos.acos().negate().add(FastMath.PI));
delta = absDelta.copySign(absDelta.getPartialDerivative(1).negate());
return true;
} else if (svbCos.getValue().getReal() > cNoon) {
// in noon turn mode
final FieldDerivativeStructure<T> absDelta = inOrbitPlaneAbsoluteAngle(svbCos.acos());
delta = absDelta.copySign(absDelta.getPartialDerivative(1).negate());
return true;
} else {
return false;
}
}
/** Get the relative orbit angle to turn center.
* @return relative orbit angle to turn center
*/
public T getDelta() {
return delta.getValue();
}
/** Get the relative orbit angle to turn center.
* @return relative orbit angle to turn center
*/
public FieldDerivativeStructure<T> getDeltaDS() {
return delta;
}
/** Check if spacecraft is in the half orbit closest to Sun.
* @return true if spacecraft is in the half orbit closest to Sun
*/
public boolean inSunSide() {
return svbCos.getValue().getReal() > 0;
}
/** Get yaw at turn start.
* @param sunBeta Sun elevation above orbital plane
* (it <em>may</em> be different from {@link #getBeta()} in
* some special cases)
* @return yaw at turn start
*/
public T getYawStart(final T sunBeta) {
return computePhi(sunBeta, FastMath.copySign(halfSpan, svbCos.getValue()));
}
/** Get yaw at turn end.
* @param sunBeta Sun elevation above orbital plane
* (it <em>may</em> be different from {@link #getBeta()} in
* some special cases)
* @return yaw at turn end
*/
public T getYawEnd(final T sunBeta) {
return computePhi(sunBeta, FastMath.copySign(halfSpan, svbCos.getValue().negate()));
}
/** Compute yaw rate.
* @param sunBeta Sun elevation above orbital plane
* (it <em>may</em> be different from {@link #getBeta()} in
* some special cases)
* @return yaw rate
*/
public T yawRate(final T sunBeta) {
return getYawEnd(sunBeta).subtract(getYawStart(sunBeta)).divide(getTurnDuration());
}
/** Get the spacecraft angular velocity.
* @return spacecraft angular velocity
*/
public T getMuRate() {
return muRate;
}
/** Project a spacecraft/Sun angle into orbital plane.
* <p>
* This method is intended to find the limits of the noon and midnight
* turns in orbital plane. The return angle is signed, depending on the
* spacecraft being before or after turn middle point.
* </p>
* @param angle spacecraft/Sun angle (or spacecraft/opposite-of-Sun)
* @return angle projected into orbital plane, always positive
*/
private FieldDerivativeStructure<T> inOrbitPlaneAbsoluteAngle(final FieldDerivativeStructure<T> angle) {
return FastMath.acos(FastMath.cos(angle).divide(FastMath.cos(beta)));
}
/** Project a spacecraft/Sun angle into orbital plane.
* <p>
* This method is intended to find the limits of the noon and midnight
* turns in orbital plane. The return angle is always positive. The
* correct sign to apply depends on the spacecraft being before or
* after turn middle point.
* </p>
* @param angle spacecraft/Sun angle (or spacecraft/opposite-of-Sun)
* @return angle projected into orbital plane, always positive
*/
public T inOrbitPlaneAbsoluteAngle(final T angle) {
return FastMath.acos(FastMath.cos(angle).divide(FastMath.cos(beta.getReal())));
}
/** Compute yaw.
* @param sunBeta Sun elevation above orbital plane
* (it <em>may</em> be different from {@link #getBeta()} in
* some special cases)
* @param inOrbitPlaneAngle in orbit angle between spacecraft
* and Sun (or opposite of Sun) projection
* @return yaw angle
*/
public T computePhi(final T sunBeta, final T inOrbitPlaneAngle) {
return FastMath.atan2(FastMath.tan(sunBeta).negate(), FastMath.sin(inOrbitPlaneAngle));
}
/** Set turn half span and compute corresponding turn time range.
* @param halfSpan half span of the turn region, as an angle in orbit plane
*/
public void setHalfSpan(final T halfSpan) {
this.halfSpan = halfSpan;
this.turnStart = svPV.getDate().shiftedBy(delta.getValue().subtract(halfSpan).divide(muRate));
this.turnEnd = svPV.getDate().shiftedBy(delta.getValue().add(halfSpan).divide(muRate));
}
/** Check if a date is within range.
* @param date date to check
* @param endMargin margin in seconds after turn end
* @return true if date is within range extended by end margin
*/
public boolean inTurnTimeRange(final FieldAbsoluteDate<T> date, final double endMargin) {
return date.durationFrom(turnStart).getReal() > 0 &&
date.durationFrom(turnEnd).getReal() < endMargin;
}
/** Get turn duration.
* @return turn duration
*/
public T getTurnDuration() {
return halfSpan.multiply(2).divide(muRate);
}
/** Get elapsed time since turn start.
* @param date date to check
* @return elapsed time from turn start to specified date
*/
public T timeSinceTurnStart(final FieldAbsoluteDate<T> date) {
return date.durationFrom(turnStart);
}
/** Generate an attitude with turn-corrected yaw.
* @param yaw yaw value to apply
* @param yawDot yaw first time derivative
* @return attitude with specified yaw
*/
public TimeStampedFieldAngularCoordinates<T> turnCorrectedAttitude(final T yaw, final T yawDot) {
return turnCorrectedAttitude(beta.getFactory().build(yaw, yawDot, yaw.getField().getZero()));
}
/** Generate an attitude with turn-corrected yaw.
* @param yaw yaw value to apply
* @return attitude with specified yaw
*/
public TimeStampedFieldAngularCoordinates<T> turnCorrectedAttitude(final FieldDerivativeStructure<T> yaw) {
// compute a linear yaw correction model
final FieldDerivativeStructure<T> nominalAngle = yawAngleDS();
final TimeStampedFieldAngularCoordinates<T> correction =
new TimeStampedFieldAngularCoordinates<>(nominalYaw.getDate(),
new FieldRotation<>(FieldVector3D.getPlusK(nominalAngle.getField()),
yaw.subtract(nominalAngle),
RotationConvention.VECTOR_OPERATOR));
// combine the two parts of the attitude
return correction.addOffset(getNominalYaw());
}
/** Compute Orbit Normal (ON) yaw.
* @return Orbit Normal yaw, using inertial frame as reference
*/
public TimeStampedFieldAngularCoordinates<T> orbitNormalYaw() {
final FieldTransform<T> t = LOFType.VVLH.transformFromInertial(svPV.getDate(), svPV);
return new TimeStampedFieldAngularCoordinates<>(svPV.getDate(),
t.getRotation(),
t.getRotationRate(),
t.getRotationAcceleration());
}
}
......@@ -16,11 +16,14 @@
*/
package org.orekit.gnss.attitude;
import org.hipparchus.Field