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

Zonal Harmonic Gravity Model — Robotics/Gravity Models

J₂J₃J₄

Robotics/Gravity_Models/Zonal_Harmonic_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.

Zonal Harmonic Gravity Model

Robotics / Gravity Models

Gravitational acceleration from a zonal harmonic expansion – the part of a planet's field that depends on latitude alone, which is its oblateness (J₂) and the two pear-shaped terms above it (J₃, J₄). Nothing here varies with longitude, so the whole model is three numbers. With r = |p|, φ = asin(z/r), ρ = √(x² + y²) and the unnormalised Legendre functions P(n,0), P(n,1) of sinφ:

  • gr = −GM/r² + Σn=2..N GM/r²·(R/r)n·(n+1)·P(n,0)·Jn
  • gφ = −Σn=2..N GM/r²·(R/r)n·P(n,1)·Jn
  • gx = ((1/r)gr − z·gφ/(rρ))·x, gy the same with y, and gz = (1/r)gr·z + (ρ/r)gφ

It is the cheap gravity model an orbit propagator actually uses: three constants instead of a spherical-harmonic coefficient file.

Ports

  • p – the position as one [3,1], [x; y; z] in the planet-fixed frame, in R's length unit. The shape is fixed: it is how the Simulink block is drawn, and one point crosses at a time.
  • g_zonal – the gravitational acceleration as one [3,1] in the same frame. It is gravitational, not gravity: the planet's spin is not in it, and Centrifugal Effect Model is the block that adds that.

Parameters

  • Degree – how far the expansion runs. This selects which arithmetic executes, not just a value:
    • Degree 2 – oblateness only, J₂.
    • Degree 3 – J₂ and J₃.
    • Degree 4 – J₂, J₃ and J₄. The default, and Simulink's.
  • Equatorial Radius – the reference radius R the expansion is written against, a scalar. Defaults to 6378136.3 metres, the value the Simulink dialog carries (EGM's, not WGS84's 6378137).
  • Gravitational Parameter – GM, a scalar in R's length unit cubed per second squared. Defaults to 3.986004415×1014.
  • Zonal Coefficients – the three dimensionless J values as a vector [J₂ J₃ J₄], either way up. Defaults to Earth's [1.0826269e-03 −2.5323000e-06 −1.6204000e-06]. Entries beyond the chosen degree are read but never used.
  • 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.

R, GM and the three J values are baked into the emitted arithmetic rather than published as tunable parameters – a planet is structural – and the chosen degree is unrolled at export time, so a core built at degree 2 contains no J₃ term at all rather than multiplying one by zero. The multiply order is the reference's, left-associated with the J last, in every target: folding J into a per-degree constant is the obvious optimisation and it moves the last two digits.

The three hardware targets are simulation-only: an arcsine, two square roots and three divisions do not belong in a Q16.16 datapath, and a fixed-point port could not carry a planet-sized position in any case – Q16.16 saturates past about 32767. VHDL additionally clamps the arcsine's argument to [−1, 1] with (|u+1| − |u−1|)/2, because IEEE.MATH_REAL.ARCSIN asserts outside that range and an assertion aborts the whole simulation; the clamp is branchless so it costs one unit in the last place on ordinary samples and nothing else. PLC Structured Text has ASIN and needs no reconstruction.

Simulink bridge

Import and export, mapped to Aerospace Blockset's aerolibgravity2/Zonal Harmonic Gravity Model. Degree → degree, Equatorial Radius → R, Gravitational Parameter → GM and Zonal Coefficients → jvalue. R, GM and the coefficients pass straight through; the degree is translated, Degree 2/3/4 → 2/3/4, which is 1:1 and therefore lossless in both directions. The options are spelled as words here on purpose: a combo is a string configuration, and one whose values parse as numbers can be typed as a matrix instead, which leaves the block unable to read its own default.

Three Simulink parameters are always implied and carry no configuration here: ptype is always Custom, units always Metric (MKS), and action always Warning. Custom is not cosmetic – measured in R2026a, a block left on its Earth setting accepts a written R or GM and discards it. action chooses what Simulink does when a requested degree exceeds the model's; this block's degree cannot exceed four, so it never fires. Simulink's ptype also offers eight named planets, which do not cross: each is a stored constant there and this block takes the numbers themselves. 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.
  • On the spin axis gx and gy are forced to zero. ρ is zero there and the shared bracket divides by it; the reference ends with the same two assignments. Without them a point over a pole is a NaN.
  • sinφ is sin(asin(z/r)), not z/r, and cosφ is cos(asin(z/r)), not √(1 − (z/r)²). The reference goes through the angle and the round trip moves the last place; matching it is what keeps this block inside a 10−12 band rather than a 10−15 one.
  • Verified against R2026a: at p = (7000000.1, −1200000.35, 4300000.7) the Simulink block and MATLAB's own gravityzonal agree to the last bit at degrees 3 and 4 and to one unit in the last place at degree 2, and this block reproduces them.

Code facts#

