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.orekit.attitudes.FrameAlignedProvider;
23  import org.orekit.estimation.measurements.EstimatedMeasurement;
24  import org.orekit.estimation.measurements.EstimatedMeasurementBase;
25  import org.orekit.estimation.measurements.EstimationModifier;
26  import org.orekit.estimation.measurements.GroundStation;
27  import org.orekit.estimation.measurements.TDOA;
28  import org.orekit.frames.TopocentricFrame;
29  import org.orekit.models.earth.ionosphere.IonosphericModel;
30  import org.orekit.propagation.FieldSpacecraftState;
31  import org.orekit.propagation.SpacecraftState;
32  import org.orekit.utils.Constants;
33  import org.orekit.utils.ParameterDriver;
34  
35  /** Class modifying theoretical TDOA measurements with ionospheric delay.
36   * <p>
37   * The effect of ionospheric correction on the TDOA is a time delay computed
38   * directly from the difference in ionospheric delays for each downlink.
39   * </p><p>
40   * The ionospheric delay depends on the frequency of the signal.
41   * </p>
42   * @author Pascal Parraud
43   * @since 11.2
44   */
45  public class TDOAIonosphericDelayModifier implements EstimationModifier<TDOA> {
46  
47      /** Ionospheric delay model. */
48      private final IonosphericModel ionoModel;
49  
50      /** Frequency [Hz]. */
51      private final double frequency;
52  
53      /** Constructor.
54       *
55       * @param model ionospheric model appropriate for the current TDOA measurement method
56       * @param freq  frequency of the signal in Hz
57       */
58      public TDOAIonosphericDelayModifier(final IonosphericModel model,
59                                          final double freq) {
60          ionoModel = model;
61          frequency = freq;
62      }
63  
64      /** {@inheritDoc} */
65      @Override
66      public String getEffectName() {
67          return "ionosphere";
68      }
69  
70      /** Compute the measurement error due to ionosphere on a single downlink.
71       * @param station station
72       * @param state spacecraft state
73       * @return the measurement error due to ionosphere (s)
74       */
75      private double timeErrorIonosphericModel(final GroundStation station,
76                                               final SpacecraftState state) {
77          // base frame associated with the station
78          final TopocentricFrame baseFrame = station.getBaseFrame();
79          // delay in meters
80          final double delay = ionoModel.pathDelay(state, baseFrame, frequency, ionoModel.getParameters(state.getDate()));
81          // return delay in seconds
82          return delay / Constants.SPEED_OF_LIGHT;
83      }
84  
85      /** Compute the measurement error due to ionosphere on a single downlink.
86       * @param <T> type of the elements
87       * @param station station
88       * @param state spacecraft state
89       * @param parameters ionospheric model parameters
90       * @return the measurement error due to ionosphere (s)
91       */
92      private <T extends CalculusFieldElement<T>> T timeErrorIonosphericModel(final GroundStation station,
93                                                                              final FieldSpacecraftState<T> state,
94                                                                              final T[] parameters) {
95          // Base frame associated with the station
96          final TopocentricFrame baseFrame = station.getBaseFrame();
97          // Delay in meters
98          final T delay = ionoModel.pathDelay(state, baseFrame, frequency, parameters);
99          // return delay in seconds
100         return delay.divide(Constants.SPEED_OF_LIGHT);
101     }
102 
103     /** {@inheritDoc} */
104     @Override
105     public List<ParameterDriver> getParametersDrivers() {
106         return ionoModel.getParametersDrivers();
107     }
108 
109     @Override
110     public void modifyWithoutDerivatives(final EstimatedMeasurementBase<TDOA> estimated) {
111 
112         final TDOA measurement              = estimated.getObservedMeasurement();
113         final GroundStation   primeStation  = measurement.getPrimeStation();
114         final GroundStation   secondStation = measurement.getSecondStation();
115 
116         TDOAModifierUtil.modifyWithoutDerivatives(estimated,  primeStation, secondStation,
117                                                   this::timeErrorIonosphericModel,
118                                                   this);
119 
120     }
121 
122     @Override
123     public void modify(final EstimatedMeasurement<TDOA> estimated) {
124 
125         final TDOA measurement              = estimated.getObservedMeasurement();
126         final GroundStation   primeStation  = measurement.getPrimeStation();
127         final GroundStation   secondStation = measurement.getSecondStation();
128         final SpacecraftState state         = estimated.getStates()[0];
129 
130         TDOAModifierUtil.modify(estimated, ionoModel,
131                                 new ModifierGradientConverter(state, 6, new FrameAlignedProvider(state.getFrame())),
132                                 primeStation, secondStation,
133                                 this::timeErrorIonosphericModel,
134                                 this::timeErrorIonosphericModel,
135                                 this);
136 
137     }
138 
139 }