1   /* Copyright 2002-2025 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.estimation.measurements.modifiers;
18  
19  import java.util.List;
20  
21  import org.hipparchus.CalculusFieldElement;
22  import org.hipparchus.Field;
23  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
24  import org.hipparchus.geometry.euclidean.threed.Vector3D;
25  import org.orekit.estimation.measurements.GroundStation;
26  import org.orekit.models.earth.troposphere.TroposphericModel;
27  import org.orekit.propagation.FieldSpacecraftState;
28  import org.orekit.propagation.SpacecraftState;
29  import org.orekit.utils.FieldTrackingCoordinates;
30  import org.orekit.utils.ParameterDriver;
31  import org.orekit.utils.TrackingCoordinates;
32  
33  /** Baselass modifying theoretical range-rate measurements with tropospheric delay.
34   * The effect of tropospheric correction on the range-rate is directly computed
35   * through the computation of the tropospheric delay difference with respect to
36   * time.
37   *
38   * In general, for GNSS, VLBI, ... there is hardly any frequency dependence in the delay.
39   * For SLR techniques however, the frequency dependence is sensitive.
40   *
41   * @author Joris Olympio
42   * @since 11.2
43   */
44  public abstract class BaseRangeRateTroposphericDelayModifier {
45  
46      /** Tropospheric delay model. */
47      private final TroposphericModel tropoModel;
48  
49      /** Constructor.
50       *
51       * @param model  Tropospheric delay model appropriate for the current range-rate measurement method.
52       * @since 12.1
53       */
54      protected BaseRangeRateTroposphericDelayModifier(final TroposphericModel model) {
55          tropoModel = model;
56      }
57  
58      /** Get the name of the effect modifying the measurement.
59       * @return name of the effect modifying the measurement
60       * @since 13.0
61       */
62      public String getEffectName() {
63          return "troposphere";
64      }
65  
66      /** Get the tropospheric delay model.
67       * @return tropospheric delay model
68       */
69      protected TroposphericModel getTropoModel() {
70          return tropoModel;
71      }
72  
73      /** Compute the measurement error due to Troposphere.
74       * @param station station
75       * @param state spacecraft state
76       * @return the measurement error due to Troposphere
77       */
78      public double rangeRateErrorTroposphericModel(final GroundStation station,
79                                                    final SpacecraftState state) {
80          // The effect of tropospheric correction on the range rate is
81          // computed using finite differences.
82  
83          final double dt = 10; // s
84  
85          // spacecraft position and elevation as seen from the ground station
86          final Vector3D position = state.getPosition();
87  
88          // tracking
89          final TrackingCoordinates trackingCoordinates1 =
90                          station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate());
91  
92          // only consider measures above the horizon
93          if (trackingCoordinates1.getElevation() > 0) {
94              // tropospheric delay in meters
95              final double d1 = tropoModel.pathDelay(trackingCoordinates1,
96                                                     station.getOffsetGeodeticPoint(state.getDate()),
97                                                     tropoModel.getParameters(state.getDate()), state.getDate()).
98                                getDelay();
99  
100             // propagate spacecraft state forward by dt
101             final SpacecraftState state2 = state.shiftedBy(dt);
102 
103             // spacecraft position and elevation as seen from the ground station
104             final Vector3D position2 = state2.getPosition();
105 
106             // tracking
107             final TrackingCoordinates trackingCoordinates2 =
108                             station.getBaseFrame().getTrackingCoordinates(position2, state2.getFrame(), state2.getDate());
109 
110             // tropospheric delay dt after
111             final double d2 = tropoModel.pathDelay(trackingCoordinates2,
112                                                    station.getOffsetGeodeticPoint(state.getDate()),
113                                                    tropoModel.getParameters(state2.getDate()), state2.getDate()).
114                               getDelay();
115 
116             return (d2 - d1) / dt;
117         }
118 
119         return 0;
120     }
121 
122 
123     /** Compute the measurement error due to Troposphere.
124      * @param <T> type of the element
125      * @param station station
126      * @param state spacecraft state
127      * @param parameters tropospheric model parameters
128      * @return the measurement error due to Troposphere
129      */
130     public <T extends CalculusFieldElement<T>> T rangeRateErrorTroposphericModel(final GroundStation station,
131                                                                                  final FieldSpacecraftState<T> state,
132                                                                                  final T[] parameters) {
133         // Field
134         final Field<T> field = state.getDate().getField();
135         final T zero         = field.getZero();
136 
137         // The effect of tropospheric correction on the range rate is
138         // computed using finite differences.
139 
140         final double dt = 10; // s
141 
142         // spacecraft position and elevation as seen from the ground station
143         final FieldVector3D<T> position     = state.getPosition();
144         final FieldTrackingCoordinates<T> trackingCoordinates1 =
145                         station.getBaseFrame().getTrackingCoordinates(position, state.getFrame(), state.getDate());
146 
147         // only consider measures above the horizon
148         if (trackingCoordinates1.getElevation().getReal() > 0) {
149             // tropospheric delay in meters
150             final T d1 = tropoModel.pathDelay(trackingCoordinates1,
151                                               station.getOffsetGeodeticPoint(state.getDate()),
152                                               parameters, state.getDate()).
153                          getDelay();
154 
155             // propagate spacecraft state forward by dt
156             final FieldSpacecraftState<T> state2 = state.shiftedBy(dt);
157 
158             // spacecraft position and elevation as seen from the ground station
159             final FieldVector3D<T> position2     = state2.getPosition();
160 
161             // elevation
162             final FieldTrackingCoordinates<T> trackingCoordinates2 =
163                             station.getBaseFrame().getTrackingCoordinates(position2, state2.getFrame(), state2.getDate());
164 
165 
166             // tropospheric delay dt after
167             final T d2 = tropoModel.pathDelay(trackingCoordinates2,
168                                               station.getOffsetGeodeticPoint(state.getDate()),
169                                               parameters, state2.getDate()).
170                          getDelay();
171 
172             return d2.subtract(d1).divide(dt);
173         }
174 
175         return zero;
176     }
177 
178     /** Get the drivers for this modifier parameters.
179      * @return drivers for this modifier parameters
180      */
181     public List<ParameterDriver> getParametersDrivers() {
182         return tropoModel.getParametersDrivers();
183     }
184 
185 }