1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.models.earth.ionosphere;
18
19 import org.hipparchus.Field;
20 import org.hipparchus.CalculusFieldElement;
21 import org.hipparchus.util.FastMath;
22 import org.hipparchus.util.FieldSinCos;
23 import org.hipparchus.util.MathArrays;
24 import org.hipparchus.util.SinCos;
25 import org.orekit.time.DateComponents;
26 import org.orekit.time.DateTimeComponents;
27 import org.orekit.time.TimeComponents;
28
29
30
31
32
33
34
35
36
37
38
39 class FieldNeQuickParameters <T extends CalculusFieldElement<T>> {
40
41
42 private static final double X0 = 86.23292796211615;
43
44
45 private final T nmF2;
46
47
48 private final T hmF2;
49
50
51 private final T hmF1;
52
53
54 private final T hmE;
55
56
57 private final T b2Bot;
58
59
60 private final T b1Top;
61
62
63 private final T b1Bot;
64
65
66 private final T beTop;
67
68
69 private final T beBot;
70
71
72 private final T h0;
73
74
75 private final T[] amplitudes;
76
77
78
79
80
81
82
83
84
85
86
87
88 FieldNeQuickParameters(final Field<T> field, final DateTimeComponents dateTime, final double[][][] f2,
89 final double[][][] fm3, final T latitude, final T longitude,
90 final double[] alpha, final double[][] modipGrip) {
91
92
93 final T zero = field.getZero();
94
95
96 final T modip = computeMODIP(latitude, longitude, modipGrip);
97
98 final T az = computeAz(modip, alpha);
99
100 final T azr = FastMath.sqrt(az.subtract(63.7).multiply(1123.6).add(167273.0)).subtract(408.99);
101
102 final DateComponents date = dateTime.getDate();
103 final TimeComponents time = dateTime.getTime();
104
105 final double hours = time.getSecondsInUTCDay() / 3600.0;
106
107 final T xeff = computeEffectiveSolarAngle(date.getMonth(), hours, latitude, longitude);
108
109
110
111 final T[][] af2 = MathArrays.buildArray(field, 76, 13);
112 for (int j = 0; j < 76; j++) {
113 for (int k = 0; k < 13; k++ ) {
114 af2[j][k] = azr.multiply(0.01).negate().add(1.0).multiply(f2[0][j][k]).add(azr.multiply(0.01).multiply(f2[1][j][k]));
115 }
116 }
117
118
119 final T[][] am3 = MathArrays.buildArray(field, 49, 9);
120 for (int j = 0; j < 49; j++) {
121 for (int k = 0; k < 9; k++ ) {
122 am3[j][k] = azr.multiply(0.01).negate().add(1.0).multiply(fm3[0][j][k]).add(azr.multiply(0.01).multiply(fm3[1][j][k]));
123 }
124 }
125
126
127 this.hmE = field.getZero().newInstance(120.0);
128
129 final T foE = computefoE(date.getMonth(), az, xeff, latitude);
130
131 final T nmE = foE.multiply(foE).multiply(0.124);
132
133
134 final double t = FastMath.toRadians(15 * hours) - FastMath.PI;
135
136 final T[] cf2 = computeCF2(field, af2, t);
137 final T[] cm3 = computeCm3(field, am3, t);
138
139 final T foF2 = computefoF2(field, modip, cf2, latitude, longitude);
140
141 final T mF2 = computeMF2(field, modip, cm3, latitude, longitude);
142
143 this.nmF2 = foF2.multiply(foF2).multiply(0.124);
144
145 this.hmF2 = computehmF2(field, foE, foF2, mF2);
146
147
148 final T foF1 = computefoF1(field, foE, foF2);
149
150 final T nmF1;
151 if (foF1.getReal() <= 0.0 && foE.getReal() > 2.0) {
152 final T foEpopf = foE.add(0.5);
153 nmF1 = foEpopf.multiply(foEpopf).multiply(0.124);
154 } else {
155 nmF1 = foF1.multiply(foF1).multiply(0.124);
156 }
157
158 this.hmF1 = hmF2.add(hmE).multiply(0.5);
159
160
161 final T a = clipExp(FastMath.log(foF2.multiply(foF2)).multiply(0.857).add(FastMath.log(mF2).multiply(2.02)).add(-3.467)).multiply(0.01);
162 this.b2Bot = nmF2.divide(a).multiply(0.385);
163 this.b1Top = hmF2.subtract(hmF1).multiply(0.3);
164 this.b1Bot = hmF1.subtract(hmE).multiply(0.5);
165 this.beTop = FastMath.max(b1Bot, zero.newInstance(7.0));
166 this.beBot = zero.newInstance(5.0);
167
168
169 this.amplitudes = computeLayerAmplitudes(field, nmE, nmF1, foF1);
170
171
172 this.h0 = computeH0(field, date.getMonth(), azr);
173 }
174
175
176
177
178
179 public T getNmF2() {
180 return nmF2;
181 }
182
183
184
185
186
187 public T getHmF2() {
188 return hmF2;
189 }
190
191
192
193
194
195 public T getHmF1() {
196 return hmF1;
197 }
198
199
200
201
202
203 public T getHmE() {
204 return hmE;
205 }
206
207
208
209
210
211 public T getB2Bot() {
212 return b2Bot;
213 }
214
215
216
217
218
219 public T getB1Top() {
220 return b1Top;
221 }
222
223
224
225
226
227 public T getB1Bot() {
228 return b1Bot;
229 }
230
231
232
233
234
235 public T getBEBot() {
236 return beBot;
237 }
238
239
240
241
242
243 public T getBETop() {
244 return beTop;
245 }
246
247
248
249
250
251
252
253
254
255
256
257
258 public T[] getLayerAmplitudes() {
259 return amplitudes.clone();
260 }
261
262
263
264
265
266 public T getH0() {
267 return h0;
268 }
269
270
271
272
273
274
275
276
277
278
279 private T computeMODIP(final T lat, final T lon, final double[][] stModip) {
280
281
282 final T zero = lat.getField().getZero();
283
284
285 final T latitude = FastMath.toDegrees(lat);
286 final T longitude = FastMath.toDegrees(lon);
287
288
289 if (latitude.getReal() == 90.0 || latitude.getReal() == -90.0) {
290 return latitude;
291 }
292
293
294 final int lF = (int) ((longitude.getReal() + 180) * 0.1);
295 int l = lF - 2;
296 if (l < -2) {
297 l += 36;
298 } else if (l > 33) {
299 l -= 36;
300 }
301
302
303 final T a = latitude.add(90).multiply(0.2).add(1.0);
304 final T aF = FastMath.floor(a);
305
306 final T x = a.subtract(aF);
307
308 final int i = (int) aF.getReal() - 2;
309
310
311 final T z1 = interpolate(zero.add(stModip[i + 1][l + 2]), zero.add(stModip[i + 2][l + 2]),
312 zero.add(stModip[i + 3][l + 2]), zero.add(stModip[i + 4][l + 2]), x);
313 final T z2 = interpolate(zero.add(stModip[i + 1][l + 3]), zero.add(stModip[i + 2][l + 3]),
314 zero.add(stModip[i + 3][l + 3]), zero.add(stModip[i + 4][l + 3]), x);
315 final T z3 = interpolate(zero.add(stModip[i + 1][l + 4]), zero.add(stModip[i + 2][l + 4]),
316 zero.add(stModip[i + 3][l + 4]), zero.add(stModip[i + 4][l + 4]), x);
317 final T z4 = interpolate(zero.add(stModip[i + 1][l + 5]), zero.add(stModip[i + 2][l + 5]),
318 zero.add(stModip[i + 3][l + 5]), zero.add(stModip[i + 4][l + 5]), x);
319
320
321 final T b = longitude.add(180).multiply(0.1);
322 final T bF = FastMath.floor(b);
323 final T y = b.subtract(bF);
324
325
326 final T modip = interpolate(z1, z2, z3, z4, y);
327
328 return modip;
329 }
330
331
332
333
334
335
336
337
338
339
340 private T computeAz(final T modip, final double[] alpha) {
341
342 final Field<T> field = modip.getField();
343
344 final T zero = field.getZero();
345
346 if (alpha[0] == 0.0 && alpha[1] == 0.0 && alpha[2] == 0.0) {
347 return zero.newInstance(63.7);
348 }
349
350 T az = modip.multiply(alpha[2]).add(alpha[1]).multiply(modip).add(alpha[0]);
351
352 az = FastMath.max(zero, az);
353
354 az = FastMath.min(zero.newInstance(400.0), az);
355 return az;
356 }
357
358
359
360
361
362
363
364
365
366
367
368
369
370 private T computeEffectiveSolarAngle(final int month,
371 final double hours,
372 final T latitude,
373 final T longitude) {
374
375 final T zero = latitude.getField().getZero();
376
377 final T lt = longitude.divide(FastMath.toRadians(15.0)).add(hours);
378
379 final double dy = 30.5 * month - 15.0;
380
381 final double t = dy + (18 - hours) / 24;
382
383 final double am = FastMath.toRadians(0.9856 * t - 3.289);
384 final double al = am + FastMath.toRadians(1.916 * FastMath.sin(am) + 0.020 * FastMath.sin(2.0 * am) + 282.634);
385
386 final double sDec = 0.39782 * FastMath.sin(al);
387 final double cDec = FastMath.sqrt(1. - sDec * sDec);
388
389 final FieldSinCos<T> scLat = FastMath.sinCos(latitude);
390 final T coef = lt.negate().add(12.0).multiply(FastMath.PI / 12);
391 final T cZenith = scLat.sin().multiply(sDec).add(scLat.cos().multiply(cDec).multiply(FastMath.cos(coef)));
392 final T angle = FastMath.atan2(FastMath.sqrt(cZenith.multiply(cZenith).negate().add(1.0)), cZenith);
393 final T x = FastMath.toDegrees(angle);
394
395 final T xeff = join(clipExp(x.multiply(0.2).negate().add(20.0)).multiply(0.24).negate().add(90.0), x,
396 zero.newInstance(12.0), x.subtract(X0));
397 return FastMath.toRadians(xeff);
398 }
399
400
401
402
403
404
405
406
407
408 private T computefoE(final int month, final T az,
409 final T xeff, final T latitude) {
410
411 final T lat = FastMath.toDegrees(latitude);
412
413 final T sqAz = FastMath.sqrt(az);
414
415 final int seas;
416 if (month == 1 || month == 2 || month == 11 || month == 12) {
417 seas = -1;
418 } else if (month == 3 || month == 4 || month == 9 || month == 10) {
419 seas = 0;
420 } else {
421 seas = 1;
422 }
423
424 final T ee = clipExp(lat.multiply(0.3));
425 final T seasp = ee.subtract(1.0).divide(ee.add(1.0)).multiply(seas);
426
427 final T coef = seasp.multiply(0.019).negate().add(1.112);
428 final T foE = FastMath.sqrt(coef .multiply(coef).multiply(sqAz).multiply(FastMath.cos(xeff).pow(0.6)).add(0.49));
429 return foE;
430 }
431
432
433
434
435
436
437
438
439
440 private T computehmF2(final Field<T> field, final T foE, final T foF2, final T mF2) {
441
442 final T zero = field.getZero();
443
444 final T fo = foF2.divide(foE);
445 final T ratio = join(fo, zero.newInstance(1.75), zero.newInstance(20.0), fo.subtract(1.75));
446
447
448 T deltaM = zero.subtract(0.012);
449 if (foE.getReal() >= 1e-30) {
450 deltaM = deltaM.add(ratio.subtract(1.215).divide(0.253).reciprocal());
451 }
452
453
454 final T mF2Sq = mF2.square();
455 final T temp = FastMath.sqrt(mF2Sq.multiply(0.0196).add(1.0).divide(mF2Sq.multiply(1.2967).subtract(1.0)));
456 final T height = mF2.multiply(1490.0).multiply(temp).divide(mF2.add(deltaM)).subtract(176.0);
457 return height;
458 }
459
460
461
462
463
464
465
466
467 private T[] computeCF2(final Field<T> field, final T[][] af2, final double t) {
468
469 final T[] cf2 = MathArrays.buildArray(field, 76);
470 for (int i = 0; i < cf2.length; i++) {
471 T sum = field.getZero();
472 for (int k = 0; k < 6; k++) {
473 final SinCos sc = FastMath.sinCos((k + 1) * t);
474 sum = sum.add(af2[i][2 * k + 1].multiply(sc.sin()).add(af2[i][2 * (k + 1)].multiply(sc.cos())));
475 }
476 cf2[i] = af2[i][0].add(sum);
477 }
478 return cf2;
479 }
480
481
482
483
484
485
486
487
488 private T[] computeCm3(final Field<T> field, final T[][] am3, final double t) {
489
490 final T[] cm3 = MathArrays.buildArray(field, 49);
491 for (int i = 0; i < cm3.length; i++) {
492 T sum = field.getZero();
493 for (int k = 0; k < 4; k++) {
494 final SinCos sc = FastMath.sinCos((k + 1) * t);
495 sum = sum.add(am3[i][2 * k + 1].multiply(sc.sin()).add(am3[i][2 * (k + 1)].multiply(sc.cos())));
496 }
497 cm3[i] = am3[i][0].add(sum);
498 }
499 return cm3;
500 }
501
502
503
504
505
506
507
508
509
510
511 private T computefoF2(final Field<T> field, final T modip, final T[] cf2,
512 final T latitude, final T longitude) {
513
514
515 final T one = field.getOne();
516
517
518 final int[] q = new int[] {
519 12, 12, 9, 5, 2, 1, 1, 1, 1
520 };
521
522
523 final T[] g = MathArrays.buildArray(field, cf2.length);
524 g[0] = one;
525
526
527 final T sinMODIP = FastMath.sin(FastMath.toRadians(modip));
528 final T[] m = MathArrays.buildArray(field, 12);
529 m[0] = one;
530 for (int i = 1; i < q[0]; i++) {
531 m[i] = sinMODIP.multiply(m[i - 1]);
532 g[i] = m[i];
533 }
534
535
536 final T cosLat = FastMath.cos(latitude);
537 final T[] p = MathArrays.buildArray(field, 8);
538 p[0] = cosLat;
539 for (int n = 2; n < 9; n++) {
540 p[n - 1] = cosLat.multiply(p[n - 2]);
541 }
542
543
544 int index = 12;
545 for (int i = 1; i < q.length; i++) {
546 final FieldSinCos<T> sc = FastMath.sinCos(longitude.multiply(i));
547 for (int j = 0; j < q[i]; j++) {
548 g[index++] = m[j].multiply(p[i - 1]).multiply(sc.cos());
549 g[index++] = m[j].multiply(p[i - 1]).multiply(sc.sin());
550 }
551 }
552
553
554 final T frequency = one.linearCombination(g, cf2);
555 return frequency;
556 }
557
558
559
560
561
562
563
564
565
566
567 private T computeMF2(final Field<T> field, final T modip, final T[] cm3,
568 final T latitude, final T longitude) {
569
570
571 final T one = field.getOne();
572
573 final int[] r = new int[] {
574 7, 8, 6, 3, 2, 1, 1
575 };
576
577
578 final T[] g = MathArrays.buildArray(field, cm3.length);
579 g[0] = one;
580
581
582 final T sinMODIP = FastMath.sin(FastMath.toRadians(modip));
583 final T[] m = MathArrays.buildArray(field, 12);
584 m[0] = one;
585 for (int i = 1; i < 12; i++) {
586 m[i] = sinMODIP.multiply(m[i - 1]);
587 if (i < 7) {
588 g[i] = m[i];
589 }
590 }
591
592
593 final T cosLat = FastMath.cos(latitude);
594 final T[] p = MathArrays.buildArray(field, 8);
595 p[0] = cosLat;
596 for (int n = 2; n < 9; n++) {
597 p[n - 1] = cosLat.multiply(p[n - 2]);
598 }
599
600
601 int index = 7;
602 for (int i = 1; i < r.length; i++) {
603 final FieldSinCos<T> sc = FastMath.sinCos(longitude.multiply(i));
604 for (int j = 0; j < r[i]; j++) {
605 g[index++] = m[j].multiply(p[i - 1]).multiply(sc.cos());
606 g[index++] = m[j].multiply(p[i - 1]).multiply(sc.sin());
607 }
608 }
609
610
611 final T m3000 = one.linearCombination(g, cm3);
612 return m3000;
613 }
614
615
616
617
618
619
620
621
622
623
624
625
626 private T computefoF1(final Field<T> field, final T foE, final T foF2) {
627 final T zero = field.getZero();
628 final T temp = join(foE.multiply(1.4), zero, zero.newInstance(1000.0), foE.subtract(2.0));
629 final T temp2 = join(zero, temp, zero.newInstance(1000.0), foE.subtract(temp));
630 final T value = join(temp2, temp2.multiply(0.85), zero.newInstance(60.0), foF2.multiply(0.85).subtract(temp2));
631 if (value.getReal() < 1.0E-6) {
632 return zero;
633 } else {
634 return value;
635 }
636 }
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654 private T[] computeLayerAmplitudes(final Field<T> field, final T nmE, final T nmF1, final T foF1) {
655
656 final T zero = field.getZero();
657
658
659 final T[] amplitude = MathArrays.buildArray(field, 3);
660
661
662 final T a1 = nmF2.multiply(4.0);
663 amplitude[0] = a1;
664
665
666 if (foF1.getReal() < 0.5) {
667 amplitude[1] = zero;
668 amplitude[2] = nmE.subtract(epst(a1, hmF2, b2Bot, hmE)).multiply(4.0);
669 } else {
670 T a2a = zero;
671 T a3a = nmE.multiply(4.0);
672 for (int i = 0; i < 5; i++) {
673 a2a = nmF1.subtract(epst(a1, hmF2, b2Bot, hmF1)).subtract(epst(a3a, hmE, beTop, hmF1)).multiply(4.0);
674 a2a = join(a2a, nmF1.multiply(0.8), field.getOne(), a2a.subtract(nmF1.multiply(0.8)));
675 a3a = nmE.subtract(epst(a2a, hmF1, b1Bot, hmE)).subtract(epst(a1, hmF2, b2Bot, hmE)).multiply(4.0);
676 }
677 amplitude[1] = a2a;
678 amplitude[2] = join(a3a, zero.newInstance(0.05), zero.newInstance(60.0), a3a.subtract(0.005));
679 }
680
681 return amplitude;
682 }
683
684
685
686
687
688
689
690
691
692 private T computeH0(final Field<T> field, final int month, final T azr) {
693
694
695 final T one = field.getOne();
696
697
698 final T ka;
699 if (month > 3 && month < 10) {
700
701 ka = azr.multiply(0.014).add(hmF2.multiply(0.008)).negate().add(6.705);
702 } else {
703
704 final T ratio = hmF2.divide(b2Bot);
705 ka = ratio.multiply(ratio).multiply(0.097).add(nmF2.multiply(0.153)).add(-7.77);
706 }
707
708
709 T kb = join(ka, one.newInstance(2.0), one, ka.subtract(2.0));
710 kb = join(one.newInstance(8.0), kb, one, kb.subtract(8.0));
711
712
713 final T hA = kb.multiply(b2Bot);
714
715
716 final T x = hA.subtract(150.0).multiply(0.01);
717 final T v = x.multiply(0.041163).subtract(0.183981).multiply(x).add(1.424472);
718
719
720 final T h = hA.divide(v);
721 return h;
722 }
723
724
725
726
727
728
729
730
731
732
733 private T clipExp(final T power) {
734 final T zero = power.getField().getZero();
735 if (power.getReal() > 80.0) {
736 return zero.newInstance(5.5406E34);
737 } else if (power.getReal() < -80) {
738 return zero.newInstance(1.8049E-35);
739 } else {
740 return FastMath.exp(power);
741 }
742 }
743
744
745
746
747
748
749
750
751
752
753
754
755 private T interpolate(final T z1, final T z2,
756 final T z3, final T z4,
757 final T x) {
758
759 if (FastMath.abs(2.0 * x.getReal()) < 1e-10) {
760 return z2;
761 }
762
763 final T delta = x.multiply(2.0).subtract(1.0);
764 final T g1 = z3.add(z2);
765 final T g2 = z3.subtract(z2);
766 final T g3 = z4.add(z1);
767 final T g4 = z4.subtract(z1).divide(3.0);
768 final T a0 = g1.multiply(9.0).subtract(g3);
769 final T a1 = g2.multiply(9.0).subtract(g4);
770 final T a2 = g3.subtract(g1);
771 final T a3 = g4.subtract(g2);
772 final T zx = delta.multiply(a3).add(a2).multiply(delta).add(a1).multiply(delta).add(a0).multiply(0.0625);
773
774 return zx;
775 }
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790 private T join(final T dF1, final T dF2,
791 final T dA, final T dX) {
792 final T ee = clipExp(dA.multiply(dX));
793 return dF1.multiply(ee).add(dF2).divide(ee.add(1.0));
794 }
795
796
797
798
799
800
801
802
803
804
805
806
807
808 private T epst(final T x, final T y,
809 final T z, final T w) {
810 final T ex = clipExp(w.subtract(y).divide(z));
811 final T opex = ex.add(1.0);
812 final T epst = x.multiply(ex).divide(opex.multiply(opex));
813 return epst;
814 }
815
816 }