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.TimeStampedAngularCoordinates;

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

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

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

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

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

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

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

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

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

  70.     },

  71.     /** Quaternion and derivatives. */
  72.     QUATERNION_DERIVATIVE("QUATERNION DERIVATIVE") {

  73.         @Override
  74.         public double[] getAttitudeData(final TimeStampedAngularCoordinates coordinates,
  75.                                         final boolean isFirst, final RotationOrder order) {
  76.             // Initialize the array of attitude data
  77.             final double[] data = new double[8];

  78.             final FieldRotation<UnivariateDerivative1> fieldRotation = coordinates.toUnivariateDerivative1Rotation();
  79.             // Quaternion components
  80.             final double q0    = fieldRotation.getQ0().getValue();
  81.             final double q1    = fieldRotation.getQ1().getValue();
  82.             final double q2    = fieldRotation.getQ2().getValue();
  83.             final double q3    = fieldRotation.getQ3().getValue();
  84.             final double q0Dot = fieldRotation.getQ0().getFirstDerivative();
  85.             final double q1Dot = fieldRotation.getQ1().getFirstDerivative();
  86.             final double q2Dot = fieldRotation.getQ2().getFirstDerivative();
  87.             final double q3Dot = fieldRotation.getQ3().getFirstDerivative();

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

  90.             // Fill the array
  91.             data[quaternionIndex[0]] = q0;
  92.             data[quaternionIndex[1]] = q1;
  93.             data[quaternionIndex[2]] = q2;
  94.             data[quaternionIndex[3]] = q3;
  95.             data[quaternionIndex[4]] = q0Dot;
  96.             data[quaternionIndex[5]] = q1Dot;
  97.             data[quaternionIndex[6]] = q2Dot;
  98.             data[quaternionIndex[7]] = q3Dot;

  99.             // Return
  100.             return data;
  101.         }

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

  107.             // Quaternion components
  108.             final DSFactory factory = new DSFactory(1, 1);
  109.             final DerivativeStructure q0DS = factory.build(data[quaternionIndex[0]], data[quaternionIndex[4]]);
  110.             final DerivativeStructure q1DS = factory.build(data[quaternionIndex[1]], data[quaternionIndex[5]]);
  111.             final DerivativeStructure q2DS = factory.build(data[quaternionIndex[2]], data[quaternionIndex[6]]);
  112.             final DerivativeStructure q3DS = factory.build(data[quaternionIndex[3]], data[quaternionIndex[7]]);

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

  115.             // Return
  116.             return new TimeStampedAngularCoordinates(date, fieldRotation);
  117.         }

  118.     },

  119.     /** Quaternion and rotation rate. */
  120.     QUATERNION_RATE("QUATERNION RATE") {

  121.         @Override
  122.         public double[] getAttitudeData(final TimeStampedAngularCoordinates coordinates,
  123.                                         final boolean isFirst, final RotationOrder order) {
  124.             // Initialize the array of attitude data
  125.             final double[] data = new double[7];

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

  128.             // Attitude
  129.             final Rotation rotation     = coordinates.getRotation();
  130.             final Vector3D rotationRate = coordinates.getRotationRate();

  131.             // Fill the array
  132.             data[quaternionIndex[0]] = rotation.getQ0();
  133.             data[quaternionIndex[1]] = rotation.getQ1();
  134.             data[quaternionIndex[2]] = rotation.getQ2();
  135.             data[quaternionIndex[3]] = rotation.getQ3();
  136.             data[4] = FastMath.toDegrees(rotationRate.getX());
  137.             data[5] = FastMath.toDegrees(rotationRate.getY());
  138.             data[6] = FastMath.toDegrees(rotationRate.getZ());

  139.             // Return
  140.             return data;
  141.         }

  142.         @Override
  143.         public TimeStampedAngularCoordinates getAngularCoordinates(final AbsoluteDate date, final double[] data,
  144.                                                                    final boolean isFirst, final RotationOrder order) {
  145.             // Data index
  146.             final int[] quaternionIndex = isFirst ? new int[] {0, 1, 2, 3} : new int[] {3, 0, 1, 2};

  147.             // Quaternion components
  148.             final double q0    = data[quaternionIndex[0]];
  149.             final double q1    = data[quaternionIndex[1]];
  150.             final double q2    = data[quaternionIndex[2]];
  151.             final double q3    = data[quaternionIndex[3]];

  152.             // Rotation rate in radians
  153.             final double xRate = FastMath.toRadians(data[4]);
  154.             final double yRate = FastMath.toRadians(data[5]);
  155.             final double zRate = FastMath.toRadians(data[6]);

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

  159.             // Return
  160.             return new TimeStampedAngularCoordinates(date, rotation, rotationRate, Vector3D.ZERO);
  161.         }

  162.     },

  163.     /** Euler angles. */
  164.     EULER_ANGLE("EULER ANGLE") {

  165.         @Override
  166.         public double[] getAttitudeData(final TimeStampedAngularCoordinates coordinates,
  167.                                         final boolean isFirst, final RotationOrder order) {
  168.             // Initialize the array of attitude data
  169.             final double[] data = new double[3];

  170.             // Attitude
  171.             final Rotation rotation = coordinates.getRotation();
  172.             final double[] angles   = rotation.getAngles(order, RotationConvention.FRAME_TRANSFORM);

  173.             // Fill the array
  174.             data[0] = FastMath.toDegrees(angles[0]);
  175.             data[1] = FastMath.toDegrees(angles[1]);
  176.             data[2] = FastMath.toDegrees(angles[2]);

  177.             // Return
  178.             return data;
  179.         }

  180.         @Override
  181.         public TimeStampedAngularCoordinates getAngularCoordinates(final AbsoluteDate date, final double[] data,
  182.                                                                    final boolean isFirst, final RotationOrder order) {
  183.             // Euler angles. They are given in degrees in CCSDS AEM files
  184.             final double alpha1 = FastMath.toRadians(data[0]);
  185.             final double alpha2 = FastMath.toRadians(data[1]);
  186.             final double alpha3 = FastMath.toRadians(data[2]);

  187.             // Build the needed objects
  188.             final Rotation rotation = new Rotation(order, RotationConvention.FRAME_TRANSFORM,
  189.                                                    alpha1, alpha2, alpha3);
  190.             // Return
  191.             return new TimeStampedAngularCoordinates(date, rotation, Vector3D.ZERO, Vector3D.ZERO);
  192.         }

  193.     },

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

  196.         @Override
  197.         public double[] getAttitudeData(final TimeStampedAngularCoordinates coordinates,
  198.                                         final boolean isFirst, final RotationOrder order) {
  199.             // Initialize the array of attitude data
  200.             final double[] data = new double[6];

  201.             // Attitude
  202.             final Rotation rotation     = coordinates.getRotation();
  203.             final Vector3D rotationRate = coordinates.getRotationRate();
  204.             final double[] angles       = rotation.getAngles(order, RotationConvention.FRAME_TRANSFORM);

  205.             // Fill the array
  206.             data[0] = FastMath.toDegrees(angles[0]);
  207.             data[1] = FastMath.toDegrees(angles[1]);
  208.             data[2] = FastMath.toDegrees(angles[2]);
  209.             data[3] = FastMath.toDegrees(rotationRate.getX());
  210.             data[4] = FastMath.toDegrees(rotationRate.getY());
  211.             data[5] = FastMath.toDegrees(rotationRate.getZ());

  212.             // Return
  213.             return data;
  214.         }

  215.         @Override
  216.         public TimeStampedAngularCoordinates getAngularCoordinates(final AbsoluteDate date, final double[] data,
  217.                                                                    final boolean isFirst, final RotationOrder order) {
  218.             // Euler angles
  219.             final double alpha1 = FastMath.toRadians(data[0]);
  220.             final double alpha2 = FastMath.toRadians(data[1]);
  221.             final double alpha3 = FastMath.toRadians(data[2]);
  222.             // Rotation rate
  223.             final double xRate = FastMath.toRadians(data[3]);
  224.             final double yRate = FastMath.toRadians(data[4]);
  225.             final double zRate = FastMath.toRadians(data[5]);

  226.             // Build the needed objects
  227.             final Rotation rotation     = new Rotation(order, RotationConvention.FRAME_TRANSFORM,
  228.                                                    alpha1, alpha2, alpha3);
  229.             final Vector3D rotationRate = new Vector3D(xRate, yRate, zRate);
  230.             // Return
  231.             return new TimeStampedAngularCoordinates(date, rotation, rotationRate, Vector3D.ZERO);
  232.         }

  233.     },

  234.     /** Spin. */
  235.     SPIN("SPIN") {

  236.         @Override
  237.         public double[] getAttitudeData(final TimeStampedAngularCoordinates coordinates,
  238.                                         final boolean isFirst, final RotationOrder order) {
  239.             // Attitude parameters in the Specified Reference Frame for a Spin Stabilized Satellite
  240.             // are optional in CCSDS AEM format. Support for this attitude type is not implemented
  241.             // yet in Orekit.
  242.             throw new OrekitException(OrekitMessages.CCSDS_AEM_ATTITUDE_TYPE_NOT_IMPLEMENTED, getName());
  243.         }

  244.         @Override
  245.         public TimeStampedAngularCoordinates getAngularCoordinates(final AbsoluteDate date, final double[] data,
  246.                                                                    final boolean isFirst, final RotationOrder order) {
  247.             // Attitude parameters in the Specified Reference Frame for a Spin Stabilized Satellite
  248.             // are optional in CCSDS AEM format. Support for this attitude type is not implemented
  249.             // yet in Orekit.
  250.             throw new OrekitException(OrekitMessages.CCSDS_AEM_ATTITUDE_TYPE_NOT_IMPLEMENTED, getName());
  251.         }

  252.     },

  253.     /** Spin and nutation. */
  254.     SPIN_NUTATION("SPIN NUTATION") {

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

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

  271.     };

  272.     /** Codes map. */
  273.     private static final Map<String, AEMAttitudeType> CODES_MAP = new HashMap<String, AEMAttitudeType>();
  274.     static {
  275.         for (final AEMAttitudeType type : values()) {
  276.             CODES_MAP.put(type.getName(), type);
  277.         }
  278.     }

  279.     /** Name of the attitude type. */
  280.     private final String name;

  281.     /**
  282.      * Constructor.
  283.      * @param name name of the attitude type
  284.      */
  285.     AEMAttitudeType(final String name) {
  286.         this.name = name;
  287.     }

  288.     /**
  289.      * Get the name of the attitude type.
  290.      * @return name
  291.      */
  292.     public String getName() {
  293.         return name;
  294.     }

  295.     /**
  296.      * Get the attitude type corresponding to the given name.
  297.      * @param name given name
  298.      * @return attitude type
  299.      */
  300.     public static AEMAttitudeType getAttitudeType(final String name) {
  301.         final AEMAttitudeType type = CODES_MAP.get(name);
  302.         if (type == null) {
  303.             // An exception is thrown if the attitude type is null
  304.             throw new OrekitException(OrekitMessages.CCSDS_AEM_NULL_ATTITUDE_TYPE, name);
  305.         }
  306.         return type;
  307.     }

  308.     /**
  309.      * Get the attitude data corresponding to the attitude type.
  310.      * <p>
  311.      * Note that, according to the CCSDS ADM documentation, angles values
  312.      * are given in degrees.
  313.      * </p>
  314.      * @param attitude angular coordinates
  315.      * @param isFirst true if QC is the first element in the attitude data
  316.      * @param order rotation order of the Euler angles
  317.      * @return the attitude data (see 4-4)
  318.      */
  319.     public abstract double[] getAttitudeData(TimeStampedAngularCoordinates attitude, boolean isFirst,
  320.                                              RotationOrder order);

  321.     /**
  322.      * Get the angular coordinates corresponding to the attitude data.
  323.      * <p>
  324.      * Note that, according to the CCSDS ADM documentation, angles values
  325.      * must be given in degrees.
  326.      * </p>
  327.      * @param date coordinates date
  328.      * @param attitudeData attitude data
  329.      * @param isFirst true if QC is the first element in the attitude data
  330.      * @param order rotation order of the Euler angles
  331.      * @return the angular coordinates
  332.      */
  333.     public abstract TimeStampedAngularCoordinates getAngularCoordinates(AbsoluteDate date, double[] attitudeData,
  334.                                                                         boolean isFirst, RotationOrder order);

  335. }