libgs_ops.propagator

date:Jan 2 10:10:48 2018
author:Kjetil Wormnes

libgs_ops.propagator has been designed to allow you to design and plan satellite passes, and to calculate the data required by scheduling when creating the Schedules to upload to the groundstation.

Usage

You can use TLEs from a database with the TLEDb interface:

>>> p = Propagator(api=TLEDb('leo_tles.txt'), gs_lat = GS_LAT, gs_lon = GS_LON, gs_elev = GS_ELEV) #<-- replace path with a txt file of recent TLEs
>>> p.get_tle(25544)
('0 ISS (ZARYA)',
 '1 25544U 98067A   17330.99569027  .00003456  00000-0  59208-4 0  9997',
 '2 25544  51.6427 306.6944 0004138 155.0450 324.2726 15.54239375 87077')

Note

This assumes the file leo_tles.txt exists, and is in the correct format. The file can contain many tles. You can download tles from Space-Track.org. They need to be in the 3le format.

A TLE that is not in the database will fail:

>>> p.get_tle(40000)
KeyError: 40000

Or you can connect directly to spacetrack if you have login credentials. Note hat uname, pwd are your Space-Track.org username and password. GS_LAT, GS_LON, GS_ELEV are the coordinates of your ground station.

>>> p = Propagator(api=SpaceTrackAPI(uname, pwd), gs_lat = GS_LAT, gs_lon = GS_LON, gs_elev = GS_ELEV)

Now we can get any TLE:

>>> [p.get_tle(25544), p.get_tle(40000)]
[('0 ISS (ZARYA)',
  '1 25544U 98067A   18191.92601852  .00011951  00000-0  18828-3 0  9990',
  '2 25544  51.6420 260.3859 0003584 301.4077  43.7815 15.54010757122205'),
 ('0 FENGYUN 2C DEB',
  '1 40000U 04042D   17363.55183407 -.00000332  00000-0  00000+0 0  9995',
  '2 40000   9.4060  40.1038 0077532 344.5713  15.1779  1.00303233 32417')]

Or you can even specify a TLE directly (only really useful for testing):

>>> tle = """0 ISS (ZARYA)
>>> 1 25544U 98067A   17284.88510854  .00004604  00000-0  76690-4 0  9997
>>> 2 25544  51.6422 176.5756 0004586  12.7905  64.0182 15.54151166 79907"""
>>> p = Propagator(tles=tle, gs_lat = GS_LAT, gs_lon = GS_LON, gs_elev = GS_ELEV)

The propagator provides many utility functions to allow you to easily visualise and plan passes. For this example, we will work with the International Space Station (ISS) which has NORAD ID 25544. To print details about it, including where it is at the moment:

>>> p.print_info(25544)
TLE (updated 12/04/2018 09:56:44):
0 ISS (ZARYA)
    1 25544U 98067A   17284.88510854  .00004604  00000-0  76690-4 0  9997
    2 25544  51.6422 176.5756 0004586  12.7905  64.0182 15.54151166 79907
Orbit:
        epoch (utc) : 2017/10/11 21:14:33
        eccentricity: 0.000459
        inclindation: 51.642200
                RAAN: 176.575607
                  AP: 12.790500
       revol per day: 15.541512
  mean anom at epoch: 64.018204
   orbit no at epoch: 7990
Observer:
                 lat: -35.291447
                 lon: 149.165655
                elev: 614
          date (utc): 2018/04/11 23:56:55
Satellite:
    ground track pos: (lat = 33.998, lon = -179.991)
            pointing: (az  = 26.178, el  = -35.329)
               range: 7997806.500000
          range rate: 5306.109375
            altitude: 400772.000000
        orbit number: 10820.520789

We can compute the details of the next pass using Propagator.compute_pass(). It returns two tables, pdat and psum. pdat includes deails about az, el and range_rate during the pass and is what the Scheduler will require (more about that later), and psum shows an overview:

>>> pdat, psum = p.compute_pass(25544)
>>> psum
. norad_id tstamp_str orbit_no az el range range_rate altitude lat long eclipsed
rise 25544 2018/4/12 12:56:27 10828.934071 341.021182 0.017601 2.362804e+06 -6453.000000 404883.78125 -15.640039 142.408351 True
peak 25544 2018/4/12 13:01:33 10828.989114 50.446186 21.951227 9.426514e+05 57.450962 408999.65625 -30.219701 155.773119 True
set 25544 2018/4/12 13:06:40 10829.044337 118.978849 0.075523 2.383968e+06 6468.492188 413027.25000 -42.669076 173.889048 True

