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/INTERFERENCE-MAP.md

Mapa de interferência e exposição de rotas

kshana interference-map constrói uma imagem diária de onde aeronaves e navios comunicaram dados de navegação degradados, a partir de ficheiros de seguimento com licença aberta que o utilizador fornece. kshana route-exposure indica depois que parte de uma rota planeada esteve dentro das células afetadas em cada dia.

O que isto é: uma descrição do aspeto que tiveram os relatos de posição publicados em dias passados. O que não é: uma medição de qualquer recetor, uma previsão ou uma prova de interferência. Uma célula degradada ou anómala tem várias causas possíveis (enumeradas abaixo), e uma célula sem entrada simplesmente não foi observada.

Tudo funciona com ficheiros locais. Os comandos predefinidos nunca abrem uma ligação de rede; o único auxiliar de descarga opcional exige uma opção explícita.

Dois dias sintéticos do mapa de interferência, desenhados a partir das amostras submetidas em examples/interference-map/output, cada um com a sua própria rota sintética e as parcelas de exposição da rota que o motor comunica. À esquerda, um dia ADS-B: 1 célula degradada, 6 não degradadas, 4 não avaliadas (a tracejado) e células sem entrada, desenhadas vazias, que não foram observadas. A rota tem 525 km: 11,5% do seu comprimento em células degradadas, 38,3% não degradadas, 9,1% não avaliadas e 41,1% não observadas. À direita, um dia AIS: células assinaladas pelos detetores de círculo e de terra firme, células não anómalas e células vazias; a rota tem 454 km, com 10,5% em células anómalas, 21,2% não anómalas, 0,0% não avaliadas e 68,3% não observadas. ADS-B e AIS são camadas separadas, nunca combinadas. Uma célula assinalada não é uma constatação de interferência, e uma célula sem cor não foi observada, o que não é o mesmo que livre. Todos os dados são inventados, em pleno meio do Atlântico, e não constituem uma medição.Dois dias sintéticos do mapa de interferência, desenhados a partir das amostras submetidas em examples/interference-map/output, cada um com a sua própria rota sintética e as parcelas de exposição da rota que o motor comunica. À esquerda, um dia ADS-B: 1 célula degradada, 6 não degradadas, 4 não avaliadas (a tracejado) e células sem entrada, desenhadas vazias, que não foram observadas. A rota tem 525 km: 11,5% do seu comprimento em células degradadas, 38,3% não degradadas, 9,1% não avaliadas e 41,1% não observadas. À direita, um dia AIS: células assinaladas pelos detetores de círculo e de terra firme, células não anómalas e células vazias; a rota tem 454 km, com 10,5% em células anómalas, 21,2% não anómalas, 0,0% não avaliadas e 68,3% não observadas. ADS-B e AIS são camadas separadas, nunca combinadas. Uma célula assinalada não é uma constatação de interferência, e uma célula sem cor não foi observada, o que não é o mesmo que livre. Todos os dados são inventados, em pleno meio do Atlântico, e não constituem uma medição.

Ambos os dias são as amostras sintéticas em examples/interference-map/output/, cada uma com uma rota sintética em examples/interference-map/input/; as parcelas de exposição da rota são as que kshana route-exposure apresenta para elas. Nada nelas é um local, uma aeronave ou uma embarcação reais.

Dados e licenças#

Apenas as fontes revistas em data/INTERFERENCE-DATA-SOURCES.md estão incorporadas, selecionadas com --dataset:

--dataset Tipo Licença Campo de licença da saída
adsb-lol ADS-B ODbL 1,0 ODbL-1.0
noaa-marinecadastre AIS Domínio público dos EUA (CC0 1,0 segundo o editor) domínio público
kystverket AIS NLOD 2,0 NLOD-2.0
custom qualquer um o que o utilizador indicar --licence, --licence-url, --attribution obrigatórios

Cada ficheiro de saída incorpora a licença, o URL da licença, a atribuição exigida e os limites de cobertura da fonte. Não existe nenhuma entrada incorporada para fontes cujos termos proíbam a utilização comercial ou a redistribuição de mapas derivados.

ODbL e edições do Kshana. Um ficheiro ADS-B por célula feito a partir de dados do adsb.lol é uma Derived Database e é lançado sob a ODbL 1,0; o seu campo licence di-lo. O código do próprio Kshana continua AGPL-3.0. As edições comerciais do Kshana que escrevem esses ficheiros incluem o mesmo aviso, e quem voltar a publicar o ficheiro tem de o manter. Os resultados ADS-B e AIS nunca são combinados num só ficheiro, pelo que a ODbL não se aplica à camada AIS.

Viés de cobertura. Os mapas herdam a cobertura da sua fonte. O adsb.lol depende de recetores voluntários, pelo que o mar aberto e as regiões com pouca cobertura são esparsos. Os dados abertos do Kystverket omitem embarcações de pesca com menos de 15 m e embarcações de recreio com menos de 45 m, pelo que o seu mapa reflete os navios maiores. O MarineCadastre cobre apenas águas dos EUA.

