Ronan Arraes Jardim Chagas

O Desempenho do SGP4/SDP4 do SatelliteToolbox.jl para Atividades Operacionais

O ecossistema SatelliteToolbox.jl é um conjunto de pacotes para a linguagem Julia que possibilita uma ampla gama de análises para missões espaciais, desde estudos de projeto de missão até as atividades do dia a dia de uma equipe operacional de dinâmica de voo.

Dentre essas atividades, poucas exigem tanto de um único algoritmo quanto a propagação de órbitas com o SGP4/SDP4. O catálogo de objetos espaciais conhecidos é distribuído na forma de elementos médios — TLEs e, mais recentemente, mensagens CCSDS de elementos médios de órbita (OMM) — e esses elementos só têm significado quando propagados com o algoritmo SGP4/SDP4 para o qual foram ajustados. A detecção de colisões é o exemplo mais claro de por que o desempenho importa: para triar as conjunções de um satélite, precisamos propagar sua órbita contra todos os objetos do banco de dados de objetos espaciais conhecidos ao longo de toda a janela de análise, e repetir o processo inteiro a cada publicação de novos conjuntos de elementos. Nessa escala, o custo de uma única chamada de propagação é multiplicado por dezenas de milhões, e a velocidade do propagador determina diretamente com que frequência e profundidade uma equipe de operações consegue triar sua frota.

O SatelliteToolbox.jl cobre esse fluxo de trabalho de ponta a ponta: ele obtém os elementos médios das bases de dados mais comuns (space-track.org e Celestrak) nos formatos TLE e OMM, e implementa o algoritmo SGP4/SDP4 para propagá-los.

Isso leva a uma pergunta que ouço com frequência: uma implementação em Julia consegue igualar o desempenho das implementações consolidadas de SGP4 usadas em contextos operacionais? Para respondê-la, comparei o propagador SGP4 do SatelliteToolbox.jl com três outras implementações:

LinguagemBibliotecaVersão
JuliaSatelliteToolbox.jl1.0.0
C++Implementação de referência de Vallado (via CelesTrak)mais recente
Rustsgp4-rs2.4.0
JavaOrekit13.0.3

O código C++ de Vallado é a referência contra a qual as implementações de SGP4 são tradicionalmente verificadas, o Orekit é a biblioteca padrão de fato para dinâmica de voo operacional na JVM, e o sgp4-rs é uma implementação moderna e bem testada em Rust.

Metodologia#

Todos os benchmarks seguem exatamente o mesmo protocolo:

  1. Ler o TLE compartilhado — o caso de teste clássico da ISS do conjunto de verificação do SGP4 de Vallado — e inicializar o propagador uma única vez, fora da região cronometrada.
  2. Aquecer com 10 chamadas de propagação não cronometradas.
  3. Cronometrar 1.000.000 de chamadas de propagação com o instante de propagação percorrendo um dia em passos de 1 minuto: t = (i mod 1441) minutos desde a época do TLE. O laço cronometrado é executado 5 vezes e a repetição mais rápida é reportada, o que suprime o ruído de escalonamento do sistema operacional, de rampa de frequência da CPU e de JIT.
  4. Acumular a soma de todas as componentes de posição como um checksum, o que impede que o compilador elimine o laço e valida as implementações entre si.

O TLE usado em todos os benchmarks é:

ISS (ZARYA)
1 25544U 98067A   08264.51782528 -.00002182  00000-0 -11606-4 0  2927
2 25544  51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537

Todas as implementações usam o modelo gravitacional WGS-72 (o padrão para TLEs) e retornam o vetor de estado no referencial TEME. O benchmark em Rust usa o construtor from_elements_afspc_compatibility_mode do sgp4-rs para que o tratamento de época e de tempo sideral seja idêntico ao das demais implementações. Com essa configuração, as quatro implementações produzem checksums idênticos bit a bit, ou seja, estamos comparando exatamente a mesma computação.

Cada benchmark usa a API pública de “propagar no instante t” da biblioteca, incluindo quaisquer objetos criados a cada chamada que isso implique. Isso mede o que o usuário realmente obtém, e não um núcleo interno otimizado à mão.

A máquina é um MacBook Pro com Apple M3 Pro e 18 GB de RAM, rodando macOS 26.6.1, Julia 1.12.6, Apple clang 21, rustc 1.97.1 e OpenJDK 26.0.2.

Resultados#

LinguagemBibliotecaChamadasTotal [ms]Tempo / Chamada [ns]
Rustsgp4-rs1.000.000176,152176,2
C++Vallado SGP41.000.000176,849176,8
JuliaSatelliteToolbox.jl1.000.000180,870180,9
JavaOrekit1.000.0001174,5131174,5

A primeira conclusão é que C++, Rust e Julia estão estatisticamente empatadas, em torno de 175–180 ns por propagação. A variação entre execuções das três implementações mais rápidas nesta máquina é de cerca de ±4% e a ordem entre elas muda a cada execução. Qualquer classificação entre elas dentro de poucos nanossegundos não é significativa.

A segunda conclusão é que o Orekit é cerca de 6,5× mais lento que as outras três. Isso não é um problema de JIT: a JVM já está completamente aquecida quando a repetição reportada é executada.

O Que Isso Significa na Prática Operacional#

A ~180 ns por propagação, o SatelliteToolbox.jl consegue propagar todo o catálogo público (~30.000 objetos) com resolução de 1 minuto ao longo de um dia inteiro (cerca de 43 milhões de propagações) em menos de 8 segundos em um único núcleo. Como as propagações são independentes, isso escala trivialmente entre threads.

Em outras palavras, a implementação de SGP4 do SatelliteToolbox.jl tem desempenho no nível da implementação de referência em C++, mantendo todas as vantagens de trabalhar em Julia: análise interativa, composição com o restante do ecossistema e nenhum problema de duas linguagens entre a prototipação e a operação.