libacfutils
A general purpose library of utility functions designed to make it easier to develop addons for the X-Plane flight simulator.
Loading...
Searching...
No Matches
wmm.c
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license in the file COPYING
10 * or http://www.opensource.org/licenses/CDDL-1.0.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file COPYING.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2018 Saso Kiselkov. All rights reserved.
24 */
25
26#include <stdlib.h>
27
28#include "GeomagnetismLibrary.h"
29
30#include <acfutils/assert.h>
31#include <acfutils/helpers.h>
32#include <acfutils/perf.h>
33#include <acfutils/safe_alloc.h>
34#include <acfutils/wmm.h>
35
36struct wmm_s {
37 /* time-modified model according to year passed to wmm_open */
38 MAGtype_MagneticModel *timed_model;
39 MAGtype_MagneticModel *fixed_model;
41};
42
43/*
44 * Opens a World Magnetic Model coefficient file and time-adjusts it.
45 *
46 * @param filename Filename containing the world magnetic model (usually
47 * named something like 'WMM.COF').
48 * @param year Fractional year for which to time-adjust the model. For
49 * example, Apr 19 2016 is the 109th day of the year 2016, so it is
50 * fractional year 2016.3 (rounding to 1 decimal digit is sufficient).
51 * N.B. the model has limits of applicability. Be sure to check them
52 * using wmm_get_start and wmm_get_end before trusting the values
53 * returned by the model.
54 *
55 * @return If successful, the initialized model suitable for passing to
56 * wmm_mag2true. If a failure occurs, returns NULL instead.
57 */
58wmm_t *
59wmm_open(const char *filename, double year)
60{
61 wmm_t *wmm;
62 int n_max, n_terms;
63 MAGtype_Date date = { .DecimalYear = year };
64
65 wmm = safe_calloc(1, sizeof (*wmm));
66 if (!MAG_robustReadMagModels(filename, &wmm->fixed_model)) {
67 free(wmm);
68 return (NULL);
69 }
70 n_max = MAX(wmm->fixed_model->nMax, 0);
71 n_terms = ((n_max + 1) * (n_max + 2) / 2);
72 wmm->timed_model = MAG_AllocateModelMemory(n_terms);
73 ASSERT(wmm->timed_model != NULL);
74 MAG_TimelyModifyMagneticModel(date, wmm->fixed_model, wmm->timed_model);
75 wmm->ellip = (MAGtype_Ellipsoid){
76 .a = wgs84.a,
77 .b = wgs84.b,
78 .fla = wgs84.f,
79 .eps = wgs84.ecc,
80 .epssq = wgs84.ecc2,
81 .re = wgs84.r
82 };
83
84 return (wmm);
85}
86
87void
88wmm_reopen(wmm_t *wmm, double year)
89{
90 MAGtype_Date date = { .DecimalYear = year };
91
92 ASSERT(wmm != NULL);
93 ASSERT(wmm->fixed_model != NULL);
94 ASSERT(wmm->timed_model != NULL);
95
96 MAG_TimelyModifyMagneticModel(date, wmm->fixed_model, wmm->timed_model);
97}
98
99/*
100 * Closes a model returned by wmm_open and releases all its resources.
101 */
102void
103wmm_close(wmm_t *wmm)
104{
105 ASSERT(wmm != NULL);
106 MAG_FreeMagneticModelMemory(wmm->fixed_model);
107 MAG_FreeMagneticModelMemory(wmm->timed_model);
108 free(wmm);
109}
110
111/*
112 * Returns the earliest fractional year at which the provided model is valid.
113 */
114double
115wmm_get_start(const wmm_t *wmm)
116{
117 return (wmm->timed_model->epoch);
118}
119
120/*
121 * Returns the latest fractional year at which the provided model is valid.
122 */
123double
124wmm_get_end(const wmm_t *wmm)
125{
126 return (wmm->timed_model->CoefficientFileEndDate);
127}
128
129/*
130 * Returns the magnetic declination (variation) in degrees at a given point.
131 * East declination is positive, west negative.
132 *
133 * @param wmm Magnetic model to use. See wmm_open.
134 * @param p Geodetic position on the WGS84 spheroid for which to determine
135 * the magnetic declination.
136 */
137double
138wmm_get_decl(const wmm_t *wmm, geo_pos3_t p)
139{
140 MAGtype_CoordSpherical coord_sph;
141 MAGtype_CoordGeodetic coord_geo = {
142 .lambda = p.lon, .phi = p.lat,
143 .HeightAboveEllipsoid = FEET2MET(p.elev)
144 };
146
147 MAG_GeodeticToSpherical(wmm->ellip, coord_geo, &coord_sph);
148 MAG_Geomag(wmm->ellip, coord_sph, coord_geo, wmm->timed_model, &gme);
149
150 return (gme.Decl);
151}
152
153/*
154 * Converts a magnetic heading to true according to the world magnetic model.
155 *
156 * @param wmm Magnetic model to use. See wmm_open.
157 * @param m Magnetic heading in degrees to convert.
158 * @param p Geodetic position on the WGS84 spheroid for which to determine
159 * the conversion.
160 *
161 * @return The converted true heading in degrees.
162 */
163double
164wmm_mag2true(const wmm_t *wmm, double m, geo_pos3_t p)
165{
167 return (normalize_hdg(m + wmm_get_decl(wmm, p)));
168}
169
170/*
171 * Converts a true heading to magnetic according to the world magnetic model.
172 *
173 * @param wmm Magnetic model to use. See wmm_open.
174 * @param t True heading in degrees to convert.
175 * @param p Geodetic position on the WGS-84 spheroid for which to determine
176 * the conversion.
177 *
178 * @return The converted magnetic heading in degrees.
179 */
180double
181wmm_true2mag(const wmm_t *wmm, double t, geo_pos3_t p)
182{
184 return (normalize_hdg(t - wmm_get_decl(wmm, p)));
185}
#define ASSERT(x)
Definition assert.h:208
const ellip_t wgs84
Definition geom.c:38
static bool_t is_valid_hdg(double hdg)
Definition helpers.h:169
static double normalize_hdg(double hdg)
Definition helpers.h:215
static void * safe_calloc(size_t nmemb, size_t size)
Definition safe_alloc.h:71
double a
Definition geom.h:131
double b
Definition geom.h:132
double f
Definition geom.h:133
double ecc2
Definition geom.h:135
double r
Definition geom.h:136
double ecc
Definition geom.h:134
double lat
Definition geom.h:41
double elev
Definition geom.h:43
double lon
Definition geom.h:42
Definition wmm.c:36