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 18 package org.orekit.files.ccsds.ndm.adm.acm; 19 20 import java.util.ArrayList; 21 import java.util.Collections; 22 import java.util.List; 23 24 import org.hipparchus.geometry.euclidean.threed.RotationOrder; 25 import org.orekit.errors.OrekitException; 26 import org.orekit.errors.OrekitMessages; 27 import org.orekit.files.ccsds.definitions.AdMethodType; 28 import org.orekit.files.ccsds.ndm.adm.AttitudeEndpoints; 29 import org.orekit.files.ccsds.section.CommentsContainer; 30 31 /** Attitude determination data. 32 * <p> 33 * Beware that the Orekit getters and setters all rely on SI units. The parsers 34 * and writers take care of converting these SI units into CCSDS mandatory units. 35 * The {@link org.orekit.utils.units.Unit Unit} class provides useful 36 * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and 37 * {@link org.orekit.utils.units.Unit#toSI(double) toSI} methods in case the callers 38 * already use CCSDS units instead of the API SI units. The general-purpose 39 * {@link org.orekit.utils.units.Unit Unit} class (without an 's') and the 40 * CCSDS-specific {@link org.orekit.files.ccsds.definitions.Units Units} class 41 * (with an 's') also provide some predefined units. These predefined units and the 42 * {@link org.orekit.utils.units.Unit#fromSI(double) fromSi} and 43 * {@link org.orekit.utils.units.Unit#toSI(double) toSI} conversion methods are indeed 44 * what the parsers and writers use for the conversions. 45 * </p> 46 * @author Luc Maisonobe 47 * @since 12.0 48 */ 49 public class AttitudeDetermination extends CommentsContainer { 50 51 /** Endpoints (i.e. frames A, B and their relationship). */ 52 private final AttitudeEndpoints endpoints; 53 54 /** Identification number. */ 55 private String id; 56 57 /** Identification of previous orbit determination. */ 58 private String prevId; 59 60 /** Attitude determination method. */ 61 private AdMethodType method; 62 63 /** Source of attitude estimate. */ 64 private String source; 65 66 /** Rotation order for Euler angles. */ 67 private RotationOrder eulerRotSeq; 68 69 /** Number of states for {@link AdMethodType#EKF}, {@link AdMethodType#BATCH} or {@link AdMethodType#FILTER_SMOOTHER}. */ 70 private int nbStates; 71 72 /** Attitude states. */ 73 private AttitudeElementsType attitudeStates; 74 75 /** Type of attitude error state. */ 76 private AttitudeCovarianceType covarianceType; 77 78 /** Attitude rate states. */ 79 private RateElementsType rateStates; 80 81 /** Rate random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}. */ 82 private double sigmaU; 83 84 /** Angle random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}. */ 85 private double sigmaV; 86 87 /** Process noise standard deviation if {@link #rateStates} is {@link RateElementsType#ANGVEL}. */ 88 private double rateProcessNoiseStdDev; 89 90 /** Sensors used. */ 91 private final List<AttitudeDeterminationSensor> sensorsUsed; 92 93 /** Simple constructor. 94 */ 95 public AttitudeDetermination() { 96 endpoints = new AttitudeEndpoints(); 97 sensorsUsed = new ArrayList<>(); 98 nbStates = -1; 99 } 100 101 /** {@inheritDoc} */ 102 @Override 103 public void validate(final double version) { 104 super.validate(version); 105 checkNotNull(attitudeStates, AttitudeDeterminationKey.ATTITUDE_STATES.name()); 106 endpoints.checkExternalFrame(AttitudeDeterminationKey.REF_FRAME_A, 107 AttitudeDeterminationKey.REF_FRAME_B); 108 109 // check sensors in increasing number 110 for (int number = 1; number <= sensorsUsed.size(); ++number) { 111 final AttitudeDeterminationSensor sensor = findSensor(number); 112 if (sensor != null) { 113 sensor.validate(version); 114 } else { 115 // no sensor has the expected index 116 throw new OrekitException(OrekitMessages.CCSDS_MISSING_SENSOR_INDEX, number); 117 } 118 119 } 120 121 } 122 123 /** Find sensor by number. 124 * @param number number of the sensor 125 * @return sensor with specified number, or null if not found 126 */ 127 private AttitudeDeterminationSensor findSensor(final int number) { 128 for (final AttitudeDeterminationSensor sensor : sensorsUsed) { 129 if (sensor.getSensorNumber() == number) { 130 return sensor; 131 } 132 } 133 return null; 134 } 135 136 /** Get the endpoints (i.e. frames A, B and their relationship). 137 * @return endpoints 138 */ 139 public AttitudeEndpoints getEndpoints() { 140 return endpoints; 141 } 142 143 /** Get identification number. 144 * @return identification number 145 */ 146 public String getId() { 147 return id; 148 } 149 150 /** Set identification number. 151 * @param id identification number 152 */ 153 public void setId(final String id) { 154 this.id = id; 155 } 156 157 /** Get identification of previous orbit determination. 158 * @return identification of previous orbit determination 159 */ 160 public String getPrevId() { 161 return prevId; 162 } 163 164 /** Set identification of previous orbit determination. 165 * @param prevId identification of previous orbit determination 166 */ 167 public void setPrevId(final String prevId) { 168 this.prevId = prevId; 169 } 170 171 /** Get attitude determination method. 172 * @return attitude determination method 173 */ 174 public AdMethodType getMethod() { 175 return method; 176 } 177 178 /** Set attitude determination method. 179 * @param method attitude determination method 180 */ 181 public void setMethod(final AdMethodType method) { 182 this.method = method; 183 } 184 185 /** Get source of attitude estimate. 186 * @return source of attitude estimate 187 */ 188 public String getSource() { 189 return source; 190 } 191 192 /** Set source of attitude estimate. 193 * @param source source of attitude estimate 194 */ 195 public void setSource(final String source) { 196 this.source = source; 197 } 198 199 /** Get the rotation order for Euler angles. 200 * @return rotation order for Euler angles 201 */ 202 public RotationOrder getEulerRotSeq() { 203 return eulerRotSeq; 204 } 205 206 /** Set the rotation order for Euler angles. 207 * @param eulerRotSeq rotation order for Euler angles 208 */ 209 public void setEulerRotSeq(final RotationOrder eulerRotSeq) { 210 this.eulerRotSeq = eulerRotSeq; 211 } 212 213 /** Get number of states for {@link AdMethodType#EKF}, {@link AdMethodType#BATCH} or {@link AdMethodType#FILTER_SMOOTHER}. 214 * @return number of states 215 */ 216 public int getNbStates() { 217 return nbStates; 218 } 219 220 /** Set number of states for {@link AdMethodType#EKF}, {@link AdMethodType#BATCH} or {@link AdMethodType#FILTER_SMOOTHER}. 221 * @param nbStates number of states 222 */ 223 public void setNbStates(final int nbStates) { 224 this.nbStates = nbStates; 225 } 226 227 /** Get attitude states. 228 * @return attitude states 229 */ 230 public AttitudeElementsType getAttitudeStates() { 231 return attitudeStates; 232 } 233 234 /** Set attitude states. 235 * @param attitudeStates attitude states 236 */ 237 public void setAttitudeStates(final AttitudeElementsType attitudeStates) { 238 this.attitudeStates = attitudeStates; 239 } 240 241 /** Get type of attitude error state. 242 * @return type of attitude error state 243 */ 244 public AttitudeCovarianceType getCovarianceType() { 245 return covarianceType; 246 } 247 248 /** Set type of attitude error state. 249 * @param covarianceType type of attitude error state 250 */ 251 public void setCovarianceType(final AttitudeCovarianceType covarianceType) { 252 this.covarianceType = covarianceType; 253 } 254 255 /** Get attitude rate states. 256 * @return attitude rate states 257 */ 258 public RateElementsType getRateStates() { 259 return rateStates; 260 } 261 262 /** Set attitude rate states. 263 * @param rateStates attitude rate states 264 */ 265 public void setRateStates(final RateElementsType rateStates) { 266 this.rateStates = rateStates; 267 } 268 269 /** Get rate random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}. 270 * @return rate random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS} 271 */ 272 public double getSigmaU() { 273 return sigmaU; 274 } 275 276 /** Set rate random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}. 277 * @param sigmaU rate random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS} 278 */ 279 public void setSigmaU(final double sigmaU) { 280 this.sigmaU = sigmaU; 281 } 282 283 /** Get angle random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}. 284 * @return angle random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS} 285 */ 286 public double getSigmaV() { 287 return sigmaV; 288 } 289 290 /** Set angle random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS}. 291 * @param sigmaV angle random walk if {@link #rateStates} is {@link RateElementsType#GYRO_BIAS} 292 */ 293 public void setSigmaV(final double sigmaV) { 294 this.sigmaV = sigmaV; 295 } 296 297 /** Get process noise standard deviation if {@link #rateStates} is {@link RateElementsType#ANGVEL}. 298 * @return process noise standard deviation if {@link #rateStates} is {@link RateElementsType#ANGVEL} 299 */ 300 public double getRateProcessNoiseStdDev() { 301 return rateProcessNoiseStdDev; 302 } 303 304 /** Set process noise standard deviation if {@link #rateStates} is {@link RateElementsType#ANGVEL}. 305 * @param rateProcessNoiseStdDev process noise standard deviation if {@link #rateStates} is {@link RateElementsType#ANGVEL} 306 */ 307 public void setRateProcessNoiseStdDev(final double rateProcessNoiseStdDev) { 308 this.rateProcessNoiseStdDev = rateProcessNoiseStdDev; 309 } 310 311 /** Get sensors used. 312 * @return sensors used 313 */ 314 public List<AttitudeDeterminationSensor> getSensorsUsed() { 315 return Collections.unmodifiableList(sensorsUsed); 316 } 317 318 /** Add a sensor used. 319 * @param sensor sensor to add 320 */ 321 public void addSensor(final AttitudeDeterminationSensor sensor) { 322 for (final AttitudeDeterminationSensor existing : sensorsUsed) { 323 if (sensor.getSensorNumber() == existing.getSensorNumber()) { 324 throw new OrekitException(OrekitMessages.CCSDS_SENSOR_INDEX_ALREADY_USED, sensor.getSensorNumber()); 325 } 326 } 327 sensorsUsed.add(sensor); 328 } 329 330 }