Generated reference › WGS84 Gravity Model — Robotics/Gravity Models
kind: generated#block#robotics-gravity-models

WGS84 Gravity Model — Robotics/Gravity Models

WGS84

Robotics/Gravity_Models/WGS84_Gravity_Model · 1 input / 1 output port(s) at insert · exports to Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Description#

The block's own DESCRIPTION_HTML, rendered verbatim — the same text the config dialog's info panel and the library navigator show. Fix a wrong sentence in the block's .cpp (R-D9), never here.

WGS84 Gravity Model

Robotics / Gravity Models

Normal gravity of the 1984 World Geodetic System's equipotential ellipsoid (NIMA TR8350.2) at a geodetic position, in the local north-east-down frame: g = [gN; 0; gD], with gD positive downward and gN positive northward. With the geodetic latitude φ, the height h and the ellipsoid's constants a, e², f, γe, k:

  • Taylor Series – gD = γ(φ)·(1 − 2(1 + f + m − 2f·sin²φ)·h/a + 3h²/a²), with γ(φ) = γe(1 + k·sin²φ) / √(1 − e²sin²φ); gN = 0.
  • Close Approximation – the point is taken to ellipsoidal-harmonic coordinates (u, β), the two components γu, γβ of the normal field are evaluated there, and gD = √(γu² + γβ²); gN = 0.
  • Exact – the same two components rotated through the geocentric latitude ψ and the deflection α = φ − ψ into the geodetic vertical (gD) and the north tangent (gN), so the north component is real.

Ports

  • lla – the position as one [3,1], [φ; λ; h]: geodetic latitude and longitude in degrees, then height above the ellipsoid in metres, in that order. A latitude past a pole is folded back and its longitude turned half a revolution, as the reference does.
  • g – the gravity vector as one [3,1], [gN; 0; gD] in m/s². The east entry is always 0, and so is the north entry except under Exact.

Parameters

  • Gravity Model – which method runs. This selects which arithmetic executes, not just a value:
    • Taylor Series – the closed-form surface gravity expanded to second order in h. The default, and Simulink's. Meant for low heights; the three switches below do not apply to it.
    • Close Approximation – the ellipsoidal-harmonic field at the point, as a magnitude. Sub-microgal below about 20000 m.
    • Exact – the same field resolved into down and north.
  • Exclude Atmosphere – on (the default) uses GM without the atmosphere's mass, 3.9860009×1014; off uses the WGS84 value including it, 3.986004418×1014 m³/s². Harmonic methods only.
  • Precessing Reference Frame – on (the default) takes Earth's rate as the IAU value plus the precession in right ascension at the date below, ω = 7.2921151467×10−5 + 7.086×10−12 + 4.3×10−15·T, T in Julian centuries from J2000; off takes the WGS84 rate 7.292115×10−5 rad/s. Harmonic methods only.
  • No Centrifugal Effects – on (the default) removes the centrifugal term, leaving pure attraction; off folds it in, which is what an instrument at rest on the Earth feels. Harmonic methods only.
  • Month – the date's month, January to December. Defaults to October. Read only with a precessing frame.
  • Day – the date's day, a whole number from 1 to 31. Defaults to 10. A day past the month's end is taken as its last day (February 30 as February 28), as Simulink does.
  • Year – the date's year, a whole number of 1 or more. Defaults to 2004. A year of 99 is special, exactly as in the reference: the Julian date is then the Day itself rather than a date in the year 99.
  • Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.

Code export

All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text.

The method and the three switches are baked in at export time: a core built for Taylor Series contains no harmonic arithmetic at all, and one built without the centrifugal term contains no centrifugal term. Earth's rate is computed from the date once, when the block's configuration is loaded, and emitted as a constant. Every target emits the reference's association operation for operation, because two of the intermediate quantities are small differences of large ones and a reordered product moves the last three digits; the C and C++ bodies also switch off fused multiply-add for the same reason.

The three hardware targets are simulation-only: sines, cosines, arctangents, square roots and divisions of a planet-sized geometry do not belong in a Q16.16 datapath, so the arithmetic runs in real and only the ports are fixed point. Q16.16 also bounds what a port can carry to about ±32767, which keeps a hardware core below about 32 km of height. VHDL carries the body as a function with its own real variables; PLC Structured Text has no floor and rebuilds it from TRUNC.

How closely a target agrees depends on its math library, because two of the intermediate quantities are small differences of large ones and magnify a rounding about a hundred thousand times. Measured over 16 configurations: the generated MATLAB reproduces the Simulink block exactly, and C, Python, Verilog and SystemVerilog (under Icarus) agree to about 5×10−15 m/s². A library that differs in the last place moves the answer by up to about 2×10−12: Java's does (7×10−13), and so does an optimising C or C++ compiler that fuses a sine and a cosine of the same angle into one call. VHDL under GHDL uses the IEEE reference MATH_REAL, whose sine and arctangent are good to about 10−8, and there agrees to about 5×10−4 m/s²; its cosine of π/2 is exactly zero, which would divide by zero at a latitude of exactly ±90°, so the VHDL body replaces that zero with the correctly rounded value.

Simulink bridge

