Maskinöversättning, inte granskad av en modersmålstalare. Engelska är referensen.

Mottagarförtroende och sjöfartRedigera på GitHubKälla: docs/MARITIME-TRUST.md

Maritimt förtroende: kan bryggan lita på den här positionsbestämningen?

kshana receiver-trust kan för ett fartyg i rörelse beräkna en löpande förtroendesiffra mellan 0 och 100 för varje positionsbestämning, utifrån det som varje mottagare redan lägger på bussen (NMEA 0183 först), och ange vilka kontroller som sänkte den. Det är ett programvarulager som sitter bredvid en mottagare. Det är inte en mottagare, det ersätter inte någon, och det gör inte en positionsbestämning mer exakt.

Rådgivande programvara. Kshana är inte typgodkänd navigationsutrustning (IEC 61108, IEC 61162) och har inte bedömts mot någon prestandastandard. Dess poäng och dess gate är stöd för navigatörens omdöme. Operatören är fortsatt ansvarig för fartygets säkra navigering och för varje beslut att lita på, eller att sluta lita på, en positionsbestämning.

Den här sidan beskriver vad kontrollerna tittar på, vad var och en kan och inte kan fånga, hur du kör det live och vad gaten gör. Poängmappningen och varje standardvärde finns i RECEIVER-TRUST.md.

Vad den läser#

Ett fartyg deklareras i sessionsfilen, med sina gränser angivna före körningen:

[platform]
kind = "vessel"
max_speed_kn = 20.0        # includes any current you want to allow for: it limits speed over ground
max_accel_mps2 = 0.2
max_turn_rate_dps = 2.0
antenna_height_m = 18.0    # antenna above the waterline
heading_sensor = true      # the stream carries a gyro or compass heading
Mening Läses
GGA position, positionskvalitet (0 = ingen positionsbestämning), höjd över medelhavsytan, geoidseparation, HDOP
RMC status (A giltig, V inte), fart och kurs över grund, datum, läge
VTG fart och kurs över grund, där RMC saknar dem
HDT, THS rättvisande kurs (THS endast när dess läge inte är V)
VHW, VBW fart genom vattnet (VBW endast när dess status är A)
ZDA tid
GSV signalstyrka per satellit (dB-Hz), elevation och azimut (för geometrin)
GSA geometrisk försämring av precisionen och använda satelliter (för geometrin, där GSV inte ger någon himmel; och det angivna HDOP som vakten jämför)
$PKSOS,<A/F/N> en OSNMA-status som en mottagare rapporterade, översatt till den här meningen av den adapter som läser mottagaren: A autentiserad, F misslyckad, N inget resultat

Epoker som mottagaren själv säger inte är en satellitbestämd position (GGA-kvalitet 0, eller 6 till 8: uppskattad, manuell, simulator; RMC-status V, eller läge E, M, S, N) används inte för positionskontrollerna och bär inget belägg åt något håll: mottagaren har redan sagt det.

De första calibration_s sekunderna utgör baslinjen och poängsätts aldrig. Varje övervakare tittar bara på den aktuella och tidigare epoker, så ett beslut vid en epok ändras inte när senare data anländer, och en löpande ström ger samma poäng som samma text läst som en fil.

Vad varje kontroll fångar, och vad den inte kan fånga#

Riktningar mellan positionsbestämningar (kursen längs spåret som används av kontrollen av girhastighet, kursen som två positioner antyder) är riktningen för kordan mellan dem, vilket är geodetens medelazimut mellan positionsbestämningarna, inte framåtazimuten vid den första positionsbestämningen; de skiljer sig med ungefär halva meridiankonvergensen mellan positionsbestämningarna (0,001 grader för en baslinje på 260 m vid 59,5 graders latitud).

