Skip to content

Commit

Permalink
Simplify how Earth satellites are constructed
Browse files Browse the repository at this point in the history
  • Loading branch information
brandon-rhodes committed Feb 28, 2017
1 parent 667aa8b commit 4dccf56
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 26 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ deltat.data
deltat.preds
hip_main.dat.gz
htmlcov/
stations.txt
tmp*.py
43 changes: 31 additions & 12 deletions skyfield/documentation/earth-satellites.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,34 @@ Once you have acquired the two-line orbital elements,
simply read them from a file or paste them directly into your script
to compute its apparent position relative to a location on Earth:

.. testcode::
.. testsetup::

text = """
open('stations.txt', 'w').write("""\
ISS (ZARYA)
1 25544U 98067A 14020.93268519 .00009878 00000-0 18200-3 0 5082
2 25544 51.6498 109.4756 0003572 55.9686 274.8005 15.49815350868473
"""
""")

.. testcode::

from skyfield.api import Topos, load

sats = load.tle('http://celestrak.com/NORAD/elements/stations.txt')
satellite = sats['ISS (ZARYA)']

.. testcode::

print(satellite)

.. testoutput::

from skyfield.api import EarthSatellite, Topos, load
EarthSatellite 'ISS (ZARYA)' number=25544 epoch=2014-01-20T22:23:04Z

.. testcode::

ts = load.timescale()
t = ts.utc(2014, 1, 21, 11, 18, 7)

satellite = EarthSatellite(text)
bluffton = Topos('40.8939 N', '83.8917 W')

difference = satellite - bluffton
Expand All @@ -55,9 +69,10 @@ to compute its apparent position relative to a location on Earth:

.. testcode::

# BAD APPROACH: Compute the satellite's position
# relative to the Solar System barycenter, then call
# observe() to compensate for light-travel time.
# A POOR APPROACH - Compute both the satellite
# and observer positions relative to the Solar
# System barycenter ("ssb"), then call observe()
# to compensate for light-travel time.

de421 = load('de421.bsp')
earth = de421['earth']
Expand All @@ -67,12 +82,12 @@ to compute its apparent position relative to a location on Earth:

# After all that work, how big is the difference, really?

error_km = (position2 - position).distance().km
print('Error: {0:.3f} km'.format(error_km))
difference_km = (position2 - position).distance().km
print('Difference: {0:.3f} km'.format(difference_km))

.. testoutput::

Error: 0.091 km
Difference: 0.091 km


To find out whether the satellite is above your local horizon,
Expand Down Expand Up @@ -131,12 +146,16 @@ so it supports all of the standard Skyfield date methods:

.. testcode::

from skyfield.api import EarthSatellite

text = """
GOCE
1 34602U 09013A 13314.96046236 .14220718 20669-5 50412-4 0 930
2 34602 096.5717 344.5256 0009826 296.2811 064.0942 16.58673376272979
"""
sat = EarthSatellite(text)
lines = text.strip().splitlines()

sat = EarthSatellite(lines[1], lines[2], lines[0])
print(sat.epoch.utc_jpl())

