Skip to content

docs/schema: server-side GNSS lever-arm correction - #680

Open
dirkwa wants to merge 5 commits into
SignalK:masterfrom
dirkwa:feat-gps-lever-arm-correction
Open

docs/schema: server-side GNSS lever-arm correction#680
dirkwa wants to merge 5 commits into
SignalK:masterfrom
dirkwa:feat-gps-lever-arm-correction

Conversation

@dirkwa

@dirkwa dirkwa commented May 31, 2026

Copy link
Copy Markdown

Summary

Document the data-model contract for server-corrected navigation.position when GNSS antenna offsets are configured.

  • sensors.<id>.$source (new, optional) links a sensor instance to the source of its data stream — needed when multiple sensors of the same class are present (e.g. multi-GNSS). Named per the $-prefix reference convention established by $source in deltas.
  • navigation.position description expanded to define the Common Coordinate Reference Point (CCRP) as center-of-vessel on the centerline (body coordinates (design.length.value.overall / 2, 0) measured from the bow), matching the NMEA 2000 / radar / AIS industry convention.
  • Documents the meta.gnssOffsetCorrection entry that travels with corrected navigation.position deltas so history-recording consumers can preserve both the corrected value and the raw antenna measurement (with full provenance: $sensor referencing the sensor instance, fromBow, fromCenter, lengthOverall, headingTrue, rawValue).
  • New section in mdbook/src/data_model.md explaining the lever-arm correction model end-to-end.

Motivation

This is the specification side of SignalK/signalk-server#2399, which adds the multi-GNSS configuration UI and the in-server lever-arm corrector. Source priorities mean the active position source can flip between antennas with different offsets, which is fragile to correct client-side; the server has the active-source resolution and the heading, so it applies the correction in-process and emits the raw value plus correction provenance in meta for downstream history.


Update: athwartships sign convention (RFC #685)

Two further commits, added after review feedback from @keesverruijt on SignalK/signalk-server#2399, who pointed out that fromCenter reads backwards versus every other signed lateral quantity in the spec.

  • fix: make sensors fromCenter positive to starboard — flips sensors.*.fromCenter to +ve to starboard, -ve to port, documents the body frame explicitly in data_model.md (x forward, y starboard, right-handed), and syncs the stale inline descriptions in the AIS test fixture. This inverts the meaning of existing data and is a MODEL-level change under SchemaVer.
  • fix: align autopilot target wind angles with environment.windsteering.autopilot.target.windAngle* said +port -starboard while environment.wind.angle* says the opposite, for the same physical quantity. Description-only, ADDITION-level, kept as a separate commit so it can be split out and landed independently.

Full argument, provenance and blast radius in #685 — including that the AIS round trip is already broken today because n2k-signalk and signalk-to-nmea2000 disagree with each other.

This PR should not merge until #685 is settled. If the RFC resolves the other way, these two commits come off and the rest of the PR stands on its own.

Downstream: SignalK/signalk-server#2943, SignalK/signalk-to-nmea2000#162.

npm test passes (207).

Document the data-model contract for server-corrected navigation.position
when GPS antenna offsets are configured. Adds sensors.<id>.sourceRef so
sensor metadata can be linked to its data stream; describes
navigation.position as the Common Coordinate Reference Point (CCRP) at
center-of-vessel on the centerline (body coordinates (length/2, 0)
measured from the bow) when correction is active; documents the
meta.gpsOffsetCorrection entry that preserves the raw value and the
correction provenance.

Motivated by SignalK/signalk-server#2399, which adds the multi-GPS
configuration UI and the in-server lever-arm corrector.
Rename the linkage field on the sensor object to $source per the
$-prefix reference convention, the correction meta to
gnssOffsetCorrection with $sensor referencing the sensor instance,
and the surrounding prose from GPS to GNSS. Matches the server
implementation in SignalK/signalk-server#2399.
@dirkwa dirkwa changed the title docs/schema: server-side GPS lever-arm correction docs/schema: server-side GNSS lever-arm correction Jul 3, 2026
dirkwa added 3 commits July 9, 2026 05:58
Update the spec to match the server implementation: correction is an opt-in
server option (replace or both modes) rather than always-on, and is not
signalled in-band. Drop the meta.gnssOffsetCorrection description - position
deltas are high volume so no per-delta marker is added; the 'both' mode keeps
the raw antenna value as a separate <id>.ccrp source instead. Document the
notifications.navigation.gnss.headingUnavailable notification raised when
correction is active but heading is missing.
fromCenter was the only signed athwartships quantity in the specification
declaring +ve to port. Every other signed lateral or rotational key --
rudderAngle, attitude.roll, attitude.yaw, rateOfTurn, thrustAngle,
keel.angle, environment.wind.angle* -- is +ve to starboard.

The wording dates to fa162f7 (2014) and has never been revisited; there is
no issue or discussion in the repository recording a rationale for it.

The clash became load-bearing with server-side lever-arm correction, which
combines fromCenter with a heading taken from the same body frame as
attitude.yaw. A port-positive offset against a starboard-positive rotation
forces a non-standard rotation matrix; under this change it collapses to
the standard NED form.

Implementations already disagree with the schema and with each other:
n2k-signalk emits +ve to starboard while signalk-to-nmea2000 encodes +ve to
port, so an AIS reference point round-trips mirrored across the hull.
NMEA 2000 itself carries no sign here -- positionReferenceFromStarboard is
unsigned -- so the signed form is a Signal K invention and there is no
external convention to preserve.

Also documents the body frame explicitly (x forward, y to starboard,
right-handed) in data_model.md, and syncs the stale inline descriptions in
the AIS test fixture with the schema.

This inverts the meaning of existing data and is a MODEL-level change under
SchemaVer.
steering.autopilot.target.windAngleApparent and windAngleTrue declared
"+port -starboard", while environment.wind.angleApparent, angleTrueGround
and angleTrueWater all declare "negative to port". These describe the same
physical quantity -- measured apparent wind angle and the target apparent
wind angle an autopilot steers to -- so an autopilot comparing the two had
to negate one or steer to the mirror image of the requested angle.

The measured side is already starboard-positive in practice: n2k-signalk
maps the NMEA 2000 wind angle (0..2pi clockwise from the bow) into
(-pi, pi], so 0..pi is starboard.

This is a description-only clarification. No consumer of the autopilot
target wind angle keys was found in signalk-server, signalk-autopilot,
signalk-to-nmea2000 or Freeboard-SK, and the only test fixture holds
positive values, so no existing data encodes a side.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant