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

LLA To Flat Earth — Robotics/Axes Transformations

Robotics/Axes_Transformations/LLA_To_Flat_Earth · 3 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.

LLA To Flat Earth

Robotics / Axes Transformations

Converts a geodetic position into offsets in a local flat-Earth frame pinned at a reference location and rotated to a reference heading. 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 and never at the point – which is exactly what makes this an approximation rather than a projection
  • dN = (φ − φ₀)·Rm·π/180 and dE = (λ − λ₀)·Rn·cosφ₀·π/180
  • x = cosψ·dN + sinψ·dE, y = −sinψ·dN + cosψ·dE, z = −h − href

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

Ports

  • mu_iota – the geodetic latitude φ and longitude λ stacked as one [2,1], both in DEGREES. The shape is fixed: it is how the Simulink block is drawn, and one point crosses at a time. Values outside the usual ranges are folded, not rejected – see Notes.
  • h – the altitude above the ellipsoid, a scalar in R's length unit.
  • href – the reference height, a scalar in the same unit. It enters only the z output, and only as an offset.
  • p_flat – the offset as one [3,1], [x; y; z] in R's length unit. The shape is fixed and does not follow the inputs.

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 both heights are read in and the output 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 by the same rules the input pair is, once, when the configuration is loaded. A reference latitude of exactly ±90 is refused: cosφ₀ is then zero and the east offset 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 and none of them can disagree about the reference. What is left per sample is two folds, a subtract and four multiply-adds.

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, which the two constants then scale. 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/LLA to Flat Earth. 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 three inputs to five; 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.
  • Out-of-range angles are FOLDED, not rejected, and the folding is part of the block. A latitude past a pole reflects back and carries its longitude half a turn; a longitude lands in −180, 180). Both rules are applied to the input pair and again to its difference from the reference, which is what the Aerospace block does – measured on a latitude of 95°, a longitude of 200° and a pair at (−91°, −190°).
  • 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, so there is no boundary case for ten backends to disagree about.
  • Verified against R2026a: the four measured cases above reproduce to 7.5×10−9 metres on offsets of order 2×107 – the last place of a double.

Code facts#

FactValue
registered typeRobotics/Axes_Transformations/LLA_To_Flat_Earth
familyRobotics/Axes_Transformations
solver environment classICoreBlock_0_Robotics_1_Axes_Transformations_2_LLA_To_Flat_Earth
source[src/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Axes_Transformations/LLA_To_Flat_Earth/ICoreBlock_0_Robotics_1_Axes_Transformations_2_LLA_To_Flat_Earth.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Axes_Transformations/LLA_To_Flat_Earth/ICoreBlock_0_Robotics_1_Axes_Transformations_2_LLA_To_Flat_Earth.h
default size on canvas160 × 90 px
ports at insert3 in, 1 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoublemu_iota
2inICoreDoubleh
3inICoreDoublehref
4outICoreDoublep_flat

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/LLA to Flat Earth
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): latitude and longitude cross TOGETHER on one [2,1] port in DEGREES, exactly as the Simulink block is drawn, with the altitude and the reference height on ports of their own and the offset leaving as one [3,1] in North-East-DOWN. '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 three inputs to five, and this block reads them from its configuration. The Simulink block has no SampleTime, so the rate stays on the ICore side. ⚠ Out-of-range angles are FOLDED on both sides -- a latitude past a pole reflects and moves its longitude half a turn -- and the fold is applied to the input pair AND to its difference from the reference, which was measured 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).

LLA To Flat Earth -- geodetic coordinates to offsets in a local flat-Earth frame 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 = (lat - lat0) * Rm * pi/180 dE = (lon - lon0) * Rn * cos(lat0) * pi/180 px = cos(psi)*dN + sin(psi)*dE py = -sin(psi)*dN + cos(psi)*dE pz = -h - href

Both curvature radii are evaluated ONCE, at the reference latitude, and never at the point. That is what makes this a flat-Earth approximation rather than a projection, and it is why everything except the two angles and the two heights is a constant folded at export time.

⚠ THE WRAPPING IS PART OF THE BLOCK, NOT A CONVENIENCE, AND THERE ARE FOUR OF THEM. MEASURED against R2026a on four cases -- an ordinary point, a latitude of 95 degrees, a longitude of 200 and a pair at (-91, -190) -- the Simulink block folds:

  1. the INPUT pair latitude past a pole reflects and moves its longitude 180
  2. the input longitude into -180, 180)
  3. the DIFFERENCE pair the same latitude rule applied to (dLat, dLon)
  4. the difference longitude

The reference pair is folded too, but that happens once at config load rather than per sample. A block that skipped any of the four agrees on every ordinary sample and is wrong by thousands of kilometres near a pole or a date line; this arrangement reproduces all four measured cases to 7.5e-9 metres on values of order 2e7, which is the last place of a double.

⚠ THE LATITUDE FOLD IS WRITTEN WITHOUT A BRANCH, AND THAT IS A CORRECTNESS CHOICE RATHER THAN A STYLE ONE. The rule is "w <= 180 gives w - 90, w > 180 gives 270 - w", and both arms are the single expression 90 - |w - 180| -- which agrees with the reference including at w = 180 exactly, where the two arms meet. Ten backends then carry one expression instead of ten copies of a conditional, and the pole itself stops being a special case. Only the longitude's half-turn still needs a test, because there the two arms genuinely differ.

ALGEBRAIC and STATELESS.

Sample results#

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