magvar 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b32c74e5be7bda26d0902c0f6362360f4918e30c
4
+ data.tar.gz: 7a36cc6855e2b95739cd9b7feeddaeaed0338912
5
+ SHA512:
6
+ metadata.gz: 07e5fca75a8ee378cb2197faea8544106613972af16de2a093ec00b6ee7d41b255644f44ca44e5ab045ea2764c6f9fb2b7c694219520aad3da9cdfa7b12a1efd
7
+ data.tar.gz: 997cddc1140028325dcb8c1b13c8646bdf9fe3c12a842c0ff76daa3b9de39f0ec74c10108db41ba63c5ce196c552d5ae05f28a2add28c1d9893ea1c3101b1519
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.2.5
5
+ before_install: gem install bundler -v 1.12.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in magvar.gemspec
4
+ gemspec
@@ -0,0 +1,282 @@
1
+ Copyright (c) 2017 Julik Tarkhanov
2
+
3
+ GNU GENERAL PUBLIC LICENSE
4
+ Version 2, June 1991
5
+
6
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
7
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
8
+ Everyone is permitted to copy and distribute verbatim copies
9
+ of this license document, but changing it is not allowed.
10
+
11
+ Preamble
12
+
13
+ The licenses for most software are designed to take away your
14
+ freedom to share and change it. By contrast, the GNU General Public
15
+ License is intended to guarantee your freedom to share and change free
16
+ software--to make sure the software is free for all its users. This
17
+ General Public License applies to most of the Free Software
18
+ Foundation's software and to any other program whose authors commit to
19
+ using it. (Some other Free Software Foundation software is covered by
20
+ the GNU Lesser General Public License instead.) You can apply it to
21
+ your programs, too.
22
+
23
+ When we speak of free software, we are referring to freedom, not
24
+ price. Our General Public Licenses are designed to make sure that you
25
+ have the freedom to distribute copies of free software (and charge for
26
+ this service if you wish), that you receive source code or can get it
27
+ if you want it, that you can change the software or use pieces of it
28
+ in new free programs; and that you know you can do these things.
29
+
30
+ To protect your rights, we need to make restrictions that forbid
31
+ anyone to deny you these rights or to ask you to surrender the rights.
32
+ These restrictions translate to certain responsibilities for you if you
33
+ distribute copies of the software, or if you modify it.
34
+
35
+ For example, if you distribute copies of such a program, whether
36
+ gratis or for a fee, you must give the recipients all the rights that
37
+ you have. You must make sure that they, too, receive or can get the
38
+ source code. And you must show them these terms so they know their
39
+ rights.
40
+
41
+ We protect your rights with two steps: (1) copyright the software, and
42
+ (2) offer you this license which gives you legal permission to copy,
43
+ distribute and/or modify the software.
44
+
45
+ Also, for each author's protection and ours, we want to make certain
46
+ that everyone understands that there is no warranty for this free
47
+ software. If the software is modified by someone else and passed on, we
48
+ want its recipients to know that what they have is not the original, so
49
+ that any problems introduced by others will not reflect on the original
50
+ authors' reputations.
51
+
52
+ Finally, any free program is threatened constantly by software
53
+ patents. We wish to avoid the danger that redistributors of a free
54
+ program will individually obtain patent licenses, in effect making the
55
+ program proprietary. To prevent this, we have made it clear that any
56
+ patent must be licensed for everyone's free use or not licensed at all.
57
+
58
+ The precise terms and conditions for copying, distribution and
59
+ modification follow.
60
+
61
+ GNU GENERAL PUBLIC LICENSE
62
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
63
+
64
+ 0. This License applies to any program or other work which contains
65
+ a notice placed by the copyright holder saying it may be distributed
66
+ under the terms of this General Public License. The "Program", below,
67
+ refers to any such program or work, and a "work based on the Program"
68
+ means either the Program or any derivative work under copyright law:
69
+ that is to say, a work containing the Program or a portion of it,
70
+ either verbatim or with modifications and/or translated into another
71
+ language. (Hereinafter, translation is included without limitation in
72
+ the term "modification".) Each licensee is addressed as "you".
73
+
74
+ Activities other than copying, distribution and modification are not
75
+ covered by this License; they are outside its scope. The act of
76
+ running the Program is not restricted, and the output from the Program
77
+ is covered only if its contents constitute a work based on the
78
+ Program (independent of having been made by running the Program).
79
+ Whether that is true depends on what the Program does.
80
+
81
+ 1. You may copy and distribute verbatim copies of the Program's
82
+ source code as you receive it, in any medium, provided that you
83
+ conspicuously and appropriately publish on each copy an appropriate
84
+ copyright notice and disclaimer of warranty; keep intact all the
85
+ notices that refer to this License and to the absence of any warranty;
86
+ and give any other recipients of the Program a copy of this License
87
+ along with the Program.
88
+
89
+ You may charge a fee for the physical act of transferring a copy, and
90
+ you may at your option offer warranty protection in exchange for a fee.
91
+
92
+ 2. You may modify your copy or copies of the Program or any portion
93
+ of it, thus forming a work based on the Program, and copy and
94
+ distribute such modifications or work under the terms of Section 1
95
+ above, provided that you also meet all of these conditions:
96
+
97
+ a) You must cause the modified files to carry prominent notices
98
+ stating that you changed the files and the date of any change.
99
+
100
+ b) You must cause any work that you distribute or publish, that in
101
+ whole or in part contains or is derived from the Program or any
102
+ part thereof, to be licensed as a whole at no charge to all third
103
+ parties under the terms of this License.
104
+
105
+ c) If the modified program normally reads commands interactively
106
+ when run, you must cause it, when started running for such
107
+ interactive use in the most ordinary way, to print or display an
108
+ announcement including an appropriate copyright notice and a
109
+ notice that there is no warranty (or else, saying that you provide
110
+ a warranty) and that users may redistribute the program under
111
+ these conditions, and telling the user how to view a copy of this
112
+ License. (Exception: if the Program itself is interactive but
113
+ does not normally print such an announcement, your work based on
114
+ the Program is not required to print an announcement.)
115
+
116
+ These requirements apply to the modified work as a whole. If
117
+ identifiable sections of that work are not derived from the Program,
118
+ and can be reasonably considered independent and separate works in
119
+ themselves, then this License, and its terms, do not apply to those
120
+ sections when you distribute them as separate works. But when you
121
+ distribute the same sections as part of a whole which is a work based
122
+ on the Program, the distribution of the whole must be on the terms of
123
+ this License, whose permissions for other licensees extend to the
124
+ entire whole, and thus to each and every part regardless of who wrote it.
125
+
126
+ Thus, it is not the intent of this section to claim rights or contest
127
+ your rights to work written entirely by you; rather, the intent is to
128
+ exercise the right to control the distribution of derivative or
129
+ collective works based on the Program.
130
+
131
+ In addition, mere aggregation of another work not based on the Program
132
+ with the Program (or with a work based on the Program) on a volume of
133
+ a storage or distribution medium does not bring the other work under
134
+ the scope of this License.
135
+
136
+ 3. You may copy and distribute the Program (or a work based on it,
137
+ under Section 2) in object code or executable form under the terms of
138
+ Sections 1 and 2 above provided that you also do one of the following:
139
+
140
+ a) Accompany it with the complete corresponding machine-readable
141
+ source code, which must be distributed under the terms of Sections
142
+ 1 and 2 above on a medium customarily used for software interchange; or,
143
+
144
+ b) Accompany it with a written offer, valid for at least three
145
+ years, to give any third party, for a charge no more than your
146
+ cost of physically performing source distribution, a complete
147
+ machine-readable copy of the corresponding source code, to be
148
+ distributed under the terms of Sections 1 and 2 above on a medium
149
+ customarily used for software interchange; or,
150
+
151
+ c) Accompany it with the information you received as to the offer
152
+ to distribute corresponding source code. (This alternative is
153
+ allowed only for noncommercial distribution and only if you
154
+ received the program in object code or executable form with such
155
+ an offer, in accord with Subsection b above.)
156
+
157
+ The source code for a work means the preferred form of the work for
158
+ making modifications to it. For an executable work, complete source
159
+ code means all the source code for all modules it contains, plus any
160
+ associated interface definition files, plus the scripts used to
161
+ control compilation and installation of the executable. However, as a
162
+ special exception, the source code distributed need not include
163
+ anything that is normally distributed (in either source or binary
164
+ form) with the major components (compiler, kernel, and so on) of the
165
+ operating system on which the executable runs, unless that component
166
+ itself accompanies the executable.
167
+
168
+ If distribution of executable or object code is made by offering
169
+ access to copy from a designated place, then offering equivalent
170
+ access to copy the source code from the same place counts as
171
+ distribution of the source code, even though third parties are not
172
+ compelled to copy the source along with the object code.
173
+
174
+ 4. You may not copy, modify, sublicense, or distribute the Program
175
+ except as expressly provided under this License. Any attempt
176
+ otherwise to copy, modify, sublicense or distribute the Program is
177
+ void, and will automatically terminate your rights under this License.
178
+ However, parties who have received copies, or rights, from you under
179
+ this License will not have their licenses terminated so long as such
180
+ parties remain in full compliance.
181
+
182
+ 5. You are not required to accept this License, since you have not
183
+ signed it. However, nothing else grants you permission to modify or
184
+ distribute the Program or its derivative works. These actions are
185
+ prohibited by law if you do not accept this License. Therefore, by
186
+ modifying or distributing the Program (or any work based on the
187
+ Program), you indicate your acceptance of this License to do so, and
188
+ all its terms and conditions for copying, distributing or modifying
189
+ the Program or works based on it.
190
+
191
+ 6. Each time you redistribute the Program (or any work based on the
192
+ Program), the recipient automatically receives a license from the
193
+ original licensor to copy, distribute or modify the Program subject to
194
+ these terms and conditions. You may not impose any further
195
+ restrictions on the recipients' exercise of the rights granted herein.
196
+ You are not responsible for enforcing compliance by third parties to
197
+ this License.
198
+
199
+ 7. If, as a consequence of a court judgment or allegation of patent
200
+ infringement or for any other reason (not limited to patent issues),
201
+ conditions are imposed on you (whether by court order, agreement or
202
+ otherwise) that contradict the conditions of this License, they do not
203
+ excuse you from the conditions of this License. If you cannot
204
+ distribute so as to satisfy simultaneously your obligations under this
205
+ License and any other pertinent obligations, then as a consequence you
206
+ may not distribute the Program at all. For example, if a patent
207
+ license would not permit royalty-free redistribution of the Program by
208
+ all those who receive copies directly or indirectly through you, then
209
+ the only way you could satisfy both it and this License would be to
210
+ refrain entirely from distribution of the Program.
211
+
212
+ If any portion of this section is held invalid or unenforceable under
213
+ any particular circumstance, the balance of the section is intended to
214
+ apply and the section as a whole is intended to apply in other
215
+ circumstances.
216
+
217
+ It is not the purpose of this section to induce you to infringe any
218
+ patents or other property right claims or to contest validity of any
219
+ such claims; this section has the sole purpose of protecting the
220
+ integrity of the free software distribution system, which is
221
+ implemented by public license practices. Many people have made
222
+ generous contributions to the wide range of software distributed
223
+ through that system in reliance on consistent application of that
224
+ system; it is up to the author/donor to decide if he or she is willing
225
+ to distribute software through any other system and a licensee cannot
226
+ impose that choice.
227
+
228
+ This section is intended to make thoroughly clear what is believed to
229
+ be a consequence of the rest of this License.
230
+
231
+ 8. If the distribution and/or use of the Program is restricted in
232
+ certain countries either by patents or by copyrighted interfaces, the
233
+ original copyright holder who places the Program under this License
234
+ may add an explicit geographical distribution limitation excluding
235
+ those countries, so that distribution is permitted only in or among
236
+ countries not thus excluded. In such case, this License incorporates
237
+ the limitation as if written in the body of this License.
238
+
239
+ 9. The Free Software Foundation may publish revised and/or new versions
240
+ of the General Public License from time to time. Such new versions will
241
+ be similar in spirit to the present version, but may differ in detail to
242
+ address new problems or concerns.
243
+
244
+ Each version is given a distinguishing version number. If the Program
245
+ specifies a version number of this License which applies to it and "any
246
+ later version", you have the option of following the terms and conditions
247
+ either of that version or of any later version published by the Free
248
+ Software Foundation. If the Program does not specify a version number of
249
+ this License, you may choose any version ever published by the Free Software
250
+ Foundation.
251
+
252
+ 10. If you wish to incorporate parts of the Program into other free
253
+ programs whose distribution conditions are different, write to the author
254
+ to ask for permission. For software which is copyrighted by the Free
255
+ Software Foundation, write to the Free Software Foundation; we sometimes
256
+ make exceptions for this. Our decision will be guided by the two goals
257
+ of preserving the free status of all derivatives of our free software and
258
+ of promoting the sharing and reuse of software generally.
259
+
260
+ NO WARRANTY
261
+
262
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
263
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
264
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
265
+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
266
+ OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
267
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
268
+ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
269
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
270
+ REPAIR OR CORRECTION.
271
+
272
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
273
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
274
+ REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
275
+ INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
276
+ OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
277
+ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
278
+ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
279
+ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
280
+ POSSIBILITY OF SUCH DAMAGES.
281
+
282
+ END OF TERMS AND CONDITIONS
@@ -0,0 +1,54 @@
1
+ # Magvar
2
+
3
+ This is a port of the FlightGear magnetic variation model to Ruby. It provides a tiny wrapper around their magnetic variatio
4
+ estimator that can be used for creating sim flight planners, estimators and such.
5
+
6
+ Please be advised that since the FlightGear code is GPLv2 liensed, this gem has to have this license as well. This situation
7
+ might change in the future, but for now it is what it is. Using GPL-licensed libraries in commercial projects is a gray area,
8
+ if this is critical for you you might need to consider alternatives.
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'magvar'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install magvar
25
+
26
+ ## Usage
27
+
28
+
29
+ ```ruby
30
+ require 'magvar'
31
+ # Location is any object that responds to `#lat` and `#lon`, and returns the
32
+ # latitude and longitude in degrees as a Float. Positive latitudes are North,
33
+ # positive longitudes are East.
34
+ pt = Struct.new(:lat, :lon).new(68.781751845, 32.752029995)
35
+ Magvar.variation_at(pt.lat, pt.lon, elev_km=0, Time.now) # ~ 16.15
36
+ ```
37
+
38
+
39
+ ## Development
40
+
41
+ After checking out the repo, run `bundle install` to install dependencies.
42
+ Then, run `rake` to run the tests.
43
+
44
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
45
+
46
+ ## Contributing
47
+
48
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/magvar.
49
+
50
+
51
+ ## License
52
+
53
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
54
+
@@ -0,0 +1,14 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ require "rake/extensiontask"
7
+
8
+ task :build => :compile
9
+
10
+ Rake::ExtensionTask.new("magvar") do |ext|
11
+ ext.lib_dir = "lib/magvar"
12
+ end
13
+
14
+ task :default => [:clobber, :compile, :spec]
@@ -0,0 +1,3 @@
1
+ require "mkmf"
2
+
3
+ create_makefile("magvar/magvar")
@@ -0,0 +1,584 @@
1
+ // coremag.cxx -- compute local magnetic variation given position,
2
+ // altitude, and date
3
+ //
4
+ // This is an implementation of the NIMA (formerly DMA) WMM2000
5
+ //
6
+ // http://www.nima.mil/GandG/ngdc-wmm2000.html
7
+ //
8
+ // Copyright (C) 2000 Edward A Williams <Ed_Williams@compuserve.com>
9
+ //
10
+ // Adapted from Excel 3.0 version 3/27/94 EAW
11
+ // Recoded in C++ by Starry Chan
12
+ // WMM95 added and rearranged in ANSI-C EAW 7/9/95
13
+ // Put shell around program and made Borland & GCC compatible EAW 11/22/95
14
+ // IGRF95 added 2/96 EAW
15
+ // WMM2000 IGR2000 added 2/00 EAW
16
+ // Released under GPL 3/26/00 EAW
17
+ // Adaptions and modifications for the SimGear project 3/27/2000 CLO
18
+ //
19
+ // Removed all pow() calls and made static roots[][] arrays to
20
+ // save many sqrt() calls on subsequent invocations
21
+ // left old code as SGMagVarOrig() for testing purposes
22
+ // 3/28/2000 Norman Vine -- nhv@yahoo.com
23
+ //
24
+ // Put in some bullet-proofing to handle magnetic and geographic poles.
25
+ // 3/28/2000 EAW
26
+ //
27
+ // Updated coefficient arrays to use the current wmm2005 model,
28
+ // (valid between 2005.0 and 2010.0)
29
+ // Also removed unused variables and corrected earth radii constants
30
+ // to the values for WGS84 and WMM2005.
31
+ // Reference:
32
+ // McLean, S., S. Macmillan, S. Maus, V. Lesur, A.
33
+ // Thomson, and D. Dater, December 2004, The
34
+ // US/UK World Magnetic Model for 2005-2010,
35
+ // NOAA Technical Report NESDIS/NGDC-1.
36
+ //
37
+ // 25/10/2006 Wim Van Hoydonck -- wim.van.hoydonck@gmail.com
38
+ //
39
+ //
40
+ // Updated coefficient arrays to use the current WMM2015 model,
41
+ // (valid between 2015.0 and 2020.0)
42
+ // Also removed unused variables and corrected earth radii constants
43
+ // to the values for WGS84 and WMM2015.
44
+ // Reference:
45
+ // A. Chulliat , S. Macmillan, P. Alken, C. Beggan, M.
46
+ // Nair, B. Hamilton, A. Woods, V. Ridley,
47
+ // S Maus, and A Thomson, December 2014, The
48
+ // US/UK World Magnetic Model for 2015-2020,
49
+ // NOAA Technical Report WMM2015_Report.pdf
50
+ //
51
+ // 18/06/2015 Jean-Paul Anceaux -- j.p.r.anceaux@gmail.com
52
+
53
+
54
+ // The routine uses a spherical harmonic expansion of the magnetic
55
+ // potential up to twelfth order, together with its time variation, as
56
+ // described in Chapter 4 of "Geomagnetism, Vol 1, Ed. J.A.Jacobs,
57
+ // Academic Press (London 1987)". The program first converts geodetic
58
+ // coordinates (lat/long on elliptic earth and altitude) to spherical
59
+ // geocentric (spherical lat/long and radius) coordinates. Using this,
60
+ // the spherical (B_r, B_theta, B_phi) magnetic field components are
61
+ // computed from the model. These are finally referred to surface (X, Y,
62
+ // Z) coordinates.
63
+ //
64
+ // Fields are accurate to better than 200nT, variation and dip to
65
+ // better than 0.5 degrees, with the exception of the declination near
66
+ // the magnetic poles (where it is ill-defined) where the error may reach
67
+ // 4 degrees or more.
68
+ //
69
+ // Variation is undefined at both the geographic and
70
+ // magnetic poles, even though the field itself is well-behaved. To
71
+ // avoid the routine blowing up, latitude entries corresponding to
72
+ // the geographic poles are slightly offset. At the magnetic poles,
73
+ // the routine returns zero variation.
74
+
75
+
76
+ //
77
+ // This library is free software; you can redistribute it and/or
78
+ // modify it under the terms of the GNU Library General Public
79
+ // License as published by the Free Software Foundation; either
80
+ // version 2 of the License, or (at your option) any later version.
81
+ //
82
+ // This library is distributed in the hope that it will be useful,
83
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
84
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
85
+ // Library General Public License for more details.
86
+ //
87
+ // You should have received a copy of the GNU General Public License
88
+ // along with this program; if not, write to the Free Software
89
+ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
90
+ //
91
+ // $Id$
92
+
93
+
94
+ #include <stdio.h>
95
+ #include <stdlib.h>
96
+ #include <math.h>
97
+
98
+ //#include <simgear/constants.h>
99
+ //#include <simgear/sg_inlines.h>
100
+
101
+ #include "magvar.h"
102
+
103
+ // return the maximum of two values
104
+ int SG_MAX2(const int a, const int b) {
105
+ return a > b ? a : b;
106
+ }
107
+
108
+ static const double a = 6378.137; /* semi-major axis (equatorial radius) of WGS84 ellipsoid */
109
+ static const double b = 6356.7523142; /* semi-minor axis referenced to the WGS84 ellipsoid */
110
+ static const double r_0 = 6371.2; /* standard Earth magnetic reference radius */
111
+
112
+
113
+ static double gnm_wmm2015[13][13] =
114
+ {
115
+ {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
116
+ {-29438.5, -1501.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
117
+ {-2445.3, 3012.5, 1676.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
118
+ {1351.1, -2352.3, 1225.6, 581.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
119
+ {907.2, 813.7, 120.3, -335.0, 70.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
120
+ {-232.6, 360.1, 192.4, -141.0, -157.4, 4.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
121
+ {69.5, 67.4, 72.8, -129.8, -29.0, 13.2, -70.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
122
+ {81.6, -76.1, -6.8, 51.9, 15.0, 9.3, -2.8, 6.7, 0.0, 0.0, 0.0, 0.0, 0.0},
123
+ {24.0, 8.6, -16.9, -3.2, -20.6, 13.3, 11.7, -16.0, -2.0, 0.0, 0.0, 0.0, 0.0},
124
+ {5.4, 8.8, 3.1, -3.1, 0.6, -13.3, -0.1, 8.7, -9.1, -10.5, 0.0, 0.0, 0.0},
125
+ {-1.9, -6.5, 0.2, 0.6, -0.6, 1.7, -0.7, 2.1, 2.3, -1.8, -3.6, 0.0, 0.0},
126
+ {3.1, -1.5, -2.3, 2.1, -0.9, 0.6, -0.7, 0.2, 1.7, -0.2, 0.4, 3.5, 0.0},
127
+ {-2.0, -0.3, 0.4, 1.3, -0.9, 0.9, 0.1, 0.5, -0.4, -0.4, 0.2, -0.9, 0.0},
128
+ };
129
+
130
+ static double hnm_wmm2015[13][13]=
131
+ {
132
+ {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
133
+ {0.0, 4796.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
134
+ {0.0, -2845.6, -642.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
135
+ {0.0, -115.3, 245.0, -538.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
136
+ {0.0, 283.4, -188.6, 180.9, -329.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
137
+ {0.0, 47.4, 196.9, -119.4, 16.1, 100.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
138
+ {0.0, -20.7, 33.2, 58.8, -66.5, 7.3, 62.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
139
+ {0.0, -54.1, -19.4, 5.6, 24.4, 3.3, -27.5, -2.3, 0.0, 0.0, 0.0, 0.0, 0.0},
140
+ {0.0, 10.2, -18.1, 13.2, -14.6, 16.2, 5.7, -9.1, 2.2, 0.0, 0.0, 0.0, 0.0},
141
+ {0.0, -21.6, 10.8, 11.7, -6.8, -6.9, 7.8, 1.0, -3.9, 8.5, 0.0, 0.0, 0.0},
142
+ {0.0, 3.3, -0.3, 4.6, 4.4, -7.9, -0.6, -4.1, -2.8, -1.1, -8.7, 0.0, 0.0},
143
+ {0.0, -0.1, 2.1, -0.7, -1.1, 0.7, -0.2, -2.1, -1.5, -2.5, -2.0, -2.3, 0.0},
144
+ {0.0, -1.0, 0.5, 1.8, -2.2, 0.3, 0.7, -0.1, 0.3, 0.2, -0.9, -0.2, 0.7},
145
+ };
146
+
147
+ static double gtnm_wmm2015[13][13]=
148
+ {
149
+ {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
150
+ {10.7, 17.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
151
+ {-8.6, -3.3, 2.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
152
+ {3.1, -6.2, -0.4, -10.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
153
+ {-0.4, 0.8, -9.2, 4.0, -4.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
154
+ {-0.2, 0.1, -1.4, 0.0, 1.3, 3.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
155
+ {-0.5, -0.2, -0.6, 2.4, -1.1, 0.3, 1.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
156
+ {0.2, -0.2, -0.4, 1.3, 0.2, -0.4, -0.9, 0.3, 0.0, 0.0, 0.0, 0.0, 0.0},
157
+ {0.0, 0.1, -0.5, 0.5, -0.2, 0.4, 0.2, -0.4, 0.3, 0.0, 0.0, 0.0, 0.0},
158
+ {0.0, -0.1, -0.1, 0.4, -0.5, -0.2, 0.1, 0.0, -0.2, -0.1, 0.0, 0.0, 0.0},
159
+ {0.0, 0.0, -0.1, 0.3, -0.1, -0.1, -0.1, 0.0, -0.2, -0.1, -0.2, 0.0, 0.0},
160
+ {0.0, 0.0, -0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.1, -0.1, 0.0},
161
+ {0.1, 0.0, 0.0, 0.1, -0.1, 0.0, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
162
+ };
163
+
164
+ static double htnm_wmm2015[13][13]=
165
+ {
166
+ {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
167
+ {0.0, -26.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
168
+ {0.0, -27.1, -13.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
169
+ {0.0, 8.4, -0.4, 2.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
170
+ {0.0, -0.6, 5.3, 3.0, -5.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
171
+ {0.0, 0.4, 1.6, -1.1, 3.3, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
172
+ {0.0, 0.0, -2.2, -0.7, 0.1, 1.0, 1.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
173
+ {0.0, 0.7, 0.5, -0.2, -0.1, -0.7, 0.1, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
174
+ {0.0, -0.3, 0.3, 0.3, 0.6, -0.1, -0.2, 0.3, 0.0, 0.0, 0.0, 0.0, 0.0},
175
+ {0.0, -0.2, -0.1, -0.2, 0.1, 0.1, 0.0, -0.2, 0.4, 0.3, 0.0, 0.0, 0.0},
176
+ {0.0, 0.1, -0.1, 0.0, 0.0, -0.2, 0.1, -0.1, -0.2, 0.1, -0.1, 0.0, 0.0},
177
+ {0.0, 0.0, 0.1, 0.0, 0.1, 0.0, 0.0, 0.1, 0.0, -0.1, 0.0, -0.1, 0.0},
178
+ {0.0, 0.0, 0.0, -0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
179
+ };
180
+
181
+
182
+ /*
183
+ static const double gnm_wmm2005[13][13]=
184
+ {
185
+ { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
186
+ {-29556.8, -1671.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
187
+ { -2340.6, 3046.9, 1657.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
188
+ { 1335.4, -2305.1, 1246.7, 674.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
189
+ { 919.8, 798.1, 211.3, -379.4, 100.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
190
+ { -227.4, 354.6, 208.7, -136.5, -168.3, -14.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
191
+ { 73.2, 69.7, 76.7, -151.2, -14.9, 14.6, -86.3, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
192
+ { 80.1, -74.5, -1.4, 38.5, 12.4, 9.5, 5.7, 1.8, 0.0, 0.0, 0.0, 0.0, 0.0},
193
+ { 24.9, 7.7, -11.6, -6.9, -18.2, 10.0, 9.2, -11.6, -5.2, 0.0, 0.0, 0.0, 0.0},
194
+ { 5.6, 9.9, 3.5, -7.0, 5.1, -10.8, -1.3, 8.8, -6.7, -9.1, 0.0, 0.0, 0.0},
195
+ { -2.3, -6.3, 1.6, -2.6, 0.0, 3.1, 0.4, 2.1, 3.9, -0.1, -2.3, 0.0, 0.0},
196
+ { 2.8, -1.6, -1.7, 1.7, -0.1, 0.1, -0.7, 0.7, 1.8, 0.0, 1.1, 4.1, 0.0},
197
+ { -2.4, -0.4, 0.2, 0.8, -0.3, 1.1, -0.5, 0.4, -0.3, -0.3, -0.1, -0.3, -0.1}
198
+ };
199
+
200
+ static const double hnm_wmm2005[13][13]=
201
+ {
202
+
203
+ { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
204
+ { 0.0, 5079.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
205
+ { 0.0,-2594.7, -516.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
206
+ { 0.0, -199.9, 269.3, -524.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
207
+ { 0.0, 281.5, -226.0, 145.8, -304.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
208
+ { 0.0, 42.4, 179.8, -123.0, -19.5, 103.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
209
+ { 0.0, -20.3, 54.7, 63.6, -63.4, -0.1, 50.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
210
+ { 0.0, -61.5, -22.4, 7.2, 25.4, 11.0, -26.4, -5.1, 0.0, 0.0, 0.0, 0.0, 0.0},
211
+ { 0.0, 11.2, -21.0, 9.6, -19.8, 16.1, 7.7, -12.9, -0.2, 0.0, 0.0, 0.0, 0.0},
212
+ { 0.0, -20.1, 12.9, 12.6, -6.7, -8.1, 8.0, 2.9, -7.9, 6.0, 0.0, 0.0, 0.0},
213
+ { 0.0, 2.4, 0.2, 4.4, 4.8, -6.5, -1.1, -3.4, -0.8, -2.3, -7.9, 0.0, 0.0},
214
+ { 0.0, 0.3, 1.2, -0.8, -2.5, 0.9, -0.6, -2.7, -0.9, -1.3, -2.0, -1.2, 0.0},
215
+ { 0.0, -0.4, 0.3, 2.4, -2.6, 0.6, 0.3, 0.0, 0.0, 0.3, -0.9, -0.4, 0.8}
216
+ };
217
+
218
+ static const double gtnm_wmm2005[13][13]=
219
+ {
220
+ { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
221
+ { 8.0, 10.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
222
+ {-15.1, -7.8, -0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
223
+ { 0.4, -2.6, -1.2, -6.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
224
+ {-2.5, 2.8, -7.0, 6.2, -3.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
225
+ {-2.8, 0.7, -3.2, -1.1, 0.1, -0.8, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
226
+ {-0.7, 0.4, -0.3, 2.3, -2.1, -0.6, 1.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
227
+ { 0.2, -0.1, -0.3, 1.1, 0.6, 0.5, -0.4, 0.6, 0.0, 0.0, 0.0, 0.0, 0.0},
228
+ { 0.1, 0.3, -0.4, 0.3, -0.3, 0.2, 0.4, -0.7, 0.4, 0.0, 0.0, 0.0, 0.0},
229
+ { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
230
+ { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
231
+ { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
232
+ { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}
233
+ };
234
+
235
+ static const double htnm_wmm2005[13][13]=
236
+ {
237
+ { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
238
+ { 0.0, -20.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
239
+ { 0.0, -23.2, -14.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
240
+ { 0.0, 5.0, -7.0, -0.6, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
241
+ { 0.0, 2.2, 1.6, 5.8, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
242
+ { 0.0, 0.0, 1.7, 2.1, 4.8, -1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
243
+ { 0.0, -0.6, -1.9, -0.4, -0.5, -0.3, 0.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
244
+ { 0.0, 0.6, 0.4, 0.2, 0.3, -0.8, -0.2, 0.1, 0.0, 0.0, 0.0, 0.0, 0.0},
245
+ { 0.0, -0.2, 0.1, 0.3, 0.4, 0.1, -0.2, 0.4, 0.4, 0.0, 0.0, 0.0, 0.0},
246
+ { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
247
+ { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
248
+ { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
249
+ { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}
250
+ };
251
+ */
252
+
253
+ static const int nmax = 12;
254
+
255
+ static double P[13][13];
256
+ static double DP[13][13];
257
+ static double gnm[13][13];
258
+ static double hnm[13][13];
259
+ static double sm[13];
260
+ static double cm[13];
261
+
262
+ static double root[13];
263
+ static double roots[13][13][2];
264
+
265
+ /* Convert date to Julian day 1950-2049 */
266
+ unsigned long int yymmdd_to_julian_days( int yy, int mm, int dd )
267
+ {
268
+ unsigned long jd;
269
+
270
+ yy = (yy < 50) ? (2000 + yy) : (1900 + yy);
271
+ jd = dd - 32075L + 1461L * (yy + 4800L + (mm - 14) / 12 ) / 4;
272
+ jd = jd + 367L * (mm - 2 - (mm - 14) / 12*12) / 12;
273
+ jd = jd - 3 * ((yy + 4900L + (mm - 14) / 12) / 100) / 4;
274
+
275
+ /* printf("julian date = %d\n", jd ); */
276
+ return jd;
277
+ }
278
+
279
+
280
+ /*
281
+ * return variation (in degrees) given geodetic latitude (degrees),
282
+ * longitude(degrees), height (km) and (Julian) date
283
+ * N and E lat and long are positive, S and W negative
284
+ * Lat and lon are given in radian
285
+ */
286
+
287
+ double calc_magvar(double lat, double lon, long dat, double h)
288
+ {
289
+ lat *= (M_PI / 180);
290
+ lon *= (M_PI / 180);
291
+ /* output field B_r,B_th,B_phi,B_x,B_y,B_z */
292
+ int n,m;
293
+ /* reference date for current model is 1 januari 2015 */
294
+ long date0_wmm2015 = yymmdd_to_julian_days(15,1,1);
295
+
296
+ double yearfrac,sr,r,theta,c,s,psi,fn,fn_0,B_r,B_theta,B_phi,X,Y,Z;
297
+ double sinpsi, cospsi, inv_s;
298
+
299
+ static int been_here = 0;
300
+
301
+ double sinlat = sin(lat);
302
+ double coslat = cos(lat);
303
+
304
+ /* convert to geocentric coords: */
305
+ // sr = sqrt(pow(a*coslat,2.0)+pow(b*sinlat,2.0));
306
+ sr = sqrt(a*a*coslat*coslat + b*b*sinlat*sinlat);
307
+ /* sr is effective radius */
308
+ theta = atan2(coslat * (h*sr + a*a),
309
+ sinlat * (h*sr + b*b));
310
+ /* theta is geocentric co-latitude */
311
+
312
+ r = h*h + 2.0*h * sr +
313
+ (a*a*a*a - ( a*a*a*a - b*b*b*b ) * sinlat*sinlat ) /
314
+ (a*a - (a*a - b*b) * sinlat*sinlat );
315
+
316
+ r = sqrt(r);
317
+
318
+ /* r is geocentric radial distance */
319
+ c = cos(theta);
320
+ s = sin(theta);
321
+ /* protect against zero divide at geographic poles */
322
+ inv_s = 1.0 / (s + (s == 0.)*1.0e-8);
323
+
324
+ /* zero out arrays */
325
+ for ( n = 0; n <= nmax; n++ ) {
326
+ for ( m = 0; m <= n; m++ ) {
327
+ P[n][m] = 0;
328
+ DP[n][m] = 0;
329
+ }
330
+ }
331
+
332
+ /* diagonal elements */
333
+ P[0][0] = 1;
334
+ P[1][1] = s;
335
+ DP[0][0] = 0;
336
+ DP[1][1] = c;
337
+ P[1][0] = c ;
338
+ DP[1][0] = -s;
339
+
340
+ // these values will not change for subsequent function calls
341
+ if( !been_here ) {
342
+ for ( n = 2; n <= nmax; n++ ) {
343
+ root[n] = sqrt((2.0*n-1) / (2.0*n));
344
+ }
345
+
346
+ for ( m = 0; m <= nmax; m++ ) {
347
+ double mm = m*m;
348
+ for ( n = SG_MAX2(m + 1, 2); n <= nmax; n++ ) {
349
+ roots[m][n][0] = sqrt((n-1)*(n-1) - mm);
350
+ roots[m][n][1] = 1.0 / sqrt( n*n - mm);
351
+ }
352
+ }
353
+ been_here = 1;
354
+ }
355
+
356
+ for ( n=2; n <= nmax; n++ ) {
357
+ // double root = sqrt((2.0*n-1) / (2.0*n));
358
+ P[n][n] = P[n-1][n-1] * s * root[n];
359
+ DP[n][n] = (DP[n-1][n-1] * s + P[n-1][n-1] * c) *
360
+ root[n];
361
+ }
362
+
363
+ /* lower triangle */
364
+ for ( m = 0; m <= nmax; m++ ) {
365
+ // double mm = m*m;
366
+ for ( n = SG_MAX2(m + 1, 2); n <= nmax; n++ ) {
367
+ // double root1 = sqrt((n-1)*(n-1) - mm);
368
+ // double root2 = 1.0 / sqrt( n*n - mm);
369
+ P[n][m] = (P[n-1][m] * c * (2.0*n-1) -
370
+ P[n-2][m] * roots[m][n][0]) *
371
+ roots[m][n][1];
372
+
373
+ DP[n][m] = ((DP[n-1][m] * c - P[n-1][m] * s) *
374
+ (2.0*n-1) - DP[n-2][m] * roots[m][n][0]) *
375
+ roots[m][n][1];
376
+ }
377
+ }
378
+
379
+ /* compute Gauss coefficients gnm and hnm of degree n and order m for the desired time
380
+ achieved by adjusting the coefficients at time t0 for linear secular variation */
381
+ /* WMM2015 */
382
+ yearfrac = (dat - date0_wmm2015) / 365.25;
383
+ for ( n = 1; n <= nmax; n++ ) {
384
+ for ( m = 0; m <= nmax; m++ ) {
385
+ gnm[n][m] = gnm_wmm2015[n][m] + yearfrac * gtnm_wmm2015[n][m];
386
+ hnm[n][m] = hnm_wmm2015[n][m] + yearfrac * htnm_wmm2015[n][m];
387
+ }
388
+ }
389
+
390
+ /* compute sm (sin(m lon) and cm (cos(m lon)) */
391
+ for ( m = 0; m <= nmax; m++ ) {
392
+ sm[m] = sin(m * lon);
393
+ cm[m] = cos(m * lon);
394
+ }
395
+
396
+ /* compute B fields */
397
+ B_r = 0.0;
398
+ B_theta = 0.0;
399
+ B_phi = 0.0;
400
+ fn_0 = r_0/r;
401
+ fn = fn_0 * fn_0;
402
+
403
+ for ( n = 1; n <= nmax; n++ ) {
404
+ double c1_n=0;
405
+ double c2_n=0;
406
+ double c3_n=0;
407
+ for ( m = 0; m <= n; m++ ) {
408
+ double tmp = (gnm[n][m] * cm[m] + hnm[n][m] * sm[m]);
409
+ c1_n=c1_n + tmp * P[n][m];
410
+ c2_n=c2_n + tmp * DP[n][m];
411
+ c3_n=c3_n + m * (gnm[n][m] * sm[m] - hnm[n][m] * cm[m]) * P[n][m];
412
+ }
413
+ // fn=pow(r_0/r,n+2.0);
414
+ fn *= fn_0;
415
+ B_r = B_r + (n + 1) * c1_n * fn;
416
+ B_theta = B_theta - c2_n * fn;
417
+ B_phi = B_phi + c3_n * fn * inv_s;
418
+ }
419
+
420
+ /* Find geodetic field components: */
421
+ psi = theta - ((M_PI / 2.0) - lat);
422
+ sinpsi = sin(psi);
423
+ cospsi = cos(psi);
424
+ X = -B_theta * cospsi - B_r * sinpsi;
425
+ Y = B_phi;
426
+ Z = B_theta * sinpsi - B_r * cospsi;
427
+
428
+
429
+ /* find variation in radians */
430
+ /* return zero variation at magnetic pole X=Y=0. */
431
+ /* E is positive */
432
+ if (X != 0. || Y != 0.) {
433
+ return atan2(Y, X) / (M_PI / 180);
434
+ } else {
435
+ return (double) 0.0;
436
+ }
437
+ }
438
+
439
+
440
+ #ifdef TEST_NHV_HACKS
441
+ double SGMagVarOrig( double lat, double lon, double h, long dat, double* field )
442
+ {
443
+ /* output field B_r,B_th,B_phi,B_x,B_y,B_z */
444
+ int n,m;
445
+ /* reference dates */
446
+ long date0_wmm2015 = yymmdd_to_julian_days(5,1,1);
447
+
448
+ double yearfrac,sr,r,theta,c,s,psi,fn,B_r,B_theta,B_phi,X,Y,Z;
449
+
450
+ /* convert to geocentric coords: */
451
+ sr = sqrt(pow(a*cos(lat),2.0)+pow(b*sin(lat),2.0));
452
+ /* sr is effective radius */
453
+ theta = atan2(cos(lat) * (h * sr + a * a),
454
+ sin(lat) * (h * sr + b * b));
455
+ /* theta is geocentric co-latitude */
456
+
457
+ r = h * h + 2.0*h * sr +
458
+ (pow(a,4.0) - (pow(a,4.0) - pow(b,4.0)) * pow(sin(lat),2.0)) /
459
+ (a * a - (a * a - b * b) * pow(sin(lat),2.0));
460
+
461
+ r = sqrt(r);
462
+
463
+ /* r is geocentric radial distance */
464
+ c = cos(theta);
465
+ s = sin(theta);
466
+
467
+ /* zero out arrays */
468
+ for ( n = 0; n <= nmax; n++ ) {
469
+ for ( m = 0; m <= n; m++ ) {
470
+ P[n][m] = 0;
471
+ DP[n][m] = 0;
472
+ }
473
+ }
474
+
475
+ /* diagonal elements */
476
+ P[0][0] = 1;
477
+ P[1][1] = s;
478
+ DP[0][0] = 0;
479
+ DP[1][1] = c;
480
+ P[1][0] = c ;
481
+ DP[1][0] = -s;
482
+
483
+ for ( n = 2; n <= nmax; n++ ) {
484
+ P[n][n] = P[n-1][n-1] * s * sqrt((2.0*n-1) / (2.0*n));
485
+ DP[n][n] = (DP[n-1][n-1] * s + P[n-1][n-1] * c) *
486
+ sqrt((2.0*n-1) / (2.0*n));
487
+ }
488
+
489
+ /* lower triangle */
490
+ for ( m = 0; m <= nmax; m++ ) {
491
+ for ( n = SG_MAX2(m + 1, 2); n <= nmax; n++ ) {
492
+ P[n][m] = (P[n-1][m] * c * (2.0*n-1) - P[n-2][m] *
493
+ sqrt(1.0*(n-1)*(n-1) - m * m)) /
494
+ sqrt(1.0* n * n - m * m);
495
+ DP[n][m] = ((DP[n-1][m] * c - P[n-1][m] * s) *
496
+ (2.0*n-1) - DP[n-2][m] *
497
+ sqrt(1.0*(n-1) * (n-1) - m * m)) /
498
+ sqrt(1.0* n * n - m * m);
499
+ }
500
+ }
501
+
502
+ /* compute gnm, hnm at dat */
503
+ /* WMM2015 */
504
+ yearfrac = (dat - date0_wmm2015) / 365.25;
505
+ for ( n = 1; n <= nmax; n++ ) {
506
+ for ( m = 0; m <= nmax; m++ ) {
507
+ gnm[n][m] = gnm_wmm2015[n][m] + yearfrac * gtnm_wmm2015[n][m];
508
+ hnm[n][m] = hnm_wmm2015[n][m] + yearfrac * htnm_wmm2015[n][m];
509
+ }
510
+ }
511
+
512
+ /* compute sm (sin(m lon) and cm (cos(m lon)) */
513
+ for ( m = 0; m <= nmax; m++ ) {
514
+ sm[m] = sin(m * lon);
515
+ cm[m] = cos(m * lon);
516
+ }
517
+
518
+ /* compute B fields */
519
+ B_r = 0.0;
520
+ B_theta = 0.0;
521
+ B_phi = 0.0;
522
+
523
+ for ( n = 1; n <= nmax; n++ ) {
524
+ double c1_n=0;
525
+ double c2_n=0;
526
+ double c3_n=0;
527
+ for ( m = 0; m <= n; m++ ) {
528
+ c1_n=c1_n + (gnm[n][m] * cm[m] + hnm[n][m] * sm[m]) * P[n][m];
529
+ c2_n=c2_n + (gnm[n][m] * cm[m] + hnm[n][m] * sm[m]) * DP[n][m];
530
+ c3_n=c3_n + m * (gnm[n][m] * sm[m] - hnm[n][m] * cm[m]) * P[n][m];
531
+ }
532
+ fn=pow(r_0/r,n+2.0);
533
+ B_r = B_r + (n + 1) * c1_n * fn;
534
+ B_theta = B_theta - c2_n * fn;
535
+ B_phi = B_phi + c3_n * fn / s;
536
+ }
537
+
538
+ /* Find geodetic field components: */
539
+ psi = theta - (pi / 2.0 - lat);
540
+ X = -B_theta * cos(psi) - B_r * sin(psi);
541
+ Y = B_phi;
542
+ Z = B_theta * sin(psi) - B_r * cos(psi);
543
+
544
+ field[0]=B_r;
545
+ field[1]=B_theta;
546
+ field[2]=B_phi;
547
+ field[3]=X;
548
+ field[4]=Y;
549
+ field[5]=Z; /* output fields */
550
+
551
+ /* find variation, leave in radians! */
552
+ return atan2(Y, X); /* E is positive */
553
+ }
554
+ #endif // TEST_NHV_HACKS
555
+
556
+ #include <ruby.h>
557
+
558
+ /* lat/lon:: decimal radians (S and W are negative)
559
+ * alt:: altitude above sea level in km
560
+ * jd:: Julian date
561
+ * Returns a two-element array, [var, dip] (radians)
562
+ */
563
+ static VALUE rb_magvar(VALUE self, VALUE deg_lat, VALUE deg_lon, VALUE elev_km_msl, VALUE at_time)
564
+ {
565
+ int yy = FIX2INT(rb_funcall(at_time, rb_intern("year"), 0));
566
+ // The year argument is not a full int but the decimal part (17 for 2017, 99 for 1999 etc)
567
+ if (yy > 20) {
568
+ yy -= 1900;
569
+ } else {
570
+ yy -= 2000;
571
+ }
572
+ int mm = FIX2INT(rb_funcall(at_time, rb_intern("month"), 0));
573
+ int dd = FIX2INT(rb_funcall(at_time, rb_intern("day"), 0));
574
+ unsigned long cjd = yymmdd_to_julian_days(yy, mm, dd);
575
+ double mv_deg = calc_magvar(NUM2DBL(deg_lat), NUM2DBL(deg_lon), cjd, NUM2DBL(elev_km_msl));
576
+ return rb_float_new(mv_deg);
577
+ }
578
+
579
+ /* Magnetic variation calculation, using the code from SimGear */
580
+ void Init_magvar() {
581
+ VALUE mod;
582
+ mod = rb_define_module("Magvar");
583
+ rb_define_module_function(mod, "variation_at", rb_magvar, 4);
584
+ }
@@ -0,0 +1,51 @@
1
+ // coremag.hxx -- compute local magnetic variation given position,
2
+ // altitude, and date
3
+ //
4
+ // This is an implimentation of the NIMA WMM 2000
5
+ //
6
+ // http://www.nima.mil/GandG/ngdc-wmm2000.html
7
+ //
8
+ // Copyright (C) 2000 Edward A Williams <Ed_Williams@compuserve.com>
9
+ //
10
+ // Adapted from Excel 3.0 version 3/27/94 EAW
11
+ // Recoded in C++ by Starry Chan
12
+ // WMM95 added and rearranged in ANSI-C EAW 7/9/95
13
+ // Put shell around program and made Borland & GCC compatible EAW 11/22/95
14
+ // IGRF95 added 2/96 EAW
15
+ // WMM2000 IGR2000 added 2/00 EAW
16
+ // Released under GPL 3/26/00 EAW
17
+ // Adaptions and modifications for the SimGear project 3/27/2000 CLO
18
+ //
19
+ // This library is free software; you can redistribute it and/or
20
+ // modify it under the terms of the GNU Library General Public
21
+ // License as published by the Free Software Foundation; either
22
+ // version 2 of the License, or (at your option) any later version.
23
+ //
24
+ // This library is distributed in the hope that it will be useful,
25
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
26
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27
+ // Library General Public License for more details.
28
+ //
29
+ // You should have received a copy of the GNU General Public License
30
+ // along with this program; if not, write to the Free Software
31
+ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
32
+ //
33
+ // $Id$
34
+
35
+
36
+ #ifndef SG_MAGVAR_HXX
37
+ #define SG_MAGVAR_HXX
38
+
39
+ //#define M_PI 3.1415926535897932384626433832795028841971693993751
40
+
41
+
42
+ /* Convert date to Julian day 1950-2049 */
43
+ unsigned long int yymmdd_to_julian_days( int yy, int mm, int dd );
44
+
45
+ /* return variation (in degrees) given geodetic latitude (degrees), longitude
46
+ (degrees) ,height (km) and (Julian) date
47
+ N and E lat and long are positive, S and W negative
48
+ */
49
+ double calc_magvar( double lat, double lon, long dat, double h);
50
+
51
+ #endif // SG_MAGVAR_HXX
@@ -0,0 +1,6 @@
1
+ require "magvar/version"
2
+ require "magvar/magvar"
3
+
4
+ module Magvar
5
+ # Your code goes here...
6
+ end
@@ -0,0 +1,3 @@
1
+ module Magvar
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'magvar/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "magvar"
8
+ spec.version = Magvar::VERSION
9
+ spec.authors = ["Julik Tarkhanov"]
10
+ spec.email = ["me@julik.nl"]
11
+
12
+ spec.summary = %q{Magnetic variation calculation ported from FlightGear}
13
+ spec.description = %q{Magnetic variation calculation ported from FlightGear}
14
+ spec.homepage = "https://github.com/julik/magvar"
15
+ spec.license = "GPLv2"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
+ end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+ spec.extensions = ["ext/magvar/extconf.rb"]
30
+
31
+ spec.add_development_dependency "bundler", "~> 1.12"
32
+ spec.add_development_dependency "rake", "~> 10.0"
33
+ spec.add_development_dependency "rake-compiler"
34
+ spec.add_development_dependency "rspec", "~> 3.0"
35
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: magvar
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Julik Tarkhanov
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-03-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake-compiler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: Magnetic variation calculation ported from FlightGear
70
+ email:
71
+ - me@julik.nl
72
+ executables: []
73
+ extensions:
74
+ - ext/magvar/extconf.rb
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - ".rspec"
79
+ - ".travis.yml"
80
+ - Gemfile
81
+ - LICENSE.txt
82
+ - README.md
83
+ - Rakefile
84
+ - ext/magvar/extconf.rb
85
+ - ext/magvar/magvar.c
86
+ - ext/magvar/magvar.h
87
+ - lib/magvar.rb
88
+ - lib/magvar/version.rb
89
+ - magvar.gemspec
90
+ homepage: https://github.com/julik/magvar
91
+ licenses:
92
+ - GPLv2
93
+ metadata:
94
+ allowed_push_host: https://rubygems.org
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ requirements: []
110
+ rubyforge_project:
111
+ rubygems_version: 2.4.5.1
112
+ signing_key:
113
+ specification_version: 4
114
+ summary: Magnetic variation calculation ported from FlightGear
115
+ test_files: []