dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
WorldMagModel.c
Go to the documentation of this file.
1 
30 /*
31  * This program is free software; you can redistribute it and/or modify
32  * it under the terms of the GNU General Public License as published by
33  * the Free Software Foundation; either version 3 of the License, or
34  * (at your option) any later version.
35  *
36  * This program is distributed in the hope that it will be useful, but
37  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
38  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
39  * for more details.
40  *
41  * You should have received a copy of the GNU General Public License along
42  * with this program; if not, see <http://www.gnu.org/licenses/>
43  */
44 
45 #include "openpilot.h"
46 #include "physical_constants.h"
47 
48 #include <stdio.h>
49 #include <string.h>
50 #include <math.h>
51 #include <stdlib.h>
52 #include <stdint.h>
53 
54 #include "WorldMagModel.h"
55 #include "WMMInternal.h"
56 
57 // const should hopefully keep them in the flash region
58 static const float CoeffFile[91][6] = COEFFS_FROM_NASA;
59 
62 static float decimal_date;
63 
64 /**************************************************************************************
65 * Example use - very simple - only two exposed functions
66 *
67 * WMM_Initialize(); // Set default values and constants
68 *
69 * WMM_GetMagVector(float Lat, float Lon, float Alt, uint16_t Month, uint16_t Day, uint16_t Year, float B[3]);
70 * e.g. Iceland in may of 2012 = WMM_GetMagVector(65.0, -20.0, 0.0, 5, 5, 2012, B);
71 * Alt is above the WGS-84 Ellipsoid
72 * B is the NED (XYZ) magnetic vector in nTesla
73 **************************************************************************************/
74 
76 // Sets default values for WMM subroutines.
77 // UPDATES : Ellip and MagneticModel
78 {
79  // Sets WGS-84 parameters
80  Ellip.a = WGS84_A; // semi-major axis of the ellipsoid in km
81  Ellip.b = WGS84_B; // semi-minor axis of the ellipsoid in km
82  Ellip.fla = WGS84_FLATTENING; // flattening
83  Ellip.eps = WGS84_EPS; // first eccentricity
84  Ellip.epssq = WGS84_EPS2; // first eccentricity squared
85  Ellip.re = WGS84_RADIUS_EARTH_KM; // Earth's radius in km
86 
87  // Sets Magnetic Model parameters
88  MagneticModel.nMax = WMM_MAX_MODEL_DEGREES;
90  MagneticModel.SecularVariationUsed = 0;
91  MagneticModel.epoch = MAGNETIC_MODEL_EPOCH;
92 
93  // Must be updated periodically. Last update expires in 2020
94 
95  return 0; // OK
96 }
97 
98 int WMM_GetMagVector(float Lat, float Lon, float AltEllipsoid, uint16_t Month, uint16_t Day, uint16_t Year, float B[3])
99 {
100  // return '0' if all appears to be OK
101  // return < 0 if error
102 
103  int returned = 0; // default to OK
104 
105  // ***********
106  // range check supplied params
107 
108  if (Lat < -90) return -1; // error
109  if (Lat > 90) return -2; // error
110 
111  if (Lon < -180) return -3; // error
112  if (Lon > 180) return -4; // error
113 
114 
115  WMMtype_CoordSpherical CoordSpherical;
116  WMMtype_CoordGeodetic CoordGeodetic;
117  WMMtype_GeoMagneticElements GeoMagneticElements;
118 
119 
120  // ***********
121 
122  if (returned >= 0)
123  {
124  if (WMM_Initialize() < 0)
125  returned = -6; // error
126  }
127 
128  if (returned >= 0)
129  {
130  CoordGeodetic.lambda = Lon;
131  CoordGeodetic.phi = Lat;
132  CoordGeodetic.HeightAboveEllipsoid = AltEllipsoid/1000.0f; // convert to km
133 
134  // Convert from geodeitic to Spherical Equations: 17-18, WMM Technical report
135  if (WMM_GeodeticToSpherical(&CoordGeodetic, &CoordSpherical) < 0)
136  returned = -7; // error
137  }
138 
139 
140  if (returned >= 0)
141  {
142  if (WMM_DateToYear(Month, Day, Year) < 0)
143  returned = -8; // error
144  }
145 
146  if (returned >= 0)
147  {
148  // Compute the geoMagnetic field elements and their time change
149  if (WMM_Geomag(&CoordSpherical, &CoordGeodetic, &GeoMagneticElements) < 0)
150  returned = -9; // error
151  else
152  { // set the returned values
153  B[0] = GeoMagneticElements.X * 1e-2f;
154  B[1] = GeoMagneticElements.Y * 1e-2f;
155  B[2] = GeoMagneticElements.Z * 1e-2f;
156  }
157  }
158 
159 
160  return returned;
161 }
162 
163 int WMM_Geomag(WMMtype_CoordSpherical * CoordSpherical, WMMtype_CoordGeodetic * CoordGeodetic, WMMtype_GeoMagneticElements * GeoMagneticElements)
164  /*
165  The main subroutine that calls a sequence of WMM sub-functions to calculate the magnetic field elements for a single point.
166  The function expects the model coefficients and point coordinates as input and returns the magnetic field elements and
167  their rate of change. Though, this subroutine can be called successively to calculate a time series, profile or grid
168  of magnetic field, these are better achieved by the subroutine WMM_Grid.
169 
170  INPUT: Ellip
171  CoordSpherical
172  CoordGeodetic
173  TimedMagneticModel
174 
175  OUTPUT : GeoMagneticElements
176 
177  CALLS: WMM_ComputeSphericalHarmonicVariables( Ellip, CoordSpherical, TimedMagneticModel->nMax, &SphVariables); (Compute Spherical Harmonic variables )
178  WMM_AssociatedLegendreFunction(CoordSpherical, TimedMagneticModel->nMax, LegendreFunction); Compute ALF
179  WMM_Summation(LegendreFunction, TimedMagneticModel, SphVariables, CoordSpherical, &MagneticResultsSph); Accumulate the spherical harmonic coefficients
180  WMM_SecVarSummation(LegendreFunction, TimedMagneticModel, SphVariables, CoordSpherical, &MagneticResultsSphVar); Sum the Secular Variation Coefficients
181  WMM_RotateMagneticVector(CoordSpherical, CoordGeodetic, MagneticResultsSph, &MagneticResultsGeo); Map the computed Magnetic fields to Geodeitic coordinates
182  WMM_RotateMagneticVector(CoordSpherical, CoordGeodetic, MagneticResultsSphVar, &MagneticResultsGeoVar); Map the secular variation field components to Geodetic coordinates
183  WMM_CalculateGeoMagneticElements(&MagneticResultsGeo, GeoMagneticElements); Calculate the Geomagnetic elements
184  WMM_CalculateSecularVariation(MagneticResultsGeoVar, GeoMagneticElements); Calculate the secular variation of each of the Geomagnetic elements
185 
186  */
187 {
188  int returned = 0; // default to OK
189 
190  WMMtype_MagneticResults MagneticResultsSph;
191  WMMtype_MagneticResults MagneticResultsGeo;
192  WMMtype_MagneticResults MagneticResultsSphVar;
193  WMMtype_MagneticResults MagneticResultsGeoVar;
194 
195  WMMtype_LegendreFunction LegendreFunction;
197 
198  // ********
199 
200  if (returned >= 0)
201  { // Compute Spherical Harmonic variables
202  if (WMM_ComputeSphericalHarmonicVariables(CoordSpherical, MagneticModel.nMax, &SphVariables) < 0)
203  returned = -2; // error
204  }
205 
206  if (returned >= 0)
207  { // Compute ALF
208  if (WMM_AssociatedLegendreFunction(CoordSpherical, MagneticModel.nMax, &LegendreFunction) < 0)
209  returned = -3; // error
210  }
211 
212  if (returned >= 0)
213  { // Accumulate the spherical harmonic coefficients
214  if (WMM_Summation(&LegendreFunction, &SphVariables, CoordSpherical, &MagneticResultsSph) < 0)
215  returned = -4; // error
216  }
217 
218  if (returned >= 0)
219  { // Sum the Secular Variation Coefficients
220  if (WMM_SecVarSummation(&LegendreFunction, &SphVariables, CoordSpherical, &MagneticResultsSphVar) < 0)
221  returned = -5; // error
222  }
223 
224  if (returned >= 0)
225  { // Map the computed Magnetic fields to Geodeitic coordinates
226  if (WMM_RotateMagneticVector(CoordSpherical, CoordGeodetic, &MagneticResultsSph, &MagneticResultsGeo) < 0)
227  returned = -6; // error
228  }
229 
230  if (returned >= 0)
231  { // Map the secular variation field components to Geodetic coordinates
232  if (WMM_RotateMagneticVector(CoordSpherical, CoordGeodetic, &MagneticResultsSphVar, &MagneticResultsGeoVar) < 0)
233  returned = -7; // error
234  }
235 
236  if (returned >= 0)
237  { // Calculate the Geomagnetic elements, Equation 18 , WMM Technical report
238  if (WMM_CalculateGeoMagneticElements(&MagneticResultsGeo, GeoMagneticElements) < 0)
239  returned = -8; // error
240  }
241 
242  if (returned >= 0)
243  { // Calculate the secular variation of each of the Geomagnetic elements
244  if (WMM_CalculateSecularVariation(&MagneticResultsGeoVar, GeoMagneticElements) < 0)
245  returned = -9; // error
246  }
247 
248  return returned;
249 }
250 
252 
253  /* Computes Spherical variables
254  Variables computed are (a/r)^(n+2), cos_m(lamda) and sin_m(lambda) for spherical harmonic
255  summations. (Equations 10-12 in the WMM Technical Report)
256  INPUT Ellip data structure with the following elements
257  float a; semi-major axis of the ellipsoid
258  float b; semi-minor axis of the ellipsoid
259  float fla; flattening
260  float epssq; first eccentricity squared
261  float eps; first eccentricity
262  float re; mean radius of ellipsoid
263  CoordSpherical A data structure with the following elements
264  float lambda; ( longitude)
265  float phig; ( geocentric latitude )
266  float r; ( distance from the center of the ellipsoid)
267  nMax integer ( Maxumum degree of spherical harmonic secular model)\
268 
269  OUTPUT SphVariables Pointer to the data structure with the following elements
270  float RelativeRadiusPower[WMM_MAX_MODEL_DEGREES+1]; [earth_reference_radius_km sph. radius ]^n
271  float cos_mlambda[WMM_MAX_MODEL_DEGREES+1]; cp(m) - cosine of (mspherical coord. longitude)
272  float sin_mlambda[WMM_MAX_MODEL_DEGREES+1]; sp(m) - sine of (mspherical coord. longitude)
273  CALLS : none
274  */
275 {
276  float cos_lambda, sin_lambda;
277  uint16_t m, n;
278 
279  cos_lambda = cosf(CoordSpherical->lambda * DEG2RAD);
280  sin_lambda = sinf(CoordSpherical->lambda * DEG2RAD);
281 
282  /* for n = 0 ... model_order, compute (Radius of Earth / Spherica radius r)^(n+2)
283  for n 1..nMax-1 (this is much faster than calling pow MAX_N+1 times). */
284 
285  SphVariables->RelativeRadiusPower[0] = (Ellip.re / CoordSpherical->r) * (Ellip.re / CoordSpherical->r);
286  for (n = 1; n <= nMax; n++)
287  SphVariables->RelativeRadiusPower[n] = SphVariables->RelativeRadiusPower[n - 1] * (Ellip.re / CoordSpherical->r);
288 
289  /*
290  Compute cos(m*lambda), sin(m*lambda) for m = 0 ... nMax
291  cos(a + b) = cos(a)*cos(b) - sin(a)*sin(b)
292  sin(a + b) = cos(a)*sin(b) + sin(a)*cos(b)
293  */
294  SphVariables->cos_mlambda[0] = 1.0;
295  SphVariables->sin_mlambda[0] = 0.0;
296 
297  SphVariables->cos_mlambda[1] = cos_lambda;
298  SphVariables->sin_mlambda[1] = sin_lambda;
299  for (m = 2; m <= nMax; m++)
300  {
301  SphVariables->cos_mlambda[m] = SphVariables->cos_mlambda[m - 1] * cos_lambda - SphVariables->sin_mlambda[m - 1] * sin_lambda;
302  SphVariables->sin_mlambda[m] = SphVariables->cos_mlambda[m - 1] * sin_lambda + SphVariables->sin_mlambda[m - 1] * cos_lambda;
303  }
304 
305  return 0; // OK
306 }
307 
308 int WMM_AssociatedLegendreFunction(WMMtype_CoordSpherical * CoordSpherical, uint16_t nMax, WMMtype_LegendreFunction * LegendreFunction)
309 
310  /* Computes all of the Schmidt-semi normalized associated Legendre
311  functions up to degree nMax. If nMax <= 16, function WMM_PcupLow is used.
312  Otherwise WMM_PcupHigh is called.
313  INPUT CoordSpherical A data structure with the following elements
314  float lambda; ( longitude)
315  float phig; ( geocentric latitude )
316  float r; ( distance from the center of the ellipsoid)
317  nMax integer ( Maxumum degree of spherical harmonic secular model)
318  LegendreFunction Pointer to data structure with the following elements
319  float *Pcup; ( pointer to store Legendre Function )
320  float *dPcup; ( pointer to store Derivative of Lagendre function )
321 
322  OUTPUT LegendreFunction Calculated Legendre variables in the data structure
323 
324  */
325 {
326  float sin_phi = sinf(CoordSpherical->phig * DEG2RAD); /* sin (geocentric latitude) */
327 
328  if (nMax <= 16 || (1 - fabsf(sin_phi)) < 1.0e-10f) /* If nMax is less tha 16 or at the poles */
329  {
330  if (WMM_PcupLow(LegendreFunction->Pcup, LegendreFunction->dPcup, sin_phi, nMax) < 0)
331  return -1; // error
332  }
333  else
334  {
335  if (WMM_PcupHigh(LegendreFunction->Pcup, LegendreFunction->dPcup, sin_phi, nMax) < 0)
336  return -2; // error
337  }
338 
339  return 0; // OK
340 }
341 
343  WMMtype_SphericalHarmonicVariables * SphVariables,
344  WMMtype_CoordSpherical * CoordSpherical, WMMtype_MagneticResults * MagneticResults)
345 {
346  /* Computes Geomagnetic Field Elements X, Y and Z in Spherical coordinate system using
347  spherical harmonic summation.
348 
349  The vector Magnetic field is given by -grad V, where V is Geomagnetic scalar potential
350  The gradient in spherical coordinates is given by:
351 
352  dV ^ 1 dV ^ 1 dV ^
353  grad V = -- r + - -- t + -------- -- p
354  dr r dt r sin(t) dp
355 
356  INPUT : LegendreFunction
357  MagneticModel
358  SphVariables
359  CoordSpherical
360  OUTPUT : MagneticResults
361 
362  CALLS : WMM_SummationSpecial
363 
364  Manoj Nair, June, 2009 Manoj.C.Nair@Noaa.Gov
365  */
366 
367  uint16_t m, n, index;
368  float cos_phi;
369 
370  MagneticResults->Bz = 0.0;
371  MagneticResults->By = 0.0;
372  MagneticResults->Bx = 0.0;
373 
374  for (n = 1; n <= MagneticModel.nMax; n++)
375  {
376  for (m = 0; m <= n; m++)
377  {
378  index = (n * (n + 1) / 2 + m);
379 
380 /* nMax (n+2) n m m m
381  Bz = -SUM (a/r) (n+1) SUM [g cos(m p) + h sin(m p)] P (sin(phi))
382  n=1 m=0 n n n */
383 /* Equation 12 in the WMM Technical report. Derivative with respect to radius.*/
384  MagneticResults->Bz -=
385  SphVariables->RelativeRadiusPower[n] *
387  SphVariables->cos_mlambda[m] + WMM_get_main_field_coeff_h(index) * SphVariables->sin_mlambda[m])
388  * (float)(n + 1) * LegendreFunction->Pcup[index];
389 
390 /* 1 nMax (n+2) n m m m
391  By = SUM (a/r) (m) SUM [g cos(m p) + h sin(m p)] dP (sin(phi))
392  n=1 m=0 n n n */
393 /* Equation 11 in the WMM Technical report. Derivative with respect to longitude, divided by radius. */
394  MagneticResults->By +=
395  SphVariables->RelativeRadiusPower[n] *
397  SphVariables->sin_mlambda[m] - WMM_get_main_field_coeff_h(index) * SphVariables->cos_mlambda[m])
398  * (float)(m) * LegendreFunction->Pcup[index];
399 /* nMax (n+2) n m m m
400  Bx = - SUM (a/r) SUM [g cos(m p) + h sin(m p)] dP (sin(phi))
401  n=1 m=0 n n n */
402 /* Equation 10 in the WMM Technical report. Derivative with respect to latitude, divided by radius. */
403 
404  MagneticResults->Bx -=
405  SphVariables->RelativeRadiusPower[n] *
407  SphVariables->cos_mlambda[m] + WMM_get_main_field_coeff_h(index) * SphVariables->sin_mlambda[m])
408  * LegendreFunction->dPcup[index];
409 
410  }
411  }
412 
413  cos_phi = cosf(CoordSpherical->phig * DEG2RAD);
414  if (fabsf(cos_phi) > 1.0e-10f)
415  {
416  MagneticResults->By = MagneticResults->By / cos_phi;
417  }
418  else
419  {
420  /* Special calculation for component - By - at Geographic poles.
421  * If the user wants to avoid using this function, please make sure that
422  * the latitude is not exactly +/-90. An option is to make use the function
423  * WMM_CheckGeographicPoles.
424  */
425  if (WMM_SummationSpecial(SphVariables, CoordSpherical, MagneticResults) < 0)
426  return -1; // error
427  }
428 
429  return 0; // OK
430 }
431 
434  SphVariables, WMMtype_CoordSpherical * CoordSpherical, WMMtype_MagneticResults * MagneticResults)
435 {
436  /*This Function sums the secular variation coefficients to get the secular variation of the Magnetic vector.
437  INPUT : LegendreFunction
438  MagneticModel
439  SphVariables
440  CoordSpherical
441  OUTPUT : MagneticResults
442 
443  CALLS : WMM_SecVarSummationSpecial
444 
445  */
446 
447  uint16_t m, n, index;
448  float cos_phi;
449 
450  MagneticModel.SecularVariationUsed = TRUE;
451 
452  MagneticResults->Bz = 0.0;
453  MagneticResults->By = 0.0;
454  MagneticResults->Bx = 0.0;
455 
456  for (n = 1; n <= MagneticModel.nMaxSecVar; n++)
457  {
458  for (m = 0; m <= n; m++)
459  {
460  index = (n * (n + 1) / 2 + m);
461 
462 /* nMax (n+2) n m m m
463  Bz = -SUM (a/r) (n+1) SUM [g cos(m p) + h sin(m p)] P (sin(phi))
464  n=1 m=0 n n n */
465 /* Derivative with respect to radius.*/
466  MagneticResults->Bz -=
467  SphVariables->RelativeRadiusPower[n] *
469  SphVariables->cos_mlambda[m] + WMM_get_secular_var_coeff_h(index) * SphVariables->sin_mlambda[m])
470  * (float)(n + 1) * LegendreFunction->Pcup[index];
471 
472 /* 1 nMax (n+2) n m m m
473  By = SUM (a/r) (m) SUM [g cos(m p) + h sin(m p)] dP (sin(phi))
474  n=1 m=0 n n n */
475 /* Derivative with respect to longitude, divided by radius. */
476  MagneticResults->By +=
477  SphVariables->RelativeRadiusPower[n] *
479  SphVariables->sin_mlambda[m] - WMM_get_secular_var_coeff_h(index) * SphVariables->cos_mlambda[m])
480  * (float)(m) * LegendreFunction->Pcup[index];
481 /* nMax (n+2) n m m m
482  Bx = - SUM (a/r) SUM [g cos(m p) + h sin(m p)] dP (sin(phi))
483  n=1 m=0 n n n */
484 /* Derivative with respect to latitude, divided by radius. */
485 
486  MagneticResults->Bx -=
487  SphVariables->RelativeRadiusPower[n] *
489  SphVariables->cos_mlambda[m] + WMM_get_secular_var_coeff_h(index) * SphVariables->sin_mlambda[m])
490  * LegendreFunction->dPcup[index];
491  }
492  }
493  cos_phi = cosf(CoordSpherical->phig * DEG2RAD);
494  if (fabsf(cos_phi) > 1.0e-10f)
495  {
496  MagneticResults->By = MagneticResults->By / cos_phi;
497  }
498  else
499  /* Special calculation for component By at Geographic poles */
500  {
501  if (WMM_SecVarSummationSpecial(SphVariables, CoordSpherical, MagneticResults) < 0)
502  return -1; // error
503  }
504 
505  return 0; // OK
506 }
507 
509  WMMtype_CoordGeodetic * CoordGeodetic,
510  WMMtype_MagneticResults * MagneticResultsSph, WMMtype_MagneticResults * MagneticResultsGeo)
511  /* Rotate the Magnetic Vectors to Geodetic Coordinates
512  Manoj Nair, June, 2009 Manoj.C.Nair@Noaa.Gov
513  Equation 16, WMM Technical report
514 
515  INPUT : CoordSpherical : Data structure WMMtype_CoordSpherical with the following elements
516  float lambda; ( longitude)
517  float phig; ( geocentric latitude )
518  float r; ( distance from the center of the ellipsoid)
519 
520  CoordGeodetic : Data structure WMMtype_CoordGeodetic with the following elements
521  float lambda; (longitude)
522  float phi; ( geodetic latitude)
523  float HeightAboveEllipsoid; (height above the ellipsoid (HaE) )
524  float HeightAboveGeoid;(height above the Geoid )
525 
526  MagneticResultsSph : Data structure WMMtype_MagneticResults with the following elements
527  float Bx; North
528  float By; East
529  float Bz; Down
530 
531  OUTPUT: MagneticResultsGeo Pointer to the data structure WMMtype_MagneticResults, with the following elements
532  float Bx; North
533  float By; East
534  float Bz; Down
535 
536  CALLS : none
537 
538  */
539 {
540  /* Difference between the spherical and Geodetic latitudes */
541  float Psi = (CoordSpherical->phig - CoordGeodetic->phi) * DEG2RAD;
542 
543  /* Rotate spherical field components to the Geodeitic system */
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;
547 
548  return 0;
549 }
550 
552 
553  /* Calculate all the Geomagnetic elements from X,Y and Z components
554  INPUT MagneticResultsGeo Pointer to data structure with the following elements
555  float Bx; ( North )
556  float By; ( East )
557  float Bz; ( Down )
558  OUTPUT GeoMagneticElements Pointer to data structure with the following elements
559  float Decl; (Angle between the magnetic field vector and true north, positive east)
560  float Incl; Angle between the magnetic field vector and the horizontal plane, positive down
561  float F; Magnetic Field Strength
562  float H; Horizontal Magnetic Field Strength
563  float X; Northern component of the magnetic field vector
564  float Y; Eastern component of the magnetic field vector
565  float Z; Downward component of the magnetic field vector
566  CALLS : none
567  */
568 {
569  GeoMagneticElements->X = MagneticResultsGeo->Bx;
570  GeoMagneticElements->Y = MagneticResultsGeo->By;
571  GeoMagneticElements->Z = MagneticResultsGeo->Bz;
572 
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;
577 
578  return 0; // OK
579 }
580 
582 /*This takes the Magnetic Variation in x, y, and z and uses it to calculate the secular variation of each of the Geomagnetic elements.
583  INPUT MagneticVariation Data structure with the following elements
584  float Bx; ( North )
585  float By; ( East )
586  float Bz; ( Down )
587  OUTPUT MagneticElements Pointer to the data structure with the following elements updated
588  float Decldot; Yearly Rate of change in declination
589  float Incldot; Yearly Rate of change in inclination
590  float Fdot; Yearly rate of change in Magnetic field strength
591  float Hdot; Yearly rate of change in horizontal field strength
592  float Xdot; Yearly rate of change in the northern component
593  float Ydot; Yearly rate of change in the eastern component
594  float Zdot; Yearly rate of change in the downward component
595  float GVdot;Yearly rate of chnage in grid variation
596  CALLS : none
597 
598 */
599 {
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; //See equation 19 in the WMM technical report
604  MagneticElements->Fdot =
605  (MagneticElements->X * MagneticElements->Xdot +
606  MagneticElements->Y * MagneticElements->Ydot + MagneticElements->Z * MagneticElements->Zdot) / MagneticElements->F;
607  MagneticElements->Decldot =
608  RAD2DEG * (MagneticElements->X * MagneticElements->Ydot -
609  MagneticElements->Y * MagneticElements->Xdot) / (MagneticElements->H * MagneticElements->H);
610  MagneticElements->Incldot =
611  RAD2DEG * (MagneticElements->H * MagneticElements->Zdot -
612  MagneticElements->Z * MagneticElements->Hdot) / (MagneticElements->F * MagneticElements->F);
613  MagneticElements->GVdot = MagneticElements->Decldot;
614 
615  return 0; // OK
616 }
617 
618 int WMM_PcupHigh(float *Pcup, float *dPcup, float x, uint16_t nMax)
619 
620 /* This function evaluates all of the Schmidt-semi normalized associated Legendre
621  functions up to degree nMax. The functions are initially scaled by
622  10^280 sin^m in order to minimize the effects of underflow at large m
623  near the poles (see Holmes and Featherstone 2002, J. Geodesy, 76, 279-299).
624  Note that this function performs the same operation as WMM_PcupLow.
625  However this function also can be used for high degree (large nMax) models.
626 
627  Calling Parameters:
628  INPUT
629  nMax: Maximum spherical harmonic degree to compute.
630  x: cos(colatitude) or sin(latitude).
631 
632  OUTPUT
633  Pcup: A vector of all associated Legendgre polynomials evaluated at
634  x up to nMax. The lenght must by greater or equal to (nMax+1)*(nMax+2)/2.
635  dPcup: Derivative of Pcup(x) with respect to latitude
636 
637  CALLS : none
638  Notes:
639 
640  Adopted from the FORTRAN code written by Mark Wieczorek September 25, 2005.
641 
642  Manoj Nair, Nov, 2009 Manoj.C.Nair@Noaa.Gov
643 
644  Change from the previous version
645  The prevous version computes the derivatives as
646  dP(n,m)(x)/dx, where x = sin(latitude) (or cos(colatitude) ).
647  However, the WMM Geomagnetic routines requires dP(n,m)(x)/dlatitude.
648  Hence the derivatives are multiplied by sin(latitude).
649  Removed the options for CS phase and normalizations.
650 
651  Note: In geomagnetism, the derivatives of ALF are usually found with
652  respect to the colatitudes. Here the derivatives are found with respect
653  to the latitude. The difference is a sign reversal for the derivative of
654  the Associated Legendre Functions.
655 
656  The derivates can't be computed for latitude = |90| degrees.
657  */
658 {
659  uint16_t k, kstart, m, n;
660  float pm2, pm1, pmm, plm, rescalem, z, scalef;
661 
662  float f1_s[NUMPCUP];
663  float f2_s[NUMPCUP];
664  float pre_sqr[NUMPCUP];
665 
666  float *f1 = f1_s;
667  float *f2 = f2_s;
668  float *PreSqr = pre_sqr;
669 
670 
671  if (fabsf(x) == 1.0f)
672  {
673  // Error in PcupHigh: derivative cannot be calculated at poles
674  return -2;
675  }
676 
677  scalef = 1.0e-280;
678 
679  for (n = 0; n <= 2 * nMax + 1; ++n)
680  PreSqr[n] = sqrtf((float)(n));
681 
682  k = 2;
683 
684  for (n = 2; n <= nMax; n++)
685  {
686  k = k + 1;
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++)
690  {
691  k = k + 1;
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];
694  }
695  k = k + 2;
696  }
697 
698  /*z = sin (geocentric latitude) */
699  z = sqrtf((1.0f - x) * (1.0f + x));
700  pm2 = 1.0;
701  Pcup[0] = 1.0;
702  dPcup[0] = 0.0;
703  if (nMax == 0)
704  {
705  return -3;
706  }
707  pm1 = x;
708  Pcup[1] = pm1;
709  dPcup[1] = z;
710  k = 1;
711 
712  for (n = 2; n <= nMax; n++)
713  {
714  k = k + n;
715  plm = f1[k] * x * pm1 - f2[k] * pm2;
716  Pcup[k] = plm;
717  dPcup[k] = (float)(n) * (pm1 - x * plm) / z;
718  pm2 = pm1;
719  pm1 = plm;
720  }
721 
722  pmm = PreSqr[2] * scalef;
723  rescalem = 1.0f / scalef;
724  kstart = 0;
725 
726  for (m = 1; m <= nMax - 1; ++m)
727  {
728  rescalem = rescalem * z;
729 
730  /* Calculate Pcup(m,m) */
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];
736  /* Calculate Pcup(m+1,m) */
737  k = kstart + 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;
741  /* Calculate Pcup(n,m) */
742  for (n = m + 2; n <= nMax; ++n)
743  {
744  k = k + 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;
748  pm2 = pm1;
749  pm1 = plm;
750  }
751  }
752 
753  /* Calculate Pcup(nMax,nMax) */
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;
759 
760  return 0; // OK
761 }
762 
763 int WMM_PcupLow(float *Pcup, float *dPcup, float x, uint16_t nMax)
764 
765 /* This function evaluates all of the Schmidt-semi normalized associated Legendre
766  functions up to degree nMax.
767 
768  Calling Parameters:
769  INPUT
770  nMax: Maximum spherical harmonic degree to compute.
771  x: cos(colatitude) or sin(latitude).
772 
773  OUTPUT
774  Pcup: A vector of all associated Legendgre polynomials evaluated at
775  x up to nMax.
776  dPcup: Derivative of Pcup(x) with respect to latitude
777 
778  Notes: Overflow may occur if nMax > 20 , especially for high-latitudes.
779  Use WMM_PcupHigh for large nMax.
780 
781  Writted by Manoj Nair, June, 2009 . Manoj.C.Nair@Noaa.Gov.
782 
783  Note: In geomagnetism, the derivatives of ALF are usually found with
784  respect to the colatitudes. Here the derivatives are found with respect
785  to the latitude. The difference is a sign reversal for the derivative of
786  the Associated Legendre Functions.
787 */
788 {
789  uint16_t n, m, index, index1, index2;
790  float k, z;
791  float schmidtQuasiNorm_s[NUMPCUP];
792  float *schmidtQuasiNorm = schmidtQuasiNorm_s;
793 
794  if (!schmidtQuasiNorm)
795  {
796  return -1;
797  }
798 
799  Pcup[0] = 1.0;
800  dPcup[0] = 0.0;
801 
802  /*sin (geocentric latitude) - sin_phi */
803  z = sqrtf((1.0f - x) * (1.0f + x));
804 
805  /* First, Compute the Gauss-normalized associated Legendre functions */
806  for (n = 1; n <= nMax; n++)
807  {
808  for (m = 0; m <= n; m++)
809  {
810  index = (n * (n + 1) / 2 + m);
811  if (n == m)
812  {
813  index1 = (n - 1) * n / 2 + m - 1;
814  Pcup[index] = z * Pcup[index1];
815  dPcup[index] = z * dPcup[index1] + x * Pcup[index1];
816  }
817  else
818  if (n == 1 && m == 0)
819  {
820  index1 = (n - 1) * n / 2 + m;
821  Pcup[index] = x * Pcup[index1];
822  dPcup[index] = x * dPcup[index1] - z * Pcup[index1];
823  }
824  else
825  if (n > 1 && n != m)
826  {
827  index1 = (n - 2) * (n - 1) / 2 + m;
828  index2 = (n - 1) * n / 2 + m;
829  if (m > n - 2)
830  {
831  Pcup[index] = x * Pcup[index2];
832  dPcup[index] = x * dPcup[index2] - z * Pcup[index2];
833  }
834  else
835  {
836  k = (float)(((n - 1) * (n - 1)) - (m * m)) / (float)((2 * n - 1)
837  * (2 * n - 3));
838  Pcup[index] = x * Pcup[index2] - k * Pcup[index1];
839  dPcup[index] = x * dPcup[index2] - z * Pcup[index2] - k * dPcup[index1];
840  }
841  }
842  }
843  }
844 /*Compute the ration between the Gauss-normalized associated Legendre
845  functions and the Schmidt quasi-normalized version. This is equivalent to
846  sqrt((m==0?1:2)*(n-m)!/(n+m!))*(2n-1)!!/(n-m)! */
847 
848  schmidtQuasiNorm[0] = 1.0;
849  for (n = 1; n <= nMax; n++)
850  {
851  index = (n * (n + 1) / 2);
852  index1 = (n - 1) * n / 2;
853  /* for m = 0 */
854  schmidtQuasiNorm[index] = schmidtQuasiNorm[index1] * (float)(2 * n - 1) / (float)n;
855 
856  for (m = 1; m <= n; m++)
857  {
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));
861  }
862 
863  }
864 
865 /* Converts the Gauss-normalized associated Legendre
866  functions to the Schmidt quasi-normalized version using pre-computed
867  relation stored in the variable schmidtQuasiNorm */
868 
869  for (n = 1; n <= nMax; n++)
870  {
871  for (m = 0; m <= n; m++)
872  {
873  index = (n * (n + 1) / 2 + m);
874  Pcup[index] = Pcup[index] * schmidtQuasiNorm[index];
875  dPcup[index] = -dPcup[index] * schmidtQuasiNorm[index];
876  /* The sign is changed since the new WMM routines use derivative with respect to latitude
877  insted of co-latitude */
878  }
879  }
880 
881  return 0; // OK
882 }
883 
885  SphVariables, WMMtype_CoordSpherical * CoordSpherical, WMMtype_MagneticResults * MagneticResults)
886  /* Special calculation for the component By at Geographic poles.
887  Manoj Nair, June, 2009 manoj.c.nair@noaa.gov
888  INPUT: MagneticModel
889  SphVariables
890  CoordSpherical
891  OUTPUT: MagneticResults
892  CALLS : none
893  See Section 1.4, "SINGULARITIES AT THE GEOGRAPHIC POLES", WMM Technical report
894 
895  */
896 {
897  uint16_t n, index;
898  float k, sin_phi;
899  float schmidtQuasiNorm1;
900  float schmidtQuasiNorm2;
901  float schmidtQuasiNorm3;
902 
903  float PcupsS_s[NUMPCUPS];
904  float *PcupS = PcupsS_s;
905  if (!PcupS)
906  return -1;
907 
908  PcupS[0] = 1;
909  schmidtQuasiNorm1 = 1.0;
910 
911  MagneticResults->By = 0.0;
912  sin_phi = sinf(CoordSpherical->phig * DEG2RAD);
913 
914  for (n = 1; n <= MagneticModel.nMax; n++)
915  {
916 
917  /*Compute the ration between the Gauss-normalized associated Legendre
918  functions and the Schmidt quasi-normalized version. This is equivalent to
919  sqrt((m==0?1:2)*(n-m)!/(n+m!))*(2n-1)!!/(n-m)! */
920 
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;
925  if (n == 1)
926  {
927  PcupS[n] = PcupS[n - 1];
928  }
929  else
930  {
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];
933  }
934 
935 /* 1 nMax (n+2) n m m m
936  By = SUM (a/r) (m) SUM [g cos(m p) + h sin(m p)] dP (sin(phi))
937  n=1 m=0 n n n */
938 /* Equation 11 in the WMM Technical report. Derivative with respect to longitude, divided by radius. */
939 
940  MagneticResults->By +=
941  SphVariables->RelativeRadiusPower[n] *
943  SphVariables->sin_mlambda[1] - WMM_get_main_field_coeff_h(index) * SphVariables->cos_mlambda[1])
944  * PcupS[n] * schmidtQuasiNorm3;
945  }
946 
947  return 0; // OK
948 }
949 
951  SphVariables, WMMtype_CoordSpherical * CoordSpherical, WMMtype_MagneticResults * MagneticResults)
952 {
953  /*Special calculation for the secular variation summation at the poles.
954 
955  INPUT: MagneticModel
956  SphVariables
957  CoordSpherical
958  OUTPUT: MagneticResults
959  CALLS : none
960 
961  */
962  uint16_t n, index;
963  float k, sin_phi;
964  float schmidtQuasiNorm1;
965  float schmidtQuasiNorm2;
966  float schmidtQuasiNorm3;
967 
968  float PcupsS_s[NUMPCUPS];
969  float *PcupS = PcupsS_s;
970  if (!PcupS)
971  return -1;
972 
973  PcupS[0] = 1;
974  schmidtQuasiNorm1 = 1.0;
975 
976  MagneticResults->By = 0.0;
977  sin_phi = sinf(CoordSpherical->phig * DEG2RAD);
978 
979  for (n = 1; n <= MagneticModel.nMaxSecVar; n++)
980  {
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;
985  if (n == 1)
986  {
987  PcupS[n] = PcupS[n - 1];
988  }
989  else
990  {
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];
993  }
994 
995 /* 1 nMax (n+2) n m m m
996  By = SUM (a/r) (m) SUM [g cos(m p) + h sin(m p)] dP (sin(phi))
997  n=1 m=0 n n n */
998 /* Derivative with respect to longitude, divided by radius. */
999 
1000  MagneticResults->By +=
1001  SphVariables->RelativeRadiusPower[n] *
1002  (WMM_get_secular_var_coeff_g(index) *
1003  SphVariables->sin_mlambda[1] - WMM_get_secular_var_coeff_h(index) * SphVariables->cos_mlambda[1])
1004  * PcupS[n] * schmidtQuasiNorm3;
1005  }
1006 
1007  return 0; // OK
1008 }
1009 
1013 float WMM_get_main_field_coeff_g(uint16_t index)
1014 {
1015  if (index >= NUMTERMS)
1016  return 0;
1017 
1018  uint16_t n, m, sum_index, a, b;
1019 
1020  float coeff = CoeffFile[index][2];
1021 
1022  a = MagneticModel.nMaxSecVar;
1023  b = (a * (a + 1) / 2 + a);
1024  for (n = 1; n <= MagneticModel.nMax; n++)
1025  {
1026  for (m = 0; m <= n; m++)
1027  {
1028 
1029  sum_index = (n * (n + 1) / 2 + m);
1030 
1031  /* Hacky for now, will solve for which conditions need summing analytically */
1032  if (sum_index != index)
1033  continue;
1034 
1035  if (index <= b)
1036  coeff += (decimal_date - MagneticModel.epoch) * WMM_get_secular_var_coeff_g(sum_index);
1037 
1038  }
1039  }
1040 
1041  return coeff;
1042 }
1043 
1044 float WMM_get_main_field_coeff_h(uint16_t index)
1045 {
1046  if (index >= NUMTERMS)
1047  return 0;
1048 
1049  uint16_t n, m, sum_index, a, b;
1050  float coeff = CoeffFile[index][3];
1051 
1052  a = MagneticModel.nMaxSecVar;
1053  b = (a * (a + 1) / 2 + a);
1054  for (n = 1; n <= MagneticModel.nMax; n++)
1055  {
1056  for (m = 0; m <= n; m++)
1057  {
1058 
1059  sum_index = (n * (n + 1) / 2 + m);
1060 
1061  /* Hacky for now, will solve for which conditions need summing analytically */
1062  if (sum_index != index)
1063  continue;
1064 
1065  if (index <= b)
1066  coeff += (decimal_date - MagneticModel.epoch) * WMM_get_secular_var_coeff_h(sum_index);
1067  }
1068  }
1069 
1070  return coeff;
1071 }
1072 
1073 float WMM_get_secular_var_coeff_g(uint16_t index)
1074 {
1075  if (index >= NUMTERMS)
1076  return 0;
1077 
1078  return CoeffFile[index][4];
1079 }
1080 
1081 float WMM_get_secular_var_coeff_h(uint16_t index)
1082 {
1083  if (index >= NUMTERMS)
1084  return 0;
1085 
1086  return CoeffFile[index][5];
1087 }
1088 
1089 int WMM_DateToYear(uint16_t month, uint16_t day, uint16_t year)
1090 // Converts a given calendar date into a decimal year
1091 {
1092  uint16_t temp = 0; // Total number of days
1093  uint16_t MonthDays[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
1094  uint16_t ExtraDay = 0;
1095  uint16_t i;
1096 
1097  if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
1098  ExtraDay = 1;
1099  MonthDays[2] += ExtraDay;
1100 
1101  /******************Validation********************************/
1102 
1103  if (month <= 0 || month > 12)
1104  return -1; // error
1105 
1106  if (day <= 0 || day > MonthDays[month])
1107  return -2; // error
1108 
1109  /****************Calculation of t***************************/
1110  for (i = 1; i <= month; i++)
1111  temp += MonthDays[i - 1];
1112  temp += day;
1113 
1114  decimal_date = year + (temp - 1) / (365.0f + ExtraDay);
1115 
1116  return 0; // OK
1117 }
1118 
1120 // Converts Geodetic coordinates to Spherical coordinates
1121 // Convert geodetic coordinates, (defined by the WGS-84
1122 // reference ellipsoid), to Earth Centered Earth Fixed Cartesian
1123 // coordinates, and then to spherical coordinates.
1124 {
1125  float CosLat, SinLat, rc, xp, zp; // all local variables
1126 
1127  CosLat = cosf(CoordGeodetic->phi * DEG2RAD);
1128  SinLat = sinf(CoordGeodetic->phi * DEG2RAD);
1129 
1130  // compute the local radius of curvature on the WGS-84 reference ellipsoid
1131  rc = Ellip.a / sqrtf(1.0f - Ellip.epssq * SinLat * SinLat);
1132 
1133  // compute ECEF Cartesian coordinates of specified point (for longitude=0)
1134 
1135  xp = (rc + CoordGeodetic->HeightAboveEllipsoid) * CosLat;
1136  zp = (rc * (1.0f - Ellip.epssq) + CoordGeodetic->HeightAboveEllipsoid) * SinLat;
1137 
1138  // compute spherical radius and angle lambda and phi of specified point
1139 
1140  CoordSpherical->r = sqrtf(xp * xp + zp * zp);
1141  CoordSpherical->phig = asinf(zp / CoordSpherical->r) * RAD2DEG; // geocentric latitude
1142  CoordSpherical->lambda = CoordGeodetic->lambda; // longitude
1143 
1144  return 0; // OK
1145 }
1146 
#define WMM_MAX_MODEL_DEGREES
Definition: WMMInternal.h:39
int WMM_SecVarSummation(WMMtype_LegendreFunction *LegendreFunction, WMMtype_SphericalHarmonicVariables *SphVariables, WMMtype_CoordSpherical *CoordSpherical, WMMtype_MagneticResults *MagneticResults)
static const float CoeffFile[91][6]
Definition: WorldMagModel.c:58
static WMMtype_MagneticModel MagneticModel
Definition: WorldMagModel.c:61
#define NUMTERMS
Definition: WMMInternal.h:41
int WMM_PcupLow(float *Pcup, float *dPcup, float x, uint16_t nMax)
int WMM_SummationSpecial(WMMtype_SphericalHarmonicVariables *SphVariables, WMMtype_CoordSpherical *CoordSpherical, WMMtype_MagneticResults *MagneticResults)
#define NUMPCUPS
Definition: WMMInternal.h:43
float cos_mlambda[WMM_MAX_MODEL_DEGREES+1]
Definition: WMMInternal.h:99
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
Definition: WMMInternal.h:40
static WMMtype_Ellipsoid Ellip
Definition: WorldMagModel.c:60
float dPcup[NUMPCUP]
Definition: WMMInternal.h:87
int WMM_PcupHigh(float *Pcup, float *dPcup, float x, uint16_t nMax)
float RelativeRadiusPower[WMM_MAX_MODEL_DEGREES+1]
Definition: WMMInternal.h:98
Source file for the World Magnetic Model.
float WMM_get_main_field_coeff_h(uint16_t index)
float WMM_get_secular_var_coeff_h(uint16_t index)
#define NUMPCUP
Definition: WMMInternal.h:42
int WMM_CalculateGeoMagneticElements(WMMtype_MagneticResults *MagneticResultsGeo, WMMtype_GeoMagneticElements *GeoMagneticElements)
static float decimal_date
Definition: WorldMagModel.c:62
int WMM_AssociatedLegendreFunction(WMMtype_CoordSpherical *CoordSpherical, uint16_t nMax, WMMtype_LegendreFunction *LegendreFunction)
uint8_t i
Definition: msp_messages.h:97
int WMM_Initialize()
Definition: WorldMagModel.c:75
int WMM_Geomag(WMMtype_CoordSpherical *CoordSpherical, WMMtype_CoordGeodetic *CoordGeodetic, WMMtype_GeoMagneticElements *GeoMagneticElements)
#define TRUE
Definition: WMMInternal.h:34
float WMM_get_secular_var_coeff_g(uint16_t index)
tuple f
Definition: px_mkfw.py:81
float Pcup[NUMPCUP]
Definition: WMMInternal.h:86
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]
Definition: WMMInternal.h:100
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
Definition: WMMInternal.h:54
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])
Definition: WorldMagModel.c:98
int WMM_Summation(WMMtype_LegendreFunction *LegendreFunction, WMMtype_SphericalHarmonicVariables *SphVariables, WMMtype_CoordSpherical *CoordSpherical, WMMtype_MagneticResults *MagneticResults)