Import and export, mapped to Aerospace Blockset's aerolibgravity2/WGS84 Gravity Model   – the library name really ends in two spaces. Gravity Model → model (Taylor Series/Close Approximation/Exact → WGS84 Taylor Series/WGS84 Close Approximation/WGS84 Exact), Exclude Atmosphere → no_atmos, Precessing Reference Frame → precessing, No Centrifugal Effects → no_centrifugal (all three on/off 1:1), Month → month (1:1), Day → day and Year → year. Every mapping is 1:1 and lossless in both directions.

Three Simulink parameters are always implied and carry no configuration here: units is always Metric (MKS) (English units do not cross), jd_loc is always off – Simulink's option of taking the Julian date on a second input port does not cross, because no configuration here can add a port, and a Julian date near 2.46×106 could not ride a hardware port in any case – and action is always Warning. That last one only chooses whether Simulink reports a height below 0 or above 20000 m, or a folded latitude; the values are the same either way, and this block computes them without a report. An imported block holding any other value of the three is reported rather than silently accepted. Simulink refuses a [3,1] MATRIX on this port: it takes a 1-D 3-element vector (or an [m,3] array of points), so feed the exported block from something that produces a vector. The Simulink block defines no SampleTime, so the rate stays on the ICore side.

Notes

  • Algebraic and stateless: the output depends only on this sample's input.
  • Not linear, so the block carries no state space and model reduction correctly reports it as unmergeable.
  • The longitude does not change the answer – the ellipsoid is symmetric about the spin axis – except in its last digits, where the reference's own rounding of it shows. It is wrapped and folded exactly as the reference does so that those digits agree too.
  • A latitude past a pole is folded in radians (π − φ across the north pole, −π − φ across the south), with the longitude turned by +π and −π respectively. Only Exact can tell the difference, and without the fold a latitude of 181 is wrong by 19.6 m/s² there.
  • Do not check Close Approximation or Exact against MATLAB's gravitywgs84 at its defaults: the function includes the centrifugal term and the atmosphere by default and the Simulink block (and this one) excludes both, so the two disagree by about 0.017 m/s² at 45°.
  • Verified against R2026a: over 16 configurations and 25 points (both hemispheres, latitudes of 95, 181, 270 and 450, heights from −500 to 32000 m, the leap-day, invalid-day and year-99 dates) the Simulink block and this arithmetic agree to 5.3×10−15.

Code facts#

FactValue
registered typeRobotics/Gravity_Models/WGS84_Gravity_Model
familyRobotics/Gravity_Models
solver environment classICoreBlock_0_Robotics_1_Gravity_Models_2_WGS84_Gravity_Model
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Gravity_Models/WGS84_Gravity_Model/ICoreBlock_0_Robotics_1_Gravity_Models_2_WGS84_Gravity_Model.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Gravity_Models/WGS84_Gravity_Model/ICoreBlock_0_Robotics_1_Gravity_Models_2_WGS84_Gravity_Model.h
default size on canvas170 × 80 px
ports at insert1 in, 1 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoublella
2outICoreDoubleg

Ports the constructor creates. A block whose port list changes with its configuration adds or removes ports at load time; the count above is the one a freshly inserted block has.

Configuration variables#

Config variableDefaultSimulink parameter
Gravity Modelstd::string(MODEL_TAYLOR)%~%MODEL_CLOSE%~%MODEL_EXACT~~MO…model
Exclude AtmosphereonOffno_atmos
Precessing Reference FrameonOffprecessing
No Centrifugal EffectsonOffno_centrifugal
Monthmonths~~MONTHS[9]month
Day10day
Year2004year

Every block also carries Sampling Time (s) from ICoreBlockSolverEnvironment: zero or less inherits the solver's rate, a positive value runs the block at that period.

supportSupport::Both
Simulink pathaerolibgravity2/WGS84 Gravity Model
port-count rulePortsParam::None
SampleTime parameterno — the counterpart defines none; the rate stays on the ICore side
always setunits = Metric (MKS), jd_loc = off, action = Warning
ICore configSimulink parameterValue translation
Gravity ModelmodelTaylor Series → WGS84 Taylor Series, Close Approximation → WGS84 Close Approximation, Exact → WGS84 Exact
Exclude Atmosphereno_atmoson → on, off → off
Precessing Reference Frameprecessingon → on, off → off
No Centrifugal Effectsno_centrifugalon → on, off → off
MonthmonthJanuary → January, February → February, March → March, April → April, May → May, June → June, July → July, August → August, September → September, October → October, November → November, December → December
Daydaypasses through
Yearyearpasses through

Caveat (shown to the user): the position crosses as [lat; lon; h] in degrees, degrees and metres, and gravity comes back as [north; 0; down] in m/s^2. ⚠ The Simulink block REFUSES a [3x1] matrix signal -- it takes a 1-D 3-element vector or an [m x 3] array of points -- so feed the exported block from something that produces a vector. 'units' is always Metric (MKS): English units do not cross. 'jd_loc' is always off: taking the Julian date on a second input port does not cross, because no configuration here adds a port. 'action' is always Warning; it only decides whether Simulink reports a height outside [0, 20000] m or a folded latitude, and the values are identical either way. The Simulink block has no SampleTime, so the rate stays on the ICore side. ⚠ Gravity Model IS A MODE: the three methods run different arithmetic and each is rigged separately