En förfalskad position måste stämma med ett fartygs fysik och med fartygets andra sensorer. Varje kontroll jämför positionsbestämningen med en av dem. En kontroll är bara så oberoende som dess andra källa: en kurs från en GNSS-kompass, eller en "fart genom vattnet" härledd från GNSS, är inte oberoende av mottagaren under test och tillför ingenting.

Kontroll Fångar upp Kan inte
kinematic ett positionssprång; ett spår vars rörelse inte förklaras av rapporterad fart och kurs; en underförstådd fart, acceleration eller girhastighet över fartygets angivna gränser en bortdragning där rapporterad fart och kurs följer det förfalskade spåret och håller sig inom gränserna (mottagaren härleder dem ur sin egen lösning, så de stämmer med varandra); en fartgräns som är angiven för högt
heading-course ett spår som avviker från fartygets stävriktning med mer än den angivna avdriftsvinkeln en bortdragning längs kursen (kursen ändras inte); en stävriktning från samma mottagare eller en GNSS-kompass; en tvärsättning över toleransen (falsklarm); farter under min_speed_kn
speed-log en bortdragning som ändrar farten över grund i förhållande till farten genom vattnet en logg som är härledd ur GNSS; en ström över det tillåtna (falsklarm); en bortdragning långsammare än det tillåtna
sea-level en höjd som inte ligger där havsytan och den angivna antennhöjden placerar den en spoofer som håller höjden rimlig; toleransen är bred eftersom det vertikala felet för fristående positionering är stort; geoidseparationen registreras men kontrolleras inte, eftersom motorn saknar geoidmodell
cn0-spread, cn0-rise signaturen från en enda sändare: C/N0 över satelliterna som faller samtidigt, eller stiger samtidigt, jämfört med kalibreringens baslinje en spoofer som formar effekten per satellit; allt medan själva baslinjen är utsatt för spoofing; en GSV-takt som är för långsam för att följa med
time-consistency att mottagarens tid stegar oregelbundet eller går baklänges; mot den här datorns klocka, att mottagarens tid driver ifrån den (endast realtidsströmmar) en förfalskad tid som är konsekvent och jämn; en klocka som är fel från början
osnma ett rapporterat OSNMA-autentiseringsfel statusen läses av, inte verifieras; en spoofer som undertrycker rapporten syns inte
cn0-drop, loss-of-lock, agc, jam-ind effektbortfall och förlust av satelliter, som i det statiska fallet de säger att miljön är fientlig, inte att positionsbestämningen är fel

Vad övervakare som bara läser NMEA inte kan göra. En spoofer som återskapar hela konstellationen med en självkonsekvent position, hastighet, kurs som är förenlig med stävriktningen, rimlig effekt per satellit och en matchande klocka är osynlig för varje kontroll ovan: ingenting i meningarna skiljer dess positionsbestämning från en verklig. Detsamma gäller en återuppspelning av inspelade verkliga signaler. Autentisering (OSNMA, eller en mottagare med eget skydd mot spoofing) och oberoende navigationssensorer är det som sluter det gapet; det här lagret kan bara använda deras rapporterade status. En ström som redan utsätts för spoofing medan baslinjen bildas har ingen ren baslinje. Att ingen larm utlöses är inget belägg för en god positionsbestämning.

Förtroendepoäng#

Varje epok efter kalibreringen får en poäng från 0 till 100 och skälen till att den inte är 100: vilka kontroller som drog av poäng, deras statistik mot tröskeln och deras poäng. Band (gränserna anges i sessionen): nominal vid 90 eller däröver, degraded vid 55 eller däröver, untrusted under det. Avbildningen, varje vikt och skälet till den finns i RECEIVER-TRUST.md; den är deterministisk och fastställd innan en logg poängsätts, utan inlärning och utan att något anpassats till händelser.

