Introduction
Le tracé des traces au sol de satellites est une tâche courante en observation de la Terre, analyse orbitale et validation de produits de télédétection. Les traces au sol sont largement utilisées pour visualiser le mouvement des satellites, estimer les heures de survol et comprendre la géométrie orbitale.
Dans cet article, nous montrons comment utiliser le package Python Skyfield pour tracer des traces au sol de satellites de manière précise. Nous clarifions également un concept important et souvent mal compris : la différence entre une trace au sol (ground track) et une fauchée instrumentale (swath).
Les exemples portent sur :
- Suomi-NPP (SNPP), un satellite d’observation de la Terre en orbite héliosynchrone
- La Station spatiale internationale (ISS), une plateforme en orbite basse à faible inclinaison
Trace au sol vs fauchée : une distinction fondamentale
Trace au sol (concept orbital)
Une trace au sol est définie comme :
Le chemin tracé à la surface de la Terre par le point sous-satellite (nadir) au cours de l’orbite.
Caractéristiques principales :
- Une courbe unidimensionnelle
- Dépend uniquement de l’orbite du satellite
- Indépendante de l’instrument embarqué
- Calculée à partir des éléments orbitaux tels que les Two-Line Elements (TLE)
Les traces au sol sont couramment utilisées pour :
- La visualisation des orbites
- L’analyse des cycles de répétition
- L’estimation des horaires de survol
- Les outils pédagogiques et de planification de mission (par ex. NOAA iSTRaK)
Fauchée (concept instrumental)
Une fauchée est définie comme :
La zone bidimensionnelle de la surface terrestre observée par un instrument lors d’un survol.
Pour VIIRS à bord de Suomi-NPP :
- Radiomètre à balayage transversal (cross-track)
- Largeur de fauchée approximative : ~3040 km
- Définie par le champ de vue de l’instrument et la géométrie de balayage
Les fauchées sont obtenues à partir de :
- Produits de géolocalisation VIIRS :
VNP03MOD,VNP03IMG - Produits feux VIIRS :
VNP14MOD,VNP14IMG(sous-ensemble de la fauchée)
Une fauchée contient la trace au sol, mais les deux ne sont pas équivalentes.
Cette distinction est cruciale : de nombreux graphiques étiquetés « trace au sol VIIRS » montrent en réalité la couverture de la fauchée ou la position des pixels, ce qui est techniquement incorrect.
Installation de Skyfield en Python
Skyfield est une bibliothèque Python dédiée à la propagation orbitale de haute précision basée sur les éphémérides du JPL. Elle est particulièrement adaptée au calcul des traces au sol, des points sous-satellites et de la géométrie d’observation pour des missions d’observation de la Terre telles que Suomi-NPP (VIIRS).
Option 1 : Installation avec Conda (recommandée)
L’utilisation de conda est la méthode la plus simple et la plus fiable pour installer Skyfield, car toutes les dépendances sont gérées automatiquement.
1 | conda install -c conda-forge skyfield |
Cette commande installe :
skyfieldnumpyjplephemsgp4
tous nécessaires à la propagation orbitale des satellites.
Pour un environnement dédié :
1 2 3 | conda create -n skyfield_env python=3.11 conda activate skyfield_env conda install -c conda-forge skyfield |
Option 2 : Installation avec pip
Il est également possible d’installer Skyfield avec pip, soit globalement, soit dans un environnement virtuel :
1 | pip install skyfield |
Afin d’éviter les conflits de dépendances, il est fortement recommandé d’utiliser un environnement virtuel :
1 2 3 | python -m venv skyfield_env source skyfield_env/bin/activate # Linux / macOS pip install skyfield |
Optionnel : Vérification de l’installation
Vous pouvez vérifier que Skyfield est correctement installé en exécutant :
1 2 | from skyfield.api import load, EarthSatellite print("Skyfield installé avec succès") |
Si aucune erreur n’apparaît, l’installation est terminée.
Remarques sur les données TLE
Skyfield propage les orbites des satellites à partir des Two-Line Elements (TLE). Pour obtenir des traces au sol précises, il est indispensable d’utiliser des TLE récents, par exemple depuis :
- CelesTrak (catalogue NORAD)
- Space-Track.org
Des TLE obsolètes peuvent entraîner des erreurs de position notables, en particulier pour les satellites en orbite basse comme Suomi-NPP.
Exemple complet fonctionnel : trace au sol de Suomi-NPP
Ci-dessous figure un exemple complet, similaire à NOAA iSTRaK, montrant plusieurs orbites complètes de Suomi-NPP, tracées correctement à l’aide de courbes géodésiques.
Code Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | from skyfield.api import load import numpy as np import matplotlib.pyplot as plt import cartopy.crs as ccrs # Chargement d’un TLE SNPP à jour ts = load.timescale() tle_url = "https://celestrak.org/NORAD/elements/gp.php?CATNR=37849&FORMAT=TLE" sat = load.tle_file(tle_url)[0] print("Époque du TLE :", sat.epoch.utc_strftime()) # Paramètres START_TIME = (2025, 12, 18, 0, 0, 0) # UTC ORBIT_PERIOD_SEC = 99 * 60 # ~99 minutes DT = 20 # pas de temps (secondes) N_ORBITS = 4 # nombre d’orbites complètes à tracer # Tableau temporel t = ts.utc( START_TIME[0], START_TIME[1], START_TIME[2], START_TIME[3], START_TIME[4], np.arange(0, ORBIT_PERIOD_SEC * N_ORBITS, DT) ) # Point sous-satellite (trace au sol) sp = sat.at(t).subpoint() lats = sp.latitude.degrees lons = (sp.longitude.degrees + 180) % 360 - 180 # Découpage en orbites individuelles points_per_orbit = int(ORBIT_PERIOD_SEC / DT) tracks = [ (lons[i*points_per_orbit:(i+1)*points_per_orbit], lats[i*points_per_orbit:(i+1)*points_per_orbit]) for i in range(N_ORBITS) ] # Tracé fig = plt.figure(figsize=(13, 6)) ax = plt.axes(projection=ccrs.Robinson()) ax.coastlines() ax.gridlines(linewidth=0.5, linestyle="--") for i, (lon, lat) in enumerate(tracks): ax.plot( lon, lat, transform=ccrs.Geodetic(), linewidth=1.8, label=f"Orbite {i+1}" ) ax.legend() ax.set_title("Traces au sol orbitales de SNPP (point nadir)") plt.savefig("SNPP_Orbital_Ground_Tracks.png", bbox_inches="tight", dpi=100) plt.show() |

