1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.estimation.measurements.modifiers;
18
19 import java.util.Arrays;
20 import java.util.List;
21
22 import org.hipparchus.CalculusFieldElement;
23 import org.hipparchus.Field;
24 import org.hipparchus.analysis.differentiation.Gradient;
25 import org.orekit.attitudes.FrameAlignedProvider;
26 import org.orekit.estimation.measurements.EstimatedMeasurement;
27 import org.orekit.estimation.measurements.EstimatedMeasurementBase;
28 import org.orekit.estimation.measurements.EstimationModifier;
29 import org.orekit.estimation.measurements.GroundStation;
30 import org.orekit.estimation.measurements.gnss.Phase;
31 import org.orekit.models.earth.troposphere.TroposphericModel;
32 import org.orekit.propagation.FieldSpacecraftState;
33 import org.orekit.propagation.SpacecraftState;
34 import org.orekit.utils.Differentiation;
35 import org.orekit.utils.FieldTrackingCoordinates;
36 import org.orekit.utils.ParameterDriver;
37 import org.orekit.utils.ParameterFunction;
38 import org.orekit.utils.TimeSpanMap.Span;
39 import org.orekit.utils.TrackingCoordinates;
40
41
42
43
44
45
46
47
48
49 public class PhaseTroposphericDelayModifier implements EstimationModifier<Phase> {
50
51
52 private final TroposphericModel tropoModel;
53
54
55
56
57
58
59 public PhaseTroposphericDelayModifier(final TroposphericModel model) {
60 tropoModel = model;
61 }
62
63
64 @Override
65 public String getEffectName() {
66 return "troposphere";
67 }
68
69
70
71
72
73
74
75 private double phaseErrorTroposphericModel(final GroundStation station, final SpacecraftState state, final double wavelength) {
76
77
78 final TrackingCoordinates trackingCoordinates =
79 station.getBaseFrame().getTrackingCoordinates(state.getPosition(), state.getFrame(), state.getDate());
80
81
82 if (trackingCoordinates.getElevation() > 0) {
83
84 final double delay = tropoModel.pathDelay(trackingCoordinates,
85 station.getOffsetGeodeticPoint(state.getDate()),
86 tropoModel.getParameters(state.getDate()), state.getDate()).
87 getDelay();
88
89 return delay / wavelength;
90 }
91
92 return 0;
93 }
94
95
96
97
98
99
100
101
102
103 private <T extends CalculusFieldElement<T>> T phaseErrorTroposphericModel(final GroundStation station,
104 final FieldSpacecraftState<T> state,
105 final T[] parameters, final double wavelength) {
106
107
108 final Field<T> field = state.getDate().getField();
109 final T zero = field.getZero();
110
111
112 final FieldTrackingCoordinates<T> trackingCoordinates =
113 station.getBaseFrame().getTrackingCoordinates(state.getPosition(), state.getFrame(), state.getDate());
114
115
116
117 if (trackingCoordinates.getElevation().getReal() > 0) {
118
119 final T delay = tropoModel.pathDelay(trackingCoordinates,
120 station.getOffsetGeodeticPoint(state.getDate()),
121 parameters, state.getDate()).
122 getDelay();
123
124 return delay.divide(wavelength);
125 }
126
127 return zero;
128 }
129
130
131
132
133
134
135
136
137 private double[][] phaseErrorJacobianState(final double[] derivatives) {
138 final double[][] finiteDifferencesJacobian = new double[1][6];
139 System.arraycopy(derivatives, 0, finiteDifferencesJacobian[0], 0, 6);
140 return finiteDifferencesJacobian;
141 }
142
143
144
145
146
147
148
149
150
151 private double phaseErrorParameterDerivative(final GroundStation station,
152 final ParameterDriver driver,
153 final SpacecraftState state,
154 final double wavelength) {
155 final ParameterFunction rangeError = (parameterDriver, date) -> phaseErrorTroposphericModel(station, state, wavelength);
156 final ParameterFunction phaseErrorDerivative =
157 Differentiation.differentiate(rangeError, 3, 10.0 * driver.getScale());
158 return phaseErrorDerivative.value(driver, state.getDate());
159
160 }
161
162
163
164
165
166
167
168
169 private double[] phaseErrorParameterDerivative(final double[] derivatives, final int freeStateParameters) {
170
171
172 return Arrays.copyOfRange(derivatives, freeStateParameters, derivatives.length);
173 }
174
175
176 @Override
177 public List<ParameterDriver> getParametersDrivers() {
178 return tropoModel.getParametersDrivers();
179 }
180
181
182 @Override
183 public void modifyWithoutDerivatives(final EstimatedMeasurementBase<Phase> estimated) {
184
185 final Phase measurement = estimated.getObservedMeasurement();
186 final GroundStation station = measurement.getStation();
187 final SpacecraftState state = estimated.getStates()[0];
188
189
190
191 final double[] newValue = estimated.getEstimatedValue();
192 final double delay = phaseErrorTroposphericModel(station, state, measurement.getWavelength());
193 newValue[0] = newValue[0] + delay;
194 estimated.modifyEstimatedValue(this, newValue);
195
196 }
197
198
199 @Override
200 public void modify(final EstimatedMeasurement<Phase> estimated) {
201 final Phase measurement = estimated.getObservedMeasurement();
202 final GroundStation station = measurement.getStation();
203 final SpacecraftState state = estimated.getStates()[0];
204
205
206 final ModifierGradientConverter converter = new ModifierGradientConverter(state, 6, new FrameAlignedProvider(state.getFrame()));
207 final FieldSpacecraftState<Gradient> gState = converter.getState(tropoModel);
208 final Gradient[] gParameters = converter.getParametersAtStateDate(gState, tropoModel);
209 final Gradient gDelay = phaseErrorTroposphericModel(station, gState, gParameters, measurement.getWavelength());
210 final double[] derivatives = gDelay.getGradient();
211
212
213 final double[][] djac = phaseErrorJacobianState(derivatives);
214 final double[][] stateDerivatives = estimated.getStateDerivatives(0);
215 for (int irow = 0; irow < stateDerivatives.length; ++irow) {
216 for (int jcol = 0; jcol < stateDerivatives[0].length; ++jcol) {
217 stateDerivatives[irow][jcol] += djac[irow][jcol];
218 }
219 }
220 estimated.setStateDerivatives(0, stateDerivatives);
221
222
223
224 int index = 0;
225 for (final ParameterDriver driver : getParametersDrivers()) {
226 if (driver.isSelected()) {
227 for (Span<String> span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
228
229
230 double parameterDerivative = estimated.getParameterDerivatives(driver, span.getStart())[0];
231 final double[] dDelaydP = phaseErrorParameterDerivative(derivatives, converter.getFreeStateParameters());
232 parameterDerivative += dDelaydP[index];
233 estimated.setParameterDerivatives(driver, span.getStart(), parameterDerivative);
234 index = index + 1;
235 }
236 }
237 }
238
239
240 for (final ParameterDriver driver : Arrays.asList(station.getClockOffsetDriver(),
241 station.getEastOffsetDriver(),
242 station.getNorthOffsetDriver(),
243 station.getZenithOffsetDriver())) {
244 if (driver.isSelected()) {
245 for (Span<String> span = driver.getNamesSpanMap().getFirstSpan(); span != null; span = span.next()) {
246
247 double parameterDerivative = estimated.getParameterDerivatives(driver, span.getStart())[0];
248 parameterDerivative += phaseErrorParameterDerivative(station, driver, state, measurement.getWavelength());
249 estimated.setParameterDerivatives(driver, span.getStart(), parameterDerivative);
250 }
251 }
252 }
253
254
255 modifyWithoutDerivatives(estimated);
256
257 }
258
259 }
260