YawSteering.java

  1. /* Copyright 2002-2025 CS GROUP
  2.  * Licensed to CS GROUP (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.CalculusFieldElement;
  20. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  21. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  22. import org.orekit.frames.Frame;
  23. import org.orekit.time.AbsoluteDate;
  24. import org.orekit.time.FieldAbsoluteDate;
  25. import org.orekit.utils.ExtendedPositionProvider;
  26. import org.orekit.utils.FieldPVCoordinates;
  27. import org.orekit.utils.FieldPVCoordinatesProvider;
  28. import org.orekit.utils.PVCoordinates;
  29. import org.orekit.utils.PVCoordinatesProvider;
  30. import org.orekit.utils.TimeStampedAngularCoordinates;
  31. import org.orekit.utils.TimeStampedFieldAngularCoordinates;


  32. /**
  33.  * This class handles yaw steering law.

  34.  * <p>
  35.  * Yaw steering is mainly used for low Earth orbiting satellites with no
  36.  * missions-related constraints on yaw angle. It sets the yaw angle in
  37.  * such a way the solar arrays have maximal lighting without changing the
  38.  * roll and pitch.
  39.  * </p>
  40.  * <p>
  41.  * The motion in yaw is smooth when the Sun is far from the orbital plane,
  42.  * but gets more and more <i>square like</i> as the Sun gets closer to the
  43.  * orbital plane. The degenerate extreme case with the Sun in the orbital
  44.  * plane leads to a yaw angle switching between two steady states, with
  45.  * instantaneous π radians rotations at each switch, two times per orbit.
  46.  * This degenerate case is clearly not operationally sound so another pointing
  47.  * mode is chosen when Sun comes closer than some predefined threshold to the
  48.  * orbital plane.
  49.  * </p>
  50.  * <p>
  51.  * This class can handle (for now) only a theoretically perfect yaw steering
  52.  * (i.e. the yaw angle is exactly the optimal angle). Smoothed yaw steering with a
  53.  * few sine waves approaching the optimal angle will be added in the future if
  54.  * needed.
  55.  * </p>
  56.  * <p>
  57.  * This attitude is implemented as a wrapper on top of an underlying ground
  58.  * pointing law that defines the roll and pitch angles.
  59.  * </p>
  60.  * <p>
  61.  * Instances of this class are guaranteed to be immutable.
  62.  * </p>
  63.  * @see    GroundPointing
  64.  * @author Luc Maisonobe
  65.  */
  66. public class YawSteering extends GroundPointingAttitudeModifier implements AttitudeProviderModifier {

  67.     /** Pointing axis. */
  68.     private static final PVCoordinates PLUS_Z =
  69.             new PVCoordinates(Vector3D.PLUS_K, Vector3D.ZERO, Vector3D.ZERO);

  70.     /** Sun motion model. */
  71.     private final ExtendedPositionProvider sun;

  72.     /** Normal to the plane where the Sun must remain. */
  73.     private final PVCoordinates phasingNormal;

  74.     /** Creates a new instance.
  75.      * @param inertialFrame frame in which orbital velocities are computed
  76.      * @param groundPointingLaw ground pointing attitude provider without yaw compensation
  77.      * @param sun sun motion model
  78.      * @param phasingAxis satellite axis that must be roughly in Sun direction
  79.      * (if solar arrays rotation axis is Y, then this axis should be either +X or -X)
  80.      * @since 7.1
  81.      */
  82.     public YawSteering(final Frame inertialFrame,
  83.                        final GroundPointing groundPointingLaw,
  84.                        final ExtendedPositionProvider sun,
  85.                        final Vector3D phasingAxis) {
  86.         super(inertialFrame, groundPointingLaw.getBodyFrame(), groundPointingLaw);
  87.         this.sun = sun;
  88.         this.phasingNormal = new PVCoordinates(Vector3D.crossProduct(Vector3D.PLUS_K, phasingAxis).normalize(),
  89.                                                Vector3D.ZERO,
  90.                                                Vector3D.ZERO);
  91.     }

  92.     /** {@inheritDoc} */
  93.     @Override
  94.     public Attitude getAttitude(final PVCoordinatesProvider pvProv,
  95.                                 final AbsoluteDate date, final Frame frame) {

  96.         // attitude from base attitude provider
  97.         final Attitude base = getBaseState(pvProv, date, frame);

  98.         // Compensation rotation definition :
  99.         //  . Z satellite axis is unchanged
  100.         //  . phasing axis shall be aligned to sun direction
  101.         final PVCoordinates sunDirection = new PVCoordinates(pvProv.getPVCoordinates(date, frame),
  102.                                                              sun.getPVCoordinates(date, frame));
  103.         final PVCoordinates sunNormal =
  104.                 PVCoordinates.crossProduct(PLUS_Z, base.getOrientation().applyTo(sunDirection));
  105.         final TimeStampedAngularCoordinates compensation =
  106.                 new TimeStampedAngularCoordinates(date,
  107.                                                   PLUS_Z, sunNormal.normalize(),
  108.                                                   PLUS_Z, phasingNormal,
  109.                                                   1.0e-9);

  110.         // add compensation
  111.         return new Attitude(frame, compensation.addOffset(base.getOrientation()));

  112.     }

  113.     /** {@inheritDoc} */
  114.     @Override
  115.     public <T extends CalculusFieldElement<T>> FieldAttitude<T> getAttitude(final FieldPVCoordinatesProvider<T> pvProv,
  116.                                                                             final FieldAbsoluteDate<T> date,
  117.                                                                             final Frame frame) {

  118.         final Field<T>              field = date.getField();
  119.         final FieldVector3D<T>      zero  = FieldVector3D.getZero(field);
  120.         final FieldPVCoordinates<T> plusZ = new FieldPVCoordinates<>(FieldVector3D.getPlusK(field), zero, zero);

  121.         // attitude from base attitude provider
  122.         final FieldAttitude<T> base = getBaseState(pvProv, date, frame);

  123.         // Compensation rotation definition :
  124.         //  . Z satellite axis is unchanged
  125.         //  . phasing axis shall be aligned to sun direction
  126.         final FieldPVCoordinates<T> sunDirection =
  127.                         new FieldPVCoordinates<>(pvProv.getPVCoordinates(date, frame),
  128.                                                  sun.getPVCoordinates(date, frame));
  129.         final FieldPVCoordinates<T> sunNormal =
  130.                 plusZ.crossProduct(base.getOrientation().applyTo(sunDirection));
  131.         final TimeStampedFieldAngularCoordinates<T> compensation =
  132.                 new TimeStampedFieldAngularCoordinates<>(date,
  133.                                                          plusZ, sunNormal.normalize(),
  134.                                                          plusZ, new FieldPVCoordinates<>(field, phasingNormal),
  135.                                                          1.0e-9);

  136.         // add compensation
  137.         return new FieldAttitude<>(frame, compensation.addOffset(base.getOrientation()));

  138.     }

  139. }