Tradução automática, não revista por um falante nativo. O inglês é a referência.

Confiança do recetor e marítimoEditar no GitHubFonte: docs/RECEIVER-TRUST.md

Confiança no recetor: avaliar um registo de um recetor GNSS real

kshana receiver-trust lê um registo de um recetor real de sistema global de navegação por satélite (GNSS), executa monitores de confiança sobre ele época a época, e indica quando e porquê a posição do recetor deixou de ser fiável. Pode também pontuar o registo face a eventos e previsões que indique antes da execução: se cada evento foi detetado a tempo, e se uma queda modelada da densidade de portadora-ruído (C/N0) concorda com o que o recetor mediu.

As observáveis são as do próprio recetor; os monitores e os seus limiares são os do motor e os seus. Cada resultado traz essa etiqueta, o SHA-256 do registo e todos os limiares com que foi executado, de modo que uma execução possa ser repetida e auditada.

Para uma embarcação em andamento, com uma pontuação em direto e uma barreira opcional à frente de um sistema de cartas, consulte MARITIME-TRUST.md.

O indicador de spoofing do próprio recetor posto ao lado dos alarmes do Kshana, a partir de uma execução real do motor v0.40.0 sobre um registo UBX fictício (200 épocas a 1 Hz). O C/N0 desce 20 dB entre 80 e 90 s e entre 120 e 130 s; o recetor assinala 120 a 130 s e 160 a 165 s. Das 140 épocas comparadas após a calibração, 11 tiveram ambos a assinalar, 6 só o recetor, 11 só o Kshana e 112 nenhum. Nenhum dos lados é verdade de referência e a concordância não é validação. Consultivo: saída de análise de uma ferramenta de investigação e engenharia, não um equipamento de navegação homologado e não um serviço de salvaguarda da vida humana.O indicador de spoofing do próprio recetor posto ao lado dos alarmes do Kshana, a partir de uma execução real do motor v0.40.0 sobre um registo UBX fictício (200 épocas a 1 Hz). O C/N0 desce 20 dB entre 80 e 90 s e entre 120 e 130 s; o recetor assinala 120 a 130 s e 160 a 165 s. Das 140 épocas comparadas após a calibração, 11 tiveram ambos a assinalar, 6 só o recetor, 11 só o Kshana e 112 nenhum. Nenhum dos lados é verdade de referência e a concordância não é validação. Consultivo: saída de análise de uma ferramenta de investigação e engenharia, não um equipamento de navegação homologado e não um serviço de salvaguarda da vida humana.

Execute-o#

kshana receiver-trust examples/receiver-trust/session.toml

Isto escreve session.result.json, session.trust.csv (uma linha por época) e session.trust.svg (C/N0 médio ao longo do tempo com o estado de confiança por baixo) junto ao cenário, e imprime um veredicto de uma linha. O registo de exemplo é sintético, feito para mostrar o formato; aponte path para o registo do seu próprio recetor.

Pontuação de confiança ao longo de uma travessia sintética, a partir de uma execução real do motor v0.40.0 sobre examples/maritime-trust (um registo NMEA fictício de um ferry numa rota de Tallinn a Helsínquia, 3001 épocas a 1 Hz). Três faixas partilham um eixo de tempo. Em cima: a distância entre a posição que o recetor indica e a posição real da embarcação, que se mantém dentro de alguns metros até cerca de 1576 s, quando o arrastamento de posição programado no registo a afasta, enquanto o recetor continua a indicar uma solução de posição válida. Ao meio: a pontuação de confiança de 0 a 100, não calculada durante os primeiros 300 s de calibração, na faixa nominal (pelo menos 90) até ao arrastamento, descendo depois pela faixa degraded (pelo menos 55) até à faixa untrusted. Em baixo: a faixa de cada época como uma fita colorida com o seu nome. A pontuação é consultiva. Software de caráter consultivo, não um equipamento de navegação homologado (IEC 61108, IEC 61162): o operador continua a ser responsável pela navegação da embarcação. O registo é fictício para mostrar o formato e os monitores; não é uma medição e nada diz sobre o desempenho de qualquer recetor.Pontuação de confiança ao longo de uma travessia sintética, a partir de uma execução real do motor v0.40.0 sobre examples/maritime-trust (um registo NMEA fictício de um ferry numa rota de Tallinn a Helsínquia, 3001 épocas a 1 Hz). Três faixas partilham um eixo de tempo. Em cima: a distância entre a posição que o recetor indica e a posição real da embarcação, que se mantém dentro de alguns metros até cerca de 1576 s, quando o arrastamento de posição programado no registo a afasta, enquanto o recetor continua a indicar uma solução de posição válida. Ao meio: a pontuação de confiança de 0 a 100, não calculada durante os primeiros 300 s de calibração, na faixa nominal (pelo menos 90) até ao arrastamento, descendo depois pela faixa degraded (pelo menos 55) até à faixa untrusted. Em baixo: a faixa de cada época como uma fita colorida com o seu nome. A pontuação é consultiva. Software de caráter consultivo, não um equipamento de navegação homologado (IEC 61108, IEC 61162): o operador continua a ser responsável pela navegação da embarcação. O registo é fictício para mostrar o formato e os monitores; não é uma medição e nada diz sobre o desempenho de qualquer recetor.

