def sv(request): tle = Tle( """ISS (ZARYA) 1 25544U 98067A 18124.55610684 .00001524 00000-0 30197-4 0 9997 2 25544 51.6421 236.2139 0003381 47.8509 47.6767 15.54198229111731""" ) return tle.orbit().as_statevector().copy(form=request.param)
def test_tle_to_and_from(): txt = """1 25544U 98067A 08264.51782528 -.00002182 00000-0 -11606-4 0 2927 2 25544 51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537""" orb = Tle(txt).orbit() new_txt = Tle.from_orbit(orb, norad_id=25544, cospar_id='1998-067A') assert str(new_txt) == txt
def test_orbit2frame(): iss = Tle("""0 ISS (ZARYA) 1 25544U 98067A 16333.80487076 .00003660 00000-0 63336-4 0 9996 2 25544 51.6440 317.1570 0006082 266.5744 156.9779 15.53752683 30592""" ).orbit() soyouz = Tle("""0 SOYUZ MS-03 1 41864U 16070A 16332.46460811 +.00003583 +00000-0 +62193-4 0 9996 2 41864 051.6436 323.8351 0006073 261.8114 220.0268 15.53741335030385""" ).orbit() # This is done to convert the TLE format to cartesian coordinates # as done during propagation soyouz = soyouz.propagate(soyouz.date) inert = iss.as_frame('iss_inert') qsw = iss.as_frame('iss_qsw', orientation='QSW') tnw = iss.as_frame('iss_tnw', orientation='TNW') assert inert.orientation == "TEME" assert qsw.orientation == "QSW" assert tnw.orientation == "TNW" s1 = soyouz.copy(frame='iss_inert') assert_vector( s1, np.array([ 70.5889585, 73.6584008, -62.5406308, 0.0521557, 0.0998631, -0.0423856 ])) s2 = soyouz.copy(frame="iss_qsw") assert_vector( s2, np.array([ 4.5450528, -18.6989377, -118.107503, 0.0393978, -0.0046244, -0.1136478 ])) s3 = soyouz.copy(frame="iss_tnw") assert_vector( s3, np.array([ -18.6974528, -4.5511611, -118.107503, -0.0046116, -0.0393993, -0.1136478 ])) # Whatever the local reference frame, the W vector is the same assert s2[2] == s3[2] # The norm of the position vectors should the same, because it's always the # same relative positions, but expressed in differents frames assert_almost_equal(norm(s1[:3]), norm(s2[:3]), decimal=5) assert_almost_equal(norm(s2[:3]), norm(s3[:3]))
def test_convert_to_orbit(tle_txt): tle = Tle(tle_txt) orb = tle.orbit() assert orb.frame.name == "TEME" assert repr(orb.form).startswith("<Form 'tle'") assert repr(orb.date) == "<Date '2008-09-20T12:25:40.104192 UTC'>" assert orb['i'] == np.deg2rad(51.6416) assert orb['Ω'] == np.deg2rad(247.4627) assert orb['e'] == 6.703e-4 assert orb['ω'] == np.deg2rad(130.5360) assert orb['M'] == np.deg2rad(325.0288) assert orb['n'] == 15.72125391 * 2 * np.pi / 86400.
def test_one(helper): test_cases = { """1 25544U 98067A 08264.51782528 -.00002182 00000-0 -11606-4 0 2927 2 25544 51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537""": ([ -3199119.3019953547, -5925838.8951945184, -104283.88301037039, 4160.9001260610321, -2340.8666910921365, 6034.2397874890266 ]), """1 27421U 02021A 15290.39156189 .00000174 00000-0 10000-3 0 9996 2 27421 98.4973 341.4832 0001168 101.4896 26.7296 14.20902451697482""": ([ -6313390.5470795343, 2392162.4266701187, -2518309.642217699, 2810.1811696038776, 188.82949370476567, -6882.790571054541 ]), """1 38012U 11076F 15290.43560975 -.00001375 00000-0 -28626-3 0 9990 2 38012 98.1856 3.4028 0001255 65.6426 294.5016 14.58534477204126""": ([ -6278750.6667313213, -8651.4824499131028, -3277187.0595075251, 3419.2465632815151, 1208.7786614934848, -6564.4998427326509 ]), """1 25544U 98067A 15290.14517523 .00013306 00000-0 20592-3 0 9999 2 25544 51.6447 195.3542 0006630 48.0978 95.2885 15.54379613967013""": ([ -6596477.2658053627, 63108.245806605715, -1577202.6429111576, -1410.6459948627141, -4877.7460063862927, 5746.8315844151275 ]), } for lines, expected in test_cases.items(): tle = Tle(lines).orbit() sgp4 = Sgp4Beta() sgp4.orbit = tle pv = sgp4.propagate(tle.date + timedelta(days=1)) helper.assert_vector(pv, expected)
def test_dump_omm_bluebook(ccsds_format, datafile, str_tle_bluebook): """Example from the CCSDS Blue Book (4-1 and 4-2) """ tle = Tle(str_tle_bluebook) omm = tle.orbit() # omm.name = tle.name # omm.norad_id = tle.norad_id # omm.cospar_id = tle.cospar_id # assert tle.epoch == Date(2007, 5, 4, 10, 34, 41, 426400) omm = dumps(omm, fmt=ccsds_format).splitlines() ref_bluebook = datafile("omm_bluebook").splitlines() assert ref_bluebook[0] == omm[0] for i in range(4, len(ref_bluebook)): assert ref_bluebook[i] == omm[i]
def tle_from_file(filename): ''' Returns: TLE:Tle, Object name:str ''' with open(filename, 'r') as f: lines = f.readlines() return Tle(''.join(lines)), lines[0].strip()
def test_to_and_from(both): tle = Tle(both) orb = tle.orbit() orb2 = orb.copy() del orb2._data["cospar_id"] tle2 = Tle.from_orbit(orb, name=tle.name, norad_id=tle.norad_id, cospar_id=tle.cospar_id) tle3 = Tle.from_orbit(orb2, name=tle.name, norad_id=tle.norad_id) assert tle2.cospar_id == tle.cospar_id assert tle3.cospar_id == "" tle, tle2 = tle.text.splitlines(), tle2.text.splitlines() for i in range(2): # We don't test the last two fields of the TLE because when we reconstruct one from scracth # we can't have any information about the element set number. And because of that, the # checksum is also different assert tle[i][:63] == tle2[i][:63]
def dump(self, all=False): bd_request = self.model.select().order_by(self.model.norad_id, self.model.epoch) if not all: bd_request = bd_request.group_by(self.model.norad_id) for tle in bd_request: yield Tle("%s\n%s" % (tle.name, tle.data), src=tle.src)
def test_tle(tle, ccsds_format): # Check that a TLE and its OMM representation are the same txt = dumps(tle, fmt=ccsds_format) orb = loads(txt) new_tle = Tle.from_orbit(orb) assert str(tle.tle) == str(new_tle) assert all(tle == orb) date = Date(2020, 9, 30) assert all(tle.propagate(date) == orb.propagate(date))
def get(cls, **kwargs): """Retrieve one TLE from the table from one of the available fields Keyword Arguments: norad_id (int) cospar_id (str) name (str) Return: Tle: """ entity = cls()._get_last_raw(**kwargs) return Tle("%s\n%s" % (entity.name, entity.data), src=entity.src)
def test_generator(caplog): text = "\n".join(ref) + "\n1 \n2 " with raises(TleParseError): for tle in Tle.from_string(text, error="raise"): continue for tle in Tle.from_string(text): continue assert len(caplog.records) == 1 assert caplog.record_tuples == [ ('beyond.io.tle', logging.WARNING, "Invalid TLE size on line 1. Expected 69, got 1.") ] caplog.clear() for tle in Tle.from_string(text, error="ignore"): continue assert len(caplog.records) == 0
def test_generator(caplog): text = "\n".join(ref) + "\n1 \n2 " with raises(TleParseError): for tle in Tle.from_string(text, error="raise"): continue for tle in Tle.from_string(text): continue assert len(caplog.records) == 1 assert caplog.record_tuples == [ ('beyond.io.tle', logging.WARNING, "invalid literal for int() with base 10: ' '") ] caplog.clear() for tle in Tle.from_string(text, error="ignore"): continue assert len(caplog.records) == 0
def get_dated(cls, limit=None, date=None, **kwargs): self = cls() if limit == "after": r = (self.model.select().where(self.model.epoch >= date).order_by( self.model.epoch.asc())) else: r = self.model.select().where(self.model.epoch <= date) try: entity = r.filter(**kwargs).get() except self.model.DoesNotExist: mode, selector = kwargs.popitem() raise TleNotFound(selector, mode=mode) from e else: return Tle("%s\n%s" % (entity.name, entity.data), src=entity.src)
def from_text(cls, text): """This method is used to parse an orbit from stdin """ sats = [cls.from_orb(tle) for tle in Tle.from_string(text)] if not sats: try: orb = ccsds.loads(text) except ValueError: raise ValueError("No valid TLE nor CCSDS") else: if isinstance(orb, (Ephem, Orbit)): sats = [cls.from_orb(orb)] else: sats = [cls.from_orb(ephem) for ephem in orb] return sats
def history(self, number=None, **kwargs): """Retrieve all the TLE of a given object Keyword Arguments: norad_id (int) cospar_id (str) name (str) Yield: TleModel: """ query = self.model.select().filter(**kwargs).order_by(self.model.epoch) if not query: mode, selector = kwargs.popitem() raise TleNotFound(selector, mode=mode) number = 0 if number is None else number for el in query[-number:]: yield Tle("%s\n%s" % (el.name, el.data), src=el.src)
def insert(self, text, src): """ Args: text (str): text containing the TLEs src (str): Where those TLEs come from Return: 2-tuple: Number of tle inserted, total tle found in the text """ with self.db.atomic(): entities = [] i = None for i, tle in enumerate(Tle.from_string(text)): try: # An entry in the table correponding to this TLE has been # found, there is no need to update it entity = self.model.get( self.model.norad_id == tle.norad_id, self.model.epoch == tle.epoch.datetime, ) continue except TleModel.DoesNotExist: # This TLE is not registered yet, lets go ! entity = { "norad_id": int(tle.norad_id), "cospar_id": tle.cospar_id, "name": tle.name, "data": tle.text, "epoch": tle.epoch.datetime, "src": src, "insert_date": datetime.now(), } entities.append(entity) if entities: TleModel.insert_many(entities).execute() elif i is None: raise ValueError("{} contains no TLE".format(src)) log.info("{:<20} {:>3}/{}".format(src, len(entities), i + 1))
def find(self, txt): """Retrieve every TLE containing a string. For each object, only get the last TLE in database Args: txt (str) Return: Tle: """ entities = (self.model.select().where( self.model.data.contains(txt) | self.model.name.contains(txt)).order_by( self.model.norad_id, self.model.epoch.desc()).group_by(self.model.norad_id)) sats = [] for entity in entities: sats.append( Tle("%s\n%s" % (entity.name, entity.data), src=entity.src)) if not sats: raise TleNotFound(txt) return sats
def iss_tle(common_env): return Tle("""ISS (ZARYA) 1 25544U 98067A 18124.55610684 .00001524 00000-0 30197-4 0 9997 2 25544 51.6421 236.2139 0003381 47.8509 47.6767 15.54198229111731""")
#!/usr/bin/env python import sys import numpy as np import matplotlib.pyplot as plt from beyond.dates import Date, timedelta from beyond.io.tle import Tle from beyond.frames import create_station from beyond.config import config tle = Tle("""ISS (ZARYA) 1 25544U 98067A 16086.49419020 .00003976 00000-0 66962-4 0 9998 2 25544 51.6423 110.4590 0001967 0.7896 153.8407 15.54256299992114""" ).orbit() # Station definition station = create_station('TLS', (43.428889, 1.497778, 178.0)) azims, elevs = [], [] print(" Time Azim Elev Distance Radial Velocity") print("=========================================================") for orb in station.visibility(tle, start=Date.now(), stop=timedelta(hours=24), step=timedelta(seconds=30), events=True): elev = np.degrees(orb.phi) # Radians are counterclockwise and azimuth is clockwise azim = np.degrees(-orb.theta) % 360
#!/usr/bin/env python from beyond.dates import Date, timedelta from beyond.io.tle import Tle from beyond.frames import create_station from beyond.orbits.listeners import stations_listeners, NodeListener, ApsideListener, LightListener tle = Tle("""ISS (ZARYA) 1 25544U 98067A 17153.89608442 .00001425 00000-0 28940-4 0 9997 2 25544 51.6419 109.5559 0004850 223.1783 180.8272 15.53969766 59532""" ).orbit() # Station definition station = create_station('TLS', (43.428889, 1.497778, 178.0)) # Listeners declaration listeners = stations_listeners(station) # AOS, LOS and MAX elevation listeners.append(NodeListener()) # Ascending and Descending Node listeners.append(ApsideListener()) # Apogee and Perigee listeners.append(LightListener()) # Illumination events start = Date.now() stop = timedelta(minutes=100) step = timedelta(seconds=180) for orb in tle.iter(start=start, stop=stop, step=step, listeners=listeners): event = orb.event if orb.event is not None else "" print("{orb.date:%Y-%m-%d %H:%M:%S} {event}".format(orb=orb, event=event))
""" import sys import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from beyond.io.tle import Tle from beyond.dates import timedelta from beyond.propagators.keplernum import KeplerNum from beyond.env.solarsystem import get_body from beyond.orbits.man import ImpulsiveMan from beyond.orbits.listeners import ApsideListener, find_event orb = Tle("""ISS (ZARYA) 1 25544U 98067A 18124.55610684 .00001524 00000-0 30197-4 0 9997 2 25544 51.6421 236.2139 0003381 47.8509 47.6767 15.54198229111731""" ).orbit() start = orb.date stop = timedelta(minutes=300) step = timedelta(seconds=60) # Changing the propagator to Keplerian, as SGP4 is not able to perform maneuvers orb.propagator = KeplerNum(step, bodies=get_body("Earth")) # Research for the next perigee perigee = find_event(orb.iter(stop=stop, listeners=ApsideListener()), 'Periapsis') man1 = ImpulsiveMan(perigee.date, (280, 0, 0), frame="TNW") orb.maneuvers = [man1]
def test_read(tle_txt): tle = Tle(tle_txt) assert tle.name == "ISS (ZARYA)" assert tle.norad_id == 25544 assert tle.cospar_id == "1998-067A" assert tle.epoch == Date(2008, 9, 20, 12, 25, 40, 104192) assert tle.ndot == -2.182e-5 * 2 assert tle.ndotdot == 0. assert tle.bstar == -0.11606e-4 assert tle.i == np.deg2rad(51.6416) assert tle.Ω == np.deg2rad(247.4627) assert tle.e == 6.703e-4 assert tle.ω == np.deg2rad(130.5360) assert tle.M == np.deg2rad(325.0288) assert tle.n == 15.72125391 * 2 * np.pi / 86400. tle = Tle(tle_txt.splitlines()[1:]) assert tle.name == "" with raises(TleParseError): ref2 = tle_txt[:-1] + "8" Tle(ref2) orbs = list(Tle.from_string("# comment\n" + tle_txt)) assert len(orbs) == 1 assert (orbs[0].orbit() == tle.orbit()).all() tle3 = Tle("Name\n" + "\n".join(tle_txt.splitlines()[1:])) assert (tle3.orbit() == tle.orbit()).all() with raises(TleParseError) as eee: l = tle_txt.splitlines() l[1] = "3" + l[1][1:] Tle("\n".join(l)) assert str(eee.value) == "Line number check failed"
def ref_orb(): tle = """1 25544U 98067A 08264.51782528 -.00002182 00000-0 -11606-4 0 2927 2 25544 51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537""" return Tle(tle).orbit()
def tle(): tle = Tle("""ISS (ZARYA) 1 25544U 98067A 08264.51782528 -.00002182 00000-0 -11606-4 0 2927 2 25544 51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537""") return tle.orbit()
#!/usr/bin/env python """Script showing the position of the ISS at the time of the TLE and the ground track for the previous and the next orbit """ import sys import numpy as np import matplotlib.pyplot as plt from pathlib import Path from beyond.io.tle import Tle from beyond.dates import Date, timedelta # Parsing of TLE tle = Tle("""ISS (ZARYA) 1 25544U 98067A 19004.59354167 .00000715 00000-0 18267-4 0 9995 2 25544 51.6416 95.0104 0002419 236.2184 323.8248 15.53730729149833""") # Conversion into `Orbit` object orb = tle.orbit() # Tables containing the positions of the ground track latitudes, longitudes = [], [] prev_lon, prev_lat = None, None period = orb.infos.period start = orb.date - period stop = 2 * period step = period / 100 for point in orb.ephemeris(start=start, stop=stop, step=step):
def molniya_tle(common_env): return Tle("""MOLNIYA 1-90 1 24960U 97054A 18123.22759647 .00000163 00000-0 24467-3 0 9999 2 24960 62.6812 182.7824 6470982 294.8616 12.8538 3.18684355160009""")