Varje fartygsutdata bär den rådgivande förklaringen: nyckeln advisory i resultat-JSON och i varje live-rad, en första kommentarsrad # i CSV-filen (läsare hoppar över den med sitt kommentarsalternativ), <desc> och en sidfot i SVG-filen. Utdata från en batchkörning: session.result.json (med poängmodellen och varje epoks avdrag), session.trust.csv (med kolumnerna score och score_reasons) och session.trust.svg, som för ett fartyg är det av mottagaren rapporterade spåret färgat efter förtroendeband ovanför poängen över tid.

En syntetisk demo#

examples/maritime-trust/ innehåller en påhittad NMEA-logg för en färja på rutten Tallinn till Helsingfors (ett utdrag på 50 minuter, ungefär 17 kn, 1 Hz: GGA, RMC, VTG, en gyrokurs, en fartlogg, GSV med en rimlig himmel) där en bortdragning av positionen drar den rapporterade positionen bort från fartygets verkliga från 1500 s. Mottagaren fortsätter hela tiden att rapportera en giltig positionsbestämning; det är förtroendepoängen som faller, genom det degraderade bandet ner i det opålitliga. session.toml anger varje tröskel, fartygets gränser och varje poängvikt före körningen.

kshana receiver-trust examples/maritime-trust/session.toml
kshana receiver-trust live examples/maritime-trust/session.toml \
  --file examples/maritime-trust/tallinn-helsinki.nmea --gate --json trust.jsonl > gated.nmea

Loggen är text skriven till en fil av cargo run --example gen_maritime_trust_demo: den modellerar ingen radiosignal och sänder ingenting. Den är ingen mätning och rutten är illustrativ, inte ett sjökort. tests/receiver_trust_maritime_demo.rs låser loggen och den förväntade utdatan som regressionsskydd för de syntetiska data; de säger ingenting om hur någon övervakare klarar sig vid verklig störning.

Förtroendepoäng över en syntetisk överfart, från en verklig körning av motor v0.40.0 på examples/maritime-trust (en påhittad NMEA-logg för en färja på rutten Tallinn till Helsingfors, 3001 epoker vid 1 Hz). Tre fält delar en tidsaxel. Överst: avståndet mellan den position mottagaren rapporterar och fartygets verkliga position, som håller sig inom några meter till ungefär 1576 s, då loggens skriptade bortdragning av positionen drar den bort, medan mottagaren fortsätter att rapportera en giltig positionsbestämning. I mitten: förtroendepoängen från 0 till 100, inte beräknad under de första 300 s av kalibreringen, i det nominella bandet (minst 90) fram till bortdragningen, och sedan fallande genom det degraderade bandet (minst 55) ner i det opålitliga bandet. Längst ned: varje epoks band som ett färgat band med sitt namn. Poängen är rådgivande. Rådgivande programvara, inte typgodkänd navigationsutrustning (IEC 61108, IEC 61162): operatören är fortsatt ansvarig för fartygets navigering. Loggen är påhittad för att visa formatet och övervakarna; den är ingen mätning och säger ingenting om hur någon mottagare skulle prestera.Förtroendepoäng över en syntetisk överfart, från en verklig körning av motor v0.40.0 på examples/maritime-trust (en påhittad NMEA-logg för en färja på rutten Tallinn till Helsingfors, 3001 epoker vid 1 Hz). Tre fält delar en tidsaxel. Överst: avståndet mellan den position mottagaren rapporterar och fartygets verkliga position, som håller sig inom några meter till ungefär 1576 s, då loggens skriptade bortdragning av positionen drar den bort, medan mottagaren fortsätter att rapportera en giltig positionsbestämning. I mitten: förtroendepoängen från 0 till 100, inte beräknad under de första 300 s av kalibreringen, i det nominella bandet (minst 90) fram till bortdragningen, och sedan fallande genom det degraderade bandet (minst 55) ner i det opålitliga bandet. Längst ned: varje epoks band som ett färgat band med sitt namn. Poängen är rådgivande. Rådgivande programvara, inte typgodkänd navigationsutrustning (IEC 61108, IEC 61162): operatören är fortsatt ansvarig för fartygets navigering. Loggen är påhittad för att visa formatet och övervakarna; den är ingen mätning och säger ingenting om hur någon mottagare skulle prestera.

