1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.models.earth.troposphere;
18
19 import java.util.Collections;
20 import java.util.List;
21
22 import org.hipparchus.CalculusFieldElement;
23 import org.hipparchus.Field;
24 import org.hipparchus.util.FastMath;
25 import org.hipparchus.util.MathArrays;
26 import org.orekit.bodies.FieldGeodeticPoint;
27 import org.orekit.bodies.GeodeticPoint;
28 import org.orekit.models.earth.weather.ConstantPressureTemperatureHumidityProvider;
29 import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity;
30 import org.orekit.models.earth.weather.PressureTemperatureHumidity;
31 import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider;
32 import org.orekit.models.earth.weather.water.CIPM2007;
33 import org.orekit.time.AbsoluteDate;
34 import org.orekit.time.FieldAbsoluteDate;
35 import org.orekit.utils.FieldTrackingCoordinates;
36 import org.orekit.utils.ParameterDriver;
37 import org.orekit.utils.TrackingCoordinates;
38 import org.orekit.utils.units.Unit;
39 import org.orekit.utils.units.UnitsConverter;
40
41
42
43
44
45
46
47
48
49
50
51
52 public class MendesPavlisModel implements TroposphericModel, TroposphereMappingFunction {
53
54
55 private static final double[] K_COEFFICIENTS = {
56 238.0185, 19990.975, 57.362, 579.55174
57 };
58
59
60 private static final double[] W_COEFFICIENTS = {
61 295.235, 2.6422, -0.032380, 0.004028
62 };
63
64
65 private static final double[][] A_COEFFICIENTS = {
66 {12100.8e-7, 1729.5e-9, 319.1e-7, -1847.8e-11},
67 {30496.5e-7, 234.4e-8, -103.5e-6, -185.6e-10},
68 {6877.7e-5, 197.2e-7, -345.8e-5, 106.0e-9}
69 };
70
71
72 private static final double C02 = 0.99995995;
73
74
75 private final double fLambdaH;
76
77
78 private final double fLambdaNH;
79
80
81 private final PressureTemperatureHumidityProvider pthProvider;
82
83
84
85
86
87
88
89
90
91 public MendesPavlisModel(final PressureTemperatureHumidityProvider pthProvider,
92 final double lambda, final Unit lambdaUnits) {
93 this.pthProvider = pthProvider;
94
95
96 final double lambdaMicrometer = new UnitsConverter(lambdaUnits, TroposphericModelUtils.MICRO_M).convert(lambda);
97 final double sigma = 1.0 / lambdaMicrometer;
98 final double sigma2 = sigma * sigma;
99 final double coef1 = K_COEFFICIENTS[0] + sigma2;
100 final double coef2 = K_COEFFICIENTS[0] - sigma2;
101 final double coef3 = K_COEFFICIENTS[2] + sigma2;
102 final double coef4 = K_COEFFICIENTS[2] - sigma2;
103 final double frac1 = coef1 / (coef2 * coef2);
104 final double frac2 = coef3 / (coef4 * coef4);
105 fLambdaH = 0.01 * (K_COEFFICIENTS[1] * frac1 + K_COEFFICIENTS[3] * frac2) * C02;
106
107
108 final double sigma4 = sigma2 * sigma2;
109 final double sigma6 = sigma4 * sigma2;
110 final double w1s2 = 3 * W_COEFFICIENTS[1] * sigma2;
111 final double w2s4 = 5 * W_COEFFICIENTS[2] * sigma4;
112 final double w3s6 = 7 * W_COEFFICIENTS[3] * sigma6;
113
114 fLambdaNH = 0.003101 * (W_COEFFICIENTS[0] + w1s2 + w2s4 + w3s6);
115
116 }
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134 public static MendesPavlisModel getStandardModel(final double lambda, final Unit lambdaUnits) {
135 final double h = 0;
136 final double p = TroposphericModelUtils.HECTO_PASCAL.toSI(1013.25);
137 final double t = 273.15 + 18;
138 final double rh = 0.5;
139 final PressureTemperatureHumidity pth = new PressureTemperatureHumidity(h, p, t,
140 new CIPM2007().waterVaporPressure(p, t, rh),
141 Double.NaN,
142 Double.NaN);
143 return new MendesPavlisModel(new ConstantPressureTemperatureHumidityProvider(pth),
144 lambda, lambdaUnits);
145 }
146
147
148 @Override
149 public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates,
150 final GeodeticPoint point,
151 final double[] parameters, final AbsoluteDate date) {
152
153 final double[] zenithDelay = computeZenithDelay(point, date);
154
155 final double[] mappingFunction = mappingFactors(trackingCoordinates, point, date);
156
157 return new TroposphericDelay(zenithDelay[0],
158 zenithDelay[1],
159 zenithDelay[0] * mappingFunction[0],
160 zenithDelay[1] * mappingFunction[1]);
161 }
162
163
164 @Override
165 public <T extends CalculusFieldElement<T>> FieldTroposphericDelay<T> pathDelay(final FieldTrackingCoordinates<T> trackingCoordinates,
166 final FieldGeodeticPoint<T> point,
167 final T[] parameters, final FieldAbsoluteDate<T> date) {
168
169 final T[] zenithDelay = computeZenithDelay(point, date);
170
171 final T[] mappingFunction = mappingFactors(trackingCoordinates, point, date);
172
173 return new FieldTroposphericDelay<>(zenithDelay[0],
174 zenithDelay[1],
175 zenithDelay[0].multiply(mappingFunction[0]),
176 zenithDelay[1].multiply(mappingFunction[1]));
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191 public double[] computeZenithDelay(final GeodeticPoint point, final AbsoluteDate date) {
192
193 final PressureTemperatureHumidity pth = pthProvider.getWeatherParameters(point, date);
194 final double fsite = getSiteFunctionValue(point);
195
196
197 final double[] delay = new double[2];
198
199
200
201 delay[0] = pth.getPressure() * 0.00002416579 * (fLambdaH / fsite);
202
203
204
205 delay[1] = 0.000001 * (5.316 * fLambdaNH - 3.759 * fLambdaH) * (pth.getWaterVaporPressure() / fsite);
206
207 return delay;
208 }
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223 public <T extends CalculusFieldElement<T>> T[] computeZenithDelay(final FieldGeodeticPoint<T> point,
224 final FieldAbsoluteDate<T> date) {
225
226 final FieldPressureTemperatureHumidity<T> pth = pthProvider.getWeatherParameters(point, date);
227
228 final T fsite = getSiteFunctionValue(point);
229
230
231 final T[] delay = MathArrays.buildArray(date.getField(), 2);
232
233
234
235 delay[0] = pth.getPressure().multiply(0.00002416579).multiply(fLambdaH).divide(fsite);
236
237
238
239 delay[1] = pth.getWaterVaporPressure().divide(fsite).
240 multiply(0.000001 * (5.316 * fLambdaNH - 3.759 * fLambdaH));
241
242 return delay;
243
244 }
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259 @Override
260 public double[] mappingFactors(final TrackingCoordinates trackingCoordinates,
261 final GeodeticPoint point,
262 final AbsoluteDate date) {
263 final double sinE = FastMath.sin(trackingCoordinates.getElevation());
264
265 final PressureTemperatureHumidity pth = pthProvider.getWeatherParameters(point, date);
266 final double T2degree = pth.getTemperature() - 273.15;
267
268
269 final double a1 = computeMFCoeffient(A_COEFFICIENTS[0][0], A_COEFFICIENTS[0][1],
270 A_COEFFICIENTS[0][2], A_COEFFICIENTS[0][3],
271 T2degree, point);
272 final double a2 = computeMFCoeffient(A_COEFFICIENTS[1][0], A_COEFFICIENTS[1][1],
273 A_COEFFICIENTS[1][2], A_COEFFICIENTS[1][3],
274 T2degree, point);
275 final double a3 = computeMFCoeffient(A_COEFFICIENTS[2][0], A_COEFFICIENTS[2][1],
276 A_COEFFICIENTS[2][2], A_COEFFICIENTS[2][3],
277 T2degree, point);
278
279
280 final double numMP = 1 + a1 / (1 + a2 / (1 + a3));
281
282 final double denMP = sinE + a1 / (sinE + a2 / (sinE + a3));
283
284 final double factor = numMP / denMP;
285
286 return new double[] {
287 factor,
288 factor
289 };
290 }
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305 @Override
306 public <T extends CalculusFieldElement<T>> T[] mappingFactors(final FieldTrackingCoordinates<T> trackingCoordinates,
307 final FieldGeodeticPoint<T> point,
308 final FieldAbsoluteDate<T> date) {
309 final Field<T> field = date.getField();
310
311 final T sinE = FastMath.sin(trackingCoordinates.getElevation());
312
313 final FieldPressureTemperatureHumidity<T> pth = pthProvider.getWeatherParameters(point, date);
314 final T T2degree = pth.getTemperature().subtract(273.15);
315
316
317 final T a1 = computeMFCoeffient(A_COEFFICIENTS[0][0], A_COEFFICIENTS[0][1],
318 A_COEFFICIENTS[0][2], A_COEFFICIENTS[0][3],
319 T2degree, point);
320 final T a2 = computeMFCoeffient(A_COEFFICIENTS[1][0], A_COEFFICIENTS[1][1],
321 A_COEFFICIENTS[1][2], A_COEFFICIENTS[1][3],
322 T2degree, point);
323 final T a3 = computeMFCoeffient(A_COEFFICIENTS[2][0], A_COEFFICIENTS[2][1],
324 A_COEFFICIENTS[2][2], A_COEFFICIENTS[2][3],
325 T2degree, point);
326
327
328 final T numMP = a1.divide(a2.divide(a3.add(1.0)).add(1.0)).add(1.0);
329
330 final T denMP = a1.divide(a2.divide(a3.add(sinE)).add(sinE)).add(sinE);
331
332 final T factor = numMP.divide(denMP);
333
334 final T[] mapping = MathArrays.buildArray(field, 2);
335 mapping[0] = factor;
336 mapping[1] = factor;
337
338 return mapping;
339 }
340
341
342 @Override
343 public List<ParameterDriver> getParametersDrivers() {
344 return Collections.emptyList();
345 }
346
347
348
349
350
351
352 private double getSiteFunctionValue(final GeodeticPoint point) {
353 return 1. - 0.00266 * FastMath.cos(2. * point.getLatitude()) - 0.00000028 * point.getAltitude();
354 }
355
356
357
358
359
360
361
362 private <T extends CalculusFieldElement<T>> T getSiteFunctionValue(final FieldGeodeticPoint<T> point) {
363 return FastMath.cos(point.getLatitude().multiply(2.)).multiply(0.00266).add(point.getAltitude().multiply(0.00000028)).negate().add(1.);
364 }
365
366
367
368
369
370
371
372
373
374
375
376 private double computeMFCoeffient(final double a0, final double a1, final double a2, final double a3,
377 final double t, final GeodeticPoint point) {
378 return a0 + a1 * t + a2 * FastMath.cos(point.getLatitude()) + a3 * point.getAltitude();
379 }
380
381
382
383
384
385
386
387
388
389
390
391
392 private <T extends CalculusFieldElement<T>> T computeMFCoeffient(final double a0, final double a1, final double a2, final double a3,
393 final T t, final FieldGeodeticPoint<T> point) {
394 return point.getAltitude().multiply(a3).add(FastMath.cos(point.getLatitude()).multiply(a2)).add(t.multiply(a1).add(a0));
395 }
396
397 }