A figura acima é a demonstração de embarcação de MARITIME-TRUST.md: um registo inventado, uma pontuação consultiva.

O mesmo cenário executa-se a partir de Python (kshana.receiver_trust(toml)), a partir do pacote WebAssembly (receiver_trust(toml), com o registo em linha) e a partir da ferramenta assess_receiver_log do servidor Model Context Protocol (MCP).

Registos que lê#

format Fonte O que é lido
ubx binário u-blox NAV-SAT C/N0 por satélite, elevação e azimute, posição NAV-PVT, controlo automático de ganho (AGC) MON-RF e o indicador de jamming jamInd, semana NAV-TIMEGPS, e os indicadores do próprio recetor: NAV-STATUS spoofDetState e SEC-SIG (self_report, ver RECEIVER-PROTOCOLS.md)
rinex ficheiro de observação RINEX 3 códigos S (C/N0) por satélite e sinal; com um ficheiro de navegação de difusão (nav), as pseudodistâncias para a posição calculada pelo próprio motor
android CSV do GnssLogger do Android linhas Raw: C/N0 e AgcDb por satélite; linhas Fix: posição
nmea texto NMEA 0183 relação sinal-ruído GSV por satélite (dB-Hz, com ou sem o identificador de sinal 4,10) e a sua elevação e azimute, diluição da precisão e satélites usados GSA, hora e posição GGA e RMC
sbf binário Septentrio (0,38, apenas leitura) posição PVTGeodetic, C/N0 MeasEpoch por satélite e sinal, contagem de bandas RFStatus; ver RECEIVER-PROTOCOLS.md
rtklib-pos ficheiro de solução RTKLIB (.pos) hora, posição (latitude/longitude ou ECEF, convertida) e satélites usados por época; os ficheiros em graus-minutos-segundos são recusados com uma mensagem
novatel registos NovAtel OEM7 ASCII ou binários posição BESTPOS (apenas solução calculada), C/No RANGE por satélite e sinal; os indicadores de emissor de jamming RXSTATUS tornam-se o self_report da época (estado de jamming 2 quando o recetor assinala um emissor de jamming, 1 quando não; não existe indicador de spoofing no RXSTATUS), confrontados com os alarmes do Kshana pela comparação receiver-self-report
gnss-sdr Fluxos GNSS-SDR Monitor e PVT-monitor como linhas JSON C/N0 por canal, posição calculada, satélites usados, HDOP, azimute e elevação; produzido por integrations/gnss-sdr/relay.py

Pormenores, fontes e limites destes três: MACHINE-INPUTS.md.

Cada época que os leitores produzem traz também source_span, desvios em bytes [start, end) na entrada: o menor intervalo contíguo que contém os registos que contribuíram para ela, de modo que a fatia bruta exata possa ser calculada em hash para uma janela de evento. NMEA: todas as linhas lidas enquanto a época está atual (um superconjunto quando uma linha não relacionada se encontra entre as suas frases). UBX: as tramas da época. RINEX 3: os registos da época desde cada linha > até à seguinte. Android: as linhas Raw da época (uma linha Fix apenas para uma época sem linhas Raw). Ausente para um fluxo em direto e sempre que não está bem definido (RINEX 2).

O ficheiro entra por path (resolvido relativamente à pasta do próprio cenário), ou em linha como text ou base64 (as únicas opções num navegador).

Um registo IMU como segundo sensor#

[log.imu] acrescenta um registo inercial no mesmo relógio:

[log.imu]
format = "csv"          # or "euroc"
path = "imu.csv"        # or text / base64
heading0_deg = 90.0     # heading at the first IMU sample
yaw_axis_down = true    # body z down (NED/FRD); false for z up (ENU/FLU)
time_offset_s = 0.0     # added to the IMU clock to reach the log's t_s

A velocidade de guinada é integrada a partir de heading0_deg e preenche o rumo sempre que o registo do recetor não o contém, pelo que o monitor heading-course (que precisa de heading_sensor = true na plataforma) compara o rumo do giroscópio com o rumo sobre o fundo. Um giroscópio deriva: o rumo é tão bom quanto a janela de integração, e hdg_cog_tol_deg decide o que conta como discordância. O formato csv está documentado em MACHINE-INPUTS.md. Os bytes do IMU fazem parte do hash do cenário e do hash do cenário de um pacote de evidências. Em linha (text/base64) funciona em todas as superfícies; um path é recusado onde os ficheiros não são lidos.

Plataforma: estática ou embarcação#

Os monitores acima assumem uma antena fixa. Um cenário declara a plataforma antes da execução numa tabela [platform] de nível superior; sem ela, a plataforma é static e nada muda.

[platform]
kind = "vessel"            # "static" (default) or "vessel"
max_speed_kn = 30.0        # default 30
max_accel_mps2 = 0.5       # default 0.5
max_turn_rate_dps = 6.0    # default 6
antenna_height_m = 18.0    # no default: without it the sea-level monitor does not run
heading_sensor = false     # true: the stream carries a gyro heading (HDT or THS)
Chave Predefinição Porque esse valor
max_speed_kn 30 Acima da velocidade de serviço dos cascos mercantes e da maioria das embarcações de passageiros, pelo que uma embarcação real nunca a atinge; muito abaixo da velocidade que um arrastamento de posição implica. Uma embarcação mais lenta deve declarar um limite mais baixo: quanto mais baixo o limite, mais cedo o arrastamento é detetado.
max_accel_mps2 0.5 Um navio grande altera a velocidade bem abaixo de 0,1 m/s²; uma embarcação pequena e rápida atinge algumas décimas numa mudança brusca de aceleração.
max_turn_rate_dps 6 Um navio grande vira bem abaixo de 1 deg/s e uma embarcação pequena numa curva fechada a poucos.
antenna_height_m none Uma propriedade da instalação; um palpite seria um limiar oculto.
heading_sensor false Declarado true e ausente do registo é um erro, de modo que um sensor em falta não possa passar por uma verificação limpa.

As chaves de embarcação são rejeitadas em kind = "static". Para uma embarcação, o monitor position-jump não é executado, porque mede a distância à média de calibração, o que é errado numa antena em movimento; o monitor_config do resultado regista a plataforma e os limites usados.

Os fluxos NMEA sintéticos de kshana nmea-scenario, feitos para formação de tripulações, são aceites pelo leitor NMEA e podem ser executados por este tipo de cenário como qualquer registo NMEA.

Monitores#

Cada monitor precisa dos seus dados; um monitor cujos dados não estão no registo não é executado e não consta de monitors_run. Os primeiros calibration_s segundos (predefinição 60) definem a linha de base e nunca dão alarme.

Monitor Dá alarme quando Precisa de
cn0-drop o C/N0 médio dos satélites comuns com a linha de base desce cn0_drop_db ou mais (predefinição 6 dB) C/N0
loss-of-lock os satélites seguidos ficam sats_lost ou mais abaixo da mediana da linha de base (predefinição 4) C/N0
agc a leitura do AGC afasta-se da sua linha de base mais de agc_k_sigma desvios-padrão (predefinição 5) UBX MON-RF ou AgcDb do Android
jam-ind o jamInd do u-blox excede jam_ind_threshold (predefinição 80 de 255) UBX MON-RF
position-jump a posição calculada pelo próprio recetor está a mais de position_jump_m da sua média de calibração (predefinição 50 m) uma posição comunicada
raim a monitorização autónoma da integridade pelo recetor (RAIM) por paridade, sobre a solução de ponto único do próprio motor, rejeita o conjunto de medições registo RINEX com nav
solve-failure a solução de ponto único do motor falha com cinco ou mais satélites registo RINEX com nav
clock o relógio do recetor afasta-se da sua reta prevista mais do que o desvio mínimo detetável do seu ruído de calibração registo RINEX com nav