Figuren är ritad av tools/gen_readme_assets.py utifrån en verklig körning av den här demon (kshana receiver-trust examples/maritime-trust/session.toml); poängen är rådgivande och loggen är påhittad.

Specifikation för Studio-vyn#

För den som bygger Studio-vyn för en fartygskörning. Ingenting i det här avsnittet är ännu implementerat i Studio; motorsidan (data nedan) är det.

Indata. Någon av:

  • resultat-JSON från en batchkörning (kshana receiver-trust <session.toml>, eller samma sak via receiver_trust(toml) i WebAssembly-paketet med loggen inbäddad): score_model (bandgränser, ramp, belägghållning, varje vikt), monitors_run, states och epochs[], var och en med t_s, state, alarms, score.{score,band,deductions[]}, marine.{position:[lat,lon], stats, ratios}, och från 0,36 geometry och varje avdrags class, med geometry_model och geometry_summary på översta nivån; eller
  • live-JSON-raderna (schema ovan), ett objekt per epok, tillagda medan strömmen pågår. Varje rad bär den av mottagaren rapporterade position (schema 1,1).

Demouppsättningen är examples/maritime-trust/: session.toml, tallinn-helsinki.nmea (loggen) och tallinn-helsinki.truth.csv (t_s,true_lat_deg,true_lon_deg: var fartyget verkligen var, vilket ingen verklig logg har). En vy bör köra sessionen och läsa referensfilen vid sidan av.

Vad som ska ritas.

  1. Spår, norr uppåt, en skala på båda axlarna: de av mottagaren rapporterade positionerna som en linje färgad efter epokens band (grå kalibrering, grön nominell, gul degraderad, röd opålitlig), start och slut markerade, en skalstock. För demon, det sanna spåret som en tunn neutral linje under, så att bortdragningen syns som att de två skiljs åt; en växel för det sanna spåret och en avläsning av avvikelsen i meter vid markörens tid.
  2. Poängtidslinje: poängen från 0 till 100 mot tid, bandgränserna (nominal_min, degraded_min från score_model) som streckade linjer, bandet som en remsa under, och starten på varje angiven händelse som en markör. Tidsaxeln delas med spåret.
  3. Skäl: för epoken under markören, avdragen (övervakare, kvot mot tröskel, poäng) som horisontella staplar, störst först, med den vikt varje övervakare bär från score_model.weights; övervakare som kördes och inte kostade något visas svagt, övervakare som inte kördes (inte i monitors_run) listas som "not run", aldrig som utan anmärkning. Övervakaren geometry har ingen post i score_model.weights: dess tak är geometry_model.cap_in_force.
  4. Övervakarremsor: en tunn remsa per övervakare i monitors_run som visar dess kvot över tid (larm vid 1), så att en läsare ser vilken kontroll som rörde sig först.
  5. Grindtillstånd: i en live-vy, gate för varje epok (off, passed, withheld) som en remsa under bandremsan, och den senaste $PKSHT. I en batchvy är de epoker en grind skulle ha hållit tillbaka de vars band är opålitligt, med frisläppningshållningen tillämpad.
  6. Geometrifält (0,36): en remsa under bandremsan färgad efter geometry.status (grön god, gul degraderad, grå streckad okänd), i en färgfamilj som skiljer sig från fälten för inkonsekvens och miljö, med förklaringen "geometry: the sky, not the signal". Avdrag färgade efter class (geometry, environment, inconsistency) i skälpanelen och övervakarremsorna, och antalet epoker per klass från geometry_summary bredvid bandantalen. För epoken under markören: geometry.note, n_used, HDOP, PDOP, VDOP, source, age_s och en flagga när reported_derived_mismatch är satt (geometriavdraget är då en inkonsekvens). unknown visas som "geometry unknown: no GSV or GSA in the log", aldrig som god. Tröskelvärdena i [geometry] och deras ursprung från geometry_model placeras bredvid poänginställningarna. Den rådgivande anmärkningen står kvar.
  7. Av mottagaren rapporterad positionsbestämning: demons mottagare rapporterar en giltig positionsbestämning hela tiden (GGA-kvalitet 1, RMC-status A); säg det i förklaringen, för det är hela poängen med vyn.

