YawCompensation.java
- /* Copyright 2002-2025 CS GROUP
 -  * Licensed to CS GROUP (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 org.hipparchus.Field;
 - import org.hipparchus.CalculusFieldElement;
 - import org.hipparchus.geometry.euclidean.threed.FieldRotation;
 - import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
 - import org.hipparchus.geometry.euclidean.threed.Rotation;
 - import org.hipparchus.geometry.euclidean.threed.RotationConvention;
 - import org.hipparchus.geometry.euclidean.threed.Vector3D;
 - import org.orekit.frames.FieldTransform;
 - import org.orekit.frames.Frame;
 - import org.orekit.frames.Transform;
 - import org.orekit.time.AbsoluteDate;
 - import org.orekit.time.FieldAbsoluteDate;
 - import org.orekit.utils.FieldPVCoordinates;
 - import org.orekit.utils.FieldPVCoordinatesProvider;
 - import org.orekit.utils.PVCoordinates;
 - import org.orekit.utils.PVCoordinatesProvider;
 - import org.orekit.utils.TimeStampedAngularCoordinates;
 - import org.orekit.utils.TimeStampedFieldAngularCoordinates;
 
- /**
 -  * This class handles yaw compensation attitude provider.
 
-  * <p>
 -  * Yaw compensation is mainly used for Earth observation satellites. As a
 -  * satellites moves along its track, the image of ground points move on
 -  * the focal point of the optical sensor. This motion is a combination of
 -  * the satellite motion, but also on the Earth rotation and on the current
 -  * attitude (in particular if the pointing includes Roll or Pitch offset).
 -  * In order to reduce geometrical distortion, the yaw angle is changed a
 -  * little from the simple ground pointing attitude such that the apparent
 -  * motion of ground points is along a prescribed axis (orthogonal to the
 -  * optical sensors rows), taking into account all effects.
 -  * </p>
 -  * <p>
 -  * This attitude is implemented as a wrapper on top of an underlying ground
 -  * pointing law that defines the roll and pitch angles.
 -  * </p>
 -  * <p>
 -  * Instances of this class are guaranteed to be immutable.
 -  * </p>
 -  * @see     GroundPointing
 -  * @author Véronique Pommier-Maurussane
 -  */
 - public class YawCompensation extends GroundPointingAttitudeModifier implements AttitudeProviderModifier {
 
-     /** J axis. */
 -     private static final PVCoordinates PLUS_J =
 -             new PVCoordinates(Vector3D.PLUS_J, Vector3D.ZERO, Vector3D.ZERO);
 
-     /** K axis. */
 -     private static final PVCoordinates PLUS_K =
 -             new PVCoordinates(Vector3D.PLUS_K, Vector3D.ZERO, Vector3D.ZERO);
 
-     /** Creates a new instance.
 -      * @param inertialFrame frame in which orbital velocities are computed
 -      * @param groundPointingLaw ground pointing attitude provider without yaw compensation
 -      * @since 7.1
 -      */
 -     public YawCompensation(final Frame inertialFrame, final GroundPointing groundPointingLaw) {
 -         super(inertialFrame, groundPointingLaw.getBodyFrame(), groundPointingLaw);
 -     }
 
-     /** {@inheritDoc} */
 -     @Override
 -     public Attitude getAttitude(final PVCoordinatesProvider pvProv,
 -                                 final AbsoluteDate date, final Frame frame) {
 
-         final Transform bodyToRef = getBodyFrame().getTransformTo(frame, date);
 
-         // compute sliding target ground point
 -         final PVCoordinates slidingRef  = getTargetPV(pvProv, date, frame);
 -         final PVCoordinates slidingBody = bodyToRef.getInverse().transformPVCoordinates(slidingRef);
 
-         // compute relative position of sliding ground point with respect to satellite
 -         final PVCoordinates relativePosition =
 -                 new PVCoordinates(pvProv.getPVCoordinates(date, frame), slidingRef);
 
-         // compute relative velocity of fixed ground point with respect to sliding ground point
 -         // the velocity part of the transformPVCoordinates for the sliding point ps
 -         // from body frame to reference frame is:
 -         //     d(ps_ref)/dt = r(d(ps_body)/dt + dq/dt) - Ω ⨯ ps_ref
 -         // where r is the rotation part of the transform, Ω is the corresponding
 -         // angular rate, and dq/dt is the derivative of the translation part of the
 -         // transform (the translation itself, without derivative, is hidden in the
 -         // ps_ref part in the cross product).
 -         // The sliding point ps is co-located to a fixed ground point pf (i.e. they have the
 -         // same position at time of computation), but this fixed point as zero velocity
 -         // with respect to the ground. So the velocity part of the transformPVCoordinates
 -         // for this fixed point can be computed using the same formula as above:
 -         // from body frame to reference frame is:
 -         //     d(pf_ref)/dt = r(0 + dq/dt) - Ω ⨯ pf_ref
 -         // so remembering that the two points are at the same location at computation time,
 -         // i.e. that at t=0 pf_ref=ps_ref, the relative velocity between the fixed point
 -         // and the sliding point is given by the simple expression:
 -         //     d(ps_ref)/dt - d(pf_ref)/dt = r(d(ps_body)/dt)
 -         // the acceleration is computed by differentiating the expression, which gives:
 -         //    d²(ps_ref)/dt² - d²(pf_ref)/dt² = r(d²(ps_body)/dt²) - Ω ⨯ [d(ps_ref)/dt - d(pf_ref)/dt]
 -         final Vector3D v = bodyToRef.getRotation().applyTo(slidingBody.getVelocity());
 -         final Vector3D a = new Vector3D(+1, bodyToRef.getRotation().applyTo(slidingBody.getAcceleration()),
 -                                         -1, Vector3D.crossProduct(bodyToRef.getRotationRate(), v));
 -         final PVCoordinates relativeVelocity = new PVCoordinates(v, a, Vector3D.ZERO);
 
-         final PVCoordinates relativeNormal =
 -                 PVCoordinates.crossProduct(relativePosition, relativeVelocity).normalize();
 
-         // attitude definition :
 -         //  . Z satellite axis points to sliding target
 -         //  . target relative velocity is in (Z, X) plane, in the -X half plane part
 -         return new Attitude(frame,
 -                             new TimeStampedAngularCoordinates(date,
 -                                                               relativePosition.normalize(),
 -                                                               relativeNormal.normalize(),
 -                                                               PLUS_K, PLUS_J,
 -                                                               1.0e-9));
 
-     }
 
-     /** {@inheritDoc} */
 -     @Override
 -     public <T extends CalculusFieldElement<T>> FieldAttitude<T> getAttitude(final FieldPVCoordinatesProvider<T> pvProv,
 -                                                                         final FieldAbsoluteDate<T> date, final Frame frame) {
 
-         final Field<T>              field = date.getField();
 -         final FieldVector3D<T>      zero  = FieldVector3D.getZero(field);
 -         final FieldPVCoordinates<T> plusJ = new FieldPVCoordinates<>(FieldVector3D.getPlusJ(field), zero, zero);
 -         final FieldPVCoordinates<T> plusK = new FieldPVCoordinates<>(FieldVector3D.getPlusK(field), zero, zero);
 
-         final FieldTransform<T> bodyToRef = getBodyFrame().getTransformTo(frame, date);
 
-         // compute sliding target ground point
 -         final FieldPVCoordinates<T> slidingRef  = getTargetPV(pvProv, date, frame);
 -         final FieldPVCoordinates<T> slidingBody = bodyToRef.getInverse().transformPVCoordinates(slidingRef);
 
-         // compute relative position of sliding ground point with respect to satellite
 -         final FieldPVCoordinates<T> relativePosition =
 -                 new FieldPVCoordinates<>(pvProv.getPVCoordinates(date, frame), slidingRef);
 
-         // compute relative velocity of fixed ground point with respect to sliding ground point
 -         // the velocity part of the transformPVCoordinates for the sliding point ps
 -         // from body frame to reference frame is:
 -         //     d(ps_ref)/dt = r(d(ps_body)/dt + dq/dt) - Ω ⨯ ps_ref
 -         // where r is the rotation part of the transform, Ω is the corresponding
 -         // angular rate, and dq/dt is the derivative of the translation part of the
 -         // transform (the translation itself, without derivative, is hidden in the
 -         // ps_ref part in the cross product).
 -         // The sliding point ps is co-located to a fixed ground point pf (i.e. they have the
 -         // same position at time of computation), but this fixed point as zero velocity
 -         // with respect to the ground. So the velocity part of the transformPVCoordinates
 -         // for this fixed point can be computed using the same formula as above:
 -         // from body frame to reference frame is:
 -         //     d(pf_ref)/dt = r(0 + dq/dt) - Ω ⨯ pf_ref
 -         // so remembering that the two points are at the same location at computation time,
 -         // i.e. that at t=0 pf_ref=ps_ref, the relative velocity between the fixed point
 -         // and the sliding point is given by the simple expression:
 -         //     d(ps_ref)/dt - d(pf_ref)/dt = r(d(ps_body)/dt)
 -         // the acceleration is computed by differentiating the expression, which gives:
 -         //    d²(ps_ref)/dt² - d²(pf_ref)/dt² = r(d²(ps_body)/dt²) - Ω ⨯ [d(ps_ref)/dt - d(pf_ref)/dt]
 -         final FieldVector3D<T> v = bodyToRef.getRotation().applyTo(slidingBody.getVelocity());
 -         final FieldVector3D<T> a = new FieldVector3D<>(+1, bodyToRef.getRotation().applyTo(slidingBody.getAcceleration()),
 -                                                        -1, FieldVector3D.crossProduct(bodyToRef.getRotationRate(), v));
 -         final FieldPVCoordinates<T> relativeVelocity = new FieldPVCoordinates<>(v, a, FieldVector3D.getZero(date.getField()));
 
-         final FieldPVCoordinates<T> relativeNormal =
 -                         relativePosition.crossProduct(relativeVelocity).normalize();
 
-         // attitude definition :
 -         //  . Z satellite axis points to sliding target
 -         //  . target relative velocity is in (Z, X) plane, in the -X half plane part
 -         return new FieldAttitude<>(frame,
 -                                    new TimeStampedFieldAngularCoordinates<>(date,
 -                                                                             relativePosition.normalize(),
 -                                                                             relativeNormal.normalize(),
 -                                                                             plusK, plusJ,
 -                                                                             1.0e-9));
 
-     }
 
-     /** Compute the yaw compensation angle at date.
 -      * @param pvProv provider for PV coordinates
 -      * @param date date at which compensation is requested
 -      * @param frame reference frame from which attitude is computed
 -      * @return yaw compensation angle for orbit.
 -      */
 -     public double getYawAngle(final PVCoordinatesProvider pvProv,
 -                               final AbsoluteDate date, final Frame frame) {
 -         final Rotation rBase        = getBaseState(pvProv, date, frame).getRotation();
 -         final Rotation rCompensated = getAttitude(pvProv, date, frame).getRotation();
 -         final Rotation compensation = rCompensated.compose(rBase.revert(), RotationConvention.VECTOR_OPERATOR);
 -         return -compensation.applyTo(Vector3D.PLUS_I).getAlpha();
 -     }
 
-     /** Compute the yaw compensation angle at date.
 -      * @param pvProv provider for PV coordinates
 -      * @param date date at which compensation is requested
 -      * @param frame reference frame from which attitude is computed
 -      * @param <T> type of the field elements
 -      * @return yaw compensation angle for orbit.
 -      * @since 9.0
 -      */
 -     public <T extends CalculusFieldElement<T>> T getYawAngle(final FieldPVCoordinatesProvider<T> pvProv,
 -                                                          final FieldAbsoluteDate<T> date,
 -                                                          final Frame frame) {
 -         final FieldRotation<T> rBase        = getBaseState(pvProv, date, frame).getRotation();
 -         final FieldRotation<T> rCompensated = getAttitude(pvProv, date, frame).getRotation();
 -         final FieldRotation<T> compensation = rCompensated.compose(rBase.revert(), RotationConvention.VECTOR_OPERATOR);
 -         return compensation.applyTo(Vector3D.PLUS_I).getAlpha().negate();
 -     }
 
- }