The Spherical Harmonic Model

This documentation was generated with the assistance of AI. Please report any inaccuracies.

Classes: WorldMagneticModel, WMMLoader, WMMEarthMagneticFluxDensityEstimator.

Coefficient files

The WMM represents the Earth’s main magnetic field (and its slow year-on-year drift) as a degree-and-order-12 spherical harmonic expansion of the geomagnetic potential. Its 168+134 Gauss coefficients are re-fit every 5 years by NCEI/NGA/BGS from satellite, aircraft, and observatory measurements, and published as a plain-text .cof coefficient file — see NOAA coefficient downloads and the file-format description ([wmm-site]). This library bundles a wmm.cof resource and loads it through WMMLoader; a newer release can be substituted by loading a different file, resource, or URL.

Each WMM release is only valid for WorldMagneticModel.LIFESPAN (5.0) years from its epoch — WMMEarthMagneticFluxDensityEstimator itself uses model.epoch + LIFESPAN / 2.0 as the default date whenever no explicit year is supplied, but it does not check, warn, or refuse to compute past that window: it will happily (and silently) extrapolate secular variation arbitrarily far past epoch + 5 years, with growing error. The bundled wmm.cof is WMM-2025 (epoch 2025.0, nominally valid through 2030.0). To use this library beyond a bundled model’s 5-year window, download the current coefficient file from NOAA/NCEI’s WMM coefficients page and load it via WMMLoader.loadFromFile(…​) / WMMLoader.loadFromResource(…​) / WMMLoader.loadFromUrl(…​) (see below) instead of the no-arg WMMEarthMagneticFluxDensityEstimator() constructor, which always loads the bundled default.

Each data line in the file has the form:

n  m  gnm  hnm  dgnm  dhnm

and are the spherical harmonic degree and order; , are the main-field Gauss coefficients (nT) at the model epoch; , are their secular-variation rates (nT/year). WorldMagneticModel stores these (Schmidt semi-normalized, see below) together with the epoch year.

WMMLoader: Schmidt semi-normalization

Raw Gauss coefficients are published in Schmidt quasi-normalized form. WMMLoader converts them, once, into the fully normalized form used internally, via the recursive Schmidt normalization factor:


and rescales (and equivalently for , , ). It also precomputes the recursion coefficients

used by WMMEarthMagneticFluxDensityEstimator to generate the associated Legendre functions.

// load a specific coefficient file (e.g. a newer WMM release than the bundled one)
WorldMagneticModel model = WMMLoader.loadFromFile("/path/to/WMM.COF");

// or from an arbitrary resource/URL:
// WMMLoader.loadFromResource("/com/irurueta/navigation/inertial/wmm/wmm.cof");
// WMMLoader.loadFromUrl("https://example.org/WMM.COF");

WMMEarthMagneticFluxDensityEstimator: evaluating the model

Given a geodetic position and a decimal year, the estimator:

flowchart TD A["geodetic latitude/longitude/height,\ndecimal year"] --> B["Convert geodetic to\ngeocentric spherical coordinates"] B --> C["Time-adjust Gauss coefficients:\ng + (year - epoch) * gdot"] C --> D["Recursively evaluate Schmidt\nsemi-normalized Legendre functions"] D --> E["Accumulate spherical-harmonic sum\n(radial, colatitude, longitude components)"] E --> F["Rotate geocentric components\nto geodetic North/East/Down"] F --> G["Declination, dip, intensity,\nNEDMagneticFluxDensity"]

1. Geodetic-to-geocentric conversion. Because the WGS84 ellipsoid is not a sphere, geodetic latitude must first be converted to a geocentric colatitude and radius before the spherical-harmonic sum applies.

2. Time adjustment. Coefficients are linearly extrapolated from the model epoch:


This is only a good approximation within the model’s 5-year validity window (see World Magnetic Model (WMM)) — extrapolating far past years accumulates error.

3. Legendre recursion. The Schmidt semi-normalized associated Legendre functions and their colatitude derivatives are generated by the stable recursion (using from WMMLoader):


4. Spherical-harmonic sum. The field components in geocentric spherical coordinates (radial , colatitude , longitude ) accumulate one term per pair, using raised to the -th power ( = 6371.2 km, the WMM reference radius):

(with the term handled by a separate polar-region recursion at the geographic poles, where ). See the NOAA WMM technical report ([wmm-site]) for the full derivation.

5. Rotate to geodetic North/East/Down. The geocentric components are rotated back into the geodetic frame using the geocentric/geodetic latitude difference angle computed during step 1:



6. Derived quantities. Horizontal intensity, total intensity, declination, and dip follow directly:




WMMEarthMagneticFluxDensityEstimator exposes each of these individually (getDeclination, getDip, getIntensity, getHorizontalIntensity, getNorthIntensity, getEastIntensity, getVerticalIntensity) as well as the full NEDMagneticFluxDensity vector via estimate(…​).

// no-arg constructor loads the coefficient file bundled with this library
WMMEarthMagneticFluxDensityEstimator estimator = new WMMEarthMagneticFluxDensityEstimator();

NEDPosition position = new NEDPosition(Math.toRadians(41.3851), Math.toRadians(2.1734), 0.0);
double year = 2026.5; // decimal year

double declination = estimator.getDeclination(position, year); // radians
double dip = estimator.getDip(position.getLatitude(), position.getLongitude(), position.getHeight(), year);

NEDMagneticFluxDensity b = new NEDMagneticFluxDensity();
estimator.estimate(position.getLatitude(), position.getLongitude(), position.getHeight(), year, b);

Where to go next