Interaktioner. En tidsmarkör som delas av varje panel (dra, piltangenter och en uppspelningsknapp som spelar upp med 1x till 60x); att hovra över spåret eller någon remsa flyttar den. Ett klick på ett avdrag markerar de epoker där den övervakaren låg över sitt insättningsvärde. Ett bandfilter (visa bara degraderade och opålitliga epoker) och ett hopp till det första avdraget och till den första opålitliga epoken. Hovertext på varje övervakarnamn med enradsbeskrivningen från den här sidan. Sessionens trösklar och vikter visas skrivskyddade bredvid diagrammet, så att det som poängen använde syns på skärmen.

Formuleringar att behålla. Sidan måste säga att det är rådgivande programvara och inte typgodkänd navigationsutrustning, att demon är syntetisk text med en påhittad bortdragning, och att en positionsbestämning utan larm inte därmed är en god positionsbestämning (se begränsningarna ovan). Ingen siffra på sidan får läsas som ett mått på hur kontrollerna klarar sig vid verklig störning.

Från kod#

För anropare som har sessionen och byten i minnet (inga filer, ingen klocka, inga sockets; säkert för WebAssembly) har kshana::receiver_trust::assess:

  • assess_vessel_log(session_toml, log_bytes) -> Result<ReceiverTrustResult, String>: en hel logg, poängsatt som en batchkörning; samma resultat som kshana receiver-trust <session.toml>, som serialiseras till resultat-JSON (score_model, monitors_run, epochs[] med poäng och avdrag).
  • assess_stream_excerpt(session_toml, excerpt_bytes) -> Result<ExcerptAssessment, String>: en begränsad del av en ström (högst 2 MiB och 20 000 epoker, och tillräckligt lång för att rymma kalibreringsfönstret), poängsatt som live-läget poängsätter och returnerad i live-JSON-lines-schemat (epochs[], den sista $PKSHT, en sammanfattning av bandantal, lägsta och slutliga poäng, första opålitliga tid). Mottagarens tid jämförs inte med en värdklocka. Det långkörande live-läget (sockets, en fil som fylls på, grinden) tillhör binärfilen.

Båda behöver en session med [platform] kind = "vessel"; dess tabell [log] är valfri.

Kör den live#

# stdin: a serial port read by another tool, or a multiplexer's output
some-nmea-source | kshana receiver-trust live session.toml

# a log file that is being appended to (it starts at the beginning; --from-end skips what is there)
kshana receiver-trust live session.toml --file /var/log/nmea.log --follow

# a TCP server (a multiplexer or a terminal server) or UDP datagrams (a bridge network)
kshana receiver-trust live session.toml --tcp 192.0.2.10:10110
kshana receiver-trust live session.toml --udp 10110

Sessionen är samma session.toml som för en batchkörning, med en tabell [platform] som deklarerar kind = "vessel"; dess tabell [log] behövs inte. Serieportar öppnas inte direkt ännu: läs porten med verktyget du redan använder (stty och cat, en terminalserver, en multiplexer) och för den vidare via pipe eller vidarebefordran. Direkt serieinmatning kan komma senare.

Varje avslutad epok skriver en JSON-rad på stdout:

{"seq":941,"t_s":940.0,"time":"2025-06-14T08:15:40.000Z","state":"degraded","score":60.0,
 "deductions":[{"monitor":"heading-course","ratio":1.5,"points":40.0}],
 "alarms":["heading-course"],"gate":"off","note":null,
 "position":{"lat_deg":59.8123456,"lon_deg":24.9012345,"height_m":39.4}}

