Finding StarLink orbital histories via Python

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
Dropping in here after quite a long time away. I have been looking at StarLink orbits on www.space-track.org, using Python 3.x.

Here's my SLTrack.py:
Code:
##
## SLTrack.py
## (c) 2019 Andrew Stokes  All Rights Reserved
##
##
## Simple Python app to extract Starlink satellite history data from www.space-track.org into a spreadsheet
## (Note action for you in the code below, to set up a config file with your access and output details)
##
##
##	Copyright Notice:
##
##	This program is free software: you can redistribute it and/or modify
##	it under the terms of the GNU General Public License as published by
##	the Free Software Foundation, either version 3 of the License, or
##	(at your option) any later version.
##
##	This program is distributed in the hope that it will be useful,
##	but WITHOUT ANY WARRANTY; without even the implied warranty of
##	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##	GNU General Public License for more details.
##
##	For full licencing terms, pleaserefer to the GNU General Public License
##	(gpl-3_0.txt) distributed with this release, or see
##	http://www.gnu.org/licenses/.
##

import requests
import json
import configparser
import xlsxwriter
import time
from datetime import datetime

class MyError(Exception):
    def __init___(self,args):
        Exception.__init__(self,"my exception was raised with arguments {0}".format(args))
        self.args = args

# See https://www.space-track.org/documentation for details on REST queries
# the "Find Starlinks" query searches all satellites with NORAD_CAT_ID > 40000, with OBJECT_NAME matching STARLINK*, 1 line per sat
# the "OMM Starlink" query gets all Orbital Mean-Elements Messages (OMM) for a specific NORAD_CAT_ID in JSON format

uriBase                = "https://www.space-track.org"
requestLogin           = "/ajaxauth/login"
requestCmdAction       = "/basicspacedata/query" 
requestFindStarlinks   = "/class/tle_latest/NORAD_CAT_ID/>40000/ORDINAL/1/OBJECT_NAME/STARLINK~~/format/json/orderby/NORAD_CAT_ID%20asc"
requestOMMStarlink1    = "/class/omm/NORAD_CAT_ID/"
requestOMMStarlink2    = "/orderby/EPOCH%20asc/format/json"

# Parameters to derive apoapsis and periapsis from mean motion (see https://en.wikipedia.org/wiki/Mean_motion)

GM = 398600441800000.0
GM13 = GM ** (1.0/3.0)
MRAD = 6378.137
PI = 3.14159265358979
TPI86 = 2.0 * PI / 86400.0

# ACTION REQUIRED FOR YOU:
#=========================
# Provide a config file in the same directory as this file, called SLTrack.ini, with this format (without the # signs)
# [configuration]
# username = XXX
# password = YYY
# output = ZZZ
#
# ... where XXX and YYY are your www.space-track.org credentials (https://www.space-track.org/auth/createAccount for free account)
# ... and ZZZ is your Excel Output file - e.g. starlink-track.xlsx (note: make it an .xlsx file)

# Use configparser package to pull in the ini file (pip install configparser)
config = configparser.ConfigParser()
config.read("./SLTrack.ini")
configUsr = config.get("configuration","username")
configPwd = config.get("configuration","password")
configOut = config.get("configuration","output")
siteCred = {'identity': configUsr, 'password': configPwd}

# User xlsxwriter package to write the xlsx file (pip install xlsxwriter)
workbook = xlsxwriter.Workbook(configOut)
worksheet = workbook.add_worksheet()
z0_format = workbook.add_format({'num_format': '#,##0'})
z1_format = workbook.add_format({'num_format': '#,##0.0'})
z2_format = workbook.add_format({'num_format': '#,##0.00'})
z3_format = workbook.add_format({'num_format': '#,##0.000'})

# write the headers on the spreadsheet
now = datetime.now()
nowStr = now.strftime("%m/%d/%Y %H:%M:%S")
worksheet.write('A1', 'Starlink data from' + uriBase + " on " + nowStr)
worksheet.write('A3','NORAD_CAT_ID')
worksheet.write('B3','SATNAME')
worksheet.write('C3','EPOCH')
worksheet.write('D3','Orb')
worksheet.write('E3','Inc')
worksheet.write('F3','Ecc')
worksheet.write('G3','MnM')
worksheet.write('H3','ApA')
worksheet.write('I3','PeA')
worksheet.write('J3','AvA')
worksheet.write('K3','LAN')
worksheet.write('L3','AgP')
worksheet.write('M3','MnA')
worksheet.write('N3','SMa')
worksheet.write('O3','T')
worksheet.write('P3','Vel')
wsline = 3