Note

pdat (and psum) returns more information (columns) than are required by Schedule, which only needs az, el and range_rate.

Most of the other functionality in this module are subsets of Propagator.get_all():

>>> p.get_all(25544)
norad_id                    25544
tstamp_str    2018/04/11 23:59:00
orbit_no                  10820.5
az                        28.9954
el                       -39.2531
range                 8.64443e+06
range_rate                5033.92
altitude                   402203
lat                       39.1371
long                     -172.682
eclipsed                    False
Name: 2018/04/11 23:59:00, dtype: object

You can provide a when=keyword to specify when you want the details computed for, or even an array of timestamps:

>>> p.get_all(25544, when=['2018/04/11 23:59:00', '2018/04/11 23:60:00', '2018/04/11 23:61:00'])
. norad_id tstamp_str orbit_no az el range range_rate altitude lat long eclipsed
2018/04/11 23:59:00 25544 2018/04/11 23:59:00 10820.5 28.9954 -39.2531 8.64443e+06 5033.92 402203 39.1371 -172.682 False
2018/04/11 23:60:00 25544 2018/04/11 23:60:00 10820.6 30.3388 -41.12 8.94222e+06 4891.28 402885 41.401 -168.776 False
2018/04/11 23:61:00 25544 2018/04/11 23:61:00 10820.6 31.6915 -42.9758 9.23124e+06 4741.58 403546 43.5045 -164.581 False

A more complicated example to show how you can do anything you can do in python. Requires mplleaflet to be installed (pip install mplleaflet):

>>> import matplotlib.pyplot as plt
>>> import mplleaflet
>>> latlon = [p.get_ground_coord(25544, when=tstamp) for tstamp in pdat.tstamp_str]
>>> lat, lon = zip(*latlon)
>>> plt.plot(lon, lat, linewidth=3, color='r')
>>> plt.plot(p.gs_lon, p.gs_lat, 'ro', markersize=10)
>>> mplleaflet.display(tiles='esri_aerial')

It can be useful to get an overview of upcoming satellite passes. Just use Propagator.get_passes() to very quickly calculate upcoming passes. It also optionally accepts the when keyword in the same way as Propagator.get_all() (if omitted when = Now) as well as N to specify the number of upcoming passes to calculate (if omitted N=1), and horizon to filter by passes that are higher than a certain elevation. For example:

>>> p.get_passes([25544, 42778, 42017], N=1, horizon=10)
. nid orbit_no rise_t rise_az max_elev_t max_elev set_t set_az
0 42778 4451.856863 2018/04/12 11:00:07 150.894247 2018/04/12 11:05:31 18.542780 2018/04/12 11:10:50 19.517481
1 42017 6406.847362 2018/04/12 12:10:13 169.722360 2018/04/12 12:16:10 83.098219 2018/04/12 12:22:01 345.571864
2 25544 10832.568897 2018/04/12 14:03:15 308.388451 2018/04/12 14:08:46 69.318347 2018/04/12 14:14:22 133.721252

Note

The horizon parameter just filters the rows to show anything with max_elev > horizon. rise_t and set_t still correspond to horizon=0. This is because get_passes uses a quick computation algorithm (See ephem.Observer.next_pass()). To get the actual rise_t and set_t for that horizon, run Propagator.compute_pass() with when set to the corresponding rise_t.

A common use of get_passes is to get the list of upcoming passes you want to create a schedule for. You then need to call compute_passes for each of the rows in the get_passes table by giving the when parameter as the corresponding rise_t. The below example uses the mpl_plot_pass() convenience function to plot a representation for each of the upcoming passes:

>>> for k,satpass in p.get_passes([25544, 42778, 42017], N=1, horizon=10).iterrows():
>>>     pdat, psum = p.compute_pass(satpass.nid, when=satpass.rise_t)
>>>     mpl_plot_pass(pdat)

Module reference

Functions

mpl_plot_pass(*args, **kwargs) A helper function to plot a pass in polar coordinates.

Classes

Propagator([api, tles, gs_lat, gs_lon, …]) Class to compute pointing angles for a satellite based on its Norad ID
SpaceTrackAPI(uname, pwd) Class to interface with space-track.org.
TLEDb([fname, tles]) Database of TLEs.

Exceptions

Error A generic exception