Identificadores. As linhas de entrada têm um identificador de aeronave ou de embarcação. É calculado em hash em memória com um sal aleatório por execução, usado apenas para contar aeronaves ou embarcações distintas, e nunca escrito, registado nem impresso. As saídas são agregadas: nenhum identificador aparece nelas.

Supressão. Uma célula com menos de 5 aeronaves ou embarcações distintas observadas nesse dia não é publicada de todo, e, para o AIS, uma contagem assinalada de um ou dois numa célula publicada é comunicada como null. Nenhum valor publicado pode identificar uma aeronave ou uma embarcação.

Formatos de entrada#

CSV simples com linha de cabeçalho, separado por vírgulas, sem aspas, horas UTC. A ordem das colunas é livre; as colunas desconhecidas são ignoradas. Uma marca temporal é em segundos Unix ou YYYY-MM-DDTHH:MM:SS[.fff]Z. As linhas que não podem ser analisadas são contadas nos metadados da saída, não descartadas em silêncio.

ADS-B (kshana interference-map adsb):

Coluna Obrigatória Significado
timestamp sim hora do relato
aircraft_id sim identificador opaco (calculado em hash, nunca guardado)
lat, lon sim graus
alt_baro_ft sim altitude em pés; ground ou vazio exclui a linha
nic, nacp pelo menos uma inteiros de 0 a 11; vazio significa não comunicado
source_type não se presente, só são usados os valores que começam por adsb (MLAT, TIS-B e semelhantes são excluídos)

Histórico readsb do adsb.lol, lido diretamente. Os arquivos diários são um tar dividido de ficheiros de rasto do readsb. Extraia um como o editor descreve (concatenar as partes, tar -xf -) e depois forneça ao Kshana o diretório extraído, um único ficheiro trace_full_*.json ou um CSV:

kshana interference-map adsb extracted-day/ --dataset adsb-lol --out maps/

Um diretório é pesquisado recursivamente à procura de ficheiros trace_full_* (os outros ficheiros, como trace_recent_*, são ignorados e as ligações simbólicas não são seguidas). Cada ficheiro está comprimido em gzip ou é JSON simples, detetado pelos seus primeiros bytes, porque o readsb escreve gzip sob um nome .json; a descompressão está limitada a 512 MiB por ficheiro. De cada entrada de rasto, o Kshana lê o desvio temporal, a latitude, a longitude, a altitude (o marcador ground exclui a entrada), os campos nic e nac_p do objeto de detalhes da aeronave e a cadeia da fonte da posição (as entradas de qualquer fonte que não ADS-B são excluídas). Uma entrada sem objeto de detalhes não tem campos de precisão e é contada como excluída. Um ficheiro que não possa ser lido é contado em trace_files_unreadable nos metadados da saída e ignorado.

AIS (kshana interference-map ais):

Coluna Obrigatória Significado
timestamp sim hora do relato
vessel_id sim identificador opaco (calculado em hash, nunca guardado)
lat, lon sim graus; os valores "não disponível" do AIS e (0, 0) são descartados
sog_kn não velocidade sobre o fundo em nós; 102,3 (não disponível) é tratado como em falta

O detetor em terra precisa de um ficheiro de polígonos de terra (--land): GeoJSON Polygon ou MultiPolygon. A camada de terra do Natural Earth de 1:10 milhões (domínio público) é o ficheiro previsto. Sem --land, o detetor fica desligado e a saída di-lo. Para a descarregar (o único acesso à rede desta funcionalidade):

kshana interference-map fetch-land --out ne_10m_land.geojson --allow-network

Isto executa o curl do sistema (como lista de argumentos, não através de uma shell) por HTTPS, uma vez, para um ficheiro num endereço fixo que identifica um único commit do repositório de origem. A descarga só é mantida se o seu SHA-256 for igual ao valor fixado no código; uma divergência elimina-a e falha. Se curl não estiver instalado, o comando di-lo e indica o endereço e a soma de verificação, para que o ficheiro possa ser obtido manualmente. Nada é incluído no repositório.

Saída#