.. testoutput::
Expand Down
11 changes: 8 additions & 3 deletions skyfield/iokit.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def __init__(self, directory, verbose=True, expire=True):
'deltat.data': parse_deltat_data,
'deltat.preds': parse_deltat_preds,
'Leap_Second.dat': parse_leap_seconds,
'stations.txt': parse_celestrak_tle,
#'stations.txt': parse_celestrak_tle,
}
self.openers = {
'.bsp': [
Expand Down Expand Up @@ -182,6 +182,11 @@ def __call__(self, filename):
def _log(self, message, *args):
self.events.append(message.format(*args))

def tle(self, url):
"""Parse a satellite TLE file."""
with self.open(url) as f:
return parse_celestrak_tle(f)

def open(self, url, mode='rb'):
"""Open a file, downloading it first if it does not yet exist.
Expand Down Expand Up @@ -322,7 +327,7 @@ def parse_celestrak_tle(fileobj):
name = line.decode('ascii').strip()
line1 = next(lines).decode('ascii')
line2 = next(lines).decode('ascii')
sat = EarthSatellite([line1, line2], None)
sat = EarthSatellite(line1, line2, name)
satellites[name] = sat
if ' (' in name:
# Given `ISS (ZARYA)` or `HTV-6 (KOUNOTORI 6)`, also support
Expand All @@ -331,7 +336,7 @@ def parse_celestrak_tle(fileobj):
secondary_name = secondary_name.rstrip(')')
satellites.setdefault(short_name, sat)
satellites.setdefault(secondary_name, sat)
return None, satellites
return satellites


def download(url, path, verbose=None, blocksize=128*1024):
Expand Down
8 changes: 3 additions & 5 deletions skyfield/sgp4lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,9 @@ class EarthSatellite(VectorFunction):
# cache for timescale
timescale = None

def __init__(self, lines):
if isinstance(lines, str):
lines = lines.splitlines()
self.name = None if len(lines) < 3 else lines[0].strip()
sat = twoline2rv(*lines[-2:], whichconst=wgs72)
def __init__(self, line1, line2, name=None):
self.name = None if name is None else name.strip()
sat = twoline2rv(line1, line2, whichconst=wgs72)
self._sgp4_satellite = sat
if EarthSatellite.timescale is None:
from skyfield import api
Expand Down
7 changes: 4 additions & 3 deletions skyfield/tests/test_earth_satellites.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def test_iss_altitude_with_gcrs_vector_subtraction(iss_transit):
t = api.load.timescale(delta_t=67.2091).utc(dt)

lines = iss_tle.splitlines()
s = EarthSatellite(lines)
s = EarthSatellite(lines[1], lines[2], lines[0])
lake_zurich = api.Topos(latitude_degrees=42.2, longitude_degrees=-88.1)

alt, az, d = (s - lake_zurich).at(t).altaz()
Expand Down Expand Up @@ -111,7 +111,7 @@ def test_appendix_c_conversion_from_TEME_to_ITRF():

def test_appendix_c_satellite():
lines = appendix_c_example.splitlines()
sat = EarthSatellite(lines)
sat = EarthSatellite(lines[1], lines[2], lines[0])

ts = api.load.timescale()
jd_epoch = sat._sgp4_satellite.jdsatepoch
Expand All @@ -136,5 +136,6 @@ def test_appendix_c_satellite():
def test_epoch_date():
# Example from https://celestrak.com/columns/v04n03/
s = appendix_c_example.replace('00179.78495062', '98001.00000000')
sat = EarthSatellite(s.splitlines())
lines = s.splitlines()
sat = EarthSatellite(lines[1], lines[2], lines[0])
assert sat.epoch.utc_jpl() == 'A.D. 1998-Jan-01 00:00:00.0000 UT'
4 changes: 2 additions & 2 deletions skyfield/tests/test_strs_and_reprs.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def test_satellite_with_name(eph):
'1 25544U 98067A 13330.58127943 .00000814 00000-0 21834-4 0 1064',
'2 25544 51.6484 23.7537 0001246 74.1647 18.7420 15.50540527859894',
]
s = EarthSatellite(lines)
s = EarthSatellite(lines[1], lines[2], lines[0])
expected = dedent("""\
EarthSatellite 'ISS (ZARYA)' number=25544 epoch=2013-11-26T13:57:03Z
""")
Expand All @@ -40,7 +40,7 @@ def test_satellite_without_name(eph):
'1 25544U 98067A 13330.58127943 .00000814 00000-0 21834-4 0 1064',
'2 25544 51.6484 23.7537 0001246 74.1647 18.7420 15.50540527859894',
]
s = EarthSatellite(lines)
s = EarthSatellite(lines[0], lines[1])
expected = dedent("""\
EarthSatellite number=25544 epoch=2013-11-26T13:57:03Z
""")
Expand Down
2 changes: 1 addition & 1 deletion skyfield/vectorlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def topos(self, latitude=None, longitude=None, latitude_degrees=None,
def satellite(self, text):
# TODO: deprecate this
from .sgp4lib import EarthSatellite
sat = EarthSatellite(text.splitlines())
sat = EarthSatellite(*text.splitlines()[-2:])
return self + sat


Expand Down

0 comments on commit 4dccf56

Please sign in to comment.