Explication du code (pas à pas)
1. Pourquoi Skyfield ?
Skyfield effectue une propagation orbitale de haute précision à l’aide du modèle SGP4 et des TLE, ce qui en fait un outil idéal pour le calcul des traces au sol de satellites.
2. Pourquoi la date est cruciale (très important)
1 | START_TIME = (2025, 12, 18, 0, 0, 0) |
Les TLE sont dépendants du temps et ne sont généralement valides que sur ~1 à 2 semaines autour de leur époque.
Si vous :
- utilisez un TLE ancien
- le propagez trop loin dans le futur ou le passé
l’orbite calculée sera physiquement incorrecte, même si le code s’exécute sans erreur.
C’est pourquoi nous :
- chargeons des TLE récents depuis CelesTrak
- faisons correspondre la date de propagation avec l’époque du TLE
Vous pouvez vérifier l’époque du TLE avec :
1 | print(sat.epoch.utc_strftime()) |
3. Choix des paramètres orbitaux
1 2 3 | ORBIT_PERIOD_SEC = 99 * 60 # ~99 minutes DT = 20 # pas de temps (secondes) N_ORBITS = 4 # nombre d’orbites |
- ORBIT_PERIOD_SEC : période orbitale approximative de SNPP
- DT : résolution temporelle de la trace au sol
- N_ORBITS : améliore la lisibilité du graphique
Tracer quelques orbites complètes est beaucoup plus clair que de tracer une trajectoire continue sur plusieurs heures.
4. Importance de ccrs.Geodetic()
1 | ax.plot(lon, lat, transform=ccrs.Geodetic()) |
Cela garantit que :
- les trajectoires sont tracées comme des arcs de grand cercle
- la trace ressemble aux visualisations officielles de la NOAA
- aucun artefact de lignes droites artificielles n’apparaît
Comparaison avec NOAA iSTRaK
Le graphique obtenu peut être comparé directement à l’outil officiel de la NOAA :
https://viirs.umd.edu/WebGL_traj/orb_npp/disp_npp_20251218.php

Les deux montrent :
- des passages orbitaux individuels
- une dérive vers l’ouest due à la rotation de la Terre
- des traces au sol lisses et courbes
Exemple de trace au sol de l’ISS
La même approche peut être appliquée à d’autres satellites, comme la Station spatiale internationale (ISS).
Différences clés
- Faible inclinaison (~51,6°)
- Période orbitale plus courte (~92 minutes)
- Absence de couverture polaire
Code exemple pour l’ISS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | # Chargement du TLE de l’ISS tle_url_iss = "https://celestrak.org/NORAD/elements/stations.txt" sats = load.tle_file(tle_url_iss) iss = [s for s in sats if s.name == "ISS (ZARYA)"][0] # Paramètres START_TIME = (2025, 12, 18, 0, 0, 0) ORBIT_PERIOD_SEC = 92 * 60 DT = 20 N_ORBITS = 3 t = ts.utc( START_TIME[0], START_TIME[1], START_TIME[2], START_TIME[3], START_TIME[4], np.arange(0, ORBIT_PERIOD_SEC * N_ORBITS, DT) ) sp = iss.at(t).subpoint() lats = sp.latitude.degrees lons = (sp.longitude.degrees + 180) % 360 - 180 points_per_orbit = int(ORBIT_PERIOD_SEC / DT) tracks = [ (lons[i*points_per_orbit:(i+1)*points_per_orbit], lats[i*points_per_orbit:(i+1)*points_per_orbit]) for i in range(N_ORBITS) ] fig = plt.figure(figsize=(13, 6)) ax = plt.axes(projection=ccrs.Robinson()) ax.coastlines() ax.gridlines() for i, (lon, lat) in enumerate(tracks): ax.plot(lon, lat, transform=ccrs.Geodetic(), label=f"Orbite ISS {i+1}") ax.legend() ax.set_title("Traces au sol orbitales de l’ISS (point nadir)") plt.show() |

Références
| Liens | Site |
|---|---|
| https://viirs.umd.edu/WebGL_traj/orb_npp/disp_npp_20251218.php | NOAA / UMD VIIRS – Prédiction de trace au sol Suomi-NPP (iSTRaK) |
| https://celestrak.org/NORAD/elements/ | CelesTrak – Données orbitales TLE |
| https://rhodesmill.org/skyfield/ | Skyfield – Bibliothèque Python de propagation orbitale |
| https://scitools.org.uk/cartopy/docs/latest/ | Cartopy – Tracé géospatial en Python |
| https://lpdaac.usgs.gov/products/vnp03modv002/ | NASA LP DAAC – Produit de géolocalisation VIIRS (VNP03MOD) |
| https://lpdaac.usgs.gov/products/vnp14modv002/ | NASA LP DAAC – Produit feux actifs VIIRS (VNP14MOD) |