Um ficheiro GeoJSON por fonte e por dia UTC, no diretório --out, com o nome <source>-<dataset>-<YYYY-MM-DD>.geojson, em que <source> é adsb ou ais, <dataset> é a chave --dataset (adsb-lol, noaa-marinecadastre, kystverket ou custom) e a data é o dia UTC dos relatos: adsb-adsb-lol-2026-03-01.geojson, ais-kystverket-2026-03-01.geojson. O conjunto de dados está no nome para que dois conjuntos de dados do mesmo tipo não possam partilhar um ficheiro, e o Kshana nunca substitui um ficheiro: se existir algum destino, o comando falha antes de escrever o que quer que seja. A CLI imprime uma linha por cada ficheiro que escreve. Um leitor pode recuperar as três partes com ^(adsb|ais)-(.+)-(\d{4}-\d{2}-\d{2})\.geojson$; a mesma informação está dentro do ficheiro (source_kind, data.dataset, date). Os ficheiros de amostra sintéticos, um por fonte, estão em examples/interference-map/output/, com o comando que os regenera, para construir e testar um visualizador. Um membro de nível superior kshana_interference_map contém o nome do esquema, a data, a grelha, o identificador do método e todos os parâmetros, os valores ao nível do dia, a licença dos dados e a atribuição, e um aviso. Cada elemento é um polígono de célula com cell_i, cell_j, status, degraded e as contagens agregadas.

A grelha é fixa: células quadradas de --cell-deg graus (por predefinição 0,5) em latitude e longitude, indexadas a partir de (-90, -180). A largura este-oeste diminui com a latitude: cerca de 55 km no equador e cerca de 28 km aos 60 graus para a predefinição. A latitude 90 pertence à última linha e a longitude 180 é o mesmo meridiano que -180. Os métodos pré-registados estão definidos na grelha de 0,5 graus. Outro --cell-deg é executado, mas não é o método pré-registado: a CLI di-lo, e o ficheiro regista grid.preregistered_cell_deg e grid.is_preregistered (falso) para que um visualizador o possa dizer também.

Contagens retidas. Toda a contagem por célula abaixo do mínimo de publicação (5) é null, incluindo o zero, pelo que null nunca significa "nenhuma" e nenhum número publicado pode identificar uma aeronave ou uma embarcação. Os campos status e degraded continuam a ser fornecidos. Nos ficheiros ADS-B, aircraft_observed é sempre pelo menos 5 para uma célula publicada; aircraft_sampled e aircraft_affected são null abaixo de 5, e affected_share é null a menos que ambos sejam pelo menos 5 (uma parcela revelaria uma contagem retida). Nos ficheiros AIS, cada entrada de vessels_flagged é null abaixo de 5.

Versão do formato e campos#

O formato está estabelecido como schema: "kshana-interference-map/v1", format_version: 1. Uma alteração que remova ou renomeie um campo, ou altere o que um significa, aumenta a versão; acrescentar um campo não, pelo que um leitor tem de ignorar os campos que não conhece. Uma contagem que seja null está retida, não é zero.

FeatureCollection
  kshana_interference_map
    schema, format_version, kshana_version, notice
    source_kind            "adsb" | "ais"
    date                   "YYYY-MM-DD" (UTC)
    grid                   { type: "fixed_lat_lon", cell_deg, preregistered_cell_deg, is_preregistered }
    method                 { id, summary, parameters{...}, guards[], input_stats{...}, caveats[] }
    day                    day-level figures (ADS-B: background_evaluated, background_share,
                           day_confounded, cells_published, cells_suppressed_below_min_distinct;
                           AIS: on_land_detector, cells_published, cells_suppressed_...)
    data                   { dataset, name, licence, licence_url, attribution, coverage_notes[] }
  features[]               Polygon (one closed ring, [lon, lat], counter-clockwise)
    properties             cell_i, cell_j, status, degraded,
                           ADS-B: aircraft_observed, aircraft_sampled|null, aircraft_affected|null,
                                  affected_share|null
                           AIS:   vessels_observed, vessels_flagged{detector: n|null}, detectors[]

Valores de status: ADS-B degraded, not_degraded, insufficient_sample, withheld_day_confounded, withheld_no_background; AIS anomalous, not_anomalous. degraded é verdadeiro apenas para degraded e anomalous. O relatório de exposição de rota tem o seu próprio esquema kshana-route-exposure/v1.

Observatório: o produto diário#

kshana interference-map daily transforma um dia UTC de relatos ADS-B nos três ficheiros do observatório (GeoJSON, PNG e um JSON de relatório de incidentes) e num manifesto de hashes, e kshana interference-map sensitivity reproduz esse dia com alterações de um parâmetro de cada vez nos parâmetros pré-registados. O comando impõe as regras de publicação: pelo menos 24 h depois de o dia terminar (--delay-hours só pode ser aumentado), células de 0,5 graus ou mais grosseiras, apenas três estados (degraded, not_degraded, not_observed), nenhuma causa atribuída e nenhum dado do OpenSky. A nota de método, os formatos de ficheiro e os limites estão em observatory/METHOD.md. Uma execução regional (--bbox south,west,north,east) lê apenas os relatos da caixa e di-lo no ficheiro.

Especificação da página de mapa do Studio#

Para a página de mapa do Studio, que carrega um ficheiro GeoJSON fornecido pelo utilizador (a página é construída no código-fonte do Studio, não neste repositório). Nada é carregado para um servidor: o ficheiro é lido no navegador, e a página não faz nenhum pedido a qualquer fonte de dados.

