AttitudeDetermination.java

  1. /* Copyright 2022-2025 Luc Maisonobe
  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.ndm.adm.acm;

  18. import java.util.ArrayList;
  19. import java.util.Collections;
  20. import java.util.List;

  21. import org.hipparchus.geometry.euclidean.threed.RotationOrder;
  22. import org.orekit.errors.OrekitException;
  23. import org.orekit.errors.OrekitMessages;
  24. import org.orekit.files.ccsds.definitions.AdMethodType;
  25. import org.orekit.files.ccsds.ndm.adm.AttitudeEndpoints;
  26. import org.orekit.files.ccsds.section.CommentsContainer;

  27. /** Attitude determination data.
  28.  * <p>
  29.  * Beware that the Orekit getters and setters all rely on SI units. The parsers
  30.  * and writers take care of converting these SI units into CCSDS mandatory units.
  31.  * The {@link org.orekit.utils.units.Unit Unit} class provides useful
  32.  * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and
  33.  * {@link org.orekit.utils.units.Unit#toSI(double) toSI} methods in case the callers
  34.  * already use CCSDS units instead of the API SI units. The general-purpose
  35.  * {@link org.orekit.utils.units.Unit Unit} class (without an 's') and the
  36.  * CCSDS-specific {@link org.orekit.files.ccsds.definitions.Units Units} class
  37.  * (with an 's') also provide some predefined units. These predefined units and the
  38.  * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and
  39.  * {@link org.orekit.utils.units.Unit#toSI(double) toSI} conversion methods are indeed
  40.  * what the parsers and writers use for the conversions.
  41.  * </p>
  42.  * @author Luc Maisonobe
  43.  * @since 12.0
  44.  */
  45. public class AttitudeDetermination extends CommentsContainer {

  46.     /** Endpoints (i.e. frames A, B and their relationship). */
  47.     private final AttitudeEndpoints endpoints;

  48.     /** Identification number. */
  49.     private String id;

  50.     /** Identification of previous orbit determination. */
  51.     private String prevId;

  52.     /** Attitude determination method. */
  53.     private AdMethodType method;

  54.     /** Source of attitude estimate. */
  55.     private String source;

  56.     /** Rotation order for Euler angles. */
  57.     private RotationOrder eulerRotSeq;

  58.     /** Number of states for {@link AdMethodType#EKF}, {@link AdMethodType#BATCH} or {@link AdMethodType#FILTER_SMOOTHER}. */
  59.     private int nbStates;

  60.     /** Attitude states. */
  61.     private AttitudeElementsType attitudeStates;

  62.     /** Type of attitude error state. */
  63.     private AttitudeCovarianceType covarianceType;

  64.     /** Attitude rate states. */
  65.     private RateElementsType rateStates;

  66.     /** Rate random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}. */
  67.     private double sigmaU;

  68.     /** Angle random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}. */
  69.     private double sigmaV;

  70.     /** Process noise standard deviation if {@link #rateStates} is {@link RateElementsType#ANGVEL}. */
  71.     private double rateProcessNoiseStdDev;

  72.     /** Sensors used. */
  73.     private final List<AttitudeDeterminationSensor> sensorsUsed;

  74.     /** Simple constructor.
  75.      */
  76.     public AttitudeDetermination() {
  77.         endpoints   = new AttitudeEndpoints();
  78.         sensorsUsed = new ArrayList<>();
  79.         nbStates    = -1;
  80.     }

  81.     /** {@inheritDoc} */
  82.     @Override
  83.     public void validate(final double version) {
  84.         super.validate(version);
  85.         checkNotNull(attitudeStates, AttitudeDeterminationKey.ATTITUDE_STATES.name());
  86.         endpoints.checkExternalFrame(AttitudeDeterminationKey.REF_FRAME_A,
  87.                                      AttitudeDeterminationKey.REF_FRAME_B);

  88.         // check sensors in increasing number
  89.         for (int number = 1; number <= sensorsUsed.size(); ++number) {
  90.             final AttitudeDeterminationSensor sensor = findSensor(number);
  91.             if (sensor != null) {
  92.                 sensor.validate(version);
  93.             } else {
  94.                 // no sensor has the expected index
  95.                 throw new OrekitException(OrekitMessages.CCSDS_MISSING_SENSOR_INDEX, number);
  96.             }

  97.         }

  98.     }

  99.     /** Find sensor by number.
  100.      * @param number number of the sensor
  101.      * @return sensor with specified number, or null if not found
  102.      */
  103.     private AttitudeDeterminationSensor findSensor(final int number) {
  104.         for (final AttitudeDeterminationSensor sensor : sensorsUsed) {
  105.             if (sensor.getSensorNumber() == number) {
  106.                 return sensor;
  107.             }
  108.         }
  109.         return null;
  110.     }

  111.     /** Get the endpoints (i.e. frames A, B and their relationship).
  112.      * @return endpoints
  113.      */
  114.     public AttitudeEndpoints getEndpoints() {
  115.         return endpoints;
  116.     }

  117.     /** Get identification number.
  118.      * @return identification number
  119.      */
  120.     public String getId() {
  121.         return id;
  122.     }

  123.     /** Set identification number.
  124.      * @param id identification number
  125.      */
  126.     public void setId(final String id) {
  127.         this.id = id;
  128.     }

  129.     /** Get identification of previous orbit determination.
  130.      * @return identification of previous orbit determination
  131.      */
  132.     public String getPrevId() {
  133.         return prevId;
  134.     }

  135.     /** Set identification of previous orbit determination.
  136.      * @param prevId identification of previous orbit determination
  137.      */
  138.     public void setPrevId(final String prevId) {
  139.         this.prevId = prevId;
  140.     }

  141.     /** Get attitude determination method.
  142.      * @return attitude determination method
  143.      */
  144.     public AdMethodType getMethod() {
  145.         return method;
  146.     }

  147.     /** Set attitude determination method.
  148.      * @param method attitude determination method
  149.      */
  150.     public void setMethod(final AdMethodType method) {
  151.         this.method = method;
  152.     }

  153.     /** Get source of attitude estimate.
  154.      * @return source of attitude estimate
  155.      */
  156.     public String getSource() {
  157.         return source;
  158.     }

  159.     /** Set source of attitude estimate.
  160.      * @param source source of attitude estimate
  161.      */
  162.     public void setSource(final String source) {
  163.         this.source = source;
  164.     }

  165.     /** Get the rotation order for Euler angles.
  166.      * @return rotation order for Euler angles
  167.      */
  168.     public RotationOrder getEulerRotSeq() {
  169.         return eulerRotSeq;
  170.     }

  171.     /** Set the rotation order for Euler angles.
  172.      * @param eulerRotSeq rotation order for Euler angles
  173.      */
  174.     public void setEulerRotSeq(final RotationOrder eulerRotSeq) {
  175.         this.eulerRotSeq = eulerRotSeq;
  176.     }

  177.     /** Get number of states for {@link AdMethodType#EKF}, {@link AdMethodType#BATCH} or {@link AdMethodType#FILTER_SMOOTHER}.
  178.      * @return number of states
  179.      */
  180.     public int getNbStates() {
  181.         return nbStates;
  182.     }

  183.     /** Set number of states for {@link AdMethodType#EKF}, {@link AdMethodType#BATCH} or {@link AdMethodType#FILTER_SMOOTHER}.
  184.      * @param nbStates number of states
  185.      */
  186.     public void setNbStates(final int nbStates) {
  187.         this.nbStates = nbStates;
  188.     }

  189.     /** Get attitude states.
  190.      * @return attitude states
  191.      */
  192.     public AttitudeElementsType getAttitudeStates() {
  193.         return attitudeStates;
  194.     }

  195.     /** Set attitude states.
  196.      * @param attitudeStates attitude states
  197.      */
  198.     public void setAttitudeStates(final AttitudeElementsType attitudeStates) {
  199.         this.attitudeStates = attitudeStates;
  200.     }

  201.     /** Get type of attitude error state.
  202.      * @return type of attitude error state
  203.      */
  204.     public AttitudeCovarianceType getCovarianceType() {
  205.         return covarianceType;
  206.     }

  207.     /** Set type of attitude error state.
  208.      * @param covarianceType type of attitude error state
  209.      */
  210.     public void setCovarianceType(final AttitudeCovarianceType covarianceType) {
  211.         this.covarianceType = covarianceType;
  212.     }

  213.     /** Get attitude rate states.
  214.      * @return attitude rate states
  215.      */
  216.     public RateElementsType getRateStates() {
  217.         return rateStates;
  218.     }

  219.     /** Set attitude rate states.
  220.      * @param rateStates attitude rate states
  221.      */
  222.     public void setRateStates(final RateElementsType rateStates) {
  223.         this.rateStates = rateStates;
  224.     }

  225.     /** Get rate random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}.
  226.      * @return rate random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}
  227.      */
  228.     public double getSigmaU() {
  229.         return sigmaU;
  230.     }

  231.     /** Set rate random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}.
  232.      * @param sigmaU rate random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}
  233.      */
  234.     public void setSigmaU(final double sigmaU) {
  235.         this.sigmaU = sigmaU;
  236.     }

  237.     /** Get angle random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}.
  238.      * @return angle random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}
  239.      */
  240.     public double getSigmaV() {
  241.         return sigmaV;
  242.     }

  243.     /** Set angle random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}.
  244.      * @param sigmaV angle random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}
  245.      */
  246.     public void setSigmaV(final double sigmaV) {
  247.         this.sigmaV = sigmaV;
  248.     }

  249.     /** Get process noise standard deviation if {@link #rateStates} is {@link RateElementsType#ANGVEL}.
  250.      * @return process noise standard deviation if {@link #rateStates} is {@link RateElementsType#ANGVEL}
  251.      */
  252.     public double getRateProcessNoiseStdDev() {
  253.         return rateProcessNoiseStdDev;
  254.     }

  255.     /** Set process noise standard deviation if {@link #rateStates} is {@link RateElementsType#ANGVEL}.
  256.      * @param rateProcessNoiseStdDev process noise standard deviation if {@link #rateStates} is {@link RateElementsType#ANGVEL}
  257.      */
  258.     public void setRateProcessNoiseStdDev(final double rateProcessNoiseStdDev) {
  259.         this.rateProcessNoiseStdDev = rateProcessNoiseStdDev;
  260.     }

  261.     /** Get sensors used.
  262.      * @return sensors used
  263.      */
  264.     public List<AttitudeDeterminationSensor> getSensorsUsed() {
  265.         return Collections.unmodifiableList(sensorsUsed);
  266.     }

  267.     /** Add a sensor used.
  268.      * @param sensor sensor to add
  269.      */
  270.     public void addSensor(final AttitudeDeterminationSensor sensor) {
  271.         for (final AttitudeDeterminationSensor existing : sensorsUsed) {
  272.             if (sensor.getSensorNumber() == existing.getSensorNumber()) {
  273.                 throw new OrekitException(OrekitMessages.CCSDS_SENSOR_INDEX_ALREADY_USED, sensor.getSensorNumber());
  274.             }
  275.         }
  276.         sensorsUsed.add(sensor);
  277.     }

  278. }