Generated reference › ECEF Position To LLA — Robotics/Axes Transformations
kind: generated#block#robotics-axes-transformations

ECEF Position To LLA — Robotics/Axes Transformations

φλh xyz

Robotics/Axes_Transformations/ECEF_Position_To_LLA · 1 input / 2 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.

ECEF Position To LLA

Robotics / Axes Transformations

Converts a Cartesian position in the planet-fixed ECEF frame back into geodetic latitude, longitude and altitude above the ellipsoid. With e² = f(2−f):

  • λ = atan2(y, x), the longitude, which is closed form
  • ρ = √(x² + y²), and φ = atan2(z, ρ) to start, which is the answer for a sphere
  • then, 32 times: N = R / √(1 − e²·sin²φ) and φ = atan2(z + e²·N·sinφ, ρ)
  • h = ρ·cosφ + (z + e²·N·sinφ)·sinφ − N

It is the exact inverse of LLA To ECEF Position, and much the more expensive half: that direction is four lines of algebra, this one is a root of a quartic.

Ports

  • p_ECEF – the position as one [3,1], [x; y; z] in R's length unit. The shape is fixed: it is how the Simulink block is drawn, and one point crosses at a time.
  • mu_iota – the geodetic latitude φ and longitude λ stacked as one [2,1], both in DEGREES. The latitude lands in [−90, 90] and the longitude in (−180, 180].
  • h – the altitude above the ellipsoid, a scalar in R's length unit.

Parameters

  • Flattening – the ellipsoid's flattening f, a dimensionless scalar. Defaults to 0.0033528106647474805, WGS84's 1/298.257223563. Zero gives a sphere, on which the iteration converges in one pass. A value of exactly 1 is refused: it is a degenerate ellipsoid with no polar extent.
  • Equatorial Radius – the ellipsoid's equatorial radius R, a scalar. Defaults to WGS84's 6378137 metres, and its unit is the unit the input position is read in and the altitude is written in.
  • 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.

Every target runs the same fixed 32 passes, and that is a deliberate choice rather than an oversight: a loop that stopped on a convergence test would stop at a different pass in different languages, and the export would then disagree with the simulation for reasons having nothing to do with the arithmetic. Thirty-two is margin – measured against R2026a, eight passes already reach 7×10−15 degrees and stay there at Earth's flattening.

The three hardware targets are simulation-only. Beyond the sine, the square root and the arctangent, VHDL carries the running latitude in Q16.16, because a VHDL process's scratch storage is fixed-point only; Verilog and SystemVerilog keep theirs in floating point, where they are allowed to declare one. A fixed-point port cannot carry an Earth-sized position at all – Q16.16 saturates past about 32767 – so a hardware export of this block is for a small custom body or for lengths in a larger unit. PLC Structured Text has no ATAN2 in IEC 61131-3, so it is rebuilt from ATAN with the quadrant tests written out, inside the loop.

Simulink bridge

Import and export, mapped to Aerospace Blockset's aerolibtransform2/ECEF Position to LLA. Flattening → F and Equatorial Radius → R, values passing straight through.

Two Simulink parameters are always implied and carry no configuration here: ptype is always Custom and units always Metric (MKS). Custom is not cosmetic – measured in R2026a, a block left on its Earth (WGS84) setting accepts a written F or R and discards it. The Simulink block defines no SampleTime, so the rate stays on the ICore side.

Notes

  • Algebraic and stateless: the 32 passes all happen inside one sample and nothing survives it.
  • Not linear, so the block carries no state space and model reduction correctly reports it as unmergeable.
  • The two sides do not run the same algorithm. MATLAB's reference iterates Bowring's recursion until a pair of auxiliary sines stops moving, capped at five passes; this block runs a fixed thirty-two. They agree to about 7×10−15 degrees rather than bit for bit, which is why the parity band is 10−12.
  • The altitude is first-order insensitive to a latitude error, which is what makes it safe to evaluate from the iterate: at the fixed point the derivatives of its two leading terms cancel exactly, leaving O(e²²).

Code facts#

