Skip to content
RFrftools.io
Satellite Communications30 de abril de 202610 min de leitura

Construindo um cronograma de passes para a estação terrestre com a Skyfield

Pronto para o pôr do sol do Ansys STK: calcule as previsões de passagem SGP4 para sua estação terrestre de rádio amador ou cubesat usando o Skyfield. Passo a passo completo do Python com busca de TLE, máscaras de elevação, Doppler e exportação do iCalendar.

Conteúdo

Por que você precisa de um agendador de passes local

Se você administra uma estação SatNogs, uma cabine de rádio amador que rastreia AO-91/ISS/NOAA ou um segmento terrestre de cubesat em estágio inicial, você precisa de previsões automatizadas de passes. As ferramentas comerciais (STK, NOVA) são um exagero. Os preditores gratuitos da web (AMSAT, Heavens-Above) não funcionam bem. Com o fim do STK Cloud em março de 2026, a alternativa gratuita mais limpa é Skyfield — o moderno sucessor do Python do PyEphem.

Esta postagem mostra um **programador completo de estações terrestres em cerca de 80 linhas de Python: busque novos TLEs, calcule as próximas 24 horas de passes para uma lista de satélites, filtre por elevação mínima, calcule o Doppler para sua frequência de downlink e emita o iCalendar para que os passes apareçam em seu aplicativo de calendário.

Instalar
pip install skyfield requests icalendar
É isso mesmo. O Skyfield obtém suas próprias efemérides (DE421, IERS) na primeira execução — cerca de 17 MB em cache localmente.

Etapa 1: Buscar os TLEs atuais

Os TLEs derivam — use-os dentro de 7 dias após a época. Extraia o conjunto de elementos atual do Celestrak:

from skyfield.api import load

stations_url = 'https://celestrak.org/NORAD/elements/gp.php?GROUP=amateur&FORMAT=tle'
sats = load.tle_file(stations_url)
by_name = {s.name: s for s in sats}
print(f'Loaded {len(sats)} amateur-radio satellites')
Escolha seus alvos pelo nome (eles diferenciam maiúsculas de minúsculas no arquivo Celestrak):
targets = [
    by_name['AO-91 (FOX-1B)'],
    by_name['ISS (ZARYA)'],
    by_name['NOAA 19'],
    by_name['GreenCube (IO-117)'],
]
## Etapa 2: defina sua estação terrestre
from skyfield.api import wgs84, load

ts = load.timescale()
my_station = wgs84.latlon(40.0150, -105.2705, elevation_m=1624)  # Boulder, CO
min_elevation_deg = 10  # horizon mask to skip low passes
Use o parâmetroelevation_m— ele afeta materialmente a faixa de inclinação em ângulos de elevação baixos.

Etapa 3: Encontre eventos de nascimento/culminar/definirSatellite.find_events()retorna uma lista plana de eventos (0 = aumento, 1 = culminar, 2 = conjunto). Processe-os em triplos:
from datetime import timedelta

t0 = ts.now()
t1 = ts.from_datetime(t0.utc_datetime() + timedelta(hours=24))

for sat in targets:
    t, events = sat.find_events(my_station, t0, t1,
                                altitude_degrees=min_elevation_deg)
    # Group into rise/peak/set triples
    triples = zip(t[0::3], t[1::3], t[2::3])
    for rise, culm, setting in triples:
        # Peak elevation
        topo = (sat - my_station).at(culm)
        alt, az, dist = topo.altaz()
        print(f'{sat.name:30s}  {rise.utc_iso():20s}  peak {alt.degrees:4.1f}°  slant {dist.km:4.0f} km')
Ignore os satélites que já estão acima do horizonte emt0(a lista de eventos começa com um par culminante/definido).

Etapa 4: mudança Doppler ao longo de uma passagem

Para UHF amador (435 MHz), um passe pode deslocar sua operadora em ± 10 kHz — seu receptor deve rastrear. Calcule o Doppler instantâneo a partir da taxa de faixa:

import numpy as np

FREQ_HZ = 435_800_000  # AO-91 downlink
C = 299_792_458.0      # m/s