Catalog contract: src/ICoreBlocks/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h

Description vs code#

The lists agree. check_block_descriptions.py finds no disagreement between the description's Ports, Parameters, Code export and Simulink bridge lists and the code's.

The verdict above is tools/docs/check_block_descriptions.py (P7.1), which compares LISTS. It cannot read a sentence: "stateless" on a block with a state, an initial-value semantic the recursion does not implement, a "not synthesizable" caveat the HDL banner contradicts. That is the agent audit (P7.3) on BLOCK_DESCRIPTION_AUDIT.md, and this tool's green is not a substitute for one.

File banner (developer view)#

The top comment of the block's .cpp — the maths, the realization and the export strategy, addressed to whoever changes it. It must not contradict the description above (P7.5).

WGS84 Gravity Model -- normal gravity of the 1984 World Geodetic System's ellipsoid Input [lat; lon; h] geodetic latitude and longitude in DEGREES, height in METRES Output [g_north; 0; g_down] in the local north-east-down frame, m/s^2

Transcribed from MathWorks' reference C, shared_aero_gravity/src/aerogravitywgs84.c (NIMA TR8350.2 eqs. 4-1..4-24), the same source the MATLAB function gravitywgs84 runs:

Taylor Series gamma(phi)*(1 - 2(1 + f + m - 2f sin^2 phi) h/a + 3 h^2/a^2), gamma(phi) = gamma_e (1 + k sin^2 phi)/sqrt(1 - e^2 sin^2 phi) Close Approximation |(gamma_u, gamma_beta)| at the point, in ellipsoidal-harmonic coordinates (u, beta), eqs. 4-5 and 4-6 Exact (gamma_u, gamma_beta) rotated through the geocentric latitude psi and the deflection alpha = phi - psi into the geodetic vertical and the north tangent, eqs. 4-16 and 4-23

MEASURED against R2026a's aerolibgravity2/WGS84 Gravity Model (the name really ends in two spaces) over 16 configurations x 25 points, including latitudes past both poles and past a full half-turn: this arithmetic reproduces the block to <= 5.3e-15 everywhere.

⚠ THE MULTIPLY ORDER IS THE REFERENCE'S, AND HERE THAT IS NOT PEDANTRY. q and q' (eqs. 4-11, 4-13) are differences of two terms that agree to five or six digits, so the arithmetic amplifies a rounding by ~1e5. Measured: one unit in the last place of the latitude IN RADIANS moves the answer by 6.2e-13, and letting the compiler fuse a multiply-add moves it by 7.1e-13 -- so this file turns contraction off (below) and every generator emits the same association as the reference.

⚠ A LATITUDE PAST A POLE IS FOLDED IN RADIANS, NOT DEGREES, AND THE LONGITUDE TURNS BY +pi ACROSS THE NORTH POLE AND -pi ACROSS THE SOUTH ONE. Both are measured: folding in degrees (90 - |mod(lat + 90, 360) - 180|, which is exact for the flat-Earth blocks) is off by 6.2e-13 at a latitude of 95, and a +pi at the south pole by 3.2e-13 at 181. The Exact method is not even symmetric under the fold -- without it a latitude of 181 is wrong by 19.6.

⚠ A YEAR OF 99 IS A SENTINEL in the reference: the Julian date is then the DAY itself, not a date in the year 99. Measured, and reproduced. An invalid day is clamped to the month's last (February 30 -> 28, April 31 -> 30), as the Simulink block does with a warning.

ALGEBRAIC and STATELESS.

Sample results#

WGS84 Gravity Model — Sine Wave, [3,1]: amplitudes 1/2/3 at 2 rad/s (tried only because every scalar stimulus was refused)WGS84 Gravity Model — Sine Wave, [3,1]: amplitudes 1/2/3 at 2 rad/s (tried only because every scalar stimulus was refused)-1-0.500.51012345t (s)in ICoreDouble-Out-0 [3x1] entry 0out ICoreDouble-Out-0 [3x1] entry 0

Plotted: vector — Sine Wave, [3,1]: amplitudes 1/2/3 at 2 rad/s (tried only because every scalar stimulus was refused)

Category dynamic · sample time 0.1 · 60 steps · commit 383c0ecf1501cf1d43d89b8f688fc2fcad5e9b52 · produced by docsSample --out <folder> --blocks Ideal_Airspeed_Correction WGS84_Gravity_Model Linear_Regression_Predictor Linear_Classifier_Predictor Crossover_Pilot_Model Precision_Pilot_Model Tustin_Pilot_Model FIR_Least_Squares_Design FIR_Equiripple_Design Cartesian_To_Keplerian_Elements Keplerian_Elements_To_Cartesian --steps 60 · data docs/generated/samples/Robotics__Gravity_Models__WGS84_Gravity_Model.json · the SVG is generated from those numbers by tools/docs/plot_svg.py, so it is a run and not a drawing (R-D10).