# use requests package to drive the RESTful session with space-track.org
with requests.Session() as session:
    # run the session in a with block to force session to close if we exit

    # need to log in first. note that we get a 200 to say the web site got the data, not that we are logged in
    resp = session.post(uriBase + requestLogin, data = siteCred)
    if resp.status_code != 200:
        raise MyError(resp, "POST fail on login")

    # this query picks up all Starlink satellites from the catalog. Note - a 401 failure shows you have bad credentials 
    resp = session.get(uriBase + requestCmdAction + requestFindStarlinks)
    if resp.status_code != 200:
        print(resp)
        raise MyError(resp, "GET fail on request for Starlink satellites")

    # use the json package to break the json formatted response text into a Python structure (a list of dictionaries)
    retData = json.loads(resp.text)
    satCount = len(retData)
    satIds = []
    for e in retData:
        # each e describes the latest elements for one Starlink satellite. We just need the NORAD_CAT_ID 
        catId = e['NORAD_CAT_ID']
        satIds.append(catId)

    # using our new list of Starlink satellite NORAD_CAT_IDs, we can now get the OMM message
    maxs = 1
    for s in satIds:
        resp = session.get(uriBase + requestCmdAction + requestOMMStarlink1 + s + requestOMMStarlink2)
        if resp.status_code != 200:
            # If you are getting error 500's here, its probably the rate throttle on the site (20/min and 200/hr)
            # wait a while and retry
            print(resp)
            raise MyError(resp, "GET fail on request for Starlink satellite " + s)

        # the data here can be quite large, as it's all the elements for every entry for one Starlink satellite
        retData = json.loads(resp.text)
        for e in retData:
            # each element is one reading of the orbital elements for one Starlink
            print("Scanning satellite " + e['OBJECT_NAME'] + " at epoch " + e['EPOCH'])
            mmoti = float(e['MEAN_MOTION'])
            ecc = float(e['ECCENTRICITY'])
            worksheet.write(wsline, 0, int(e['NORAD_CAT_ID']))
            worksheet.write(wsline, 1, e['OBJECT_NAME'])
            worksheet.write(wsline, 2, e['EPOCH'])
            worksheet.write(wsline, 3, float(e['REV_AT_EPOCH']))
            worksheet.write(wsline, 4, float(e['INCLINATION']),z1_format)
            worksheet.write(wsline, 5, ecc,z3_format)
            worksheet.write(wsline, 6, mmoti,z1_format)
            # do some ninja-fu to flip Mean Motion into Apoapsis and Periapsis, and to get the orbital period and velocity
            sma = GM13 / ((TPI86 * mmoti) ** (2.0 / 3.0)) / 1000.0
            apo = sma * (1.0 + ecc) - MRAD
            per = sma * (1.0 - ecc) - MRAD
            smak = sma * 1000.0
            orbT = 2.0 * PI * ((smak ** 3.0) / GM) ** (0.5)
            orbV = (GM / smak) ** (0.5)
            worksheet.write(wsline, 7, apo,z1_format)
            worksheet.write(wsline, 8, per,z1_format)
            worksheet.write(wsline, 9, (apo+per)/2.0,z1_format)
            worksheet.write(wsline, 10, float(e['RA_OF_ASC_NODE']),z1_format)
            worksheet.write(wsline, 11, float(e['ARG_OF_PERICENTER']),z1_format)
            worksheet.write(wsline, 12, float(e['MEAN_ANOMALY']),z1_format)
            worksheet.write(wsline, 13, sma,z1_format)
            worksheet.write(wsline, 14, orbT,z0_format)
            worksheet.write(wsline, 15, orbV,z0_format)
            wsline = wsline + 1
        maxs = maxs + 1
        if maxs > 18:
            print("Snoozing for 60 secs for rate limit reasons (max 20/min and 200/hr)...")
            time.sleep(60)
            maxs = 1
    session.close()
workbook.close()
print("Completed session")

Sample output (of thousands of lines):

Code:
Starlink data fromhttps://www.space-track.org on 11/26/2019 20:59:55															
															
