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:
| Linguagem | Biblioteca | Versão |
|---|---|---|
| Julia | SatelliteToolbox.jl | 1.0.0 |
| C++ | Implementação de referência de Vallado (via CelesTrak) | mais recente |
| Rust | sgp4-rs | 2.4.0 |
| Java | Orekit | 13.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:
- 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.
- Aquecer com 10 chamadas de propagação não cronometradas.
- 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) minutosdesde 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. - 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#
| Linguagem | Biblioteca | Chamadas | Total [ms] | Tempo / Chamada [ns] |
|---|---|---|---|---|
| Rust | sgp4-rs | 1.000.000 | 176,152 | 176,2 |
| C++ | Vallado SGP4 | 1.000.000 | 176,849 | 176,8 |
| Julia | SatelliteToolbox.jl | 1.000.000 | 180,870 | 180,9 |
| Java | Orekit | 1.000.000 | 1174,513 | 1174,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.