1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.models.earth;
18
19 import java.util.Collections;
20 import java.util.List;
21
22 import org.hipparchus.Field;
23 import org.hipparchus.RealFieldElement;
24 import org.hipparchus.util.FastMath;
25 import org.hipparchus.util.MathArrays;
26 import org.orekit.time.AbsoluteDate;
27 import org.orekit.time.DateTimeComponents;
28 import org.orekit.time.FieldAbsoluteDate;
29 import org.orekit.time.TimeScalesFactory;
30 import org.orekit.utils.ParameterDriver;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 public class ViennaOneModel implements DiscreteTroposphericModel {
48
49
50 private static final long serialVersionUID = 2584920506094034855L;
51
52
53 private final double[] coefficientsA;
54
55
56 private final double[] zenithDelay;
57
58
59 private final double latitude;
60
61
62
63
64
65
66 public ViennaOneModel(final double[] coefficientA, final double[] zenithDelay,
67 final double latitude) {
68 this.coefficientsA = coefficientA.clone();
69 this.zenithDelay = zenithDelay.clone();
70 this.latitude = latitude;
71 }
72
73
74 @Override
75 public double pathDelay(final double elevation, final double height,
76 final double[] parameters, final AbsoluteDate date) {
77
78 final double[] delays = computeZenithDelay(height, parameters, date);
79
80 final double[] mappingFunction = mappingFactors(elevation, height, parameters, date);
81
82 return delays[0] * mappingFunction[0] + delays[1] * mappingFunction[1];
83 }
84
85
86 @Override
87 public <T extends RealFieldElement<T>> T pathDelay(final T elevation, final T height,
88 final T[] parameters, final FieldAbsoluteDate<T> date) {
89
90 final T[] delays = computeZenithDelay(height, parameters, date);
91
92 final T[] mappingFunction = mappingFactors(elevation, height, parameters, date);
93
94 return delays[0].multiply(mappingFunction[0]).add(delays[1].multiply(mappingFunction[1]));
95 }
96
97
98 @Override
99 public double[] computeZenithDelay(final double height, final double[] parameters, final AbsoluteDate date) {
100 return zenithDelay;
101 }
102
103
104 @Override
105 public <T extends RealFieldElement<T>> T[] computeZenithDelay(final T height, final T[] parameters,
106 final FieldAbsoluteDate<T> date) {
107 final Field<T> field = height.getField();
108 final T zero = field.getZero();
109 final T[] delays = MathArrays.buildArray(field, 2);
110 delays[0] = zero.add(zenithDelay[0]);
111 delays[1] = zero.add(zenithDelay[1]);
112 return delays;
113 }
114
115
116 @Override
117 public double[] mappingFactors(final double elevation, final double height,
118 final double[] parameters, final AbsoluteDate date) {
119
120 final DateTimeComponents dtc = date.getComponents(TimeScalesFactory.getUTC());
121 final int dofyear = dtc.getDate().getDayOfYear();
122
123
124 final double bh = 0.0029;
125 final double c0h = 0.062;
126 final double c10h;
127 final double c11h;
128 final double psi;
129
130
131 if (FastMath.sin(latitude) > 0) {
132 c10h = 0.001;
133 c11h = 0.005;
134 psi = 0;
135 } else {
136 c10h = 0.002;
137 c11h = 0.007;
138 psi = FastMath.PI;
139 }
140
141
142 double t0 = 28;
143 if (latitude < 0) {
144
145 t0 += 183;
146 }
147
148 final double coef = ((dofyear - t0) / 365) * 2 * FastMath.PI + psi;
149 final double ch = c0h + ((FastMath.cos(coef) + 1) * (c11h / 2) + c10h) * (1 - FastMath.cos(latitude));
150
151
152 final double bw = 0.00146;
153 final double cw = 0.04391;
154
155 final double[] function = new double[2];
156 function[0] = computeFunction(coefficientsA[0], bh, ch, elevation);
157 function[1] = computeFunction(coefficientsA[1], bw, cw, elevation);
158
159
160 final double correction = computeHeightCorrection(elevation, height);
161 function[0] = function[0] + correction;
162
163 return function;
164 }
165
166
167 @Override
168 public <T extends RealFieldElement<T>> T[] mappingFactors(final T elevation, final T height,
169 final T[] parameters, final FieldAbsoluteDate<T> date) {
170 final Field<T> field = date.getField();
171 final T zero = field.getZero();
172
173
174 final DateTimeComponents dtc = date.getComponents(TimeScalesFactory.getUTC());
175 final int dofyear = dtc.getDate().getDayOfYear();
176
177
178 final T bh = zero.add(0.0029);
179 final T c0h = zero.add(0.062);
180 final T c10h;
181 final T c11h;
182 final T psi;
183
184
185 if (FastMath.sin(latitude) > 0) {
186 c10h = zero.add(0.001);
187 c11h = zero.add(0.005);
188 psi = zero;
189 } else {
190 c10h = zero.add(0.002);
191 c11h = zero.add(0.007);
192 psi = zero.add(FastMath.PI);
193 }
194
195
196
197 double t0 = 28;
198 if (latitude < 0) {
199
200 t0 += 183;
201 }
202 final T coef = psi.add(((dofyear - t0) / 365) * 2 * FastMath.PI);
203 final T ch = c11h.divide(2.0).multiply(FastMath.cos(coef).add(1.0)).add(c10h).multiply(1 - FastMath.cos(latitude)).add(c0h);
204
205
206 final T bw = zero.add(0.00146);
207 final T cw = zero.add(0.04391);
208
209 final T[] function = MathArrays.buildArray(field, 2);
210 function[0] = computeFunction(zero.add(coefficientsA[0]), bh, ch, elevation);
211 function[1] = computeFunction(zero.add(coefficientsA[1]), bw, cw, elevation);
212
213
214 final T correction = computeHeightCorrection(elevation, height, field);
215 function[0] = function[0].add(correction);
216
217 return function;
218 }
219
220
221 @Override
222 public List<ParameterDriver> getParametersDrivers() {
223 return Collections.emptyList();
224 }
225
226
227
228
229
230
231
232
233 private double computeFunction(final double a, final double b, final double c, final double elevation) {
234 final double sinE = FastMath.sin(elevation);
235
236 final double numMP = 1 + a / (1 + b / (1 + c));
237
238 final double denMP = sinE + a / (sinE + b / (sinE + c));
239
240 final double felevation = numMP / denMP;
241
242 return felevation;
243 }
244
245
246
247
248
249
250
251
252
253 private <T extends RealFieldElement<T>> T computeFunction(final T a, final T b, final T c, final T elevation) {
254 final T sinE = FastMath.sin(elevation);
255
256 final T numMP = a.divide(b.divide(c.add(1.0)).add(1.0)).add(1.0);
257
258 final T denMP = a.divide(b.divide(c.add(sinE)).add(sinE)).add(sinE);
259
260 final T felevation = numMP.divide(denMP);
261
262 return felevation;
263 }
264
265
266
267
268
269
270
271
272
273
274
275
276
277 private double computeHeightCorrection(final double elevation, final double height) {
278 final double fixedHeight = FastMath.max(0.0, height);
279 final double sinE = FastMath.sin(elevation);
280
281 final double function = computeFunction(2.53e-5, 5.49e-3, 1.14e-3, elevation);
282
283 final double dmdh = (1 / sinE) - function;
284
285 final double correction = dmdh * (fixedHeight / 1000);
286 return correction;
287 }
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303 private <T extends RealFieldElement<T>> T computeHeightCorrection(final T elevation, final T height, final Field<T> field) {
304 final T zero = field.getZero();
305 final T fixedHeight = FastMath.max(zero, height);
306 final T sinE = FastMath.sin(elevation);
307
308 final T function = computeFunction(zero.add(2.53e-5), zero.add(5.49e-3), zero.add(1.14e-3), elevation);
309
310 final T dmdh = sinE.reciprocal().subtract(function);
311
312 final T correction = dmdh.multiply(fixedHeight.divide(1000.0));
313 return correction;
314 }
315
316 }