state är calibrating, nominal, degraded eller untrusted (poängens band, med gränserna i sessionens tabell [score]); score saknas under kalibreringen; deductions anger vilka kontroller som drog av poäng och hur många, störst först.

JSON-lines-schema (version 1,1)#

Ett JSON-objekt per avslutad epok, nycklarna i den här ordningen:

Nyckel Typ Betydelse
seq heltal antal rapporterade epoker, från 1
t_s tal sekunder sedan strömmens första epok
time sträng eller null epokens tid så som strömmen anger den (ISO-8601 UTC med datum när en RMC har setts, annars hh:mm:ss.mmm UTC (date not in log))
state sträng calibrating, nominal, degraded eller untrusted
score tal eller null 0 till 100, en decimal; null under kalibreringen eller när note anger varför ingen kunde produceras
deductions lista {"monitor": string, "ratio": number, "points": number, "class": string}, största poäng först; ratio är statistiken delad med tröskeln (larm vid 1 eller mer); bara övervakare som kostade poäng listas; class (tillagd i 1,3) är geometry, environment eller inconsistency
alarms lista med strängar övervakare vid eller över sin tröskel
gate sträng off, passed eller withheld
note sträng eller null varför ingen poäng producerades (till exempel en deklarerad kurssensor som saknas)
position objekt eller null (tillagd i 1,1) den position mottagaren rapporterade vid den här epoken, {"lat_deg", "lon_deg", "height_m"} (höjden ellipsoidisk där meningen anger geoidseparationen, annars över medelhavsnivån); null när mottagaren inte gav någon, även för kalibreringsepoker utan positionsbestämning
advisory sträng (tillagd i 1,2) vad den här programvaran är och inte är: rådgivande, inte typgodkänd navigationsutrustning, operatören är fortsatt ansvarig
geometry objekt (tillagd i 1,3) satellitgeometrin: status (good, degraded, unknown när strömmen saknar GSV-elevationer och -azimuter och saknar GSA), reasons (few-satellites, high-pdop, high-hdop, sky-blocked), source (derived, reported, none), n_used, hdop, pdop, vdop, open_fraction, max_azimuth_gap_deg, age_s, reported_hdop, reported_derived_mismatch, note, in_view, signal_loss (satelliter i sikte men inte spårade medan DOP för det som är i sikte är god: geometriavdraget är då environment), label (good, fair, poor, unknown: rapporteras alltid, poängsätts aldrig; poängen drar bara av för poor) (se RECEIVER-TRUST.md)

Övervakarnamn (kebab-case; 17): cn0-drop, agc, jam-ind, loss-of-lock, position-jump, raim, clock, solve-failure, kinematic, heading-course, speed-log, sea-level, cn0-spread, cn0-rise, time-consistency, osnma, och från 1,3 geometry. Nya namn kan läggas till i senare versioner; konsumenter bör behandla ett okänt övervakarnamn som en övervakare. Layouten för $PKSHT nedan bär en formatversion i sitt första fält; det här JSON-schemat är version 1,3: 1,1 lade till position, 1,2 advisory, 1,3 geometry i slutet och class i varje avdrag, och det ändras bara genom att nycklar läggs till i slutet.

Autentiseringsindata#

Övervakaren osnma tar autentiseringsstatus per satellit från en autentiseringskälla via MarineObs::sat_auth (en lista med (satellite, status), status Authenticated, Failed eller Unavailable), vid sidan av den övergripande MarineObs::osnma. På NMEA-sidan bärs samma sak av $PKSOS,<A|F|N>[,<sat>:<A|F|N>...], till exempel $PKSOS,A,E11:A,E19:F. Varje fel, övergripande eller på en satellit, larmar övervakaren och kostar hela dess vikt (den ges kvoten 1,5); framgång är inget belägg. Kshana verifierar ingenting här: källan som gör det ansvarar för den status den rapporterar.

