The RF terrain solver port.
Everything that turns terrain into a link-margin raster goes through one
call with one shape, so the JS implementation that ships in the engine and
the WASM implementation that will replace it are byte-comparable and swap
without touching a single caller:
solve(request) -> rasters
WHY A PORT AND NOT A FUNCTION. Owner law 2026-07-29: every surface that
consumes a propagator takes it as a pluggable parameter, never hardwired to
one provider. A terrain solver is a propagation consumer of exactly that kind
— it is where a Longley-Rice, a poly-coverage or a paid high-fidelity module
would be substituted — so `RfTerrainAnalysis` resolves it by instance, name
or id the same way
PropagatedPositionProperty resolves a propagator.
WHY RASTER-IN / RASTER-OUT AND NOT PER-CELL. Ruled by JANUS (module-SDK
oracle, 2026-08-07) while scoping the WASM packaging: a per-cell scalar port
cannot be satisfied by a WASM module later. A 9,216-cell solve would be 9,216
boundary crossings, and the delivery contract for these modules
(`sdn-rf-modules-sdn-delivery-cutover` section 7) is one grant, one instance,
shared. So the port takes typed arrays in and returns typed arrays out, once.
Do not add a per-cell entry point to this interface; it would be a shape the
replacement implementation cannot honour.
WHY THE WASM MODULE IS NOT HERE YET. Also ruled by JANUS: the closed RF module
family has no born-protected build lane today — the key-material producer
lives SDN-side inside Hermes' in-flight cutover, so a module built now would
be born as a plaintext public artifact, which is the exact P1 that cutover is
purging. The solver therefore ships in-engine BEHIND this port, and
`orbpro-rf-terrain-solver-packaging` (blocked on that cutover) moves the
implementation across without changing the interface.Members
Name of the in-engine solver used when no WASM solver is registered and the
caller chose nothing: the ITU-R P.526-15 raster walk.
It is NOT a JS propagation implementation. Every path loss, link margin and
diffraction parameter it reports comes from the propagation port
RfTerrainAnalysis now requires (a CommsPlugin over the delivered rf-* WASM
kernels); the walk contributes grid iteration, terrain sampling and profile
construction. That is why its `backend` reads `port-delegated` rather than
the `javascript` it used to claim — the old label was accurate when the walk
built its own RfCommsCore, and that is exactly what has been removed (the
file itself left the shipped tree on 2026-08-10).
Module id reserved for the WASM implementation, so callers can pin the name
now and get the module when it lands (`orbpro-rf-terrain-solver-packaging`,
blocked on `sdn-rf-modules-sdn-delivery-cutover`). Ratified by JANUS
2026-08-07 against the `com.orbpro.rf-*` family convention.
Methods
| Name | Type | Description |
|---|---|---|
name |
string |
Returns:
Returns:
Registered solver names.
Registers a solver implementation under a name.
| Name | Type | Description |
|---|---|---|
name |
string | Registry key, e.g. `"builtin-itu-p526"` or the module id `"com.orbpro.rf-terrain-solver"` once the WASM implementation lands. |
solver |
object | An object with a `solve(request)` method. |
Resolves whatever a caller passed for `terrainSolver` into a solver.
Accepts an instance, a registered name, or `undefined` for the built-in.
Fails loudly on an unknown name rather than quietly falling back to the
built-in: a caller who asked for a specific solver and silently got a
different one has been given a wrong answer that looks right, which is the
failure mode this whole task exists to remove.
| Name | Type | Description |
|---|---|---|
solver |
object | string | optional |
Returns:
Type Definitions
The request handed to a solver implementation.
Everything is plain data or a typed array so the payload can cross a WASM
boundary unchanged. The one exception is `propagation`, the propagation port
itself (a `CommsPlugin` or anything exposing `getPathLoss` /
`calculateLinkBudget`); a WASM implementation links the equivalent physics
kernels directly instead of calling back out.
Properties:
| Name | Type | Description | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
gridWidth |
number | Output raster width in cells. | ||||||||||||||||||
gridHeight |
number | Output raster height in cells. | ||||||||||||||||||
groundHeights |
Float32Array | Terrain height per output cell (m). | ||||||||||||||||||
profile |
object | Obstruction field the path walk marches over —
deliberately a DIFFERENT and finer field than the output raster; see
`buildProfileField` in RfTerrainAnalysis.js for why those two
resolutions must not be the same number.
Properties
|
||||||||||||||||||
transmitter |
object | Emitter geometry in the analysis ENU frame. | ||||||||||||||||||
rf |
object | Frequency, bandwidth, powers, gains, atmosphere. | ||||||||||||||||||
propagation |
object | The propagation port. | ||||||||||||||||||
solverModel |
string | Fidelity tier (see RfTerrainAnalysis.SolverModel). |
The rasters a solver returns. Every layer is one value per output cell, in
row-major order, and every layer is defined for EVERY cell — a solver may not
leave shadowed cells undefined and let the renderer guess, which is how a
shadow ends up drawn as open ground.
Properties:
| Name | Type | Description |
|---|---|---|
visibleMask |
Uint8Array | 1 where the geometric ray clears terrain. |
occludedMask |
Uint8Array | Complement of `visibleMask`. |
pathLossDb |
Float32Array | Total path loss including atmosphere. |
excessLossDb |
Float32Array | Loss above free space, i.e. what the terrain cost this cell. |
linkMarginDb |
Float32Array | Margin from the link budget. |
positiveLinkMask |
Uint8Array | 1 where `linkMarginDb > 0`. |
diffractionParameter |
Float32Array | ITU-R P.526-15 eq. (29) v of the dominant edge. |
pathClass |
Uint8Array | OPEN / GRAZING / DIFFRACTED — see RfTerrainAnalysis.PathClass. |
reflectionContributionDb |
Float32Array | Specular contribution, zero outside the SPECULAR_SINGLE_BOUNCE tier. |