Support wrapping raw sgp4 satellite object

This commit is contained in:
Brandon Rhodes 2020-06-03 16:32:27 -04:00
parent 3c24f5ce11
commit e3f0cdca94
2 changed files with 88 additions and 10 deletions

View File

@ -656,3 +656,59 @@ and otherwise recording the propagator error:
None,
None,
'mrt is less than 1.0 which indicates the satellite has decayed']
Building a satellite from orbital elements
------------------------------------------
If you are starting with raw satellite orbital parameters
instead of TLE text,
you will want to interact directly
with the `sgp4 <https://github.com/brandon-rhodes/python-sgp4>`_ library
that Skyfield uses for its low-level satellite calculations.
The underlying library provides access to a low-level constructor
that builds a satellite model directly from numeric orbital parameters:
.. testcode::
from sgp4.api import Satrec, WGS72
satrec = Satrec()
satrec.sgp4init(
WGS72, # gravity model
'i', # 'a' = old AFSPC mode, 'i' = improved mode
5, # satnum: Satellite number
18441.785, # epoch: days since 1949 December 31 00:00 UT
2.8098e-05, # bstar: drag coefficient (/earth radii)
6.969196665e-13, # ndot: ballistic coefficient (revs/day)
0.0, # nddot: second derivative of mean motion (revs/day^3)
0.1859667, # ecco: eccentricity
5.7904160274885, # argpo: argument of perigee (radians)
0.5980929187319, # inclo: inclination (radians)
0.3373093125574, # mo: mean anomaly (radians)
0.0472294454407, # no_kozai: mean motion (radians/minute)
6.0863854713832, # nodeo: right ascension of ascending node (radians)
)
If you need any more details,
this ``sgp4init`` constructor
is documented in the
`Providing your own elements <https://pypi.org/project/sgp4/#providing-your-own-elements>`_
section of the sgp4 librarys documentation on the Python Packaging Index.
To wrap this low-level satellite model in a Skyfield object,
call this special constructor:
.. testcode::
sat = EarthSatellite.from_satrec(satrec, ts)
print('Satellite number:', sat.model.satnum)
print('Epoch:', sat.epoch.utc_jpl())
.. testoutput::
Satellite number: 5
Epoch: A.D. 2000-Jun-27 06:50:24.0000 UT
The result should be a satellite object that behaves
exactly as though it had been loaded from TLE lines.

View File

@ -10,7 +10,7 @@ from .constants import AU_KM, DAY_S, T0, tau
from .functions import rot_x, rot_y, rot_z
from .positionlib import ITRF_to_GCRS2
from .searchlib import _find_discrete, find_maxima
from .timelib import Timescale
from .timelib import Timescale, calendar_date
from .vectorlib import VectorFunction
_minutes_per_day = 1440.
@ -90,24 +90,46 @@ class EarthSatellite(VectorFunction):
ts = ts or _ts
self.name = None if name is None else name.strip()
sat = Satrec.twoline2rv(line1, line2)
self.model = sat
satrec = Satrec.twoline2rv(line1, line2)
self.model = satrec
# TODO: just use the Julian dates instead
two_digit_year = sat.epochyr
two_digit_year = satrec.epochyr
if two_digit_year < 57:
year = two_digit_year + 2000;
year = two_digit_year + 2000
else:
year = two_digit_year + 1900;
year = two_digit_year + 1900
self.epoch = ts.utc(year, 1, sat.epochdays)
self.epoch = ts.utc(year, 1, satrec.epochdays)
self.target = -100000 - self.model.satnum
self._setup(satrec, ts)
def _setup(self, satrec, ts):
# If only I had not made __init__() specific to TLE lines, but
# had put them in an alternate construtor instead, this would
# simply have lived in __init__(). Alas! I was so young then.
self.target = -100000 - satrec.satnum
self.target_name = 'Satellite{0} {1}'.format(
self.model.satnum,
satrec.satnum,
' ' + repr(self.name) if self.name else '',
)
@classmethod
def from_satrec(cls, satrec, ts):
"""Build an EarthSatellite from a raw sgp4 Satrec object."""
self = cls.__new__(cls)
self.model = satrec
self.name = None
# TODO: once sgp4 starts filling in epochyr and epochdays in
# sgp4init(), the separate epoch code here and in __init__() can
# be unified to always use epochyr and epochdays.
year, month, day = calendar_date(satrec.jdsatepoch)
self.epoch = ts.utc(year, month, day + satrec.jdsatepochF)
self._setup(satrec, ts)
return self
def __str__(self):
sat = self.model
return 'EarthSatellite{0} number={1!r} epoch={2}'.format(