FactValue
registered typeRobotics/Gravity_Models/Zonal_Harmonic_Gravity_Model
familyRobotics/Gravity_Models
solver environment classICoreBlock_0_Robotics_1_Gravity_Models_2_Zonal_Harmonic_Gravity_Model
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Gravity_Models/Zonal_Harmonic_Gravity_Model/ICoreBlock_0_Robotics_1_Gravity_Models_2_Zonal_Harmonic_Gravity_Model.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Gravity_Models/Zonal_Harmonic_Gravity_Model/ICoreBlock_0_Robotics_1_Gravity_Models_2_Zonal_Harmonic_Gravity_Model.h
default size on canvas160 × 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
1inICoreDoublep
2outICoreDoubleg_zonal

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
Degreestd::string(DEGREE_2)%~%DEGREE_3%~%DEGREE_4~~DEGREE_4—
Equatorial RadiuscFmt(EARTH_R)—
Gravitational ParametercFmt(EARTH_GM)—
Zonal Coefficients[cFmt(EARTH_J2) cFmt(EARTH_J3) cFmt(EARTH_J4)]—

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/Zonal Harmonic Gravity Model
port-count rulePortsParam::None
SampleTime parameterno — the counterpart defines none; the rate stays on the ICore side
always setptype = Custom, units = Metric (MKS), action = Warning
ICore configSimulink parameterValue translation
CONFIG_DEGREE.c_str()degreeDEGREE_2 → 2, DEGREE_3 → 3, DEGREE_4 → 4
CONFIG_R.c_str()Rpasses through
CONFIG_GM.c_str()GMpasses through
CONFIG_J.c_str()jvaluepasses through

Caveat (shown to the user): the position crosses as one [3,1] in the planet-fixed frame and the GRAVITATIONAL acceleration comes back the same shape -- the planet's spin is not in it, and Centrifugal Effect Model is what adds that. 'ptype' is always written as Custom, because a block left on Earth accepts a written R or GM and discards it -- measured in R2026a. Simulink's eight other named planets do not cross: each is a stored constant there and this block takes the numbers themselves. 'action' is always Warning and never fires, the degree being capped at four on both sides. The Simulink block has no SampleTime, so the rate stays on the ICore side. ⚠ DEGREE IS A MODE: 2, 3 and 4 run different arithmetic, so each is rigged separately rather than one standing for all three

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

Description vs code#

The checker has a blind spot here — it could not resolve something (a grouped port bullet, a computed config name), which is reported and never counted as a pass. A reader has to settle it:

  • B0 4 Simulink params rule(s) this tool cannot resolve
  • B0 every stimulus in the sample errored — cross-checks skipped

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).

Zonal Harmonic Gravity Model -- oblateness gravity, J2 through J4 r = |p|, phi = asin(z/r), s = sin(phi), c = cos(phi), rho = sqrt(x^2 + y^2) gr = -GM/r^2 + SUM(n=2..N) GM/r^2 * (R/r)^n * (n+1) * P(n,0) * J(n) gl = - SUM(n=2..N) GM/r^2 * (R/r)^n * P(n,1) * J(n) gx = ( (1/r)*gr - z*gl/(r*rho) ) * x gy = ( (1/r)*gr - z*gl/(r*rho) ) * y gz = (1/r)*gr*z + (rho/r)*gl

The zonal harmonics are the part of a planet's field that depends on LATITUDE alone -- its oblateness and the pear-shaped terms above that -- so nothing here varies with longitude and the whole model is three numbers, J2, J3 and J4. It is the cheap gravity model an orbit propagator actually uses.

⚠ THE MULTIPLY ORDER IS THE REFERENCE'S AND IT IS WRITTEN OUT DELIBERATELY. MATLAB's gravityzonal accumulates GM./(r.*r).*(Re./r).^n.*(n+1).*P.*J, which associates LEFT: the (n+1) comes before the Legendre value and the J AFTER it. Folding J into a per-degree constant, which is the obvious optimisation, moves a rounding and takes the last two digits with it. Every one of the ten backends emits the same association for the same reason.

⚠ THE LEGENDRE FUNCTIONS ARE WRITTEN OUT, NOT RECURSED, because the degree never exceeds four and a recursion would have to be identical in ten languages to be worth anything: P(2,0) = (3s^2 - 1)/2 P(2,1) = 3sc P(3,0) = (5s^3 - 3s)/2 P(3,1) = c(15s^2 - 3)/2 P(4,0) = (35s^4 - 30s^2 + 3)/8 P(4,1) = 2.5c(7s^3 - 3s)

⚠ AND s IS sin(asin(z/r)) RATHER THAN z/r, WHICH IS NOT THE SAME NUMBER. The reference goes through the angle -- rlat = asin(...), then srlat = sin(rlat) -- and the round trip moves the last place. c is cos(asin(z/r)) for the same reason, and not sqrt(1 - (z/r)^2).

⚠ ON THE SPIN AXIS gx AND gy ARE FORCED TO ZERO. rho is zero there and the shared bracket divides by it; the reference ends with the same two assignments. Without them a point over a pole is a NaN in nine backends and whatever the tenth's division does.

⚠ DEGREE IS A MODE, NOT A TUNING: two, three and four run different arithmetic, so each gets a rig of its own (ADDING_NEW_BLOCKS §6, "Blocks with modes").

ALGEBRAIC and STATELESS.

Sample results#

No stimulus produced a sampled output in this rig — Invalid input size at Zonal Harmonic Gravity Model block: ICore Blocks/Home/Zonal Harmonic Gravity Model. That is a fact about the single-block rig, not a verdict on the block: an offline batch fit, a block whose output only appears at onSolverFinish, or one that needs a driven environment cannot be exercised alone.

Category unsampled · sample time 0.1 · 60 steps · commit bdad587a606126371cea1bff31197cd014d7b244 · produced by docsSample --out <folder> --blocks Centrifugal_Effect_Model Zonal_Harmonic_Gravity_Model --steps 60

Sample data: docs/generated/samples/Robotics__Gravity_Models__Zonal_Harmonic_Gravity_Model.json