Ler um ficheiro. Aceite um ficheiro apenas se kshana_interference_map.schema começar por kshana-interference-map/ e format_version for um número que a página suporte; caso contrário, indique que o ficheiro não é um mapa de interferência do Kshana suportado. Leia os campos enumerados acima; ignore os desconhecidos. Um ficheiro contém uma fonte e um dia. Podem ser carregados vários ficheiros.

Células. Desenhe o polígono de cada elemento. Colora segundo status e indique sempre numa legenda o que cada cor significa. Quatro estados, nenhum dos quais pode ser ocultado ou fundido:

Estado Significado Origem
Degradada (ou anómala no AIS) uma parcela elevada de aeronaves comunicou baixa precisão, ou embarcações apresentaram anomalias, nesse dia degraded é verdadeiro
Livre observada com aeronaves ou embarcações suficientes e não assinalada status é not_degraded ou not_anomalous
Não avaliada observada mas sem aeronaves amostradas suficientes, o dia foi confundido, ou o fundo do dia não pôde ser estimado status é insufficient_sample, withheld_day_confounded ou withheld_no_background
Não observada aeronaves ou embarcações em número insuficiente, pelo que a célula não foi publicada nenhum elemento para essa célula

"Não observada" é a ausência de um elemento: desenhe-a de forma neutra (sem preenchimento, ou com tracejado), nunca na cor de "livre". Use um esquema de cores que não dependa apenas do vermelho face ao verde. Os detalhes da célula ao passar o cursor ou ao selecionar mostram as contagens em properties tal como fornecidas, e cada contagem null como "retida (menos de 5)", nunca como zero. Um visualizador deve também indicar, quando grid.is_preregistered é falso, que o ficheiro usa um tamanho de célula fora do método pré-registado.

Camadas. ADS-B e AIS são camadas separadas, com os seus próprios interruptores, legendas e linhas de licença. Nunca as funda num só campo de cor ou numa só contagem, nunca as desenhe como uma célula combinada e nunca some as suas células. Dias diferentes são ficheiros diferentes: mostre um dia de cada vez, com um seletor de dia, em vez de sobrepor dias.

Licença e atribuição. Para cada camada visível, mostre, no mapa e em qualquer exportação ou captura de ecrã, o texto de data.attribution literalmente, o data.licence com uma ligação para data.licence_url, e o data.coverage_notes. Se for mostrada uma camada ADS-B, a sua licença ODbL aplica-se apenas a essa camada. Não ofereça a exportação de um ficheiro combinado.

Método. Ofereça o identificador e os parâmetros do método (method.id, method.parameters) e os valores de day num painel de detalhes, incluindo day_confounded (diga com clareza que nenhuma célula foi considerada degradada por causa do fundo do dia) e input_stats.

Ressalvas a manter (mostre os próprios method.caveats e notice do ficheiro, e mantenha esta formulação, ou uma equivalente, visível junto do mapa):

  • Uma célula degradada ou anómala não é uma constatação de interferência. Existem outras causas.
  • Uma célula sem cor não foi observada. Não é prova de que a área estivesse livre.
  • Isto é uma descrição de relatos de posição passados, não uma previsão e não uma medição de qualquer recetor.
  • A cobertura segue a fonte de dados; leia as notas de cobertura.

A página não deve nomear nem mostrar nenhuma aeronave ou embarcação individual, e os ficheiros não contêm nenhuma.

Exposição de rota. Se a página carregar também um relatório kshana-route-exposure/v1, mostre as suas linhas por dia e fonte com as quatro parcelas (degradada, livre, não avaliada, não observada) em conjunto, nunca apenas a parcela degradada, mais os caveats do relatório, e o map_licence e o map_attribution de cada linha.

Região do emissor (interference-map locate)#

kshana interference-map locate estima onde pode estar uma fonte de interferência a partir dos mesmos relatos abertos ADS-B ou AIS: uma região em níveis de confiança declarados, um centroide com uma elipse de incerteza e as sessões no tempo. Nunca devolve um ponto isolado. MODELLED (linha VM-bc70cb57 do registo): a física é a linha de vista de rádio dos manuais, a credibilidade das regiões depende do modelo, e a única verificação externa é a comparação com o Jammertest fixada antecipadamente em emitter-region/PREREGISTRATION.md. A publicação de regiões de emissores no observatório público é uma decisão separada do responsável e está desativada: o observatório não lê este módulo, e um teste fixa-o.

kshana interference-map locate input.csv --source adsb --dataset adsb-lol --out regions/
kshana interference-map locate day-dir/  --source adsb --dataset adsb-lol --out regions/     # readsb traces
kshana interference-map locate ais.csv   --source ais  --dataset kystverket --land land.geojson --out regions/

Opções: --levels 0.5,0.9,0.95, --cell-km, --session-gap-min, --emitter-height-m min,max, --ship-height-m (AIS), --tdoa fix.json (fundir uma solução TDOA; abaixo). Qualquer opção que difira do valor fixado antecipadamente é anunciada como "não é o método fixado antecipadamente". Os ficheiros nunca são substituídos.

