1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
use TAU;
use Float;
// todo: Update the table; it's from 2012
// #include <stdio.h>
// #include <math.h>
// /*
// Adjust electronic compass readings from magnetic north to true north using a subset of data generated by the NOAA WMM70.exe software.
// Approximate magnetic declination for latitudes -60..60 and all longitudes for July 15, 2012 (the midpoint of the the period covered by
// the model.) Points at 10 degree intervals of a (latitude, longitude) grid are plotted for declination with the WMM2010 software.
// Declinations are stored in the source program in a literal string. Bilinear interpolation is then used to approximate the declinations
// within these 10 degree grids. This method allows microcontrollers with minimal memory resources to correct readings from a compass sensor
// for true north. Test readings should be within a few degrees of the WMM2010 model for most inhabited locations.
// If you just need to use the existing lookup table here for use in your program, you will need
// only the declination() function to retrieve values from the lookup table dec_tbl[]
// Call declination with your latitude and longitude. approximation for declination is returned.
// To create your own lookup table:
// STEP 1: download and install geomag70.exe from www.ngdc.noaa.gov/geomag/WMM/soft.shtml
// STEP 2: read the readme.txt file
// eg. run the program at the command prompt for help: geomag70 h
// then modify fprintf() format string in the build_wmm_input_file() for your required values
// run this program and choose '3. Build Input File' to create geomag70_input.txt
// the file contents will look something like this:
// 2012.5 D M100 -60 -180
// 2012.5 D M100 -60 -170
// :
// 2012.5 D M100 60 170
// 2012.5 D M100 60 180
// STEP 3: To create the raw output file run: geomage70.exe WMM2010.COF f geomag70_input.txt geomag70_output.txt
// the file contents will look something like this:
// Date Coord-System Altitude Latitude Longitude D_deg D_min I_deg I_min H_nT X_nT Y_nT Z_nT F_nT dD_min dI_min dH_nT dX_nT dY_nT dZ_nT dF_nT
// 2012.5 D M100 -60 -180 46d 37m -77d 45m 13243.3 9095.8 9625.6 -60953.3 62375.4 6.6 1.2 10.5 -11.2 25.0 55.3 -51.8
// 2012.5 D M100 -60 -170 45d 31m -75d 45m 14906.9 10446.2 10634.5 -58725.1 60587.5 5.8 1.4 8.1 -12.3 23.3 66.1 -62.1
// :
// 2012.5 D M100 60 170 -1d 28m 70d 21m 18169.1 18163.1 -467.1 50891.8 54037.8 -2.2 1.9 -6.5 -6.8 -11.6 68.4 62.3
// 2012.5 D M100 60 180 3d 58m 70d 23m 18041.0 17997.9 1247.3 50595.9 53716.1 -6.4 1.8 -5.0 -2.7 -33.6 69.0 63.3
// STEP 4: To build the lookup table run this program and choose '4. Build Lookup Table'
// this will extract the declination values from the 6th and 7th columns in the geomag70_output.txt file for each lat,lon
// to create the file wmm_ss.txt containing a comma-separated list of declinations as minutes
// the file contents will look something like this:
// 46,45,44,42,41,40,37,-68,0,0,0,...
// Break this into multiple lines in your program with the '\' line continuation directive:
// 46,45,...32,-4, \ (one space after comma, then '\', then hit return)
// 37,22-3,...,25, \
// etc.
// STEP 5: using a text editor, copy the data into the declination() function dec_tbl[] lookup table
// STEP 6: test the declination() function by choosing option '2. Lookup Declinations' using various latitudes and longitudes
// compare the approximated declinations with the geomag_70.exe calculated declinations
// scottfromscott@bellsouth.net
// */
// void build_wmm_input_file()
// {
// /*
// Build input file for processing by the geomag70.exe program available from the NOAA web site above
// The input file has the following format
// where columns are date, coord_system, meters_above_sea_level, lat, lon
// 2012.5 is midpoint of WMM2010 model's range
// 100 meters above sea level is is the average elevation of populated areas
// 2012.5 D M100 -60 -180
// 2012.5 D M100 -60 -170
// :
// 2012.5 D M100 60 170
// 2012.5 D M100 60 180
// */
// int lat_index, lon_index;
// FILE *fp;
// fp = fopen("geomag70_input.txt", "w");
// for (lat_index=-60;lat_index<=60;lat_index += 10)
// {
// for(lon_index=-180;lon_index<=180;lon_index += 10)
// {
// fprintf(fp,"2012.5 D M100 %hd %hd\n",lat_index,lon_index);
// }
// }
// fclose(fp);
// }
// void build_lookup_table()
// {
// /*
// for each lat,lon, read declination value from geomag70_output.txt file
// write declination value rounded to nearest degree as char type: -128..127 to the wmm_ss.txt file
// */
// FILE *inf, *outf;
// short d, m, dec, entry_counter;
// int i, j, k, lat_index, lon_index;
// char line[160], dec_deg[4], dec_min[4];
// inf = fopen("geomag70_output.txt", "r");
// outf = fopen("wmm_ss.txt", "w");
// fgets ( line, sizeof(line), inf );
// // -60..0..60 step 10 => 2(6) + 1 = 13 dimensions for lat
// for (lat_index=0;lat_index<13;lat_index++)
// {// -180..0..180 step 10 => 2(18) + 1 = 37 dimensions for lon
// for(lon_index=0;lon_index<37;lon_index++)
// {
// // get declination from file
// fgets ( line, sizeof(line), inf );
// // dig out the degrees and minutes
// i = 0;
// for(j=1;j<=5;j++)
// {
// while(line[i]!=' ') i++;
// i++;
// }
// i+=2;
// j = 0;
// while (line[i]!='d') dec_deg[j++] = line[i++];
// dec_deg[j]='\0';
// i+=2;
// j=0;
// while (line[i]!='m') dec_min[j++] = line[i++];
// dec_min[j]='\0';
// d = atoi(dec_deg); // d is signed
// m = atoi(dec_min);
// m=(d<0)? -m : m; // m is not signed, so adjust it for negative d's
// dec = round(d+(m/60)); // round to nearest degree
// //output to clean file...
// fprintf(outf,"%i,",dec);
// }
// }
// fclose(inf);
// fclose(outf);
// }
// -60..0..60 step 10 => 2(6) + 1 = 13 dimensions for lat; -180..0..180 step 10 => 2(18) + 1 = 37 dimensions for lon
const LUT: = ;
/// lat and lon input here are in degrees. The result is in radians.