AEMAttitudeType.java

  1. /* Copyright 2002-2020 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.files.ccsds;

  18. import java.util.HashMap;
  19. import java.util.Map;

  20. import org.hipparchus.analysis.differentiation.DSFactory;
  21. import org.hipparchus.analysis.differentiation.DerivativeStructure;
  22. import org.hipparchus.analysis.differentiation.UnivariateDerivative1;
  23. import org.hipparchus.geometry.euclidean.threed.FieldRotation;
  24. import org.hipparchus.geometry.euclidean.threed.Rotation;
  25. import org.hipparchus.geometry.euclidean.threed.RotationConvention;
  26. import org.hipparchus.geometry.euclidean.threed.RotationOrder;
  27. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  28. import org.hipparchus.util.FastMath;
  29. import org.orekit.errors.OrekitException;
  30. import org.orekit.errors.OrekitMessages;
  31. import org.orekit.time.AbsoluteDate;
  32. import org.orekit.utils.AngularDerivativesFilter;
  33. import org.orekit.utils.TimeStampedAngularCoordinates;

  34. /** Enumerate for AEM attitude type.
  35.  * @author Bryan Cazabonne
  36.  * @since 10.2
  37.  */
  38. public enum AEMAttitudeType {

  39.     /** Quaternion. */
  40.     QUATERNION("QUATERNION") {

  41.         @Override
  42.         public double[] getAttitudeData(final TimeStampedAngularCoordinates coordinates,
  43.                                         final boolean isFirst, final RotationOrder order) {
  44.             // Initialize the array of attitude data
  45.             final double[] data = new double[4];

  46.             // Data index
  47.             final int[] quaternionIndex = isFirst ? new int[] {0, 1, 2, 3} : new int[] {3, 0, 1, 2};

  48.             // Fill the array
  49.             final Rotation rotation  = coordinates.getRotation();
  50.             data[quaternionIndex[0]] = rotation.getQ0();
  51.             data[quaternionIndex[1]] = rotation.getQ1();
  52.             data[quaternionIndex[2]] = rotation.getQ2();
  53.             data[quaternionIndex[3]] = rotation.getQ3();

  54.             // Return
  55.             return data;
  56.         }

  57.         @Override
  58.         public TimeStampedAngularCoordinates getAngularCoordinates(final AbsoluteDate date, final double[] data,
  59.                                                                    final boolean isFirst, final RotationOrder order) {
  60.             // Data index
  61.             final int[] quaternionIndex = isFirst ? new int[] {0, 1, 2, 3} : new int[] {3, 0, 1, 2};

  62.             // Build the needed objects
  63.             final Rotation rotation = new Rotation(data[quaternionIndex[0]],
  64.                                                    data[quaternionIndex[1]],
  65.                                                    data[quaternionIndex[2]],
  66.                                                    data[quaternionIndex[3]],
  67.                                                    false);

  68.             // Return
  69.             return new TimeStampedAngularCoordinates(date, rotation, Vector3D.ZERO, Vector3D.ZERO);
  70.         }

  71.         @Override
  72.         public AngularDerivativesFilter getAngularDerivativesFilter() {
  73.             return AngularDerivativesFilter.USE_R;
  74.         }

  75.     },

  76.     /** Quaternion and derivatives. */
  77.     QUATERNION_DERIVATIVE("QUATERNION DERIVATIVE") {

  78.         @Override
  79.         public double[] getAttitudeData(final TimeStampedAngularCoordinates coordinates,
  80.                                         final boolean isFirst, final RotationOrder order) {
  81.             // Initialize the array of attitude data
  82.             final double[] data = new double[8];

  83.             final FieldRotation<UnivariateDerivative1> fieldRotation = coordinates.toUnivariateDerivative1Rotation();
  84.             // Quaternion components
  85.             final double q0    = fieldRotation.getQ0().getValue();
  86.             final double q1    = fieldRotation.getQ1().getValue();
  87.             final double q2    = fieldRotation.getQ2().getValue();
  88.             final double q3    = fieldRotation.getQ3().getValue();
  89.             final double q0Dot = fieldRotation.getQ0().getFirstDerivative();
  90.             final double q1Dot = fieldRotation.getQ1().getFirstDerivative();
  91.             final double q2Dot = fieldRotation.getQ2().getFirstDerivative();
  92.             final double q3Dot = fieldRotation.getQ3().getFirstDerivative();

  93.             // Data index
  94.             final int[] quaternionIndex = isFirst ? new int[] {0, 1, 2, 3, 4, 5, 6, 7} : new int[] {3, 0, 1, 2, 7, 4, 5, 6};

  95.             // Fill the array
  96.             data[quaternionIndex[0]] = q0;
  97.             data[quaternionIndex[1]] = q1;
  98.             data[quaternionIndex[2]] = q2;
  99.             data[quaternionIndex[3]] = q3;
  100.             data[quaternionIndex[4]] = q0Dot;
  101.             data[quaternionIndex[5]] = q1Dot;
  102.             data[quaternionIndex[6]] = q2Dot;
  103.             data[quaternionIndex[7]] = q3Dot;

  104.             // Return
  105.             return data;
  106.         }

  107.         @Override
  108.         public TimeStampedAngularCoordinates getAngularCoordinates(final AbsoluteDate date, final double[] data,
  109.                                                                    final boolean isFirst, final RotationOrder order) {
  110.             // Data index
  111.             final int[] quaternionIndex = isFirst ? new int[] {0, 1, 2, 3, 4, 5, 6, 7} : new int[] {3, 0, 1, 2, 7, 4, 5, 6};

  112.             // Quaternion components
  113.             final DSFactory factory = new DSFactory(1, 1);
  114.             final DerivativeStructure q0DS = factory.build(data[quaternionIndex[0]], data[quaternionIndex[4]]);
  115.             final DerivativeStructure q1DS = factory.build(data[quaternionIndex[1]], data[quaternionIndex[5]]);
  116.             final DerivativeStructure q2DS = factory.build(data[quaternionIndex[2]], data[quaternionIndex[6]]);
  117.             final DerivativeStructure q3DS = factory.build(data[quaternionIndex[3]], data[quaternionIndex[7]]);

  118.             // Rotation
  119.             final FieldRotation<DerivativeStructure> fieldRotation = new FieldRotation<>(q0DS, q1DS, q2DS, q3DS, false);

  120.             // Return
  121.             return new TimeStampedAngularCoordinates(date, fieldRotation);
  122.         }

  123.         @Override
  124.         public AngularDerivativesFilter getAngularDerivativesFilter() {
  125.             return AngularDerivativesFilter.USE_RR;
  126.         }

  127.     },

  128.     /** Quaternion and rotation rate. */
  129.     QUATERNION_RATE("QUATERNION RATE") {

  130.         @Override
  131.         public double[] getAttitudeData(final TimeStampedAngularCoordinates coordinates,
  132.                                         final boolean isFirst, final RotationOrder order) {
  133.             // Initialize the array of attitude data
  134.             final double[] data = new double[7];

  135.             // Data index
  136.             final int[] quaternionIndex = isFirst ? new int[] {0, 1, 2, 3} : new int[] {3, 0, 1, 2};

  137.             // Attitude
  138.             final Rotation rotation     = coordinates.getRotation();
  139.             final Vector3D rotationRate = coordinates.getRotationRate();

  140.             // Fill the array
  141.             data[quaternionIndex[0]] = rotation.getQ0();
  142.             data[quaternionIndex[1]] = rotation.getQ1();
  143.             data[quaternionIndex[2]] = rotation.getQ2();
  144.             data[quaternionIndex[3]] = rotation.getQ3();
  145.             data[4] = FastMath.toDegrees(rotationRate.getX());
  146.             data[5] = FastMath.toDegrees(rotationRate.getY());
  147.             data[6] = FastMath.toDegrees(rotationRate.getZ());

  148.             // Return
  149.             return data;
  150.         }

  151.         @Override
  152.         public TimeStampedAngularCoordinates getAngularCoordinates(final AbsoluteDate date, final double[] data,
  153.                                                                    final boolean isFirst, final RotationOrder order) {
  154.             // Data index
  155.             final int[] quaternionIndex = isFirst ? new int[] {0, 1, 2, 3} : new int[] {3, 0, 1, 2};

  156.             // Quaternion components
  157.             final double q0    = data[quaternionIndex[0]];
  158.             final double q1    = data[quaternionIndex[1]];
  159.             final double q2    = data[quaternionIndex[2]];
  160.             final double q3    = data[quaternionIndex[3]];

  161.             // Rotation rate in radians
  162.             final double xRate = FastMath.toRadians(data[4]);
  163.             final double yRate = FastMath.toRadians(data[5]);
  164.             final double zRate = FastMath.toRadians(data[6]);

  165.             // Build the needed objects
  166.             final Rotation rotation     = new Rotation(q0, q1, q2, q3, false);
  167.             final Vector3D rotationRate = new Vector3D(xRate, yRate, zRate);

  168.             // Return
  169.             return new TimeStampedAngularCoordinates(date, rotation, rotationRate, Vector3D.ZERO);
  170.         }

  171.         @Override
  172.         public AngularDerivativesFilter getAngularDerivativesFilter() {
  173.             return AngularDerivativesFilter.USE_RR;
  174.         }

  175.     },

  176.     /** Euler angles. */
  177.     EULER_ANGLE("EULER ANGLE") {

  178.         @Override
  179.         public double[] getAttitudeData(final TimeStampedAngularCoordinates coordinates,
  180.                                         final boolean isFirst, final RotationOrder order) {
  181.             // Initialize the array of attitude data
  182.             final double[] data = new double[3];

  183.             // Attitude
  184.             final Rotation rotation = coordinates.getRotation();
  185.             final double[] angles   = rotation.getAngles(order, RotationConvention.FRAME_TRANSFORM);

  186.             // Fill the array
  187.             data[0] = FastMath.toDegrees(angles[0]);
  188.             data[1] = FastMath.toDegrees(angles[1]);
  189.             data[2] = FastMath.toDegrees(angles[2]);

  190.             // Return
  191.             return data;
  192.         }

  193.         @Override
  194.         public TimeStampedAngularCoordinates getAngularCoordinates(final AbsoluteDate date, final double[] data,
  195.                                                                    final boolean isFirst, final RotationOrder order) {
  196.             // Euler angles. They are given in degrees in CCSDS AEM files
  197.             final double alpha1 = FastMath.toRadians(data[0]);
  198.             final double alpha2 = FastMath.toRadians(data[1]);
  199.             final double alpha3 = FastMath.toRadians(data[2]);

  200.             // Build the needed objects
  201.             final Rotation rotation = new Rotation(order, RotationConvention.FRAME_TRANSFORM,
  202.                                                    alpha1, alpha2, alpha3);
  203.             // Return
  204.             return new TimeStampedAngularCoordinates(date, rotation, Vector3D.ZERO, Vector3D.ZERO);
  205.         }

  206.         @Override
  207.         public AngularDerivativesFilter getAngularDerivativesFilter() {
  208.             return AngularDerivativesFilter.USE_R;
  209.         }

  210.     },

  211.     /** Euler angles and rotation rate. */
  212.     EULER_ANGLE_RATE("EULER ANGLE RATE") {

  213.         @Override
  214.         public double[] getAttitudeData(final TimeStampedAngularCoordinates coordinates,
  215.                                         final boolean isFirst, final RotationOrder order) {
  216.             // Initialize the array of attitude data
  217.             final double[] data = new double[6];

  218.             // Attitude
  219.             final Rotation rotation     = coordinates.getRotation();
  220.             final Vector3D rotationRate = coordinates.getRotationRate();
  221.             final double[] angles       = rotation.getAngles(order, RotationConvention.FRAME_TRANSFORM);

  222.             // Fill the array
  223.             data[0] = FastMath.toDegrees(angles[0]);
  224.             data[1] = FastMath.toDegrees(angles[1]);
  225.             data[2] = FastMath.toDegrees(angles[2]);
  226.             data[3] = FastMath.toDegrees(rotationRate.getX());
  227.             data[4] = FastMath.toDegrees(rotationRate.getY());
  228.             data[5] = FastMath.toDegrees(rotationRate.getZ());

  229.             // Return
  230.             return data;
  231.         }

  232.         @Override
  233.         public TimeStampedAngularCoordinates getAngularCoordinates(final AbsoluteDate date, final double[] data,
  234.                                                                    final boolean isFirst, final RotationOrder order) {
  235.             // Euler angles
  236.             final double alpha1 = FastMath.toRadians(data[0]);
  237.             final double alpha2 = FastMath.toRadians(data[1]);
  238.             final double alpha3 = FastMath.toRadians(data[2]);
  239.             // Rotation rate
  240.             final double xRate = FastMath.toRadians(data[3]);
  241.             final double yRate = FastMath.toRadians(data[4]);
  242.             final double zRate = FastMath.toRadians(data[5]);

  243.             // Build the needed objects
  244.             final Rotation rotation     = new Rotation(order, RotationConvention.FRAME_TRANSFORM,
  245.                                                    alpha1, alpha2, alpha3);
  246.             final Vector3D rotationRate = new Vector3D(xRate, yRate, zRate);
  247.             // Return
  248.             return new TimeStampedAngularCoordinates(date, rotation, rotationRate, Vector3D.ZERO);
  249.         }

  250.         @Override
  251.         public AngularDerivativesFilter getAngularDerivativesFilter() {
  252.             return AngularDerivativesFilter.USE_RR;
  253.         }

  254.     },

  255.     /** Spin. */
  256.     SPIN("SPIN") {

  257.         @Override
  258.         public double[] getAttitudeData(final TimeStampedAngularCoordinates coordinates,
  259.                                         final boolean isFirst, final RotationOrder order) {
  260.             // Attitude parameters in the Specified Reference Frame for a Spin Stabilized Satellite
  261.             // are optional in CCSDS AEM format. Support for this attitude type is not implemented
  262.             // yet in Orekit.
  263.             throw new OrekitException(OrekitMessages.CCSDS_AEM_ATTITUDE_TYPE_NOT_IMPLEMENTED, getName());
  264.         }

  265.         @Override
  266.         public TimeStampedAngularCoordinates getAngularCoordinates(final AbsoluteDate date, final double[] data,
  267.                                                                    final boolean isFirst, final RotationOrder order) {
  268.             // Attitude parameters in the Specified Reference Frame for a Spin Stabilized Satellite
  269.             // are optional in CCSDS AEM format. Support for this attitude type is not implemented
  270.             // yet in Orekit.
  271.             throw new OrekitException(OrekitMessages.CCSDS_AEM_ATTITUDE_TYPE_NOT_IMPLEMENTED, getName());
  272.         }

  273.         @Override
  274.         public AngularDerivativesFilter getAngularDerivativesFilter() {
  275.             // Attitude parameters in the Specified Reference Frame for a Spin Stabilized Satellite
  276.             // are optional in CCSDS AEM format. Support for this attitude type is not implemented
  277.             // yet in Orekit.
  278.             throw new OrekitException(OrekitMessages.CCSDS_AEM_ATTITUDE_TYPE_NOT_IMPLEMENTED, getName());
  279.         }

  280.     },

  281.     /** Spin and nutation. */
  282.     SPIN_NUTATION("SPIN NUTATION") {

  283.         @Override
  284.         public double[] getAttitudeData(final TimeStampedAngularCoordinates coordinates,
  285.                                         final boolean isFirst, final RotationOrder order) {
  286.             // Attitude parameters in the Specified Reference Frame for a Spin Stabilized Satellite
  287.             // are optional in CCSDS AEM format. Support for this attitude type is not implemented
  288.             // yet in Orekit.
  289.             throw new OrekitException(OrekitMessages.CCSDS_AEM_ATTITUDE_TYPE_NOT_IMPLEMENTED, getName());
  290.         }

  291.         @Override
  292.         public TimeStampedAngularCoordinates getAngularCoordinates(final AbsoluteDate date, final double[] data,
  293.                                                                    final boolean isFirst, final RotationOrder order) {
  294.             // Attitude parameters in the Specified Reference Frame for a Spin Stabilized Satellite
  295.             // are optional in CCSDS AEM format. Support for this attitude type is not implemented
  296.             // yet in Orekit.
  297.             throw new OrekitException(OrekitMessages.CCSDS_AEM_ATTITUDE_TYPE_NOT_IMPLEMENTED, getName());
  298.         }

  299.         @Override
  300.         public AngularDerivativesFilter getAngularDerivativesFilter() {
  301.             // Attitude parameters in the Specified Reference Frame for a Spin Stabilized Satellite
  302.             // are optional in CCSDS AEM format. Support for this attitude type is not implemented
  303.             // yet in Orekit.
  304.             throw new OrekitException(OrekitMessages.CCSDS_AEM_ATTITUDE_TYPE_NOT_IMPLEMENTED, getName());
  305.         }

  306.     };

  307.     /** Codes map. */
  308.     private static final Map<String, AEMAttitudeType> CODES_MAP = new HashMap<String, AEMAttitudeType>();
  309.     static {
  310.         for (final AEMAttitudeType type : values()) {
  311.             CODES_MAP.put(type.getName(), type);
  312.         }
  313.     }

  314.     /** Name of the attitude type. */
  315.     private final String name;

  316.     /**
  317.      * Constructor.
  318.      * @param name name of the attitude type
  319.      */
  320.     AEMAttitudeType(final String name) {
  321.         this.name = name;
  322.     }

  323.     /**
  324.      * Get the name of the attitude type.
  325.      * @return name
  326.      */
  327.     public String getName() {
  328.         return name;
  329.     }

  330.     /**
  331.      * Get the attitude type corresponding to the given name.
  332.      * @param name given name
  333.      * @return attitude type
  334.      */
  335.     public static AEMAttitudeType getAttitudeType(final String name) {
  336.         final AEMAttitudeType type = CODES_MAP.get(name);
  337.         if (type == null) {
  338.             // An exception is thrown if the attitude type is null
  339.             throw new OrekitException(OrekitMessages.CCSDS_AEM_NULL_ATTITUDE_TYPE, name);
  340.         }
  341.         return type;
  342.     }

  343.     /**
  344.      * Get the attitude data corresponding to the attitude type.
  345.      * <p>
  346.      * Note that, according to the CCSDS ADM documentation, angles values
  347.      * are given in degrees.
  348.      * </p>
  349.      * @param attitude angular coordinates
  350.      * @param isFirst true if QC is the first element in the attitude data
  351.      * @param order rotation order of the Euler angles
  352.      * @return the attitude data (see 4-4)
  353.      */
  354.     public abstract double[] getAttitudeData(TimeStampedAngularCoordinates attitude, boolean isFirst,
  355.                                              RotationOrder order);

  356.     /**
  357.      * Get the angular coordinates corresponding to the attitude data.
  358.      * <p>
  359.      * Note that, according to the CCSDS ADM documentation, angles values
  360.      * must be given in degrees.
  361.      * </p>
  362.      * @param date coordinates date
  363.      * @param attitudeData attitude data
  364.      * @param isFirst true if QC is the first element in the attitude data
  365.      * @param order rotation order of the Euler angles
  366.      * @return the angular coordinates
  367.      */
  368.     public abstract TimeStampedAngularCoordinates getAngularCoordinates(AbsoluteDate date, double[] attitudeData,
  369.                                                                         boolean isFirst, RotationOrder order);

  370.     /**
  371.      * Get the angular derivative filter corresponding to the attitude data.
  372.      * @return the angular derivative filter corresponding to the attitude data
  373.      */
  374.     public abstract AngularDerivativesFilter getAngularDerivativesFilter();

  375. }