NORAD_CAT_ID	SATNAME	EPOCH	Orb	Inc	Ecc	MnM	ApA	PeA	AvA	LAN	AgP	MnA	SMa	T	Vel
44235	STARLINK-31	2019-05-25T17:16:34	147	53.0	0.001	15.4	442.5	433.0	437.7	167.6	280.5	79.6	6,815.8	5,600	7,647
44235	STARLINK-31	2019-05-26T05:42:53	155	53.0	0.001	15.4	442.5	433.8	438.2	165.2	272.2	87.9	6,816.3	5,601	7,647
44235	STARLINK-31	2019-05-26T21:46:33	166	53.0	0.000	15.4	445.2	443.4	444.3	162.0	179.5	292.5	6,822.4	5,608	7,644
44235	STARLINK-31	2019-05-27T13:22:30	149	53.0	0.000	15.4	445.2	443.4	444.3	158.9	181.9	297.0	6,822.4	5,608	7,644
44235	STARLINK-31	2019-05-29T17:52:01	210	53.0	0.000	15.4	458.8	452.8	455.8	148.7	27.1	333.1	6,833.9	5,622	7,637
44235	STARLINK-31	2019-05-30T20:24:21	227	53.0	0.000	15.4	460.3	457.7	459.0	143.5	57.1	303.0	6,837.1	5,626	7,635
44235	STARLINK-31	2019-06-02T21:56:09	136	53.0	0.000	15.3	475.3	472.7	474.0	129.2	87.4	272.7	6,852.1	5,645	7,627
44235	STARLINK-31	2019-06-02T21:56:09	274	53.0	0.000	15.3	475.3	472.7	474.0	129.2	87.4	272.7	6,852.1	5,645	7,627
44235	STARLINK-31	2019-06-05T17:39:01	317	53.0	0.000	15.3	489.9	487.3	488.6	116.1	85.7	324.1	6,866.8	5,663	7,619
44235	STARLINK-31	2019-06-05T23:51:19	130	53.0	0.000	15.3	491.3	488.7	490.0	115.0	92.2	298.2	6,868.1	5,665	7,618
44235	STARLINK-31	2019-06-06T21:44:58	334	53.0	0.001	15.2	498.3	491.1	494.7	110.7	123.1	237.1	6,872.8	5,670	7,616
44235	STARLINK-31	2019-06-07T08:46:35	342	53.0	0.000	15.2	500.3	496.7	498.5	108.6	107.9	252.2	6,876.6	5,675	7,613
44235	STARLINK-31	2019-06-08T02:06:36	353	53.0	0.000	15.2	504.6	500.2	502.4	105.3	116.8	243.3	6,880.5	5,680	7,611
44235	STARLINK-31	2019-06-08T08:24:38	357	53.0	0.000	15.2	502.8	499.8	501.3	104.1	136.2	223.9	6,879.4	5,679	7,612
44235	STARLINK-31	2019-06-08T21:02:05	365	53.0	0.000	15.2	508.4	504.8	506.6	101.7	152.3	207.8	6,884.8	5,685	7,609
44235	STARLINK-31	2019-06-09T04:55:29	370	53.0	0.000	15.2	510.2	506.4	508.3	100.2	62.3	297.8	6,886.4	5,687	7,608
44235	STARLINK-31	2019-06-09T09:39:34	373	53.0	0.000	15.2	510.5	507.9	509.2	99.3	76.6	283.5	6,887.4	5,688	7,608
44235	STARLINK-31	2019-06-09T20:42:42	380	53.0	0.000	15.2	513.0	509.1	511.0	97.2	121.5	238.6	6,889.2	5,691	7,607
44235	STARLINK-31	2019-06-10T04:36:40	385	53.0	0.000	15.2	514.1	509.8	512.0	95.7	225.8	134.2	6,890.1	5,692	7,606
44235	STARLINK-31	2019-06-10T09:21:26	388	53.0	0.000	15.2	516.5	512.6	514.6	94.8	145.7	214.4	6,892.7	5,695	7,605
44235	STARLINK-31	2019-06-11T04:20:14	400	53.0	0.000	15.1	523.7	519.2	521.4	91.2	205.3	154.7	6,899.6	5,704	7,601


Tested under Windows 10, VS Code, and Python 3.x.

Ask me anything!
 
Top