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
- Instalar```bash
- Etapa 1: Buscar os TLEs atuais
- Etapa 3: Encontre eventos de nascimento/culminar/definir`Satellite.find_events()`retorna uma lista plana de eventos (0 = aumento, 1 = culminar, 2 = conjunto). Processe-os em triplos:```python
- Etapa 4: mudança Doppler ao longo de uma passagem
- Etapa 5: vincular o orçamento de cada passe
- Etapa 6: emita o iCalendar para que os passes apareçam no seu calendário
- Etapa 7: execute-o no cron
- Substituindo o STK Cloud, peça por peça
- Leitura adicional
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.
Instalarpip 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.
pip install skyfield requests icalendarEtapa 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 terrestrefrom 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 passesUse 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).
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')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 dBPara 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.logEmparelhe-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 Cloud | Substituição gratuita |
|---|---|
| Previsão de passes | Skyfield |
| Orçamento de links | rftools Satellite Link Budget Analyzer |
| Curvas de Doppler/alcance | Taxa de alcance Skyfield |
| Máscaras de elevação + terreno | Skyfield + DEM local (SRTM) |
| Visualização 3D | Cesium.js |
| Análise conjunta | SÓCRATES |
Leitura adicional
- Documentação do Skyfield
- Catálogos Celestrak TLE
- rftools Satellite Pass Predictor — versão hospedada deste agendador para os satélites amadores mais comuns
- Migrando do STK Cloud: alternativas gratuitas — a postagem complementar sobre a substituição do fluxo de trabalho completo do STK
- Dimensionando um orçamento UHF CubeSat Link — exemplo funcional de ponta a ponta
Artigos Relacionados
Scripting Satellite Link Budgets with ITU-Rpy (Python Examples)
STK-free link-budget automation: sweep frequency, rain availability, and elevation in pure Python using the ITU-Rpy reference implementation of P.618/P.676/P.840. Companion to the rftools Satellite Link Budget Analyzer.
30 de abr. de 2026
Satellite CommunicationsSizing a 9600-baud UHF Downlink for a 3U CubeSat: Full Walkthrough
End-to-end link budget for an amateur-band 3U cubesat: EIRP, ground-station G/T, ITU-R propagation losses, and Monte Carlo availability. Uses the Amateur CubeSat preset.
29 de abr. de 2026
Satellite CommunicationsMigrating from STK Cloud: Free Alternatives for Link Budget and Orbit Analysis
Ansys is sunsetting STK Cloud in March 2026. Here are the free open-source replacements for the two things it did best — ITU-R link budgets and orbital pass prediction.
29 de abr. de 2026