Perfil calibrado (opcional). [monitors] profile = "jammertest-2024-calibrated" substitui os três limiares de interferência por valores calibrados no conjunto de dados público JammerTest 2024 (um u-blox ZED-F9P por cenário; Zenodo 15911589): cn0_drop_db = 1.5, agc_k_sigma = 3.5, jam_ind_threshold = 29. A calibração foi pré-registada (xval/jammertest-trust/PREREGISTRATION.md) e o perfil é MODELLED, ajustado numa única campanha pública: o seu limiar cn0_drop_db não atingiu o limiar de falsos alarmes fixado antecipadamente sobre o conjunto reservado (0,0231 contra 0,02); os limiares do AGC e do indicador de jamming e o limiar da união (falsos alarmes 0,033, deteção 0,81) foram satisfeitos (xval/jammertest-trust/RESULTS.md). Vale para esse tipo de recetor nesse evento, face a janelas de ataque programadas, e foi calibrado nos registos CSV do conjunto de dados (os seus registos UBX dão mais falsos alarmes em duas pastas). Um resultado executado com o perfil repete os limiares que aplicou e traz uma profile_note que diz tudo isto. Sem o perfil aplicam-se as predefinições acima e todas as saídas ficam inalteradas.

Para uma plataforma vessel, os monitores de plataforma em movimento também são executados (limiares numa tabela [maritime] de nível superior, cada predefinição documentada em src/receiver_trust/maritime.rs); cada um precisa dos seus dados e só consta de monitors_run quando chegou a decidir:

Monitor Dá alarme quando Precisa de
kinematic a variação de posição discorda da velocidade e do rumo comunicados, ou implica uma velocidade, aceleração ou taxa de viragem acima dos limites da embarcação posições calculadas; velocidade e rumo (RMC ou VTG) para a parte de navegação à estima
heading-course o rumo do giroscópio e o rumo sobre o fundo diferem mais de hdg_cog_tol_deg (velocidade acima de min_speed_kn) rumo HDT, THS ou VHW, heading_sensor = true
speed-log a velocidade na água e a velocidade sobre o fundo diferem mais de stw_sog_tol_kn VHW ou VBW, e velocidade sobre o fundo
sea-level a altitude GGA difere de antenna_height_m mais de sea_level_tol_m altitude GGA, antenna_height_m
cn0-spread a dispersão do C/N0 entre satélites desce para cn0_spread_frac da sua mediana de calibração GSV
cn0-rise o C/N0 dos satélites comuns subiu cn0_rise_db em média e cn0_rise_frac deles subiram GSV
time-consistency as horas de épocas consecutivas avançam de forma irregular, recuam ou abandonam o relógio do anfitrião hora NMEA; relógio do anfitrião para a última parte
osnma o recetor comunica uma falha de autenticação OSNMA (é lido um estado comunicado; nada é verificado; para verificar o OSNMA a partir das próprias páginas I/NAV, consulte docs/OSNMA.md) frase de estado $PKSOS

Uma época é não fiável quando o RAIM, o monitor do relógio, uma falha de resolução ou um salto de posição dá alarme, ou quando a queda de C/N0 atinge o dobro do seu limiar; degradada com qualquer outro alarme; e nominal nos restantes casos.

O caminho do motor (raim, solve-failure, clock) é o mesmo cálculo que a referência independente de spoofing do JammerTest 2024 em tests/jammertest_spoof_oracle_support: tests/receiver_trust_jammertest.rs verifica que, nos oito inícios publicados, o primeiro alarme ocorre na mesma época e é do mesmo tipo.

Pontuação de confiança (plataforma embarcação)#

Numa embarcação, cada época após a calibração recebe também uma pontuação de 0 a 100 e as razões pelas quais não é 100. O mapeamento é determinístico e fixado antes de qualquer registo ser pontuado: sem aprendizagem, nada ajustado a eventos. Cada monitor reduz a sua evidência a uma razão statistic / threshold (um alarme em 1 ou mais); uma razão custa à pontuação

points = weight * clamp((ratio - onset_ratio) / (full_ratio - onset_ratio), 0, 1)
score  = round_to_0.1( clamp(100 - sum of points, 0, 100) )

de modo que um monitor não custa nada enquanto estiver abaixo de onset_ratio do seu limiar (predefinição 0,5), custa metade do seu peso no seu limiar, e o peso todo a full_ratio vezes o limiar (predefinição 1,5); a pontuação é não crescente em cada estatística. Uma fonte que não comunica numa época mantém a sua última estatística durante evidence_hold_s (predefinição 10 s: dois ciclos de uma frase de C/N0 enviada a cada 5 s), tanto como alarme como como dedução.

