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.geometry.euclidean.threed.Vector3D;
22 import org.hipparchus.util.MathUtils;
23 import org.orekit.estimation.measurements.AngularAzEl;
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.frames.Frame;
28 import org.orekit.frames.TopocentricFrame;
29 import org.orekit.models.earth.ionosphere.IonosphericModel;
30 import org.orekit.propagation.SpacecraftState;
31 import org.orekit.time.AbsoluteDate;
32 import org.orekit.utils.Constants;
33 import org.orekit.utils.ParameterDriver;
34 import org.orekit.utils.TrackingCoordinates;
35
36 /** Class modifying theoretical angular measurement with ionospheric delay.
37 * <p>
38 * The effect of ionospheric correction on the angular measurement is computed
39 * through the computation of the ionospheric delay. The spacecraft state
40 * is shifted by the computed delay time and elevation and azimuth are computed
41 * again with the new spacecraft state.
42 * </p>
43 * <p>
44 * The ionospheric delay depends on the frequency of the signal (GNSS, VLBI, ...).
45 * For optical measurements (e.g. SLR), the ray is not affected by ionosphere charged particles.
46 * </p>
47 * <p>
48 * Since 10.0, state derivatives and ionospheric parameters derivates are computed
49 * using automatic differentiation.
50 * </p>
51 * @author Thierry Ceolin
52 * @since 8.0
53 */
54 public class AngularIonosphericDelayModifier implements EstimationModifier<AngularAzEl> {
55
56 /** Ionospheric delay model. */
57 private final IonosphericModel ionoModel;
58
59 /** Frequency [Hz]. */
60 private final double frequency;
61
62 /** Constructor.
63 *
64 * @param model Ionospheric delay model appropriate for the current angular measurement method.
65 * @param freq frequency of the signal in Hz
66 */
67 public AngularIonosphericDelayModifier(final IonosphericModel model,
68 final double freq) {
69 ionoModel = model;
70 frequency = freq;
71 }
72
73 /** {@inheritDoc} */
74 @Override
75 public String getEffectName() {
76 return "ionosphere";
77 }
78
79 /** Compute the measurement error due to ionosphere.
80 * @param station station
81 * @param state spacecraft state
82 * @return the measurement error due to ionosphere
83 */
84 private double angularErrorIonosphericModel(final GroundStation station,
85 final SpacecraftState state) {
86 // Base frame associated with the station
87 final TopocentricFrame baseFrame = station.getBaseFrame();
88 // delay in meters
89 return ionoModel.pathDelay(state, baseFrame, frequency, ionoModel.getParameters(state.getDate()));
90 }
91
92 /** {@inheritDoc} */
93 @Override
94 public List<ParameterDriver> getParametersDrivers() {
95 return ionoModel.getParametersDrivers();
96 }
97
98 @Override
99 public void modifyWithoutDerivatives(final EstimatedMeasurementBase<AngularAzEl> estimated) {
100 final AngularAzEl measure = estimated.getObservedMeasurement();
101 final GroundStation station = measure.getStation();
102 final SpacecraftState state = estimated.getStates()[0];
103
104 final double delay = angularErrorIonosphericModel(station, state);
105 // Delay is taken into account to shift the spacecraft position
106 final double dt = delay / Constants.SPEED_OF_LIGHT;
107
108 // Position of the spacecraft shifted of dt
109 final SpacecraftState transitState = state.shiftedBy(-dt);
110
111 // Update estimated value taking into account the ionospheric delay.
112 final AbsoluteDate date = transitState.getDate();
113 final Vector3D position = transitState.getPosition();
114 final Frame inertial = transitState.getFrame();
115
116 // Elevation and azimuth in radians
117 final TrackingCoordinates tc = station.getBaseFrame().getTrackingCoordinates(position, inertial, date);
118 final double twoPiWrap = MathUtils.normalizeAngle(tc.getAzimuth(), measure.getObservedValue()[0]) - tc.getAzimuth();
119 final double azimuth = tc.getAzimuth() + twoPiWrap;
120
121 // Update estimated value taking into account the ionospheric delay.
122 // Azimuth - elevation values
123 estimated.modifyEstimatedValue(this, azimuth, tc.getElevation());
124 }
125
126 }