Modelo. Os relatos são agrupados em unidades (uma aeronave ou embarcação num intervalo de 2 minutos), cada uma afetada (ADS-B: pelo menos metade dos seus relatos tem NIC ou NACp baixo pela regra do próprio mapa; AIS: uma velocidade ou salto implausível, ou uma posição no interior do continente face à linha de costa) ou não. Uma aeronave ou embarcação só conta com pelo menos 5 bons relatos na entrada (a mesma proteção de linha de base de equipamento do mapa). As unidades afetadas são agrupadas em sessões: um intervalo de mais de 30 minutos separa no tempo e, dentro de um agrupamento no tempo, duas unidades pertencem ao mesmo grupo quando um único emissor poderia estar ao alcance de ambas. Para uma sessão, cada posição candidata numa grelha recebe uma verossimilhança:

  • Linha de vista. Uma aeronave à altura h e uma antena de emissor em h_e veem-se mutuamente até 4.122 (sqrt h + sqrt h_e) km num raio terrestre de 4/3. h_e é marginalizada sobre 2 a 100 m (8 valores espaçados logaritmicamente).
  • Potência. A potência do emissor é desconhecida, portanto um alcance efetivo de 12 km a 426 km (em passos de 1,25) ou "apenas linha de vista" limita o alcance, marginalizado com peso igual. O limite do alcance é suave: uma unidade conta como ao alcance com um peso que cai linearmente ao longo de 15% do alcance de cada lado (pelo menos três quartos de uma célula da grelha), porque o terreno, o diagrama da antena e o trajeto não são conhecidos com precisão melhor do que essa.
  • Afetadas e não afetadas. Uma aeronave ou embarcação é suscetível com probabilidade 0,6 (o equipamento recetor, a antena e o trajeto do sinal diferem), uma unidade de uma suscetível dentro do alcance é afetada com probabilidade 0,9, e qualquer outra unidade é afetada com a probabilidade de fundo 0,03 (outras causas). A suscetibilidade é uma propriedade latente da aeronave, somada por aeronave, assim como uma falha persistente de equipamento (probabilidade 0,03: todas as unidades dessa aeronave são afetadas onde quer que ela esteja), o que impede que um transponder defeituoso arraste a região. Assim, uma aeronave afetada puxa a posterior para posições que a alcançam, e uma aeronave não afetada com linha de vista empurra contra posições que a teriam alcançado no máximo com o peso de uma aeronave, por mais relatos que tenha enviado, enquanto uma aeronave não afetada sem linha de vista nada diz.
  • Sem terreno. O terreno, a formação de condutas e a difração não são modelados (o terreno só pode remover a linha de vista).
  • Atenuação. O logaritmo da verossimilhança é multiplicado por 0,3 (uma posterior de potência). A evidência do modelo é mais dependente e os seus extremos menos nítidos do que a independência que a verossimilhança supõe, e em dados sintéticos com essas falhas as regiões sem atenuação continham a fonte verdadeira em proporção bem inferior à declarada; 0,3 foi escolhido apenas com dados sintéticos (a derivação está em docs/emitter-region/PREREGISTRATION.md, secção 8).

A posterior fornece regiões de maior densidade nos níveis declarados (aninhadas; polígonos com furos quando necessário), o centroide ponderado pela posterior e a sua elipse de momentos (escalada a 95% sob uma gaussiana; os polígonos, e não a elipse, são os níveis calibrados). A grelha é grosseira (cerca de 5 a 10 km) sobre todo o domínio e toda célula grosseira que contém massa é dividida 4 por 4. O enviesamento de cobertura é tratado condicionando a onde existem relatos: uma região é larga onde havia poucas aeronaves, e uma sessão cuja região de 95% ocupa mais de 80% de do seu domínio de busca é informada como unconstrained sem centroide.

Sessões e perfil. Cada sessão publicada tem início, fim, duração, a área das células de 0,5 grau que contêm uma unidade afetada e pelo menos 5 aeronaves ou embarcações distintas, as contagens de afetadas e observadas distintas, e a contraevidência (distintas não afetadas com linha de vista ao centroide; retida abaixo de 5). Uma sessão com menos de 5 aeronaves ou embarcações afetadas distintas é retida e contada. O perfil fornece, por hora UTC do dia, as aeronaves afetadas distintas (null abaixo de 5) e os minutos de tempo de sessão, e as horas de tempo de sessão por dia UTC.

Fusão TDOA opcional. --tdoa fix.json recebe {"receivers": [[lat, lon, height_m], ...], "tdoa_s": [...], "sigma_s": 1e-7, "start": [lat, lon]} (pelo menos três recetores; tdoa_s[i] é o recetor i+1 menos o recetor 0). A posição é resolvida na superfície da Terra por Gauss-Newton sobre geolocation::tdoa_predict, a sua covariância é geolocation::tdoa_crlb_on_sphere, e a gaussiana é multiplicada na posterior. O limite de Cramer-Rao é um limite inferior sobre um modelo, não uma precisão medida.