O arredondamento é por excesso a partir de meio (floor(x * 10 + 0.5) / 10), a banda é a da pontuação arredondada, e o limite é aplicado antes do arredondamento. Só os monitores cujos pontos são superiores a zero constam das deduções, com a sua razão e pontos não arredondados, primeiro os de mais pontos; as deduções com pontos iguais constam pela ordem dos nomes dos monitores 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, geometry. A um monitor cujo teste é passa ou falha (uma resolução falhada, uma autenticação falhada) é atribuída a razão 1,5, o peso total. Os pontos indicados são os anteriores ao limite em 0.

[score]
nominal_min = 90.0         # score >= 90: nominal
degraded_min = 55.0        # 55 <= score < 90: degraded; below 55: untrusted
onset_ratio = 0.5
full_ratio = 1.5
evidence_hold_s = 10.0
[score.weights]            # overrides; a monitor not listed keeps its default
sea-level = 30.0
Peso (pontos) Monitores Porquê
70 osnma uma falha de autenticação é uma afirmação, não uma estatística
60 kinematic, raim, clock, position-jump, time-consistency uma posição falsificada tem de contradizer a física ou as verificações do próprio recetor, e o tempo não pode andar para trás; uma violação em força total (1,5 vezes o seu limiar: 60 pontos, pontuação 40) é não fiável, e no seu limiar (30 pontos, pontuação 70) é degradada
40 heading-course, speed-log, solve-failure um sensor independente em desacordo é degradado; dois em força total são não fiáveis
30 sea-level, cn0-spread, cn0-rise, cn0-drop o ambiente de sinal, ou uma verificação pouco informativa
25 loss-of-lock, agc, jam-ind o ambiente é hostil; só isso não mostra que a posição está errada
até 15, [geometry] geometry (0.36) não é um peso nesta rampa: nada, a menos que o céu seja fraco, e depois até cap_points (15); a geometria sozinha atinge o estado degradado, nunca o não fiável, e não dá alarme (ver "Geometria" abaixo)

Os limites das bandas decorrem dos pesos: o monitor mais leve que dá alarme custa 12,5 pontos no seu limiar, pelo que qualquer alarme faz sair da banda nominal; nenhum monitor isolado com menos de 60 pontos pode atingir sozinho a banda não fiável (vários em conjunto podem). O resultado regista o modelo de pontuação (score_model) e cada época traz score.deductions: que monitores deduziram, as suas razões e os seus pontos. Numa embarcação, o estado da época é a banda da sua pontuação.

Geometria: degradação natural distinta da inconsistência semelhante a um ataque#

Um recetor junto a uma grua de cais, numa eclusa ou sob um casco alto perde satélites e a sua posição calculada piora por uma razão que não é um ataque. A partir de 0,36, segundo a nota de projeto de geometria (docs/design/2026-10-12-geometry-and-skyline-design.md, secção 4), cada época traz a sua geometria de satélites, a pontuação de uma embarcação tem um monitor de geometria, e cada dedução traz uma classe: geometry (o céu), environment (o ambiente de sinal) ou inconsistency (evidência semelhante a um ataque).

De onde vem a geometria. A elevação e o azimute de cada satélite seguido (NMEA GSV, UBX NAV-SAT), a partir dos quais a diluição da precisão (DOP) é derivada com o único núcleo de DOP do motor (orbit::dop, VALIDATED face a gnss_lib_py): source = derived. Na falta disso, o DOP e os satélites usados que o recetor indica (NMEA GSA): source = reported. As posições no céu e o GSA contam durante o evidence_hold_s da pontuação (predefinição 10 s), porque muitos barramentos enviam GSV de poucos em poucos segundos; um conjunto GSV incompleto numa época (o fim de um excerto, uma frase perdida) não é usado. Um registo sem nenhum dos dois, como NMEA só com GGA e RMC, ou os registos Android e RINEX atualmente, recebe o estado unknown com a nota "geometry unknown": o motor não adivinha uma geometria que não lhe foi dada, e o monitor de geometria não é executado.

geometry.status Significado
good satélites suficientes e DOP dentro dos limiares
degraded uma ou mais razões: few-satellites, high-pdop, high-hdop, e (informativo, não incluído na pontuação) sky-blocked quando todos os satélites seguidos estão numa metade do horizonte
unknown o registo não dá geometria de satélites para esta época

