YawSteering.java

  1. /* Copyright 2002-2024 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.FieldPVCoordinates;
  26. import org.orekit.utils.FieldPVCoordinatesProvider;
  27. import org.orekit.utils.PVCoordinates;
  28. import org.orekit.utils.PVCoordinatesProvider;
  29. import org.orekit.utils.TimeStampedAngularCoordinates;
  30. import org.orekit.utils.TimeStampedFieldAngularCoordinates;
  31. import org.orekit.utils.TimeStampedFieldPVCoordinates;
  32. import org.orekit.utils.TimeStampedPVCoordinates;


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

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

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

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

  73.     /** Sun motion model. */
  74.     private final PVCoordinatesProvider sun;

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

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

  96.     /** Get the underlying (ground pointing) attitude provider.
  97.      * @return underlying attitude provider, which in this case is a {@link GroundPointing} instance
  98.      */
  99.     public AttitudeProvider getUnderlyingAttitudeProvider() {
  100.         return groundPointingLaw;
  101.     }

  102.     /** {@inheritDoc} */
  103.     public TimeStampedPVCoordinates getTargetPV(final PVCoordinatesProvider pvProv,
  104.                                                 final AbsoluteDate date, final Frame frame) {
  105.         return groundPointingLaw.getTargetPV(pvProv, date, frame);
  106.     }

  107.     /** {@inheritDoc} */
  108.     public <T extends CalculusFieldElement<T>> TimeStampedFieldPVCoordinates<T> getTargetPV(final FieldPVCoordinatesProvider<T> pvProv,
  109.                                                                                         final FieldAbsoluteDate<T> date,
  110.                                                                                         final Frame frame) {
  111.         return groundPointingLaw.getTargetPV(pvProv, date, frame);
  112.     }

  113.     /** Compute the base system state at given date, without compensation.
  114.      * @param pvProv provider for PV coordinates
  115.      * @param date date at which state is requested
  116.      * @param frame reference frame from which attitude is computed
  117.      * @return satellite base attitude state, i.e without compensation.
  118.      */
  119.     public Attitude getBaseState(final PVCoordinatesProvider pvProv,
  120.                                  final AbsoluteDate date, final Frame frame) {
  121.         return groundPointingLaw.getAttitude(pvProv, date, frame);
  122.     }

  123.     /** Compute the base system state at given date, without compensation.
  124.      * @param pvProv provider for PV coordinates
  125.      * @param date date at which state is requested
  126.      * @param frame reference frame from which attitude is computed
  127.      * @param <T> type of the field elements
  128.      * @return satellite base attitude state, i.e without compensation.
  129.      * @since 9.0
  130.      */
  131.     public <T extends CalculusFieldElement<T>> FieldAttitude<T> getBaseState(final FieldPVCoordinatesProvider<T> pvProv,
  132.                                                                          final FieldAbsoluteDate<T> date, final Frame frame) {
  133.         return groundPointingLaw.getAttitude(pvProv, date, frame);
  134.     }

  135.     /** {@inheritDoc} */
  136.     @Override
  137.     public Attitude getAttitude(final PVCoordinatesProvider pvProv,
  138.                                 final AbsoluteDate date, final Frame frame) {

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

  141.         // Compensation rotation definition :
  142.         //  . Z satellite axis is unchanged
  143.         //  . phasing axis shall be aligned to sun direction
  144.         final PVCoordinates sunDirection = new PVCoordinates(pvProv.getPVCoordinates(date, frame),
  145.                                                              sun.getPVCoordinates(date, frame));
  146.         final PVCoordinates sunNormal =
  147.                 PVCoordinates.crossProduct(PLUS_Z, base.getOrientation().applyTo(sunDirection));
  148.         final TimeStampedAngularCoordinates compensation =
  149.                 new TimeStampedAngularCoordinates(date,
  150.                                                   PLUS_Z, sunNormal.normalize(),
  151.                                                   PLUS_Z, phasingNormal,
  152.                                                   1.0e-9);

  153.         // add compensation
  154.         return new Attitude(frame, compensation.addOffset(base.getOrientation()));

  155.     }

  156.     /** {@inheritDoc} */
  157.     @Override
  158.     public <T extends CalculusFieldElement<T>> FieldAttitude<T> getAttitude(final FieldPVCoordinatesProvider<T> pvProv,
  159.                                                                         final FieldAbsoluteDate<T> date, final Frame frame) {

  160.         final Field<T>              field = date.getField();
  161.         final FieldVector3D<T>      zero  = FieldVector3D.getZero(field);
  162.         final FieldPVCoordinates<T> plusZ = new FieldPVCoordinates<>(FieldVector3D.getPlusK(field), zero, zero);

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

  165.         // Compensation rotation definition :
  166.         //  . Z satellite axis is unchanged
  167.         //  . phasing axis shall be aligned to sun direction
  168.         final FieldPVCoordinates<T> sunDirection =
  169.                         new FieldPVCoordinates<>(pvProv.getPVCoordinates(date, frame),
  170.                                                  new FieldPVCoordinates<>(field,
  171.                                                                           sun.getPVCoordinates(date.toAbsoluteDate(), frame)));
  172.         final FieldPVCoordinates<T> sunNormal =
  173.                 plusZ.crossProduct(base.getOrientation().applyTo(sunDirection));
  174.         final TimeStampedFieldAngularCoordinates<T> compensation =
  175.                 new TimeStampedFieldAngularCoordinates<>(date,
  176.                                                          plusZ, sunNormal.normalize(),
  177.                                                          plusZ, new FieldPVCoordinates<>(field, phasingNormal),
  178.                                                          1.0e-9);

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

  181.     }

  182. }