Saídas (emitter-<source>-<dataset>-<day>): .geojson (região MultiPolygon por nível e sessão, o polígono da elipse, o ponto do centroide que leva a respetiva elipse), -summary.json, -sessions.csv, -figure.svg. Cada uma incorpora a licença do conjunto de dados, a URL da licença e a atribuição, o id do método kshana-interference-map/emitter-region/v1, todos os parâmetros, as hipóteses e os limites, e traz a sua etiqueta de evidência (nível MODELLED, ids das linhas do registo; a faixa sob a figura, linhas # evidence na tabela, um membro evidence no JSON). Os ficheiros de máquina são em inglês qualquer que seja o idioma; o texto da figura e as linhas da linha de comandos são localizados. Há um exemplo sintético em examples/emitter-region/ (regenerate.sh).

Privacidade e formulação. Nenhum identificador de aeronave ou embarcação aparece em qualquer saída; nenhuma posição de relato é desenhada; uma sessão precisa de pelo menos 5 aeronaves ou embarcações distintas; contagens abaixo de 5 são null. A formulação é neutra: "região estimada do emissor", "região da fonte de interferência". Uma região não é a posição de ninguém, não é uma constatação da causa e nada diz sobre quem ou o que está por trás de uma fonte; o teste de formulação ampliado verifica nas saídas as palavras de atores, intenção e conflito.

Limites. A credibilidade depende do modelo. Em dados sintéticos (um gerador que partilha o modelo, com extremos de alcance incertos em 15% por aeronave, falhas persistentes de equipamento, potência desconhecida e altura de antena desconhecida) a região de 95% continha a fonte verdadeira em 0,99 (geometria de aeronaves) e 1,00 (geometria de navios) das sessões e a região de 50% em cerca de 0,77: os níveis são conservadores, pelo expoente da verossimilhança de 0,3, e o erro do centroide de uma sessão tem mediana de 23 km (aeronaves) e 12 km (navios). A calibração é verificada apenas com dados sintéticos; a comparação com o Jammertest foi fixada antecipadamente (emitter-region/PREREGISTRATION.md) e executada uma vez: NOT ASSESSABLE para as duas fontes (emitter-region/RESULTS.md). Uma fonte por sessão; várias fontes próximas parecem uma só. Uma causa regional (uma avaria de constelação, clima espacial) dá uma região que não é uma fonte. O ADS-B fornece poucos relatos fora do espaço aéreo movimentado, e apenas cerca de um quarto dos pontos de rasto do readsb traz NIC e NACp, de modo que áreas esparsas dão regiões largas ou nenhuma (31% das sessões de geometria de navios foram unconstrained).

Método ADS-B (kshana-interference-map/adsb/v2)#

Cada relato ADS-B em voo inclui dois campos de qualidade de navegação autoavaliados: NIC (o raio de contenção da posição) e NACp (o limite de precisão de 95%, EPU). Quando o recetor a bordo perde ou deixa de confiar na sua posição por satélite, ambos descem, razão pela qual constituem uma assinatura de interferência. Descem também por outros motivos.

Parâmetros pré-registados (constantes no código, escritas em cada ficheiro; uma alteração implica uma nova versão do método):

Parâmetro Valor
Limite mínimo de altitude altitude barométrica de pelo menos 5000 ft
Relato de baixa precisão NACp no máximo 6 (o limite de EPU comunicado é 556 m, 0,3 NM, ou superior, ou desconhecido) ou NIC no máximo 5 (o limite do raio de contenção comunicado é 1852 m, 1 NM, ou superior, ou desconhecido)
Bom relato NACp pelo menos 8 e NIC pelo menos 7; avaliado com os campos que a entrada tem (ambos quando ambos estão presentes, o que estiver presente caso contrário)
Linha de base do equipamento uma aeronave conta numa célula apenas com pelo menos 5 bons relatos fora dessa célula no mesmo dia
Aeronaves amostradas numa célula pelo menos 3 relatos na célula
Aeronaves afetadas numa célula pelo menos 50% dos seus relatos na célula são de baixa precisão
Amostra mínima pelo menos 10 aeronaves amostradas
Degradada pelo menos 5 aeronaves afetadas, uma parcela de afetadas entre as aeronaves amostradas de pelo menos 0,30, e pelo menos 0,15 acima da parcela mediana das células nesse dia
Dia confundido parcela mediana das células (sobre pelo menos 5 células com amostra completa) de pelo menos 0,15: nenhuma célula é declarada degradada
Sem fundo menos de 5 células com amostra completa, pelo que a mediana não pode ser estimada: uma célula que atinja os limiares é withheld_no_background, não degradada
Mínimo de publicação pelo menos 5 aeronaves distintas observadas

Estes valores foram fixados a partir das definições dos códigos NIC e NACp e da regra de privacidade antes de se olhar para quaisquer dados. Não foram ajustados com dados reais, e os testes usam apenas dados sintéticos. Estados das células: degraded, not_degraded, insufficient_sample (publicada mas com menos de 10 aeronaves amostradas), withheld_day_confounded e withheld_no_background.

Versão 2. A versão 1 declarava uma célula degradada com apenas 3 aeronaves afetadas, menos do que o mínimo de publicação de 5 aeronaves, e saltava a verificação do fundo do dia, sem o dizer, quando menos de 5 células tinham amostra completa. A versão 2 exige pelo menos 5 aeronaves afetadas e retém a classificação (withheld_no_background) quando o fundo não pode ser estimado. Ambas as alterações tornam o método mais restritivo (nada que não estivesse degradado na versão 1 está degradado na versão 2); o motivo é que uma classificação publicada nunca deve assentar em menos aeronaves do que o número abaixo do qual as contagens são retidas. Os ficheiros da versão 1 não foram publicados.

Porque descem os campos de precisão por motivos que não a interferência, e a salvaguarda para cada um:

Causa Salvaguarda
Transponders mais antigos que nunca comunicam NIC ou NACp, ou os comunicam com um valor baixo fixo a linha de base do equipamento: uma aeronave sem bons relatos noutros locais nesse dia não é contada
Baixa altitude e operações à superfície (ocultação pelo terreno, formatos de posição diferentes) limite mínimo de altitude; as linhas marcadas ground são excluídas
Posições MLAT ou outras não GNSS filtro source_type quando a coluna está presente
Uma aeronave que envia muitos relatos contam-se as aeronaves distintas, não os relatos
Uma falha de constelação ou de aumento, ou um evento de meteorologia espacial, que reduz a precisão numa área ampla a célula tem de exceder a parcela mediana das células do dia por uma margem, e um dia cuja mediana seja ela própria elevada é marcado como confundido e não declara nenhuma célula
Uma falha no equipamento de uma aeronave exige uma parcela de muitas aeronaves distintas, com uma amostra mínima
Poucas aeronaves na célula amostra mínima; abaixo de 5 observadas, a célula não é publicada

O que resta: o método não consegue distinguir interferência de uma causa regional que seja local e não ampla (um efeito local de geometria de satélites ou uma falha de aumento terrestre pareceriam o mesmo), e é conservador num sentido: uma aeronave que voa apenas dentro de uma região afetada durante todo o dia não tem linha de base e não é contada, pelo que as grandes áreas persistentes são subcomunicadas.

Método AIS (kshana-interference-map/ais/v2)#

Por embarcação e por dia, cinco detetores. Um detetor qualifica-se numa célula quando assinala pelo menos 5 embarcações distintas que representem pelo menos 20% das embarcações aí observadas; a célula é anomalous se algum detetor se qualificar.

Detetor Regra (pré-registada)
on_land pelo menos 3 relatos na célula a mais de 2000 m para o interior da linha de costa fornecida
circle uma janela de 20 relatos consecutivos (passo 10, intervalos de no máximo 30 min) cujo raio médio ao centroide é de 500 m a 20 km, coeficiente de variação do raio de no máximo 0,15, um sentido de deslocação com enrolamento total de pelo menos 270 graus (passos de no máximo 90 graus, líquido de pelo menos 80% do total) e velocidade média de pelo menos 2 kn
implausible_jump pelo menos 2 saltos que chegam à célula: relatos consecutivos com pelo menos 1000 m de distância e no máximo 1 h de intervalo, implicando mais de 70 kn (a velocidade implícita usa pelo menos 1 s entre os relatos, pelo que dois relatos com a mesma marca temporal e posições a 1 km ou mais de distância contam como um salto)
implausible_speed pelo menos 3 velocidades comunicadas acima de 70 kn na célula
same_position pelo menos 5 embarcações distintas a comunicar a mesma posição (arredondada a 1e-4 graus, cerca de 11 m) na mesma janela de 10 minutos

As células com menos de 5 embarcações distintas não são publicadas; toda a contagem assinalada abaixo de 5, incluindo o zero, é comunicada como null.

Versão 2. A versão 1 qualificava um detetor a partir de 3 embarcações assinaladas e publicava contagens de 3 e 4. A versão 2 eleva o mínimo de embarcações assinaladas para 5, o mínimo de publicação, de modo que uma classificação anomalous nunca assenta em menos embarcações do que o número abaixo do qual as contagens são retidas. Isto torna o método mais restritivo e nenhum ficheiro da versão 1 foi publicado.

Causas conhecidas de falsos positivos, que a regra da parcela e os limiares reduzem mas não eliminam: embarcações em rios, canais e portos próximos de uma linha de costa grosseira (a margem de 2 km para o interior existe por este motivo); duas embarcações que partilham um identificador, o que parece saltos; transponders com uma posição errada ou equipamento de ensaio; e a permanência em torno de uma zona por barcos de pilotos e de busca, que pode assemelhar-se a círculos. Um ficheiro de linha de costa de 1:10 milhões tem uma exatidão de cerca de um quilómetro.

Os detetores de saltos e de velocidade comparam relatos dentro de um ficheiro de entrada; uma trajetória dividida por vários ficheiros ou dias não é reunida.

Memória. A entrada é lida linha a linha e nunca mantida por inteiro. O ADS-B guarda apenas contadores por aeronave e por célula. O AIS guarda cada relato aceite num registo compacto (cerca de 40 bytes) até o seu dia ser avaliado, pelo que a memória cresce com o número de relatos AIS na entrada; divida por dia uma entrada AIS muito grande.

Exposição de rota#

kshana route-exposure --route route.geojson --map out/ [--map other/] \
    [--from 2026-03-01] [--to 2026-03-07] [--out report.json] [--json]

--route é um GeoJSON LineString (isolado, num Feature ou num FeatureCollection) ou um CSV de linhas lat,lon. --map aceita ficheiros de mapa ou diretórios com eles, e pode ser repetido. Os pontos de passagem são unidos por linhas retas em latitude e longitude, pelo que se devem densificar os troços longos; um troço toma o caminho mais curto em longitude, pelo que um que atravesse o antimeridiano (179,5 E a 179,5 W) o atravessa. A rota é dividida em segmentos de cerca de 250 m. Cada segmento é medido entre os seus dois extremos numa esfera de raio 6371,0088 km (o mesmo caminho que decide em que célula se encontra) e atribuído à célula que contém o seu ponto médio.

Por dia e por fonte, o relatório dá o comprimento da rota e quatro parcelas cuja soma é 1: share_degraded, share_not_degraded, share_unassessed (célula presente mas sem classificação) e share_not_observed (célula ausente do mapa). Leia as duas últimas juntamente com a primeira: uma rota com uma parcela degradada baixa e uma parcela não observada elevada não foi demonstrada como livre. As linhas ADS-B e AIS são comunicadas em separado e nunca combinadas. Cada linha inclui a licença e a atribuição do mapa.

Funções da biblioteca#

Para quem tem dados em memória (ligações, o servidor MCP, a versão de navegador), o módulo kshana::interference_map::api expõe os mesmos métodos com texto ou bytes à entrada e JSON à saída, sem tocar em nenhum ficheiro nem na rede:

Função Entrada Saída
adsb_maps_from_csv(csv, &DatasetSpec, cell_deg) texto CSV ADS-B Vec<DayMap>
adsb_maps_from_readsb_traces(&[&[u8]], &DatasetSpec, cell_deg) uma fatia de bytes por ficheiro de rasto do readsb (gzip ou simples) Vec<DayMap>
ais_maps_from_csv(csv, &DatasetSpec, cell_deg, Option<&str>) texto CSV AIS, texto GeoJSON de terra opcional Vec<DayMap>
route_exposure(route_text, &[&str], from, to) texto da rota, textos GeoJSON de mapas, limites YYYY-MM-DD opcionais JSON kshana-route-exposure/v1

Um DayMap tem file_name (<source>-<dataset>-<date>.geojson), date e geojson (o documento v1). DatasetSpec é Preset("adsb-lol" | "noaa-marinecadastre" | "kystverket") ou Custom { licence, licence_url, attribution }; DEFAULT_CELL_DEG é 0,5. Os erros são MapError. As regras do conjunto de dados (predefinições aceites, texto de licença obrigatório, o tipo tem de coincidir) aplicam-se exatamente como na linha de comandos.

Validação externa#

tests/interference_map_reference.rs compara o Kshana com implementações independentes sobre entradas sintéticas, com tolerâncias pré-registadas em tests/fixtures/interference_map_ref/PREREGISTRATION.md: os significados dos códigos NIC e NACp face à descodificação por pyModeS de tramas ADS-B sintéticas, os valores "não disponível" do AIS face à descodificação por pyais de frases AIVDM sintéticas, a atribuição de células da grelha face ao shapely, o comprimento da rota por estado de célula face ao shapely e ao GeographicLib, e o mascaramento em terra face ao shapely e ao pyproj. Os dados de teste são produzidos por scripts/gen_interference_map_ref.py; a CI não precisa de Python. Isto valida a forma como os códigos e os valores dos campos são lidos e a geometria. Não valida que uma célula assinalada seja interferência.

Testes#

Todos os testes usam dados sintéticos gerados e nenhuma rede: testes unitários em src/interference_map/, e tests/interference_map_cli.rs para os comandos de ponta a ponta, incluindo que nenhum identificador chega a uma saída e que as recusas não deixam ficheiros para trás.