O estado é descritivo e o que conta para a pontuação é a etiqueta (abaixo): degraded inclui o caso informativo sky-blocked, que pode surgir com DOP bom ou razoável, e só uma etiqueta poor é pontuada.

A etiqueta (sempre comunicada, nunca pontuada). O geometry.label de cada época é good (HDOP no máximo hdop_good 2, PDOP no máximo pdop_good 3 e pelo menos used_good 6 satélites), poor (HDOP acima de hdop_max 4, PDOP acima de pdop_max 6 ou menos de min_used 5 satélites), fair entre os dois, ou unknown. A nota da época abre sempre com a etiqueta e os números, por exemplo "geometry fair: HDOP 1,105, PDOP 1,831, VDOP 1,410, 8 satellites; not scored (the score deducts only above HDOP 4, PDOP 6 or below 5 satellites)", e acrescenta ", signal loss" quando esta se verifica.

O monitor de geometria (pontuação da embarcação). Não deduz nada a menos que a geometria seja fraca: a sua razão é max(hdop / hdop_max, pdop / pdop_max, min_used / n_used), e enquanto esta for no máximo 1 (geometria boa ou razoável, incluindo um céu aberto só com GPS de 8 satélites) não custa nada, pelo que um registo assim é pontuado exatamente como em 0,35. Acima de 1 a dedução cresce linearmente até cap_points (15) em full_ratio (1,5 vezes os limiares: HDOP 6, PDOP 9, 3 satélites): 7,5 pontos na razão 1,25 (HDOP 5, ou 4 satélites), 15 a partir de 1,5 (pontuação 85, degradada). Por si só, nunca pode levar a pontuação abaixo de floor (predefinição: o degraded_min da pontuação, 55), pelo que a geometria sozinha atinge no máximo a banda degradada e nunca a não fiável: o limite em vigor é min(cap_points, 100 - floor), pelo que uma tabela [score] que aumente degraded_min (uma de 0,35 com degraded_min 90, por exemplo) reduz o limite para 100 - degraded_min em vez de ser recusada, e um floor definido abaixo de degraded_min é recusado. O monitor não dá alarme; consta em último lugar de monitors_run quando decidiu em alguma época (uma embarcação cujo registo dá a geometria), e não é contado na identidade com 0,35; não é uma entrada de [score.weights] (defini-la é recusado), e o limite e o mínimo em vigor ficam registados em geometry_model.cap_in_force e geometry_model.floor_in_force. A nota de uma época fraca diz porquê, por exemplo "geometry poor: HDOP 5,200, PDOP 7,900, VDOP 4,100, 7 satellites; degraded by geometry: HDOP 5,200 above 4 (derived from 7 logged satellites); not an inconsistency".

Classes. Cada dedução (score.deductions[].class):

Classe Monitores
geometry geometry (geometria fraca); loss-of-lock quando todos os satélites perdidos face à linha de base de calibração estavam abaixo de low_elev_deg no seu último comunicado
environment cn0-drop, cn0-spread, cn0-rise, agc, jam-ind, loss-of-lock nos restantes casos; geometry durante perda de sinal (abaixo)
inconsistency kinematic, heading-course, speed-log, sea-level, time-consistency, clock, raim, position-jump, osnma, solve-failure; e geometry quando a geometria é fraca e o HDOP indicado discorda do céu indicado (abaixo)

A proteção contra um céu fraco forjado. Um spoofer poderia enviar um GSV escasso, ou comunicar um HDOP elevado, para obter tolerância. O motor etiqueta e não perdoa: nenhuma outra verificação é alargada por uma geometria fraca, e o HDOP que o recetor indica (GSA dentro do período de retenção, senão GGA) é comparado com o HDOP derivado do céu que ele indica. Quando diferem mais de max(reported_vs_derived_tol, reported_vs_derived_rel × derived HDOP) (1,0, ou 25 % do HDOP derivado, o que for maior), a época traz reported_derived_mismatch: true e, quando a geometria é fraca, a sua dedução é classificada como inconsistency. Com geometria boa ou razoável, a discordância é comunicada e não pontuada: nada é deduzido a menos que a geometria seja fraca. Esta é uma escolha deliberada (0,36): "zero, a menos que seja fraca" vale para todas as épocas, pelo que a geometria boa e razoável é pontuada exatamente como em 0,35, e um HDOP forjado nunca passa em silêncio. O indicador (reported_derived_mismatch) está em todas as épocas do resultado e em todas as linhas em direto, a nota diz "…beyond the tolerance: reported, not scored (the geometry is not poor)" ou "…: the geometry deduction is classed an inconsistency", geometry_summary.hdop_mismatch conta as épocas, e a página de resumo das evidências mostra a contagem, incluindo zero. Os 25 % são uma escolha de engenharia REPRESENTATIVE, não um valor medido nem normalizado: um recetor que resolve um relógio por constelação, ou com um subconjunto dos satélites que segue (uma máscara de elevação, um corte de C/N0, uma exclusão RAIM), indica um HDOP que difere do HDOP de relógio único de todos os satélites seguidos numa medida que cresce com o HDOP, pelo que uma tolerância fixa sozinha leria uma geometria fraca natural como uma inconsistência. Uma diferença maior continua a ser lida como tal. Uma dedução classificada como geometry é uma afirmação sobre o céu, não uma conclusão de que não ocorreu nenhum ataque.