def doppler_shift(sat, observer, t):
    """Positive when satellite approaching (received frequency is higher)."""
    # Numerical range rate from 1s apart
    dt = 1.0  # seconds
    t_next = ts.from_datetime(t.utc_datetime() + timedelta(seconds=dt))
    r0 = (sat - observer).at(t).distance().m
    r1 = (sat - observer).at(t_next).distance().m
    range_rate = (r1 - r0) / dt  # m/s, positive = moving away
    return -FREQ_HZ * range_rate / C  # Hz, positive = approaching

# Sample across a pass
for pct in [0, 25, 50, 75, 100]:
    t_sample = ts.from_datetime(
        rise.utc_datetime() + (setting.utc_datetime() - rise.utc_datetime()) * pct / 100
    )
    d = doppler_shift(sat, my_station, t_sample)
    print(f'  {pct:3d}% pass:  doppler = {d:+8.0f} Hz')
Para uma passagem aérea típica de 6 minutos do AO-91, você verá o Doppler varrer de cerca de +10 kHz (aumento) até 0 (zênite) até −10 kHz (conjunto). Acompanhe isso no VFO principal do rádio para não perder o sinal.

Etapa 5: vincular o orçamento de cada passe

Depois de obter o alcance inclinado, insira-o na rftools Free-Space Path Loss Calculator ou calcule em linha:

def fspl_db(distance_m, freq_hz):
    return 20 * np.log10(4 * np.pi * distance_m * freq_hz / C)

# At zenith of an AO-91 pass (~800 km slant at 40° elevation from Boulder)
fspl = fspl_db(800_000, FREQ_HZ)
print(f'FSPL = {fspl:.1f} dB')  # ~143 dB
Para obter um orçamento completo de links de Monte Carlo com modelos de propagação ITU-R, use o Satellite Link Budget Analyzer e compartilhe o URL do cenário com o diário de bordo da sua estação.

Etapa 6: emita o iCalendar para que os passes apareçam no seu calendário

É aqui que o agendador se torna útil para humanos:

from icalendar import Calendar, Event
from datetime import datetime
import pytz

cal = Calendar()
cal.add('prodid', '-//rftools ground station//')
cal.add('version', '2.0')

for sat in targets:
    t, events = sat.find_events(my_station, t0, t1, altitude_degrees=10)
    triples = zip(t[0::3], t[1::3], t[2::3])
    for rise, culm, setting in triples:
        topo = (sat - my_station).at(culm)
        alt, az, _ = topo.altaz()
        ev = Event()
        ev.add('summary', f'{sat.name} (peak {alt.degrees:.0f}°)')
        ev.add('dtstart', rise.utc_datetime())
        ev.add('dtend', setting.utc_datetime())
        ev.add('description', f'Culminate at {culm.utc_iso()}, AZ {az.degrees:.0f}°')
        cal.add_component(ev)

with open('passes.ics', 'wb') as f:
    f.write(cal.to_ical())
print('Wrote passes.ics — import into Google Calendar / Apple Calendar / Outlook')
Importepasses.icspara o Apple Calendar/Google Calendar/Outlook e você receberá notificações push 5 minutos antes de cada passagem.

Etapa 7: execute-o no cron

Coloque o script em~/bin/station-passes.pye faça o cron uma vez por dia:

# Refresh pass schedule nightly at 03:00 local
0 3 * * * /usr/bin/python3 ~/bin/station-passes.py > ~/passes.ics 2>> ~/station.log
Emparelhe-o com ocurl --upload-fileem um calendário webdav e seu telefone verá cada passe automaticamente.

Substituindo o STK Cloud, peça por peça

Para operações comerciais amadoras/cubesat/pequenas, o kit de ferramentas combinado substitui os recursos de driver diário do STK Cloud:

Recurso STK CloudSubstituição gratuita
Previsão de passesSkyfield
Orçamento de linksrftools Satellite Link Budget Analyzer
Curvas de Doppler/alcanceTaxa de alcance Skyfield
Máscaras de elevação + terrenoSkyfield + DEM local (SRTM)
Visualização 3DCesium.js
Análise conjuntaSÓCRATES
Para estudos comerciais de design de missões ou programas institucionais, você ainda desejará o desktop STK ou o NASA GMAT. Para tudo menos isso, incluindo as análises de design da AMSAT, a pilha Skyfield + rftools está completa.

Leitura adicional

Artigos Relacionados