46 #include "physical_constants.h"
58 static const float CoeffFile[91][6] = COEFFS_FROM_NASA;
82 Ellip.
fla = WGS84_FLATTENING;
83 Ellip.
eps = WGS84_EPS;
84 Ellip.
epssq = WGS84_EPS2;
85 Ellip.
re = WGS84_RADIUS_EARTH_KM;
91 MagneticModel.
epoch = MAGNETIC_MODEL_EPOCH;
98 int WMM_GetMagVector(
float Lat,
float Lon,
float AltEllipsoid, uint16_t Month, uint16_t Day, uint16_t Year,
float B[3])
108 if (Lat < -90)
return -1;
109 if (Lat > 90)
return -2;
111 if (Lon < -180)
return -3;
112 if (Lon > 180)
return -4;
130 CoordGeodetic.
lambda = Lon;
131 CoordGeodetic.
phi = Lat;
149 if (
WMM_Geomag(&CoordSpherical, &CoordGeodetic, &GeoMagneticElements) < 0)
153 B[0] = GeoMagneticElements.
X * 1e-2
f;
154 B[1] = GeoMagneticElements.
Y * 1e-2
f;
155 B[2] = GeoMagneticElements.
Z * 1e-2
f;
214 if (
WMM_Summation(&LegendreFunction, &SphVariables, CoordSpherical, &MagneticResultsSph) < 0)
220 if (
WMM_SecVarSummation(&LegendreFunction, &SphVariables, CoordSpherical, &MagneticResultsSphVar) < 0)
276 float cos_lambda, sin_lambda;
279 cos_lambda = cosf(CoordSpherical->
lambda * DEG2RAD);
280 sin_lambda = sinf(CoordSpherical->
lambda * DEG2RAD);
286 for (n = 1; n <= nMax; n++)
299 for (m = 2; m <= nMax; m++)
326 float sin_phi = sinf(CoordSpherical->
phig * DEG2RAD);
328 if (nMax <= 16 || (1 - fabsf(sin_phi)) < 1.0e-10
f)
367 uint16_t m, n, index;
370 MagneticResults->
Bz = 0.0;
371 MagneticResults->
By = 0.0;
372 MagneticResults->
Bx = 0.0;
374 for (n = 1; n <= MagneticModel.
nMax; n++)
376 for (m = 0; m <= n; m++)
378 index = (n * (n + 1) / 2 + m);
384 MagneticResults->
Bz -=
388 * (
float)(n + 1) * LegendreFunction->
Pcup[index];
394 MagneticResults->
By +=
398 * (
float)(m) * LegendreFunction->
Pcup[index];
404 MagneticResults->
Bx -=
408 * LegendreFunction->
dPcup[index];
413 cos_phi = cosf(CoordSpherical->
phig * DEG2RAD);
414 if (fabsf(cos_phi) > 1.0e-10
f)
416 MagneticResults->
By = MagneticResults->
By / cos_phi;
447 uint16_t m, n, index;
452 MagneticResults->
Bz = 0.0;
453 MagneticResults->
By = 0.0;
454 MagneticResults->
Bx = 0.0;
456 for (n = 1; n <= MagneticModel.
nMaxSecVar; n++)
458 for (m = 0; m <= n; m++)
460 index = (n * (n + 1) / 2 + m);
466 MagneticResults->
Bz -=
470 * (
float)(n + 1) * LegendreFunction->
Pcup[index];
476 MagneticResults->
By +=
480 * (
float)(m) * LegendreFunction->
Pcup[index];
486 MagneticResults->
Bx -=
490 * LegendreFunction->
dPcup[index];
493 cos_phi = cosf(CoordSpherical->
phig * DEG2RAD);
494 if (fabsf(cos_phi) > 1.0e-10
f)
496 MagneticResults->
By = MagneticResults->
By / cos_phi;
541 float Psi = (CoordSpherical->
phig - CoordGeodetic->
phi) * DEG2RAD;
544 MagneticResultsGeo->
Bz = MagneticResultsSph->
Bx * sinf(Psi) + MagneticResultsSph->
Bz * cosf(Psi);
545 MagneticResultsGeo->
Bx = MagneticResultsSph->
Bx * cosf(Psi) - MagneticResultsSph->
Bz * sinf(Psi);
546 MagneticResultsGeo->
By = MagneticResultsSph->
By;
569 GeoMagneticElements->
X = MagneticResultsGeo->
Bx;
570 GeoMagneticElements->
Y = MagneticResultsGeo->
By;
571 GeoMagneticElements->
Z = MagneticResultsGeo->
Bz;
573 GeoMagneticElements->
H = sqrtf(MagneticResultsGeo->
Bx * MagneticResultsGeo->
Bx + MagneticResultsGeo->
By * MagneticResultsGeo->
By);
574 GeoMagneticElements->
F = sqrtf(GeoMagneticElements->
H * GeoMagneticElements->
H + MagneticResultsGeo->
Bz * MagneticResultsGeo->
Bz);
575 GeoMagneticElements->
Decl = atan2f(GeoMagneticElements->
Y, GeoMagneticElements->
X) * RAD2DEG;
576 GeoMagneticElements->
Incl = atan2f(GeoMagneticElements->
Z, GeoMagneticElements->
H) * RAD2DEG;
600 MagneticElements->
Xdot = MagneticVariation->
Bx;
601 MagneticElements->
Ydot = MagneticVariation->
By;
602 MagneticElements->
Zdot = MagneticVariation->
Bz;
603 MagneticElements->
Hdot = (MagneticElements->
X * MagneticElements->
Xdot + MagneticElements->
Y * MagneticElements->
Ydot) / MagneticElements->
H;
604 MagneticElements->
Fdot =
605 (MagneticElements->
X * MagneticElements->
Xdot +
606 MagneticElements->
Y * MagneticElements->
Ydot + MagneticElements->
Z * MagneticElements->
Zdot) / MagneticElements->
F;
608 RAD2DEG * (MagneticElements->
X * MagneticElements->
Ydot -
609 MagneticElements->
Y * MagneticElements->
Xdot) / (MagneticElements->
H * MagneticElements->
H);
611 RAD2DEG * (MagneticElements->
H * MagneticElements->
Zdot -
612 MagneticElements->
Z * MagneticElements->
Hdot) / (MagneticElements->
F * MagneticElements->
F);
659 uint16_t k, kstart, m, n;
660 float pm2, pm1, pmm, plm, rescalem, z, scalef;
668 float *PreSqr = pre_sqr;
671 if (fabsf(x) == 1.0
f)
679 for (n = 0; n <= 2 * nMax + 1; ++n)
680 PreSqr[n] = sqrtf((
float)(n));
684 for (n = 2; n <= nMax; n++)
687 f1[k] = (float)(2 * n - 1) / (float)(n);
688 f2[k] = (float)(n - 1) / (float)(n);
689 for (m = 1; m <= n - 2; m++)
692 f1[k] = (float)(2 * n - 1) / PreSqr[n + m] / PreSqr[n - m];
693 f2[k] = PreSqr[n - m - 1] * PreSqr[n + m - 1] / PreSqr[n + m] / PreSqr[n - m];
699 z = sqrtf((1.0
f - x) * (1.0
f + x));
712 for (n = 2; n <= nMax; n++)
715 plm = f1[k] * x * pm1 - f2[k] * pm2;
717 dPcup[k] = (float)(n) * (pm1 - x * plm) / z;
722 pmm = PreSqr[2] * scalef;
723 rescalem = 1.0f / scalef;
726 for (m = 1; m <= nMax - 1; ++m)
728 rescalem = rescalem * z;
731 kstart = kstart + m + 1;
732 pmm = pmm * PreSqr[2 * m + 1] / PreSqr[2 * m];
733 Pcup[kstart] = pmm * rescalem / PreSqr[2 * m + 1];
734 dPcup[kstart] = -((float)(m) * x * Pcup[kstart] / z);
735 pm2 = pmm / PreSqr[2 * m + 1];
738 pm1 = x * PreSqr[2 * m + 1] * pm2;
739 Pcup[k] = pm1 * rescalem;
740 dPcup[k] = ((pm2 * rescalem) * PreSqr[2 * m + 1] - x * (
float)(m + 1) * Pcup[k]) / z;
742 for (n = m + 2; n <= nMax; ++n)
745 plm = x * f1[k] * pm1 - f2[k] * pm2;
746 Pcup[k] = plm * rescalem;
747 dPcup[k] = (PreSqr[n + m] * PreSqr[n - m] * (pm1 * rescalem) - (
float)(n) * x * Pcup[k]) / z;
754 rescalem = rescalem * z;
755 kstart = kstart + m + 1;
756 pmm = pmm / PreSqr[2 * nMax];
757 Pcup[kstart] = pmm * rescalem;
758 dPcup[kstart] = -(float)(nMax) * x * Pcup[kstart] / z;
763 int WMM_PcupLow(
float *Pcup,
float *dPcup,
float x, uint16_t nMax)
789 uint16_t n, m, index, index1, index2;
791 float schmidtQuasiNorm_s[
NUMPCUP];
792 float *schmidtQuasiNorm = schmidtQuasiNorm_s;
794 if (!schmidtQuasiNorm)
803 z = sqrtf((1.0
f - x) * (1.0
f + x));
806 for (n = 1; n <= nMax; n++)
808 for (m = 0; m <= n; m++)
810 index = (n * (n + 1) / 2 + m);
813 index1 = (n - 1) * n / 2 + m - 1;
814 Pcup[index] = z * Pcup[index1];
815 dPcup[index] = z * dPcup[index1] + x * Pcup[index1];
818 if (n == 1 && m == 0)
820 index1 = (n - 1) * n / 2 + m;
821 Pcup[index] = x * Pcup[index1];
822 dPcup[index] = x * dPcup[index1] - z * Pcup[index1];
827 index1 = (n - 2) * (n - 1) / 2 + m;
828 index2 = (n - 1) * n / 2 + m;
831 Pcup[index] = x * Pcup[index2];
832 dPcup[index] = x * dPcup[index2] - z * Pcup[index2];
836 k = (float)(((n - 1) * (n - 1)) - (m * m)) / (float)((2 * n - 1)
838 Pcup[index] = x * Pcup[index2] - k * Pcup[index1];
839 dPcup[index] = x * dPcup[index2] - z * Pcup[index2] - k * dPcup[index1];
848 schmidtQuasiNorm[0] = 1.0;
849 for (n = 1; n <= nMax; n++)
851 index = (n * (n + 1) / 2);
852 index1 = (n - 1) * n / 2;
854 schmidtQuasiNorm[index] = schmidtQuasiNorm[index1] * (float)(2 * n - 1) / (float)n;
856 for (m = 1; m <= n; m++)
858 index = (n * (n + 1) / 2 + m);
859 index1 = (n * (n + 1) / 2 + m - 1);
860 schmidtQuasiNorm[index] = schmidtQuasiNorm[index1] * sqrtf((
float)((n - m + 1) * (m == 1 ? 2 : 1)) / (
float)(n + m));
869 for (n = 1; n <= nMax; n++)
871 for (m = 0; m <= n; m++)
873 index = (n * (n + 1) / 2 + m);
874 Pcup[index] = Pcup[index] * schmidtQuasiNorm[index];
875 dPcup[index] = -dPcup[index] * schmidtQuasiNorm[index];
899 float schmidtQuasiNorm1;
900 float schmidtQuasiNorm2;
901 float schmidtQuasiNorm3;
904 float *PcupS = PcupsS_s;
909 schmidtQuasiNorm1 = 1.0;
911 MagneticResults->
By = 0.0;
912 sin_phi = sinf(CoordSpherical->
phig * DEG2RAD);
914 for (n = 1; n <= MagneticModel.
nMax; n++)
921 index = (n * (n + 1) / 2 + 1);
922 schmidtQuasiNorm2 = schmidtQuasiNorm1 * (float)(2 * n - 1) / (float)n;
923 schmidtQuasiNorm3 = schmidtQuasiNorm2 * sqrtf((
float)(n * 2) / (
float)(n + 1));
924 schmidtQuasiNorm1 = schmidtQuasiNorm2;
927 PcupS[n] = PcupS[n - 1];
931 k = (float)(((n - 1) * (n - 1)) - 1) / (
float)((2 * n - 1) * (2 * n - 3));
932 PcupS[n] = sin_phi * PcupS[n - 1] - k * PcupS[n - 2];
940 MagneticResults->
By +=
944 * PcupS[n] * schmidtQuasiNorm3;
964 float schmidtQuasiNorm1;
965 float schmidtQuasiNorm2;
966 float schmidtQuasiNorm3;
969 float *PcupS = PcupsS_s;
974 schmidtQuasiNorm1 = 1.0;
976 MagneticResults->
By = 0.0;
977 sin_phi = sinf(CoordSpherical->
phig * DEG2RAD);
979 for (n = 1; n <= MagneticModel.
nMaxSecVar; n++)
981 index = (n * (n + 1) / 2 + 1);
982 schmidtQuasiNorm2 = schmidtQuasiNorm1 * (float)(2 * n - 1) / (float)n;
983 schmidtQuasiNorm3 = schmidtQuasiNorm2 * sqrtf((
float)(n * 2) / (
float)(n + 1));
984 schmidtQuasiNorm1 = schmidtQuasiNorm2;
987 PcupS[n] = PcupS[n - 1];
991 k = (float)(((n - 1) * (n - 1)) - 1) / (
float)((2 * n - 1) * (2 * n - 3));
992 PcupS[n] = sin_phi * PcupS[n - 1] - k * PcupS[n - 2];
1000 MagneticResults->
By +=
1004 * PcupS[n] * schmidtQuasiNorm3;
1018 uint16_t n, m, sum_index, a, b;
1023 b = (a * (a + 1) / 2 + a);
1024 for (n = 1; n <= MagneticModel.
nMax; n++)
1026 for (m = 0; m <= n; m++)
1029 sum_index = (n * (n + 1) / 2 + m);
1032 if (sum_index != index)
1049 uint16_t n, m, sum_index, a, b;
1053 b = (a * (a + 1) / 2 + a);
1054 for (n = 1; n <= MagneticModel.
nMax; n++)
1056 for (m = 0; m <= n; m++)
1059 sum_index = (n * (n + 1) / 2 + m);
1062 if (sum_index != index)
1093 uint16_t MonthDays[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
1094 uint16_t ExtraDay = 0;
1097 if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
1099 MonthDays[2] += ExtraDay;
1103 if (month <= 0 || month > 12)
1106 if (day <= 0 || day > MonthDays[month])
1110 for (i = 1; i <= month; i++)
1111 temp += MonthDays[i - 1];
1125 float CosLat, SinLat, rc, xp, zp;
1127 CosLat = cosf(CoordGeodetic->
phi * DEG2RAD);
1128 SinLat = sinf(CoordGeodetic->
phi * DEG2RAD);
1131 rc = Ellip.
a / sqrtf(1.0
f - Ellip.
epssq * SinLat * SinLat);
1140 CoordSpherical->
r = sqrtf(xp * xp + zp * zp);
1141 CoordSpherical->
phig = asinf(zp / CoordSpherical->
r) * RAD2DEG;
#define WMM_MAX_MODEL_DEGREES
int WMM_SecVarSummation(WMMtype_LegendreFunction *LegendreFunction, WMMtype_SphericalHarmonicVariables *SphVariables, WMMtype_CoordSpherical *CoordSpherical, WMMtype_MagneticResults *MagneticResults)
static const float CoeffFile[91][6]
static WMMtype_MagneticModel MagneticModel
int WMM_PcupLow(float *Pcup, float *dPcup, float x, uint16_t nMax)
int WMM_SummationSpecial(WMMtype_SphericalHarmonicVariables *SphVariables, WMMtype_CoordSpherical *CoordSpherical, WMMtype_MagneticResults *MagneticResults)
float cos_mlambda[WMM_MAX_MODEL_DEGREES+1]
int WMM_SecVarSummationSpecial(WMMtype_SphericalHarmonicVariables *SphVariables, WMMtype_CoordSpherical *CoordSpherical, WMMtype_MagneticResults *MagneticResults)
int WMM_ComputeSphericalHarmonicVariables(WMMtype_CoordSpherical *CoordSpherical, uint16_t nMax, WMMtype_SphericalHarmonicVariables *SphVariables)
#define WMM_MAX_SECULAR_VARIATION_MODEL_DEGREES
static WMMtype_Ellipsoid Ellip
int WMM_PcupHigh(float *Pcup, float *dPcup, float x, uint16_t nMax)
float RelativeRadiusPower[WMM_MAX_MODEL_DEGREES+1]
Source file for the World Magnetic Model.
float HeightAboveEllipsoid
float WMM_get_main_field_coeff_h(uint16_t index)
float WMM_get_secular_var_coeff_h(uint16_t index)
int WMM_CalculateGeoMagneticElements(WMMtype_MagneticResults *MagneticResultsGeo, WMMtype_GeoMagneticElements *GeoMagneticElements)
static float decimal_date
int WMM_AssociatedLegendreFunction(WMMtype_CoordSpherical *CoordSpherical, uint16_t nMax, WMMtype_LegendreFunction *LegendreFunction)
int WMM_Geomag(WMMtype_CoordSpherical *CoordSpherical, WMMtype_CoordGeodetic *CoordGeodetic, WMMtype_GeoMagneticElements *GeoMagneticElements)
float WMM_get_secular_var_coeff_g(uint16_t index)
float WMM_get_main_field_coeff_g(uint16_t index)
Comput the MainFieldCoeffH accounting for the date.
Includes PiOS and core architecture components.
Include file of the WorldMagModel internal functionality.
float sin_mlambda[WMM_MAX_MODEL_DEGREES+1]
int WMM_GeodeticToSpherical(WMMtype_CoordGeodetic *CoordGeodetic, WMMtype_CoordSpherical *CoordSpherical)
int WMM_RotateMagneticVector(WMMtype_CoordSpherical *, WMMtype_CoordGeodetic *CoordGeodetic, WMMtype_MagneticResults *MagneticResultsSph, WMMtype_MagneticResults *MagneticResultsGeo)
int WMM_DateToYear(uint16_t month, uint16_t day, uint16_t year)
uint16_t SecularVariationUsed
int WMM_CalculateSecularVariation(WMMtype_MagneticResults *MagneticVariation, WMMtype_GeoMagneticElements *MagneticElements)
int WMM_GetMagVector(float Lat, float Lon, float AltEllipsoid, uint16_t Month, uint16_t Day, uint16_t Year, float B[3])
int WMM_Summation(WMMtype_LegendreFunction *LegendreFunction, WMMtype_SphericalHarmonicVariables *SphVariables, WMMtype_CoordSpherical *CoordSpherical, WMMtype_MagneticResults *MagneticResults)