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

Flat Earth To LLA — Robotics/Axes Transformations

Robotics/Axes_Transformations/Flat_Earth_To_LLA · 2 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.

Flat Earth To LLA

Robotics / Axes Transformations

Converts offsets in a local flat-Earth frame back into a geodetic position. With e² = f(2−f) and the reference latitude φ₀:

  • Rn = R / √(1 − e²·sin²φ₀) and Rm = Rn(1 − e²) / (1 − e²·sin²φ₀), both evaluated at the reference
  • dN = cosψ·x − sinψ·y and dE = sinψ·x + cosψ·y
  • φ = dN / (Rm·π/180) + φ₀ and λ = dE / (Rn·cosφ₀·π/180) + λ₀, then folded back into range
  • h = −z − href

The frame is North-East-Down: z grows downward, which is why both heights leave it negated.

Ports

  • p_flat – the offset as one [3,1], [x; y; z] in R's length unit, North-East-Down. The shape is fixed: it is how the Simulink block is drawn, and one point crosses at a time.
  • href – the reference height, a scalar in the same unit. It enters only the altitude, and only as an offset.
  • 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 Rn and Rm are both R. 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 offsets are read in and the altitude is written in.
  • Reference Location – the geodetic [latitude longitude] the flat frame is pinned at, in DEGREES, given as a two-element vector either way up. Defaults to [0 10]. It is folded once, when the configuration is loaded. A reference latitude of exactly ±90 is refused: cosφ₀ is then zero and the longitude would divide by it.
  • Reference Heading – the angle ψ from north to the flat frame's x axis, in DEGREES, positive clockwise. Defaults to 0, at which x is north and y is east.
  • 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.

Everything that depends on the ellipsoid or the reference – Rm·π/180, Rn·cosφ₀·π/180, sinψ, cosψ and the folded reference pair – is folded into four literals at export time, so no target evaluates a trigonometric function of a constant. What is left per sample is two multiply-adds, two divisions and one fold.

The three hardware targets are simulation-only. The fold needs a floor, which all three have, but VHDL carries the running latitude and longitude in Q16.16 because a VHDL process's scratch storage is fixed-point only; that costs about 1.5×10−5 degrees on each. Verilog and SystemVerilog keep theirs in floating point. A fixed-point port also cannot carry an Earth-sized offset – 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 FLOOR in IEC 61131-3, so it is rebuilt from TRUNC, which rounds toward zero and therefore differs on every negative non-integer.

Simulink bridge

Import and export, mapped to Aerospace Blockset's aerolibtransform2/Flat Earth to LLA. Flattening → F, Equatorial Radius → R, Reference Location → LL0 and Reference Heading → psi, values passing straight through.

Three Simulink parameters are always implied and carry no configuration here: ptype is always Custom, units always Metric (MKS), and refPosPort always off. Custom is not cosmetic – measured in R2026a, a block left on its Earth (WGS84) setting accepts a written F or R and discards it. refPosPort would move the reference location and heading onto two more input ports, taking the Simulink block from two inputs to four; this block reads them from its configuration, so it is pinned off. 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 inputs.
  • Not linear, so the block carries no state space and model reduction correctly reports it as unmergeable.
  • It is not an exact inverse of LLA To Flat Earth, and cannot be. The forward block folds its input pair before differencing, so a latitude past a pole and its reflection land on the same offsets; nothing here can recover which was meant. A position that needed no folding round-trips exactly.
  • The output pair is folded, and that is not cosmetic: an offset large enough walks over a pole. Measured against R2026a at x = 8×106 and at y = −3×107, the Simulink block returns a folded pair that the raw arithmetic does not produce; both reproduce here to 4.3×10−14 degrees.
  • The latitude fold is branchless: 90 − |w − 180| with w = mod(φ + 90, 360) is the whole two-arm rule, and the two arms agree at the pole where they meet.

Code facts#

FactValue
registered typeRobotics/Axes_Transformations/Flat_Earth_To_LLA
familyRobotics/Axes_Transformations
solver environment classICoreBlock_0_Robotics_1_Axes_Transformations_2_Flat_Earth_To_LLA
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Axes_Transformations/Flat_Earth_To_LLA/ICoreBlock_0_Robotics_1_Axes_Transformations_2_Flat_Earth_To_LLA.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Axes_Transformations/Flat_Earth_To_LLA/ICoreBlock_0_Robotics_1_Axes_Transformations_2_Flat_Earth_To_LLA.h
default size on canvas160 × 90 px
ports at insert2 in, 2 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoublep_flat
2inICoreDoublehref
3outICoreDoublemu_iota
4outICoreDoubleh

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)—
Reference Location[0 10]—
Reference Heading0—

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/Flat Earth 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), refPosPort = off
ICore configSimulink parameterValue translation
CONFIG_F.c_str()Fpasses through
CONFIG_R.c_str()Rpasses through
CONFIG_LL0.c_str()LL0passes through
CONFIG_PSI.c_str()psipasses through

Caveat (shown to the user): the offset crosses as one [3,1] in North-East-DOWN 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. 'refPosPort' is always off: switching it on moves the reference location and heading onto TWO MORE INPUT PORTS, taking the Simulink block from two inputs to four, and this block reads them from its configuration. The Simulink block has no SampleTime, so the rate stays on the ICore side. ⚠ The OUTPUT pair is folded on both sides -- an offset large enough walks over a pole -- which was measured at x = 8e6 and at y = -3e7 rather than assumed

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

Flat Earth To LLA -- local flat-Earth offsets back to geodetic coordinates Rn = R / sqrt(1 - e2 * sin(lat0)^2) prime vertical radius AT THE REFERENCE Rm = Rn * (1 - e2) / (1 - e2 * sin(lat0)^2) meridional radius AT THE REFERENCE dN = cos(psi)*px - sin(psi)*py dE = sin(psi)*px + cos(psi)*py lat = dN / (Rm * pi/180) + lat0 lon = dE / (Rn * cos(lat0) * pi/180) + lon0 h = -pz - href then fold (lat, lon) back into range

The inverse of LLA To Flat Earth, and the cheaper half of the pair: only its OUTPUT needs folding, where the forward direction folds twice.

⚠ IT IS NOT AN EXACT INVERSE, AND CANNOT BE MADE ONE. The forward block folds its input pair before differencing, so a latitude past a pole and its reflection land on the same offsets; no arithmetic here can recover which of the two was meant. A position that needed no folding round-trips exactly, and that is the whole of what the pair promises.

⚠ THE FOLD ON THE WAY OUT IS NOT COSMETIC. An offset large enough walks over a pole, and MEASURED against R2026a at px = 8e6 and at py = -3e7 the Simulink block returns a folded pair -- 70.98 degrees latitude in the first case, and a longitude of -80.58 in the second, neither of which the raw arithmetic produces. Both reproduce here to 4.3e-14 degrees.

The latitude fold is written as lat = 90 - |w - 180|, w = mod(lat + 90, 360), which is the two-arm rule with no branch and no boundary case -- the sibling's banner has the reasoning in full. Only the longitude's half-turn still needs a test.

ALGEBRAIC and STATELESS.

Sample results#

No stimulus produced a sampled output in this rig — Invalid input size at Flat Earth To LLA block: ICore Blocks/Home/Flat Earth 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__Flat_Earth_To_LLA.json