LLA To ECEF Position — Robotics/Axes Transformations
Robotics/Axes_Transformations/LLA_To_ECEF_Position · 2 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 ECEF Position
Robotics / Axes Transformations
Converts a geodetic position – latitude, longitude and altitude above the ellipsoid – into a Cartesian position in the planet-fixed ECEF frame. With e² = f(2−f):
- N = R / √(1 − e²·sin²φ), the prime vertical radius of curvature
- ρ = (N + h)·cosφ, the distance from the spin axis
- z = (N(1 − e²) + h)·sinφ
- x = ρ·cosλ and y = ρ·sinλ
It is the cheap direction of the pair: four lines of algebra with no iteration, where its inverse ECEF Position To LLA is a root of a quartic.
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.
- h – the altitude above the ellipsoid, a scalar in R's length unit.
- p_ECEF – the position 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. A value of exactly 1 is refused: it is a degenerate ellipsoid with no polar extent and N then divides by zero at the poles.
- Equatorial Radius – the ellipsoid's equatorial radius R, a scalar. Defaults to WGS84's 6378137 metres, and its unit is the unit h is read in and the output 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.
Both f and R are baked into the emitted arithmetic at export time rather than published as tunable parameters – an ellipsoid is structural, and e² and N's numerator are folded once by the generator so no target repeats the algebra. Literals are printed at 17 significant digits, so the software targets match the C++ reference to the last bit.
The three hardware targets are simulation-only: they carry the
whole computation in floating-point real and quantize only at the
port boundary, because a sine, a square root and a division do not belong in a
Q16.16 datapath. A fixed-point port also cannot carry an Earth-sized
radius – 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.
Simulink bridge
Import and export, mapped to Aerospace Blockset's
aerolibtransform2/LLA to ECEF Position. 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, answering for WGS84 regardless. 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.
- The angles are converted with ×π/180 rather than through a
pre-divided slope or a degree-exact sine. MATLAB's own
lla2ecefreaches its sines throughsind/cosd, which is exact at multiples of 90 and cannot be reproduced by a plain sine; the two agree to about a unit in the last place, which is why this block is held to a 10−12 band rather than to zero. - Verified against R2026a: driven end to end through the parity rig, the exported MATLAB core agrees with the Simulink block to well inside that band.
Code facts#
| Fact | Value |
|---|---|
| registered type | Robotics/Axes_Transformations/LLA_To_ECEF_Position |
| family | Robotics/Axes_Transformations |
| solver environment class | ICoreBlock_0_Robotics_1_Axes_Transformations_2_LLA_To_ECEF_Position |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Axes_Transformations/LLA_To_ECEF_Position/ICoreBlock_0_Robotics_1_Axes_Transformations_2_LLA_To_ECEF_Position.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Robotics/Axes_Transformations/LLA_To_ECEF_Position/ICoreBlock_0_Robotics_1_Axes_Transformations_2_LLA_To_ECEF_Position.h |
| default size on canvas | 150 × 78 px |
| ports at insert | 2 in, 1 out |
| code generators implemented | Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text |
Ports#
| # | Direction | Signal type | Description label |
|---|---|---|---|
| 1 | in | ICoreDouble | mu_iota |
| 2 | in | ICoreDouble | h |
| 3 | out | ICoreDouble | p_ECEF |
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 variable | Default | Simulink parameter |
|---|---|---|
Flattening | cFmt(WGS84_F) | — |
Equatorial Radius | cFmt(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.
Simulink bridge#
| support | Support::Both |
| Simulink path | aerolibtransform2/LLA to ECEF Position |
| port-count rule | PortsParam::None |
SampleTime parameter | no — the counterpart defines none; the rate stays on the ICore side |
| always set | ptype = Custom, units = Metric (MKS) |
| ICore config | Simulink parameter | Value translation |
|---|---|---|
CONFIG_F.c_str() | F | passes through |
CONFIG_R.c_str() | R | passes 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 on a port of its own and the position leaving as one [3,1]. '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 spell the degree conversion the same way -- MATLAB reaches its sines through sind/cosd, which is exact at multiples of 90 -- so they agree to about a unit in the last place rather than bit for bit
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:
B02 Simulink params rule(s) this tool cannot resolveB0every 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 ECEF Position -- geodetic coordinates to a Cartesian planet-fixed position N = R / sqrt(1 - e2 * sin(lat)^2) the prime vertical radius of curvature rho = (N + h) * cos(lat) distance from the spin axis z = (N * (1 - e2) + h) * sin(lat) x = rho * cos(lon), y = rho * sin(lon)
Four lines of algebra and no iteration anywhere, which is what makes this the cheap direction of the pair: its inverse, ECEF Position To LLA, is a root of a quartic and has to be solved by repetition.
⚠ THE PORT SHAPES MIRROR THE SIMULINK BLOCK AND ARE FIXED. Latitude and longitude arrive TOGETHER on one [2,1] port in DEGREES -- that is how the Aerospace Blockset block is drawn, and splitting them here would put a port on the ICore side that the bridge could not carry. The altitude has a port of its own, and the position leaves as one [3,1].
⚠ THE ANGLES ARE CONVERTED WITH
* PI / 180, NOT WITH A PRE-DIVIDED SLOPE. MATLAB's own lla2ecef reaches its sines throughsind/cosd, which is exact at multiples of 90 and therefore not reproducible from a plain sine at all; the two spellings agree to about a unit in the last place, which is why this block is held to the 1e-12 band rather than to zero.Geodetic To Geocentric Latitudemeasured the same distinction and recorded it -- an algebraically identical spelling is not a numerically identical one.ALGEBRAIC and STATELESS.
Sample results#
No stimulus produced a sampled output in this rig — Invalid input size at LLA To ECEF Position block: ICore Blocks/Home/LLA To ECEF Position. 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_ECEF_Position.json