diff --git a/examples/iss.txt b/examples/iss.txt new file mode 100644 index 0000000..6351b02 --- /dev/null +++ b/examples/iss.txt @@ -0,0 +1,3 @@ +ISS (ZARYA) +1 25544U 98067A 19004.59354167 .00000715 00000-0 18267-4 0 9995 +2 25544 51.6416 95.0104 0002419 236.2184 323.8248 15.53730729149833 diff --git a/examples/sathyabamasat.txt b/examples/sathyabamasat.txt new file mode 100644 index 0000000..cad8f04 --- /dev/null +++ b/examples/sathyabamasat.txt @@ -0,0 +1,3 @@ +SATHYABAMASAT +1 41600U 16040B 19310.17193730 .00001455 00000-0 63216-4 0 9994 +2 41600 97.3537 10.1403 0012192 255.4467 104.5418 15.23822105187350 diff --git a/python/README.md b/python/README.md new file mode 100644 index 0000000..43e5ff0 --- /dev/null +++ b/python/README.md @@ -0,0 +1,18 @@ +## Notes + + +## Setup +- Dependency installation via pip: + ``` + pip install -r requirements.txt + ``` + +- In order to be able to use `ground_track.py`, + download [earth.png](https://raw.githubusercontent.com/galactics/beyond/master/doc/source/_static/earth.png) into this directory. + +## Usage + +- Plot the ground track of satellite based on it's TLE around the epoch: + ``` + ./ground_track.py ../examples/sathyabamasat.txt + ``` diff --git a/python/ground_track.py b/python/ground_track.py new file mode 100755 index 0000000..2b60edb --- /dev/null +++ b/python/ground_track.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python3 + +""" +Script showing the position of the ISS at the time of the TLE +and the ground track for the previous and the next orbit + +(original) source: https://github.com/galactics/beyond/blob/master/doc/source/_static/ground-track.py +""" + +import sys +import argparse + +import numpy as np +import matplotlib.pyplot as plt + +from pathlib import Path + +from beyond.io.tle import Tle +from beyond.dates import Date, timedelta + + +def tle_from_file(filename): + ''' + Returns: TLE:Tle, Object name:str + ''' + + with open(filename, 'r') as f: + lines = f.readlines() + + return Tle(''.join(lines)), lines[0].strip() + + +if __name__ == "__main__": + # Parse arguments + parser = argparse.ArgumentParser( + description="Plot the ground track of a TLE") + parser.add_argument('TLEFILE', help="the tle file", type=str) + + args = parser.parse_args() + + # Parsing of TLE + tle, name = tle_from_file(args.TLEFILE) + + # Conversion into `Orbit` object + orb = tle.orbit() + + # Tables containing the positions of the ground track + latitudes, longitudes = [], [] + prev_lon, prev_lat = None, None + + period = orb.infos.period + start = orb.date - period + stop = 2 * period + step = period / 100 + + for point in orb.ephemeris(start=start, stop=stop, step=step): + + # Conversion to earth rotating frame + point.frame = 'ITRF' + + # Conversion from cartesian to spherical coordinates (range, latitude, longitude) + point.form = 'spherical' + + # Conversion from radians to degrees + lon, lat = np.degrees(point[1:3]) + + # Creation of multiple segments in order to not have a ground track + # doing impossible paths + if prev_lon is None: + lons = [] + lats = [] + longitudes.append(lons) + latitudes.append(lats) + elif orb.i < np.pi /2 and (np.sign(prev_lon) == 1 and np.sign(lon) == -1): + lons.append(lon + 360) + lats.append(lat) + lons = [prev_lon - 360] + lats = [prev_lat] + longitudes.append(lons) + latitudes.append(lats) + elif orb.i > np.pi/2 and (np.sign(prev_lon) == -1 and np.sign(lon) == 1): + lons.append(lon - 360) + lats.append(lat) + lons = [prev_lon + 360] + lats = [prev_lat] + longitudes.append(lons) + latitudes.append(lats) + + lons.append(lon) + lats.append(lat) + prev_lon = lon + prev_lat = lat + + + fig = plt.figure(figsize=(15.2, 8.2)) + ax = fig.add_subplot(111) + + ax.set_title(name) + + # Plot earth + img = Path(__file__).parent / "earth.png" + im = plt.imread(str(img)) + ax.imshow(im, extent=[-180, 180, -90, 90]) + + # Plot ground track + for lons, lats in zip(longitudes, latitudes): + ax.plot(lons, lats, 'r-') + + # Plot location at epoch time + lon, lat = np.degrees(orb.copy(frame='ITRF', form='spherical')[1:3]) + ax.plot([lon], [lat], 'bo') + + ax.set_xlim([-180, 180]) + ax.set_ylim([-90, 90]) + ax.grid(True, color='w', linestyle=":", alpha=0.4) + ax.set_xticks(range(-180, 181, 30)) + ax.set_yticks(range(-90, 91, 30)) + fig.tight_layout() + + if "no-display" not in sys.argv: + plt.show()