En epok är avslutad när nästa tidsatta mening kommer; meningar från långsammare eller osynkroniserade instrument (en gyro några tiondels sekunder efter mottagaren) som kommer före dess tillhör den. Om strömmen står still i [live] idle_flush_s (standard 1,5 s, sätt det över det längsta glappet mellan din mottagares tidsatta meningar) avslutas epoken som den är. De första calibration_s sekunderna av strömmen utgör baslinjen och poängsätts aldrig, så en ström som redan utsätts för spoofing när den först ansluts har ingen ren baslinje: starta lagret före resan, eller medan positionsbestämningen är känd för att vara god. Kalibreringsfönstret stängs en gång, efter ankomst: en epok vars tid är tidigare än en tid som redan setts (en tillbakaspolning, en återuppspelning av strömmens början) är aldrig kalibrering vad dess tid än säger; den poängsätts med ett fullt avdrag för time-consistency, vilket är opålitligt. Live-motorn poängsätter varje epok över kalibreringsepokerna och den senaste minuten eller så av strömmen, så dess kostnad per epok växer med calibration_s gånger epokfrekvensen; håll fönstret kort på en snabb mottagare. Dess buffertar är begränsade (en störtflod av rader utan tidsatt mening avslutas var 5 000:e rad, kalibrering och historik är begränsade till 20 000 epoker).

Mottagarens tid jämförs också med den här datorns monotona klocka, vilket bara betyder något för en ström som kommer i realtid. En lagrad logg som matas in i full fart via stdin, TCP eller UDP utlöser den kontrollen av konstruktion: ange --replay. (--file utan --follow innebär det redan.) En --file ... --follow läses som en återuppspelning tills den har lästs till slutet, och värdklockan kopplas in från då och framåt, så att en eftersläpning inte läses som ett klockfel; kontrollen kräver då att kalibreringsfönstret fortfarande är öppet (annars har den ingen baslinje och körs inte).

Strömmens slut och fel: stdin och en fil som läses till slutet avslutas normalt (exit 0). En TCP-anslutning som stängs av motparten är inte ett normalt slut för en ström som borde fortsätta: lagret avslutas med en kod som inte är noll efter att ha poängsatt och skrivit allt det tagit emot och ansluter inte igen, så kör det under en övervakare som startar om det. UDP-datagram som delar en mening fogas ihop; läsarna av stdin, en fil och TCP backas upp av en begränsad kö som trycker tillbaka mot avsändaren (ingenting går förlorat), medan UDP, som inte kan trycka tillbaka, släpper datagram som motorn inte kan ta emot och säger det på stderr. --udp <port> binder loopback-adressen; ange --udp <addr>:<port> för att lyssna någon annanstans (en varning skrivs ut).

$PKSHT: den proprietära meningen#

Varje epok producerar också en NMEA 0183-mening, med giltig kontrollsumma, som --pksht <path|-> skriver till en fil eller stdout och som grinden sätter in i den vidarebefordrade strömmen:

$PKSHT,1,080140.25,30.0,U,W,heading-course:40.0/cn0-spread:30.0*2F
Fält Betydelse
1 1: formatversionen
2 epokens UTC-tid, hhmmss.ss; tom om strömmen inte gav någon
3 förtroendepoäng 0 till 100, en decimal; tom under kalibreringen eller när ingen kunde produceras
4 band: C kalibrering, N nominell, D degraderad, U opålitlig
5 grind: - av, P släppt igenom, W tillbakahållen (positionsbestämningen markerades som ogiltig i den vidarebefordrade cykeln)
6 upp till två skäl, monitor:points sammanfogade med /; tom när inget drogs av

Adressen är P + tillverkarens mnemonik KSH + T. Utrustning som inte känner till en proprietär mening ignorerar den. Kshana ignorerar sin egen $PKSHT vid indata.

Grindläge#