FactValue
registered typeRobotics/Axes_Transformations/ECEF_Position_To_LLA
familyRobotics/Axes_Transformations
solver environment classICoreBlock_0_Robotics_1_Axes_Transformations_2_ECEF_Position_To_LLA
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Axes_Transformations/ECEF_Position_To_LLA/ICoreBlock_0_Robotics_1_Axes_Transformations_2_ECEF_Position_To_LLA.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Axes_Transformations/ECEF_Position_To_LLA/ICoreBlock_0_Robotics_1_Axes_Transformations_2_ECEF_Position_To_LLA.h
default size on canvas150 × 78 px
ports at insert1 in, 2 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoublep_ECEF
2outICoreDoublemu_iota
3outICoreDoubleh

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
FlatteningcFmt(WGS84_F)—
Equatorial RadiuscFmt(WGS84_R)—

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 pathaerolibtransform2/ECEF Position to LLA
port-count rulePortsParam::None
SampleTime parameterno — the counterpart defines none; the rate stays on the ICore side
always setptype = Custom, units = Metric (MKS)
ICore configSimulink parameterValue translation
CONFIG_F.c_str()Fpasses through
CONFIG_R.c_str()Rpasses through

Caveat (shown to the user): the position crosses as one [3,1] and the latitude and longitude come back TOGETHER on one [2,1] in DEGREES, with the altitude on a port of its own -- exactly as the Simulink block is drawn. 'ptype' is always written as Custom, because a block left on Earth (WGS84) accepts a written F or R and discards it -- measured in R2026a. The Simulink block has no SampleTime, so the rate stays on the ICore side. ⚠ The two sides do not run the same algorithm -- MATLAB iterates Bowring's recursion to a convergence test capped at five passes, this block runs a fixed 32 -- so they agree to about 7e-15 degrees rather than bit for bit, which is the reason the parity band is 1e-12 and not 0

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

ECEF Position To LLA -- a planet-fixed Cartesian position back to geodetic coordinates lon = atan2(y, x) closed form, and the easy one rho = sqrt(x^2 + y^2) lat = atan2(z, rho) the spherical answer, as a start repeat 32: N = R / sqrt(1 - e2 * sin(lat)^2) lat = atan2(z + e2 * N * sin(lat), rho) h = rho*cos(lat) + (z + e2*N*sin(lat))*sin(lat) - N

The exact inverse of LLA To ECEF Position, and much the more expensive half: that direction is four lines of algebra, this one is a root of a quartic.

⚠ THE PASS COUNT IS A CONSTANT, NOT A CONVERGENCE TEST, for the reason its sibling Geocentric To Geodetic Latitude states in full: a loop that stops when it likes cannot be written identically in ten languages -- the stopping sample would differ by a unit in the last place between backends and the export would disagree with the simulation for reasons having nothing to do with the arithmetic.

⚠ MATLAB'S OWN REFERENCE DOES STOP ON A TEST, and that is worth knowing rather than copying. map.geodesy.internal.cylindrical2geodetic runs Bowring's recursion on (cos beta, sin beta) until the pair moves less than eps(pi/2), capped at five passes. MEASURED against R2026a's block over twelve random points spanning the whole ellipsoid, worst case:

1 fixed pass lat 8.3e-04 h 6.7e-04 2 passes lat 4.0e-06 h 1.3e-08 3 passes lat 1.9e-08 h 1.9e-09 4 passes lat 1.2e-10 h 1.9e-09 8 passes lat 7.1e-15 h 9.3e-10 32 passes lat 7.1e-15 h 9.3e-10

Eight passes are already at the floor and thirty-two is margin for a flattening far larger than Earth's, exactly as the sibling measured. The residual 9.3e-10 on the altitude is not the iteration at all -- MATLAB's own ecef2lla shows the same figure -- it is the cancellation in the h line at a radius of 6.4e6.

⚠ AND THE ALTITUDE IS FIRST-ORDER INSENSITIVE TO A LATITUDE ERROR, which is what makes it safe to evaluate from the iterate rather than from a separately converged angle. At the fixed point z + e2*N*sin(lat) = rho*tan(lat), so d/dlat of the first two terms is -rho*sin(lat) + rho*tan(lat)*cos(lat) = 0, and what is left is O(e2^2).

ALGEBRAIC and STATELESS: the 32 passes happen inside one sample, and nothing survives it.

Sample results#

No stimulus produced a sampled output in this rig — Invalid input size at ECEF Position To LLA block: ICore Blocks/Home/ECEF Position To LLA. 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 d6e8ad5247e8aa12ff4e80d2fcde8399b98c5f00 · produced by docsSample --out <folder> --blocks LLA_To_ECEF_Position ECEF_Position_To_LLA LLA_To_Flat_Earth Flat_Earth_To_LLA --steps 60

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