Perda de sinal não é o céu. Quando satélites que o recetor lista à vista (acima de low_elev_deg) não são seguidos, o motor deriva também o DOP de todos os satélites à vista. Se esse DOP à vista estiver dentro dos limiares e ou nada for seguido ou os satélites não seguidos estiverem espalhados pelo horizonte (não confinados a uma metade dele), o céu estava lá e o sinal não: a época traz signal_loss: true, a nota "satellites in view but not tracked: signal environment, not geometry", e a dedução de geometria é classificada como environment. Os satélites não seguidos confinados a uma metade do horizonte continuam a ser lidos como um céu bloqueado (uma parede, uma falésia, um cais). Uma obstrução bilateral (um desfiladeiro ou um fiorde estreito) é lida como perda de sinal até ser configurada uma linha de horizonte. Os valores sentinela de ausência de posição do recetor não são DOP: um HDOP ou PDOP indicado de 99 ou mais, qualidade GGA 0 e modo GSA 1 não dão DOP indicado.

chave [geometry] Predefinição Proveniência
hdop_max 4 escolhido (nota de projeto 4,2): com sigma_uere_m 1,5 m, um HDOP 4 é um 2drms de 12 m, o kin_pos_tol_m da verificação cinemática. A IEC 61108-1 é habitualmente citada como indicando os seus requisitos de exatidão para HDOP ≤ 4 (ou PDOP ≤ 6): recordado a partir da literatura secundária sobre recetores GNSS, sem consulta de nenhuma fonte secundária específica e sem leitura da norma; a verificar face ao texto da norma
pdop_max 6 o limiar de disponibilidade de PDOP de scenarios/polar-arctic-leo-coverage.toml; GPS SPS Performance Standard, 5.ª ed. (2020), PDOP ≤ 6, como citado em tests/constellation_availability_published_spec_oracle.rs; a verificar face ao texto da norma
min_used 5 mais um do que uma posição calculada precisa, para que uma única perda não termine a posição calculada; o mínimo com uma medição redundante para o RAIM
sigma_uere_m 1.5 uma entrada declarada para a ligação 2drms de hdop_max; defina o valor do próprio recetor
reported_vs_derived_tol 1,0 HDOP escolhido (nota de projeto 4,2): a parte absoluta da tolerância; uma discordância para além da tolerância não é geometria
reported_vs_derived_rel 0.25 escolha de engenharia REPRESENTATIVE: a parte relativa, para recetores com relógios por constelação ou soluções por subconjunto
low_elev_deg 15 nota de projeto 4,3: os satélites perdidos abaixo dele perdem-se para o céu; uma linha de horizonte (item 1 de 0,36) alargará isto
azimuth_gap_deg 180 geométrico, informativo: todos os satélites numa metade do horizonte
cap_points 15 nota de projeto 4,2: a geometria sozinha move a pontuação de nominal para degradada e nunca para não fiável; deduzido apenas quando a geometria é fraca (decisão do fundador B1, 0,36)
full_ratio 1.5 o full_ratio próprio da pontuação: a rampa atinge cap_points a 1,5 vezes os limiares de geometria fraca
floor o degraded_min da pontuação (55) a geometria sozinha nunca atinge a banda não fiável; o limite em vigor é min(cap_points, 100 - floor); um mínimo abaixo de degraded_min é recusado
hdop_good 2 REPRESENTATIVE, só para a etiqueta: metade de hdop_max (a razão de início da pontuação de 0,35)
pdop_good 3 REPRESENTATIVE, só para a etiqueta: metade de pdop_max
used_good 6 REPRESENTATIVE, só para a etiqueta: mais um do que min_used, pelo que uma única perda ainda deixa uma medição redundante

