Mapa de interferência e exposição de rota
kshana interference-map constrói um retrato diário de onde aeronaves e navios informaram dados de navegação degradados, a partir de arquivos de rastreamento com licença aberta que você fornece. kshana route-exposure informa então quanto de uma rota planejada ficou dentro das células afetadas em cada dia.
O que isto é: uma descrição de como eram os relatórios de posição publicados em dias passados. O que não é: uma medição de qualquer receptor, uma previsão ou prova de interferência. Uma célula degradada ou anômala tem várias causas possíveis (listadas abaixo), e uma célula sem entrada simplesmente não foi observada.
Tudo roda em arquivos locais. Os comandos padrão nunca abrem uma conexão de rede; o único auxiliar de download opcional exige uma flag explícita.
Os dois 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 de rota são o que kshana route-exposure imprime para elas. Nada nelas é um lugar, uma aeronave ou uma embarcação reais.
Dados e licenças#
Apenas as fontes revisadas em data/INTERFERENCE-DATA-SOURCES.md estão embutidas, 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 publicador) | domínio público |
kystverket |
AIS | NLOD 2,0 | NLOD-2.0 |
custom |
qualquer um | o que você declarar | --licence, --licence-url, --attribution obrigatórios |
Cada arquivo 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 há entrada embutida para fontes cujos termos proíbem o uso comercial ou a redistribuição de mapas derivados.
ODbL e edições do Kshana. Um arquivo de ADS-B por célula feito a partir de dados do adsb.lol é um Derived Database e é lançado sob a ODbL 1,0; o seu campo licence diz isso. O código do próprio Kshana continua AGPL-3.0. As edições comerciais do Kshana que gravam esses arquivos levam o mesmo aviso, e quem republicar o arquivo deve mantê-lo. Os resultados de ADS-B e de AIS nunca são combinados em um único arquivo, de modo que a ODbL não se aplica à camada de AIS.
Viés de cobertura. Os mapas herdam a cobertura de sua fonte. O adsb.lol segue receptores voluntários, de modo que o mar aberto e as regiões pouco cobertas ficam esparsos. Os dados abertos do Kystverket omitem embarcações pesqueiras com menos de 15 m e embarcações de recreio com menos de 45 m, de modo que seu mapa reflete navios maiores. O MarineCadastre cobre apenas águas dos EUA.
Identificadores. As linhas de entrada trazem um identificador de aeronave ou de embarcação. Ele passa por hash em memória com um sal aleatório por execução, é usado apenas para contar aeronaves ou embarcações distintas e nunca é gravado, registrado em log nem impresso. As saídas são agregadas: nenhum identificador aparece em lugar algum delas.
Supressão. Uma célula com menos de 5 aeronaves ou embarcações distintas observadas naquele dia não é publicada de forma alguma e, para AIS, uma contagem sinalizada de um ou dois em uma célula publicada é informada como null. Nenhum valor publicado pode individualizar uma aeronave ou uma embarcação.
Formatos de entrada#
CSV simples com linha de cabeçalho, separado por vírgulas, sem aspas, horários em UTC. A ordem das colunas é livre; colunas desconhecidas são ignoradas. Um carimbo de data e hora é 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 silenciosamente.
ADS-B (kshana interference-map adsb):
| Coluna | Obrigatória | Significado |
|---|---|---|
timestamp |
sim | horário do relatório |
aircraft_id |
sim | identificador opaco (passa por hash, nunca é armazenado) |
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 informado |
source_type |
não | se presente, só são usados os valores que começam com 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 arquivos de rastro do readsb. Extraia um como o publicador descreve (concatene as partes, tar -xf -) e então forneça ao Kshana o diretório extraído, um único arquivo trace_full_*.json ou um CSV:
kshana interference-map adsb extracted-day/ --dataset adsb-lol --out maps/
Um diretório é pesquisado recursivamente em busca de arquivos trace_full_* (outros arquivos, como trace_recent_*, são ignorados e links simbólicos não são seguidos). Cada arquivo é compactado em gzip ou é JSON simples, detectado pelos seus primeiros bytes, porque o readsb grava gzip sob um nome .json; a descompressão é limitada a 512 MiB por arquivo. De cada entrada de rastro, o Kshana lê o deslocamento de tempo, 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 de fonte da posição (entradas de qualquer fonte que não seja 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 arquivo que não pode 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 | horário do relatório |
vessel_id |
sim | identificador opaco (passa por hash, nunca é armazenado) |
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 ausente |
O detector de terra firme precisa de um arquivo 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 arquivo pretendido. Sem --land, o detector fica desligado e a saída informa isso. Para baixá-lo (o único acesso à rede neste recurso):
kshana interference-map fetch-land --out ne_10m_land.geojson --allow-network
Isto executa o curl do sistema (como lista de argumentos, não por meio de um shell) por HTTPS, uma vez, para um arquivo em um endereço fixo que nomeia um único commit do repositório de origem. O download só é mantido se o seu SHA-256 for igual ao valor fixado no código; uma divergência o exclui e falha. Se o curl não estiver instalado, o comando informa isso e fornece o endereço e a soma de verificação para que o arquivo possa ser obtido manualmente. Nada é incluído no repositório.
Saída#
Um arquivo GeoJSON por fonte 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 relatórios: adsb-adsb-lol-2026-03-01.geojson, ais-kystverket-2026-03-01.geojson. O conjunto de dados está no nome para que dois conjuntos do mesmo tipo não possam compartilhar um arquivo, e o Kshana nunca sobrescreve um arquivo: se qualquer destino existir, o comando falha antes de gravar qualquer coisa. A CLI imprime uma linha por arquivo gravado. 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 arquivo (source_kind, data.dataset, date). Arquivos 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 grade, o id do método e todos os parâmetros, as figuras do nível do dia, a licença e a atribuição dos dados e um aviso. Cada feature é um polígono de célula com cell_i, cell_j, status, degraded e as contagens agregadas.
A grade é fixa: células quadradas de --cell-deg graus (padrão 0,5) em latitude e longitude, indexadas a partir de (-90, -180). A largura leste-oeste diminui com a latitude: cerca de 55 km no equador e cerca de 28 km a 60 graus para o padrão. A latitude 90 pertence à última linha e a longitude 180 é o mesmo meridiano que -180. Os métodos pré-registrados são definidos na grade de 0,5 grau. Outro --cell-deg executa, mas não é o método pré-registrado: a CLI informa isso, e o arquivo registra grid.preregistered_cell_deg e grid.is_preregistered (false) para que um visualizador também possa dizê-lo.
Contagens retidas. Toda contagem por célula abaixo do mínimo de publicação (5) é null, inclusive o zero, de modo que null nunca significa "nenhum" e nenhum número publicado pode individualizar uma aeronave ou uma embarcação. Os campos status e degraded continuam sendo fornecidos. Nos arquivos de ADS-B, aircraft_observed é sempre de 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 de pelo menos 5 (uma parcela revelaria uma contagem retida). Nos arquivos de 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 mudança que remove ou renomeia um campo, ou altera o que um campo significa, aumenta a versão; acrescentar um campo não aumenta, de modo que um leitor deve ignorar campos que não conhece. Uma contagem que é 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 seu próprio esquema kshana-route-exposure/v1.
Observatório: o produto diário#
kshana interference-map daily transforma um dia UTC de relatórios de ADS-B nos três arquivos do observatório (GeoJSON, PNG e um JSON de relatório de incidente) e em um manifesto de hashes, e kshana interference-map sensitivity reexecuta esse dia sob alterações de um parâmetro por vez dos parâmetros pré-registrados. O comando impõe as regras de lançamento: pelo menos 24 h depois do fim do dia (--delay-hours só pode ser aumentado), células de 0,5 grau ou mais grossas, 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 arquivo e os limites estão em observatory/METHOD.md. Uma execução regional (--bbox south,west,north,east) lê apenas os relatórios da caixa e informa isso no arquivo.
Especificação da página de mapa do Studio#
Para a página de mapa do Studio, que carrega um arquivo GeoJSON fornecido pelo usuário (a página é construída no código-fonte do Studio, não neste repositório). Nada é enviado: o arquivo é lido no navegador, e a página não faz nenhuma requisição a qualquer fonte de dados.
Leitura de um arquivo. Aceite um arquivo apenas se kshana_interference_map.schema começar com kshana-interference-map/ e format_version for um número que a página suporta; caso contrário, informe que o arquivo não é um mapa de interferência do Kshana suportado. Leia os campos listados acima; ignore os desconhecidos. Um arquivo contém uma fonte e um dia. Vários arquivos podem ser carregados.
Células. Desenhe o polígono de cada feature. Colora por status e sempre diga o que cada cor significa em uma legenda. Quatro estados, nenhum dos quais pode ser ocultado ou mesclado:
| Estado | Significado | De onde vem |
|---|---|---|
| Degradada (ou anômala, para AIS) | uma parcela alta das aeronaves informou baixa precisão, ou as embarcações apresentaram anomalias, naquele dia | degraded é verdadeiro |
| Livre | observada com aeronaves ou embarcações suficientes e não sinalizada | 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, de modo que a célula não foi publicada | nenhuma feature para essa célula |
"Não observada" é a ausência de uma feature: desenhe-a de forma neutra (sem preenchimento, ou com hachura), nunca na cor de "livre". Use um esquema de cores que não dependa apenas de vermelho contra verde. Os detalhes da célula ao passar o mouse ou ao selecionar mostram as contagens de properties como fornecidas e toda contagem null como "retida (menos de 5)", nunca como zero. Um visualizador também deve informar, quando grid.is_preregistered for false, que o arquivo usa um tamanho de célula fora do método pré-registrado.
Camadas. ADS-B e AIS são camadas separadas, com seus próprios controles, legendas e linhas de licença. Nunca as mescle em um único campo de cor ou em uma única contagem, nunca as desenhe como uma célula combinada e nunca some suas células. Dias diferentes são arquivos diferentes: mostre um dia por 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 tela, o texto de data.attribution literalmente, o data.licence com um link para data.licence_url e o data.coverage_notes. Se uma camada de ADS-B for mostrada, a sua licença ODbL se aplica apenas a essa camada. Não ofereça a exportação de um arquivo combinado.
Método. Ofereça o id e os parâmetros do método (method.id, method.parameters) e as figuras de day em um painel de detalhes, incluindo day_confounded (diga claramente 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 arquivo e mantenha esta redação, ou o seu equivalente, visível junto ao 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. Isso não é evidência de que a área estava livre.
- Esta é uma descrição de relatórios de posição passados, não uma previsão e não uma medição de qualquer receptor.
- 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 arquivos não contêm nenhuma.
Exposição de rota. Se a página também carregar um relatório kshana-route-exposure/v1, mostre 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, além dos caveats do relatório e do map_licence e do 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 registro): a física é a linha de visada de rádio dos livros-texto, 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 o fixa.
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 arquivos nunca são sobrescritos.
Modelo. Os relatos são agrupados em unidades (uma aeronave ou embarcação em um intervalo de 2 minutos), cada uma afetada (ADS-B: pelo menos metade de 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 em relação à 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 em uma grade recebe uma verossimilhança:
- Linha de visada. Uma aeronave à altura
he uma antena de emissor emh_eveem-se mutuamente até4.122 (sqrt h + sqrt h_e)km em um 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 visada" limita o alcance, marginalizado com peso igual. A borda 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 grade), porque o terreno, o diagrama da antena e o trajeto não são conhecidos com precisão melhor que essa.
- Afetadas e não afetadas. Uma aeronave ou embarcação é suscetível com probabilidade 0,6 (o equipamento receptor, 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 visada 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 visada nada diz.
- Sem terreno. O terreno, a formação de dutos e a difração não são modelados (o terreno só pode remover a linha de visada).
- Atenuação. O logaritmo da verossimilhança é multiplicado por 0,3 (uma posterior de potência). A evidência do modelo é mais dependente e suas bordas menos nítidas 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, seçã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 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 grade é 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 viés 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 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 visada 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 receptores; tdoa_s[i] é o receptor i+1 menos o receptor 0). A posição é resolvida na superfície da Terra por Gauss-Newton sobre geolocation::tdoa_predict, 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 sua 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 seu rótulo de evidência (nível MODELLED, ids das linhas do registro; a faixa sob a figura, linhas # evidence na tabela, um membro evidence no JSON). Os arquivos de máquina são em inglês qualquer que seja o idioma; o texto da figura e as linhas da linha de comando são localizados. Há um exemplo sintético em examples/emitter-region/ (regenerate.sh).
Privacidade e redaçã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 redaçã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 redaçã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 compartilha o modelo, com bordas de alcance incertas 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 pane 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 rastro 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 de ADS-B (kshana-interference-map/adsb/v2)#
Cada relatório ADS-B em voo traz 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 receptor a bordo perde ou deixa de confiar na sua posição por satélite, ambos caem, e é por isso que carregam uma assinatura de interferência. Eles também caem por outros motivos.
Parâmetros pré-registrados (constantes no código, gravadas em cada arquivo; uma mudança significa uma nova versão do método):
| Parâmetro | Valor |
|---|---|
| Piso de altitude | altitude barométrica de pelo menos 5000 ft |
| Relatório de baixa precisão | NACp no máximo 6 (o limite de EPU informado é 556 m, 0,3 NM, ou maior, ou desconhecido) ou NIC no máximo 5 (o limite do raio de contenção informado é 1852 m, 1 NM, ou maior, ou desconhecido) |
| Bom relatório | NACp de pelo menos 8 e NIC de pelo menos 7; avaliados nos 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 só conta em uma célula com pelo menos 5 bons relatórios fora dessa célula no mesmo dia |
| Aeronaves amostradas em uma célula | pelo menos 3 relatórios na célula |
| Aeronaves afetadas em uma célula | pelo menos 50% dos seus relatórios 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 afetada das aeronaves amostradas de pelo menos 0,30 e pelo menos 0,15 acima da parcela mediana das células do 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, de modo que a mediana não pode ser estimada: uma célula que atinge os limiares é withheld_no_background, não degradada |
| Mínimo de publicação | pelo menos 5 aeronaves distintas observadas |
Esses valores foram definidos a partir das definições dos códigos NIC e NACp e da regra de privacidade, antes de qualquer dado ser examinado. 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 pulava a verificação do fundo do dia, sem avisar, quando menos de 5 células eram totalmente amostradas. 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. As duas mudanças tornam o método mais rigoroso (nada que não era degradado na versão 1 é degradado na versão 2); o motivo é que uma classificação publicada nunca deve se apoiar em menos aeronaves do que o número abaixo do qual as contagens são retidas. Os arquivos da versão 1 não foram lançados.
Por que os campos de precisão caem por motivos que não são interferência, e a salvaguarda para cada um:
| Causa | Salvaguarda |
|---|---|
| Transponders mais antigos que nunca informam NIC ou NACp, ou os informam com um valor baixo fixo | a linha de base do equipamento: uma aeronave sem bons relatórios em outros lugares naquele dia não é contada |
| Baixa altitude e operações em superfície (mascaramento pelo terreno, formatos de posição diferentes) | piso de altitude; linhas marcadas com ground excluídas |
| MLAT ou outras posições que não são de GNSS | filtro de source_type quando a coluna está presente |
| Uma aeronave enviando muitos relatórios | contam-se aeronaves distintas, não relatórios |
| Uma interrupção de constelação ou de aumentação, ou um evento de clima espacial, que reduz a precisão em uma área ampla | a célula deve exceder a parcela mediana das células do dia por uma margem, e um dia cuja mediana já é alta é 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; com menos 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 interrupção de aumentação terrestre pareceria igual), e é conservador em um sentido: uma aeronave que voa apenas dentro de uma região afetada o dia todo não tem linha de base e não é contada, de modo que áreas grandes e persistentes são subnotificadas.
Método de AIS (kshana-interference-map/ais/v2)#
Por embarcação por dia, cinco detectores. Um detector qualifica em uma célula quando sinaliza pelo menos 5 embarcações distintas que representem pelo menos 20% das embarcações observadas ali; a célula é anomalous se algum detector qualificar.
| Detector | Regra (pré-registrada) |
|---|---|
on_land |
pelo menos 3 relatórios na célula a mais de 2000 m para o interior da linha de costa fornecida |
circle |
uma janela de 20 relatórios consecutivos (passo 10, intervalos de no máximo 30 min) cujo raio médio em relação ao centroide é de 500 m a 20 km, coeficiente de variação do raio de no máximo 0,15, um sentido de deslocamento 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 chegando à célula: relatórios consecutivos separados por pelo menos 1000 m, com no máximo 1 h de intervalo, que implicam mais de 70 kn (a velocidade implícita usa pelo menos 1 s entre os relatórios; assim, dois relatórios com o mesmo carimbo de tempo e posições distantes 1 km ou mais contam como um salto) |
implausible_speed |
pelo menos 3 velocidades informadas acima de 70 kn na célula |
same_position |
pelo menos 5 embarcações distintas informando a mesma posição (arredondada a 1e-4 graus, cerca de 11 m) na mesma janela de 10 minutos |
Células com menos de 5 embarcações distintas não são publicadas; toda contagem sinalizada abaixo de 5, inclusive o zero, é informada como null.
Versão 2. A versão 1 qualificava um detector a partir de 3 embarcações sinalizadas e publicava contagens de 3 e 4. A versão 2 eleva o mínimo de embarcações sinalizadas para 5, o mínimo de publicação, de modo que uma classificação anomalous nunca se apoie em menos embarcações do que o número abaixo do qual as contagens são retidas. Isso torna o método mais rigoroso, e nenhum arquivo da versão 1 foi lançado.
Causas conhecidas de falsos positivos, que a regra de 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 isso); duas embarcações que compartilham um mesmo identificador, o que parece saltos; transponders com posição ruim ou equipamento de teste; e a permanência de lanchas de praticagem e embarcações de busca em uma área, que pode se parecer com círculos. Um arquivo de linha de costa em 1:10 milhões é preciso a cerca de um quilômetro.
Os detectores de salto e de velocidade comparam relatórios dentro de um mesmo arquivo de entrada; uma trilha dividida entre arquivos ou dias não é unida.
Memória. A entrada é lida linha a linha e nunca mantida inteira. O ADS-B guarda apenas contadores por aeronave e por célula. O AIS guarda cada relatório aceito em um registro compacto (cerca de 40 bytes) até o seu dia ser avaliado, de modo que a memória cresce com o número de relatórios de AIS na entrada; divida por dia uma entrada de 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 LineString GeoJSON (simples, dentro de uma Feature ou de uma FeatureCollection) ou um CSV de linhas lat,lon. --map aceita arquivos de mapa ou diretórios deles e pode ser repetido. Os pontos de passagem são unidos por retas em latitude e longitude, portanto densifique os trechos longos; um trecho toma o caminho mais curto em longitude, de modo que um que cruze o antimeridiano (179,5 E a 179,5 W) o cruza. A rota é dividida em partes de cerca de 250 m. Cada parte é medida entre os seus dois pontos extremos em uma esfera de raio 6371,0088 km (o mesmo caminho que decide em qual célula ela se encontra) e atribuída à célula que contém o seu ponto médio.
Por dia e por fonte, o relatório informa o comprimento da rota e quatro parcelas que somam 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 junto com a primeira: uma rota com baixa parcela degradada e alta parcela não observada não foi demonstrada como livre. As linhas de ADS-B e de AIS são informadas separadamente e nunca combinadas. Cada linha traz a licença e a atribuição do mapa.
Funções da biblioteca#
Para chamadores que mantêm os dados em memória (bindings, o servidor MCP, a build para navegador), o módulo kshana::interference_map::api expõe os mesmos métodos com texto ou bytes na entrada e JSON na saída, sem tocar em nenhum arquivo nem na rede:
| Função | Entrada | Saída |
|---|---|---|
adsb_maps_from_csv(csv, &DatasetSpec, cell_deg) |
texto CSV de ADS-B | Vec<DayMap> |
adsb_maps_from_readsb_traces(&[&[u8]], &DatasetSpec, cell_deg) |
uma fatia de bytes por arquivo de rastro do readsb (gzip ou simples) | Vec<DayMap> |
ais_maps_from_csv(csv, &DatasetSpec, cell_deg, Option<&str>) |
texto CSV de AIS, texto GeoJSON de terra opcional | Vec<DayMap> |
route_exposure(route_text, &[&str], from, to) |
texto da rota, textos GeoJSON dos 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 aprovadas, texto de licença obrigatório, o tipo deve corresponder) aplicam-se exatamente como na linha de comando.
Validação externa#
tests/interference_map_reference.rs compara o Kshana com implementações independentes em entradas sintéticas, com tolerâncias pré-registradas em tests/fixtures/interference_map_ref/PREREGISTRATION.md: os significados dos códigos NIC e NACp contra a decodificação de quadros ADS-B sintéticos pelo pyModeS, os valores "não disponível" do AIS contra a decodificação de sentenças AIVDM sintéticas pelo pyais, a atribuição de célula da grade contra o shapely, o comprimento de rota por estado de célula contra o shapely e o GeographicLib, e a máscara de terra firme contra o shapely e o pyproj. As fixtures são geradas por scripts/gen_interference_map_ref.py; a CI não precisa de Python. Isso valida como os códigos e os valores de campo são lidos e a geometria. Não valida que uma célula sinalizada 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 arquivos para trás.