YawCompensation.java

  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. import org.hipparchus.Field;
  19. import org.hipparchus.RealFieldElement;
  20. import org.hipparchus.geometry.euclidean.threed.FieldRotation;
  21. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  22. import org.hipparchus.geometry.euclidean.threed.Rotation;
  23. import org.hipparchus.geometry.euclidean.threed.RotationConvention;
  24. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  25. import org.orekit.errors.OrekitException;
  26. import org.orekit.frames.FieldTransform;
  27. import org.orekit.frames.Frame;
  28. import org.orekit.frames.Transform;
  29. import org.orekit.time.AbsoluteDate;
  30. import org.orekit.time.FieldAbsoluteDate;
  31. import org.orekit.utils.FieldPVCoordinates;
  32. import org.orekit.utils.FieldPVCoordinatesProvider;
  33. import org.orekit.utils.PVCoordinates;
  34. import org.orekit.utils.PVCoordinatesProvider;
  35. import org.orekit.utils.TimeStampedAngularCoordinates;
  36. import org.orekit.utils.TimeStampedFieldAngularCoordinates;
  37. import org.orekit.utils.TimeStampedFieldPVCoordinates;
  38. import org.orekit.utils.TimeStampedPVCoordinates;


  39. /**
  40.  * This class handles yaw compensation attitude provider.

  41.  * <p>
  42.  * Yaw compensation is mainly used for Earth observation satellites. As a
  43.  * satellites moves along its track, the image of ground points move on
  44.  * the focal point of the optical sensor. This motion is a combination of
  45.  * the satellite motion, but also on the Earth rotation and on the current
  46.  * attitude (in particular if the pointing includes Roll or Pitch offset).
  47.  * In order to reduce geometrical distortion, the yaw angle is changed a
  48.  * little from the simple ground pointing attitude such that the apparent
  49.  * motion of ground points is along a prescribed axis (orthogonal to the
  50.  * optical sensors rows), taking into account all effects.
  51.  * </p>
  52.  * <p>
  53.  * This attitude is implemented as a wrapper on top of an underlying ground
  54.  * pointing law that defines the roll and pitch angles.
  55.  * </p>
  56.  * <p>
  57.  * Instances of this class are guaranteed to be immutable.
  58.  * </p>
  59.  * @see     GroundPointing
  60.  * @author V&eacute;ronique Pommier-Maurussane
  61.  */
  62. public class YawCompensation extends GroundPointing implements AttitudeProviderModifier {

  63.     /** Serializable UID. */
  64.     private static final long serialVersionUID = 20150529L;

  65.     /** J axis. */
  66.     private static final PVCoordinates PLUS_J =
  67.             new PVCoordinates(Vector3D.PLUS_J, Vector3D.ZERO, Vector3D.ZERO);

  68.     /** K axis. */
  69.     private static final PVCoordinates PLUS_K =
  70.             new PVCoordinates(Vector3D.PLUS_K, Vector3D.ZERO, Vector3D.ZERO);

  71.     /** Underlying ground pointing attitude provider.  */
  72.     private final GroundPointing groundPointingLaw;

  73.     /** Creates a new instance.
  74.      * @param inertialFrame frame in which orbital velocities are computed
  75.      * @param groundPointingLaw ground pointing attitude provider without yaw compensation
  76.      * @exception OrekitException if the frame specified is not a pseudo-inertial frame
  77.      * @since 7.1
  78.      */
  79.     public YawCompensation(final Frame inertialFrame, final GroundPointing groundPointingLaw)
  80.         throws OrekitException {
  81.         super(inertialFrame, groundPointingLaw.getBodyFrame());
  82.         this.groundPointingLaw = groundPointingLaw;
  83.     }

  84.     /** Get the underlying (ground pointing) attitude provider.
  85.      * @return underlying attitude provider, which in this case is a {@link GroundPointing} instance
  86.      */
  87.     public AttitudeProvider getUnderlyingAttitudeProvider() {
  88.         return groundPointingLaw;
  89.     }

  90.     /** {@inheritDoc} */
  91.     public TimeStampedPVCoordinates getTargetPV(final PVCoordinatesProvider pvProv,
  92.                                                 final AbsoluteDate date, final Frame frame)
  93.         throws OrekitException {
  94.         return groundPointingLaw.getTargetPV(pvProv, date, frame);
  95.     }

  96.     /** {@inheritDoc} */
  97.     public <T extends RealFieldElement<T>> TimeStampedFieldPVCoordinates<T> getTargetPV(final FieldPVCoordinatesProvider<T> pvProv,
  98.                                                                                         final FieldAbsoluteDate<T> date,
  99.                                                                                         final Frame frame)
  100.         throws OrekitException {
  101.         return groundPointingLaw.getTargetPV(pvProv, date, frame);
  102.     }

  103.     /** Compute the base system state at given date, without compensation.
  104.      * @param pvProv provider for PV coordinates
  105.      * @param date date at which state is requested
  106.      * @param frame reference frame from which attitude is computed
  107.      * @return satellite base attitude state, i.e without compensation.
  108.      * @throws OrekitException if some specific error occurs
  109.      */
  110.     public Attitude getBaseState(final PVCoordinatesProvider pvProv,
  111.                                  final AbsoluteDate date, final Frame frame)
  112.         throws OrekitException {
  113.         return groundPointingLaw.getAttitude(pvProv, date, frame);
  114.     }

  115.     /** Compute the base system state at given date, without compensation.
  116.      * @param pvProv provider for PV coordinates
  117.      * @param date date at which state is requested
  118.      * @param frame reference frame from which attitude is computed
  119.      * @param <T> type of the field elements
  120.      * @return satellite base attitude state, i.e without compensation.
  121.      * @throws OrekitException if some specific error occurs
  122.      * @since 9.0
  123.      */
  124.     public <T extends RealFieldElement<T>> FieldAttitude<T> getBaseState(final FieldPVCoordinatesProvider<T> pvProv,
  125.                                                                          final FieldAbsoluteDate<T> date, final Frame frame)
  126.         throws OrekitException {
  127.         return groundPointingLaw.getAttitude(pvProv, date, frame);
  128.     }

  129.     /** {@inheritDoc} */
  130.     @Override
  131.     public Attitude getAttitude(final PVCoordinatesProvider pvProv,
  132.                                 final AbsoluteDate date, final Frame frame)
  133.         throws OrekitException {

  134.         final Transform bodyToRef = getBodyFrame().getTransformTo(frame, date);

  135.         // compute sliding target ground point
  136.         final PVCoordinates slidingRef  = getTargetPV(pvProv, date, frame);
  137.         final PVCoordinates slidingBody = bodyToRef.getInverse().transformPVCoordinates(slidingRef);

  138.         // compute relative position of sliding ground point with respect to satellite
  139.         final PVCoordinates relativePosition =
  140.                 new PVCoordinates(pvProv.getPVCoordinates(date, frame), slidingRef);

  141.         // compute relative velocity of fixed ground point with respect to sliding ground point
  142.         // the velocity part of the transformPVCoordinates for the sliding point ps
  143.         // from body frame to reference frame is:
  144.         //     d(ps_ref)/dt = r(d(ps_body)/dt + dq/dt) - Ω ⨯ ps_ref
  145.         // where r is the rotation part of the transform, Ω is the corresponding
  146.         // angular rate, and dq/dt is the derivative of the translation part of the
  147.         // transform (the translation itself, without derivative, is hidden in the
  148.         // ps_ref part in the cross product).
  149.         // The sliding point ps is co-located to a fixed ground point pf (i.e. they have the
  150.         // same position at time of computation), but this fixed point as zero velocity
  151.         // with respect to the ground. So the velocity part of the transformPVCoordinates
  152.         // for this fixed point can be computed using the same formula as above:
  153.         // from body frame to reference frame is:
  154.         //     d(pf_ref)/dt = r(0 + dq/dt) - Ω ⨯ pf_ref
  155.         // so remembering that the two points are at the same location at computation time,
  156.         // i.e. that at t=0 pf_ref=ps_ref, the relative velocity between the fixed point
  157.         // and the sliding point is given by the simple expression:
  158.         //     d(ps_ref)/dt - d(pf_ref)/dt = r(d(ps_body)/dt)
  159.         // the acceleration is computed by differentiating the expression, which gives:
  160.         //    d²(ps_ref)/dt² - d²(pf_ref)/dt² = r(d²(ps_body)/dt²) - Ω ⨯ [d(ps_ref)/dt - d(pf_ref)/dt]
  161.         final Vector3D v = bodyToRef.getRotation().applyTo(slidingBody.getVelocity());
  162.         final Vector3D a = new Vector3D(+1, bodyToRef.getRotation().applyTo(slidingBody.getAcceleration()),
  163.                                         -1, Vector3D.crossProduct(bodyToRef.getRotationRate(), v));
  164.         final PVCoordinates relativeVelocity = new PVCoordinates(v, a, Vector3D.ZERO);

  165.         final PVCoordinates relativeNormal =
  166.                 PVCoordinates.crossProduct(relativePosition, relativeVelocity).normalize();

  167.         // attitude definition :
  168.         //  . Z satellite axis points to sliding target
  169.         //  . target relative velocity is in (Z, X) plane, in the -X half plane part
  170.         return new Attitude(frame,
  171.                             new TimeStampedAngularCoordinates(date,
  172.                                                               relativePosition.normalize(),
  173.                                                               relativeNormal.normalize(),
  174.                                                               PLUS_K, PLUS_J,
  175.                                                               1.0e-9));

  176.     }

  177.     /** {@inheritDoc} */
  178.     @Override
  179.     public <T extends RealFieldElement<T>> FieldAttitude<T> getAttitude(final FieldPVCoordinatesProvider<T> pvProv,
  180.                                                                         final FieldAbsoluteDate<T> date, final Frame frame)
  181.         throws OrekitException {

  182.         final Field<T>              field = date.getField();
  183.         final FieldVector3D<T>      zero  = FieldVector3D.getZero(field);
  184.         final FieldPVCoordinates<T> plusJ = new FieldPVCoordinates<>(FieldVector3D.getPlusJ(field), zero, zero);
  185.         final FieldPVCoordinates<T> plusK = new FieldPVCoordinates<>(FieldVector3D.getPlusK(field), zero, zero);

  186.         final FieldTransform<T> bodyToRef = getBodyFrame().getTransformTo(frame, date);

  187.         // compute sliding target ground point
  188.         final FieldPVCoordinates<T> slidingRef  = getTargetPV(pvProv, date, frame);
  189.         final FieldPVCoordinates<T> slidingBody = bodyToRef.getInverse().transformPVCoordinates(slidingRef);

  190.         // compute relative position of sliding ground point with respect to satellite
  191.         final FieldPVCoordinates<T> relativePosition =
  192.                 new FieldPVCoordinates<>(pvProv.getPVCoordinates(date, frame), slidingRef);

  193.         // compute relative velocity of fixed ground point with respect to sliding ground point
  194.         // the velocity part of the transformPVCoordinates for the sliding point ps
  195.         // from body frame to reference frame is:
  196.         //     d(ps_ref)/dt = r(d(ps_body)/dt + dq/dt) - Ω ⨯ ps_ref
  197.         // where r is the rotation part of the transform, Ω is the corresponding
  198.         // angular rate, and dq/dt is the derivative of the translation part of the
  199.         // transform (the translation itself, without derivative, is hidden in the
  200.         // ps_ref part in the cross product).
  201.         // The sliding point ps is co-located to a fixed ground point pf (i.e. they have the
  202.         // same position at time of computation), but this fixed point as zero velocity
  203.         // with respect to the ground. So the velocity part of the transformPVCoordinates
  204.         // for this fixed point can be computed using the same formula as above:
  205.         // from body frame to reference frame is:
  206.         //     d(pf_ref)/dt = r(0 + dq/dt) - Ω ⨯ pf_ref
  207.         // so remembering that the two points are at the same location at computation time,
  208.         // i.e. that at t=0 pf_ref=ps_ref, the relative velocity between the fixed point
  209.         // and the sliding point is given by the simple expression:
  210.         //     d(ps_ref)/dt - d(pf_ref)/dt = r(d(ps_body)/dt)
  211.         // the acceleration is computed by differentiating the expression, which gives:
  212.         //    d²(ps_ref)/dt² - d²(pf_ref)/dt² = r(d²(ps_body)/dt²) - Ω ⨯ [d(ps_ref)/dt - d(pf_ref)/dt]
  213.         final FieldVector3D<T> v = bodyToRef.getRotation().applyTo(slidingBody.getVelocity());
  214.         final FieldVector3D<T> a = new FieldVector3D<>(+1, bodyToRef.getRotation().applyTo(slidingBody.getAcceleration()),
  215.                                                        -1, FieldVector3D.crossProduct(bodyToRef.getRotationRate(), v));
  216.         final FieldPVCoordinates<T> relativeVelocity = new FieldPVCoordinates<>(v, a, FieldVector3D.getZero(date.getField()));

  217.         final FieldPVCoordinates<T> relativeNormal =
  218.                         relativePosition.crossProduct(relativeVelocity).normalize();

  219.         // attitude definition :
  220.         //  . Z satellite axis points to sliding target
  221.         //  . target relative velocity is in (Z, X) plane, in the -X half plane part
  222.         return new FieldAttitude<>(frame,
  223.                                    new TimeStampedFieldAngularCoordinates<>(date,
  224.                                                                             relativePosition.normalize(),
  225.                                                                             relativeNormal.normalize(),
  226.                                                                             plusK, plusJ,
  227.                                                                             1.0e-9));

  228.     }

  229.     /** Compute the yaw compensation angle at date.
  230.      * @param pvProv provider for PV coordinates
  231.      * @param date date at which compensation is requested
  232.      * @param frame reference frame from which attitude is computed
  233.      * @return yaw compensation angle for orbit.
  234.      * @throws OrekitException if some specific error occurs
  235.      */
  236.     public double getYawAngle(final PVCoordinatesProvider pvProv,
  237.                               final AbsoluteDate date, final Frame frame)
  238.         throws OrekitException {
  239.         final Rotation rBase        = getBaseState(pvProv, date, frame).getRotation();
  240.         final Rotation rCompensated = getAttitude(pvProv, date, frame).getRotation();
  241.         final Rotation compensation = rCompensated.compose(rBase.revert(), RotationConvention.VECTOR_OPERATOR);
  242.         return -compensation.applyTo(Vector3D.PLUS_I).getAlpha();
  243.     }

  244.     /** Compute the yaw compensation angle at date.
  245.      * @param pvProv provider for PV coordinates
  246.      * @param date date at which compensation is requested
  247.      * @param frame reference frame from which attitude is computed
  248.      * @param <T> type of the field elements
  249.      * @return yaw compensation angle for orbit.
  250.      * @throws OrekitException if some specific error occurs
  251.      * @since 9.0
  252.      */
  253.     public <T extends RealFieldElement<T>> T getYawAngle(final FieldPVCoordinatesProvider<T> pvProv,
  254.                                                          final FieldAbsoluteDate<T> date,
  255.                                                          final Frame frame)
  256.         throws OrekitException {
  257.         final FieldRotation<T> rBase        = getBaseState(pvProv, date, frame).getRotation();
  258.         final FieldRotation<T> rCompensated = getAttitude(pvProv, date, frame).getRotation();
  259.         final FieldRotation<T> compensation = rCompensated.compose(rBase.revert(), RotationConvention.VECTOR_OPERATOR);
  260.         return compensation.applyTo(Vector3D.PLUS_I).getAlpha().negate();
  261.     }

  262. }