Closed tmamedzadeh closed 6 years ago
Solved, loading the TLE directly from URL celestrak.com/cgi-bin/TLE.pl?CATNR=40052
and parsing achieved 3 lines.
Closing this issue, however this functionality would be useful.
I didn't know that names changed! I think this is a good idea, and I've re-opened this issue so that I remember to add that feature (or so that someone else can).
FWIW, another user finds it essential to be able to do satellites[cat Id #] instead of satellites[name]. I know you have a gazillion things to do, but do know this is not just a "gee, it'd be nice if..." need for some of us.
If someone needs this quickly, I believe they can build their own dictionary with something like:
satcat = {sat.model.satnum: sat for sat in satellites.values()}
Then they could say satcat[...cat Id #...]
— if someone could test this out and see if it works, a follow-up comment letting other users know will doubtless be appreciated!
Oh, duh! Good idea. This, for example, works:
geosats = loader.tle(celestrak+'geo.txt')
[...]
satcats = [geosats, gpssats, sciencesats, stationsats, tdrss, visualsats]
sats = {}
for cat in satcats:
for name in cat.keys():
sat = cat[name]
sats.update( {sat.model.satnum:sat, name:sat} )
Then one can access either way:
sats['GOES 16']
sats[41866]
Very nice! You might find it slightly more efficient to:
sats[sat.model.satnum] = sat
sats[name] = sat
instead of building and then disposing of an entire new dictionary — but, honestly, you'll never notice the difference since it's plenty fast either way for the number of satellites involved. :)
For completeness, and in case someone else might find it useful at some point:
import urllib
from skyfield import api as sf
datadir = os.environ['HOME']+'/programming/python/astro/skyfield-data/'
loader = sf.Loader(datadir, expire=False)
# Satellite TLEs.
celestrak = 'http://celestrak.com/NORAD/elements/'
geosats = loader.tle(celestrak+'geo.txt')
gpssats = loader.tle(celestrak+'supplemental/gps.txt')
sciencesats = loader.tle(celestrak+'science.txt')
stationsats = loader.tle(celestrak+'stations.txt')
tdrss = loader.tle(celestrak+'tdrss.txt')
visualsats = loader.tle(celestrak+'visual.txt')
# Make catalogs indexable by either name or catalog number.
# Also create sats, a merge of the individual ones.
satcats = [geosats, gpssats, sciencesats, stationsats, tdrss, visualsats]
sats = {}
for cat in satcats:
names = [key for key in cat.keys()]
for name in names:
sat = cat[name]
satnum = sat.model.satnum
cat[satnum] = sat
sats[satnum] = sat
sats[name] = sat
def getsat(satid):
"""
Return a skyfield EarthSatellite.
<satid> is case independent if it is a satellite name (str).
Retrieve directly from CelesTrak by catalog number if not in local database.
"""
if isinstance(satid, str):
satid = satid.upper()
if satid in sats.keys():
return sats[satid]
if not isinstance(satid, int):
msg = 'satid must be an integer for satellites not in the local set'
raise Exception(msg)
base = 'http://celestrak.com/cgi-bin/TLE.pl?CATNR='
url = base + str(satid)
with urllib.request.urlopen(url) as fd:
lines = fd.readlines()
for k, line in enumerate(lines):
if 'PRE' in line.decode():
name = lines[k+1].decode().strip()
if name == 'No TLE found':
msg = '%i is not in the CelesTrak database!' % satid
raise Exception(msg)
tle1 = lines[k+2].decode().strip()
tle2 = lines[k+3].decode().strip()
break
sat = sf.EarthSatellite(tle1, tle2, name)
return sat
>> sat = getsat(28129)
...print(sat)
...sat = getsat('goes 16')
...print(sat)
EarthSatellite 'GPS BIIR-10 (PRN 22)' number=28129 epoch=2018-04-21T19:50:06Z
EarthSatellite 'GOES 16' number=41866 epoch=2018-04-18T15:14:01Z
For completeness, and in case someone else might find it useful at some point:
import urllib from skyfield import api as sf datadir = os.environ['HOME']+'/programming/python/astro/skyfield-data/' loader = sf.Loader(datadir, expire=False) # Satellite TLEs. celestrak = 'http://celestrak.com/NORAD/elements/' geosats = loader.tle(celestrak+'geo.txt') gpssats = loader.tle(celestrak+'supplemental/gps.txt') sciencesats = loader.tle(celestrak+'science.txt') stationsats = loader.tle(celestrak+'stations.txt') tdrss = loader.tle(celestrak+'tdrss.txt') visualsats = loader.tle(celestrak+'visual.txt') # Make catalogs indexable by either name or catalog number. # Also create sats, a merge of the individual ones. satcats = [geosats, gpssats, sciencesats, stationsats, tdrss, visualsats] sats = {} for cat in satcats: names = [key for key in cat.keys()] for name in names: sat = cat[name] satnum = sat.model.satnum cat[satnum] = sat sats[satnum] = sat sats[name] = sat def getsat(satid): """ Return a skyfield EarthSatellite. <satid> is case independent if it is a satellite name (str). Retrieve directly from CelesTrak by catalog number if not in local database. """ if isinstance(satid, str): satid = satid.upper() if satid in sats.keys(): return sats[satid] if not isinstance(satid, int): msg = 'satid must be an integer for satellites not in the local set' raise Exception(msg) base = 'http://celestrak.com/cgi-bin/TLE.pl?CATNR=' url = base + str(satid) with urllib.request.urlopen(url) as fd: lines = fd.readlines() for k, line in enumerate(lines): if 'PRE' in line.decode(): name = lines[k+1].decode().strip() if name == 'No TLE found': msg = '%i is not in the CelesTrak database!' % satid raise Exception(msg) tle1 = lines[k+2].decode().strip() tle2 = lines[k+3].decode().strip() break sat = sf.EarthSatellite(tle1, tle2, name) return sat >> sat = getsat(28129) ...print(sat) ...sat = getsat('goes 16') ...print(sat) EarthSatellite 'GPS BIIR-10 (PRN 22)' number=28129 epoch=2018-04-21T19:50:06Z EarthSatellite 'GOES 16' number=41866 epoch=2018-04-18T15:14:01Z
thanks a lot for this code. I am getting a strange error when i call the function with your example:
sat = getsat(28129) ...print(sat)
line 66, in getsat sat = sf.EarthSatellite(tle1, tle2, name)
UnboundLocalError: local variable 'tle1' referenced before assignment
???
There is a code, describing the retrieval of satellite data from the TLE:
However, the names sometimes are changed, but ID is constant. Is there a way to get the data by ID, something like
satellites[40053]
? For now, my solution is just looping through the lines.