O que mudou nas saídas, e o que não mudou. Nenhuma pontuação muda, a menos que a geometria seja fraca; a etiqueta é sempre comunicada. Chaves acrescentadas: epochs[].geometry (status, reasons, source, n_used, hdop, pdop, vdop arredondado a 0,001, open_fraction (nulo até ser configurada uma linha de horizonte), max_azimuth_gap_deg, age_s, reported_hdop, reported_derived_mismatch, note, in_view (satélites listados acima de low_elev_deg), signal_loss, label), class em cada dedução, e no fim geometry_model (limiares, período de retenção, o limite e o mínimo em vigor, proveniência, regras de classe) e geometry_summary (épocas por estado, por etiqueta e por classe de dedução, e as épocas com uma discordância do HDOP indicado); score_model.weights é como em 0,35. Dois testes mantêm isto ao byte face à linha de base "0,36 portable" depois de removidas essas chaves (os hashes de 0.35.0, rebaseados quando o motor passou para matemática portátil e mantidos nos testes como registo do que a 0.35.0 publicou: docs/revisions/STUDIO15-portable-math-rebaseline.md). tests/geometry_trust_no_change.rs abrange todas as saídas de ambas as sessões de exemplo (JSON de resultado, CSV, SVG, veredicto, linhas em direto reproduzidas, $PKSHT, Prometheus, CEF, LEEF). tests/geometry_corpus_identity.rs abrange o resultado em lote, o resumo, as linhas em direto e o $PKSHT de cada corpus NMEA de embarcação submetido (a demonstração e os ficheiros de teste de referência marítimos, cada um também como céu aberto só com GPS com 8 satélites, e os cenários de formação de tripulações gerados a partir das suas sementes); nos dois cenários de formação em que o jamming torna a geometria fraca, todas as épocas que não são fracas são idênticas e todas as fracas diferem apenas pela dedução de geometria. Um registo cuja geometria é fraca perde até 15 pontos que não perdia em 0,35; essa é a alteração pretendida. Na demonstração, o arrastamento lê-se como inconsistency; tests/geometry_trust.rs edita o registo para mascarar o céu ocidental (razoável: etiquetado, não pontuado), para o mascarar e a dois satélites orientais (fraca: deduções de geometria, perda de bloqueio environment porque os satélites altos também desapareceram), para perder apenas satélites abaixo de 15° (perda de bloqueio geometry), e para indicar um HDOP que o céu não explica (a dedução de geometria fraca passa a inconsistency). Os limiares são MODELLED: escolhidos, não ajustados a nenhum registo; nada aqui afirma com que frequência a degradação natural e os ataques são distinguidos em dados reais.

Declarar eventos e previsões#

[[events]]
label = "jammer on"
kind = "jamming"            # jamming, spoofing or other
onset_s = 120.0             # seconds since the first epoch of the log
end_s = 240.0               # optional; otherwise onset_s + compare.horizon_s
predicted_cn0_drop_db = 12.0  # optional, e.g. from a `jamming` scenario's link budget

[compare]
detect_tol_s = 10.0         # an alarm this soon after onset counts as a detection
cn0_tol_db = 3.0            # predicted and observed drops agree within this

Para cada evento, o resultado dá os falsos alarmes entre a calibração e o início, o primeiro alarme e os seus monitores, a latência, o desfecho (detected, late, missed ou not-evaluable), e a queda mediana de C/N0 observada face à previsão (agree, disagree, no-prediction ou not-evaluable). A discordância é comunicada, nunca ajustada para desaparecer: as tolerâncias estão no cenário, e o cenário está no hash do resultado.

O que isto não afirma#

Os monitores de confiança são MODELLED: os seus limiares são entradas, e o seu desempenho de deteção em interferência real é o que a pontuação de eventos mede, não algo que este tipo de cenário afirme. Nas sessões de spoofing do JammerTest 2024, os monitores do caminho do motor apanham alguns inícios em 10 s e chegam tarde noutros; consulte a linha "Clock-aided χ², RAIM, AGC, SQM fused per-epoch security FoM" em VERIFICATION-MATRIX.md para os números. Uma previsão que concorda com um registo é um ponto de dados, não uma validação.