1   /* Copyright 2022-2026 Romain Serra
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.estimation.measurements.model;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
21  import org.hipparchus.geometry.euclidean.threed.Vector3D;
22  import org.hipparchus.util.MathArrays;
23  import org.orekit.errors.OrekitException;
24  import org.orekit.errors.OrekitMessages;
25  import org.orekit.frames.FieldStaticTransform;
26  import org.orekit.frames.Frame;
27  import org.orekit.frames.StaticTransform;
28  import org.orekit.signal.FieldSignalReceptionCondition;
29  import org.orekit.signal.SignalReceptionCondition;
30  import org.orekit.signal.SignalTravelTimeModel;
31  import org.orekit.time.AbsoluteDate;
32  import org.orekit.time.FieldAbsoluteDate;
33  import org.orekit.utils.FieldPVCoordinatesProvider;
34  import org.orekit.utils.PVCoordinatesProvider;
35  
36  /**
37   * Perfect measurement model for right ascension and declination. It is assumed that the signal reception date is known.
38   * @since 14.0
39   * @author Romain Serra
40   */
41  public class RaDecModel extends AbstractAngularMeasurementModel {
42  
43      /** Reference frame defining axis used with right ascension and declination. */
44      private final Frame referenceFrame;
45  
46      /**
47       * Constructor.
48       * @param referenceFrame reference frame for RA-Dec (must be inertial)
49       * @param signalTravelTimeModel time delay computer
50       */
51      public RaDecModel(final Frame referenceFrame, final SignalTravelTimeModel signalTravelTimeModel) {
52          super(signalTravelTimeModel);
53          if (!referenceFrame.isPseudoInertial()) {
54              throw new OrekitException(OrekitMessages.NON_PSEUDO_INERTIAL_FRAME, referenceFrame.getName());
55          }
56          this.referenceFrame = referenceFrame;
57      }
58  
59      /**
60       * Compute theoretical measurement.
61       * @param receptionCondition signal reception condition
62       * @param emitter signal emitter coordinates provider
63       * @return RA-Dec (radians)
64       */
65      public double[] value(final SignalReceptionCondition receptionCondition,
66                            final PVCoordinatesProvider emitter) {
67          return value(receptionCondition, emitter, receptionCondition.receptionDate());
68      }
69  
70      /**
71       * Compute theoretical measurement with guess for the emission date.
72       * @param receptionCondition signal reception condition
73       * @param emitter signal emitter coordinates provider
74       * @param approxEmissionDate guess for the emission date (shall be adjusted by signal travel time computer)
75       * @return RA-Dec (radians)
76       */
77      public double[] value(final SignalReceptionCondition receptionCondition,
78                            final PVCoordinatesProvider emitter, final AbsoluteDate approxEmissionDate) {
79          // Compute line-of-sight
80          final Vector3D apparentLineOfSightInInputFrame = getEmitterToReceiverVector(receptionCondition, emitter,
81                  approxEmissionDate).normalize();
82          final StaticTransform toInertialFrameAtReception = receptionCondition.referenceFrame()
83                  .getStaticTransformTo(referenceFrame, receptionCondition.receptionDate());
84          final Vector3D apparentLineOfSight = toInertialFrameAtReception.transformVector(apparentLineOfSightInInputFrame);
85  
86          // Compute right ascension and declination
87          final double rightAscension = apparentLineOfSight.getAlpha();
88          final double declination = apparentLineOfSight.getDelta();
89          return new double[] { rightAscension, declination };
90      }
91  
92      /**
93       * Compute theoretical measurement with FIeld.
94       * @param <T> field type
95       * @param receptionCondition signal reception condition
96       * @param emitter signal emitter coordinates provider
97       * @return RA-Dec (radians)
98       */
99      public <T extends CalculusFieldElement<T>> T[] value(final FieldSignalReceptionCondition<T> receptionCondition,
100                                                          final FieldPVCoordinatesProvider<T> emitter) {
101         return value(receptionCondition, emitter, receptionCondition.receptionDate());
102     }
103 
104     /**
105      * Compute theoretical measurement with FIeld with guess for emission date.
106      * @param <T> field type
107      * @param receptionCondition signal reception condition
108      * @param emitter signal emitter coordinates provider
109      * @param approxEmissionDate guess for the emission date (shall be adjusted by signal travel time computer)
110      * @return RA-Dec (radians)
111      */
112     public <T extends CalculusFieldElement<T>> T[] value(final FieldSignalReceptionCondition<T> receptionCondition,
113                                                          final FieldPVCoordinatesProvider<T> emitter,
114                                                          final FieldAbsoluteDate<T> approxEmissionDate) {
115         // Compute line-of-sight
116         final FieldVector3D<T> apparentLineOfSightInInputFrame = getEmitterToReceiverVector(receptionCondition,
117                 emitter, approxEmissionDate).normalize();
118         final FieldAbsoluteDate<T> receptionDate = receptionCondition.receptionDate();
119         final FieldStaticTransform<T> toInertialFrameAtReception = receptionCondition.referenceFrame()
120                 .getStaticTransformTo(referenceFrame, receptionDate);
121         final FieldVector3D<T> apparentLineOfSight = toInertialFrameAtReception.transformVector(apparentLineOfSightInInputFrame);
122 
123         // Compute right ascension and declination
124         final T rightAscension = apparentLineOfSight.getAlpha();
125         final T declination = apparentLineOfSight.getDelta();
126         final T[] output = MathArrays.buildArray(receptionDate.getField(), 2);
127         output[0] = rightAscension;
128         output[1] = declination;
129         return output;
130     }
131 }