Skip to content
RFrftools.io
Satellite Communications30 avril 20265 min de lecture

Élaboration d'un calendrier de pass pour les stations terrestres avec Skyfield

Ansys STK Sunset-ready : calculez les prévisions de passage SGP4 pour votre radio amateur ou votre station au sol Cubesat à l'aide de Skyfield.

Sommaire

Pourquoi avez-vous besoin d'un planificateur de passes local

Si vous gérez une station SatNOGS, une cabine de radioamateur qui suit l'AO-91/ISS/NOAA, ou un segment sol Cubesat à un stade précoce, vous avez besoin de prévisions de passes automatisées. Les outils commerciaux (STK, NOVA) sont excessifs. Les prédicteurs Web gratuits (AMSAT, Heavens-Above) ne scriptent pas bien. STK Cloud expirant en mars 2026, l'alternative gratuite la plus propre est Skyfield, le successeur Python moderne de PyEphem.

Cet article présente un planificateur complet de stations terrestres en environ 80 lignes de Python : récupérez de nouveaux TLE, calculez les prochaines 24 heures de passes pour une liste de satellites, filtrez par altitude minimale, calculez le Doppler pour la fréquence de votre liaison descendante et émettez iCalendar pour que les passes apparaissent dans votre application de calendrier.

Installer

pip install skyfield requests icalendar

C'est ça. Skyfield extrait ses propres éphémérides (DE421, IERS) lors de la première exécution, soit environ 17 Mo mis en cache localement.

Étape 1 : récupérer les TLE actuels

Les TLE dérivent : utilisez-les dans les 7 jours suivant l'époque. Extrayez l'ensemble d'éléments actuel de 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')

Choisissez vos cibles par leur nom (elles sont sensibles aux majuscules et minuscules dans le fichier Celestrak) :

targets = [
    by_name['AO-91 (FOX-1B)'],
    by_name['ISS (ZARYA)'],
    by_name['NOAA 19'],
    by_name['GreenCube (IO-117)'],
]

Étape 2 : Définissez votre station au sol

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

Utilisez le paramètre elevation_m : il affecte sensiblement la plage d'inclinaison à des angles de faible altitude.

Étape 3 : Trouvez les événements qui augmenter/culminer/définir

Satellite.find_events() renvoie une liste plate d'événements (0 = hausse, 1 = point culminant, 2 = défini). Traitez-les en trois étapes :
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')

Ignorez les satellites déjà au-dessus de l'horizon au t0(la liste des événements commence par une paire culminant/set).

Étape 4 : décalage Doppler sur une passe

Pour l'UHF amateur (435 MHz), une passe peut décaler votre porteuse de ±10 kHz ; votre récepteur doit suivre. Calculez le Doppler instantané à partir de la plage de fréquence :

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')

Pour un passage aérien typique de 6 minutes avec l'AO-91, vous verrez un balayage Doppler d'environ +10 kHz (hausse) à 0 (zénith) et −10 kHz (réglage). Suivez-le sur le VFO principal de la radio pour ne pas perdre le signal.

Étape 5 : Lier le budget pour chaque pass

Une fois que vous avez défini la plage d'inclinaison, introduisez-la dans le calculateur de perte de trajectoire en espace libre rftools ou calculez en ligne :

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

Pour obtenir un budget complet des liaisons Monte-Carlo avec des modèles de propagation UIT-R, utilisez le Satellite Link Budget Analyzer et partagez l'URL du scénario avec le journal de bord de votre station.

Étape 6 : Émettez iCalendar pour que les passes apparaissent dans votre calendrier

C'est là que le planificateur devient utile pour les humains :

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')

Importez le passes.ics dans Apple Calendar/Google Calendar/Outlook et vous recevrez des notifications push 5 minutes avant chaque passe.

Étape 7 : Exécutez-le sur cron

Déposez le script au ~/bin/station-passes.py et crénez-le une fois par jour :

# Refresh pass schedule nightly at 03:00 local
0 3 * * * /usr/bin/python3 ~/bin/station-passes.py > ~/passes.ics 2>> ~/station.log

Associez-le au curl --upload-file à un calendrier Webdav et votre téléphone verra automatiquement chaque passe.

Remplacer STK Cloud, pièce par pièce

Pour les activités amateurs, cubesats et petites entreprises commerciales, la boîte à outils combinée remplace les fonctionnalités quotidiennes de STK Cloud :

Fonctionnalité STK CloudRemplacement gratuit
Prédiction de passesSkyfield
Budget du lienAnalyseur de budget de liaison satellite rftools
Courbes Doppler/plageRange-rate Skyfield
Masques d'élévation + terrainSkyfield + DEM local (SRTM)
Visualisation 3DCesium.js
Dépistage conjonctifSOCRATES
Pour les études commerciales sur la conception de missions ou les programmes institutionnels, vous aurez toujours besoin d'un STK ou d'un GMAT de la NASA pour ordinateur de bureau. Pour tout le reste, y compris les revues de conception d'AMSAT, la pile Skyfield + rftools est complète.

Lectures complémentaires

Foire Aux Questions

Pour la prédiction des passes, les courbes Doppler, les chronologies d'altitude et les téléchargements planifiés, oui. Skyfield implémente SGP4 avec des éphémérides validées par rapport à JPL Horizons et correspond aux prévisions de temps de passage de STK en quelques secondes sur des horizons de 30 jours. Il ne remplace pas la visualisation 3D, les rapports intégrés ou l'analyse des conjonctions de STK. Utilisez Cesium.js ou SOCRATES pour cela.
Dans les 7 jours suivant l'époque pour une précision de position inférieure à 1 km pour les satellites LEO. Les TLE datant de plus de 14 jours peuvent dériver de plus de 10 km le long de la piste, ce qui entraîne un décalage des temps de passage de plus de 30 secondes, soit suffisamment pour manquer une fenêtre de passe de 6 minutes. Extrayez de nouveaux TLE de Celestrak avant chaque exécution de planification.
Trois causes probables : (1) les coordonnées de votre station au sol sont décalées de plusieurs dizaines de mètres — vérifiez avec le GPS, (2) vous utilisez une époque TLE plus ancienne que le prédicteur d'AMSAT, (3) vous ne tenez pas compte de l'altitude de la station au-dessus du niveau de la mer (utilisez elevation_m in wgs84.latlon). Des différences inférieures à 10 secondes sont attendues et n'affectent pas les opérations pratiques.
Numériquement : calculez la plage d'inclinaison au temps t et t+1s, divisez pour obtenir la vitesse de portée en m/s, puis doppler_shift_hz = -frequency_hz * range_rate / c (positif à l'approche du satellite). Skyfield n'a pas de fonction Doppler intégrée car elle dépend de la fréquence de votre liaison descendante/montante. Calculez-la vous-même. Une passe LEO typique à 435 MHz balaie ±10 kHz pendant environ 6 minutes.
Pour GEO (géostationnaire) oui, mais la précision du SGP4/TLE se dégrade au-dessus d'environ 6 000 km. Utilisez un solveur d'éléments Keplerian ou des éphémérides complètes (DE440) pour GEO. Pour les missions dans l'espace lointain, utilisez les éphémérides à base de noyaux de Skyfield avec les noyaux SPICE de la NASA. Pour les orbites lunaires, chargez les éphémérides DE440 ou jup365 via skyfield.api.load ('de440.bsp').

Articles connexes