--gate placerar Kshana mellan mottagaren och den utrustning som använder dess positionsbestämning (ett sjökortssystem, ett spårstyrningssystem). NMEA-strömmen går in, kommer ut på stdout och är:

  • vidarebefordrad oförändrad så länge epoken inte är opålitlig (och under kalibreringen), med en $PKSHT efter varje cykel av meningar; och
  • markerad som ogiltig medan den är opålitlig: GGA-kvalitet 0; RMC-status V (och dess lägesindikator N och navigationsstatus V där de finns); GNS-läge N i varje position; GLL-status V och läge N; VTG-läge N där det har ett. Positionsfälten lämnas som de var: poängen är att utrustningen ser mottagaren själv deklarera positionsbestämningen som ogiltig och utlöser sitt eget larm. Varje omskriven mening får sin kontrollsumma omräknad.

När positionsbestämningen väl hållits tillbaka släpps den först efter att epokerna varit utanför det opålitliga bandet i [live] gate_release_s (standard 30 s), så att en poäng vid bandgränsen inte kan få positionsbestämningen att flimra. JSON-raderna går bara dit --json <path> anger (som standard ingenstans, eftersom strömmen har stdout).

receiver-nmea-source | kshana receiver-trust live session.toml --gate --json trust.jsonl | downstream-equipment

För att låta en kartplotter ansluta direkt, servera den grindade strömmen över TCP i stället för stdout:

receiver-nmea-source | kshana receiver-trust live session.toml --gate --listen tcp:10110

--listen tcp:<port> lyssnar på loopback-adressen; tcp:<addr>:<port> lyssnar någon annanstans (en varning skrivs ut, eftersom vem som helst som når adressen kan läsa strömmen). Valfritt antal klienter kan ansluta; var och en får samma ström från det ögonblick den ansluter, och klienter läser bara. Varje klient har sin egen begränsade kö och skrivare, så en som inte hänger med släpps (dess anslutning stängs, en rad på stderr) och fördröjer aldrig de andra eller indata. --listen kräver --gate; stdout bär då ingenting av strömmen, så --json - är ledigt.

Vad grinden inte gör, och vad du bör veta innan du använder den:

  • Den är opt-in. Ingenting markerar en positionsbestämning som ogiltig om inte --gate anges.
  • Den ger fördröjning: en cykel hålls tills dess epok är poängsatt, vilket är tiden till nästa tidsatta mening (ungefär en cykel: en sekund för en mottagare på 1 Hz), eller idle_flush_s efter den sista när strömmen står still. Utrustning som behöver en mening inom några tiotal millisekunder från mottagarens utdata får inte sitta bakom den.
  • Den är en enda punkt i kedjan: om den stannar stannar strömmen. Kör den övervakad och bestäm i förväg vad den efterföljande utrustningen gör utan en ström.
  • Den stänger säkert vid egna fel: om övervakarna inte kan producera en poäng efter kalibreringen (en deklarerad kurssensor som inte skickar något, för få kalibreringsepoker) är epoken opålitlig, bär en note och hålls tillbaka; frisläppningshållningen tidsätts efter den här datorns klocka, inte efter mottagarens tid, vilket är vad en spoofer styr (för en återuppspelning finns bara mottagarens tid).
  • Den kan hålla tillbaka en god positionsbestämning (ett falsklarm) och släppa igenom en spoofad (ett missat larm). Övervakarna kontrollerar en positionsbestämning mot ett fartygs fysik och dess andra sensorer; en förfalskning som är konsekvent med alla dem syns inte (se begränsningarna nedan).
  • Den förväntar sig en ren NMEA 0183-textström. Binära ramar som blandats in i strömmen vidarebefordras oförändrade, men en $PKSHT kan då hamna mellan byten i en ram.
  • Den är inte typgodkänd och ingenting i den har bedömts mot IEC 61108 eller IEC 61162. Operatören är fortsatt ansvarig för fartygets navigering.