diff --git a/examples/irvine01.txt b/examples/irvine01.txt new file mode 100644 index 0000000..a475db8 --- /dev/null +++ b/examples/irvine01.txt @@ -0,0 +1,3 @@ +IRVINE01 +1 70002U 18599A 18315.16151858 .00000000 00000-0 00000-0 0 07 +2 70002 85.1205 90.1568 0012705 292.5520 107.9249 15.20792276 04 diff --git a/python/README.md b/python/README.md index 9c8aed6..46d9a18 100644 --- a/python/README.md +++ b/python/README.md @@ -21,3 +21,14 @@ ``` ./pass.py ../examples/sathyabamasat.txt $ST_DATADIR/sites.txt -s 7300 --starttime 2019-11-06T19:30:00 ``` + +- Adjust a TLE to a new launch time + ``` + # Data from https://community.libre.space/t/electron-its-business-time-launch-this-weekend-irvine-01-amateur-payload/2819/4 + $ ./launchtle.py ../examples/irvine01.txt 2018-11-11T03:00:00 2018-11-11T04:05:00 + New TLE for a launch delay of 1:05:00h : + + IRVINE01-delayed + 1 70002U 18599A 18315.20665747 .00000000 00000-0 00000-0 0 09 + 2 70002 85.1205 106.4513 0012705 292.5520 107.9249 15.20792276 05 + ``` diff --git a/python/launchtle.py b/python/launchtle.py new file mode 100755 index 0000000..498e477 --- /dev/null +++ b/python/launchtle.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 + +import argparse +from datetime import datetime, timedelta + +from sgp4.io import twoline2rv +from sgp4.earth_gravity import wgs84 + +from astropy.coordinates import Longitude, Angle +from astropy import units as u +from astropy.time import Time + + + +def gmst(t): + return Time(t).sidereal_time('mean', 'greenwich') + +def fractional_days(t): + d = t - datetime(t.year, 1, 1) + return t.timetuple().tm_yday + (d.seconds + d.microseconds/1e6)/(60*60*24) + +def print_tle(tle, new_epoch, new_nodeo): + def checksum(proto_tle): + s = 0 + for c in proto_tle: + if c.isdigit(): + s += int(c) + if c == '-': + s += 1 + return s%10 + + tle0,old1,old2 = tle + tle1_proto = '{} {:2d}{:.8f} {}'.format(old1[:17], + abs(new_epoch.year)%100, + fractional_days(new_epoch), + old1[33:-1]) + tle2_proto = '{} {:>8.4f} {}'.format(old2[:16], + Angle(new_nodeo*u.radian).degree, + old2[26:68]) + + return (tle0, + tle1_proto + str(checksum(tle1_proto)), + tle2_proto + str(checksum(tle2_proto))) + +def launch_tle(tle, launch_date, new_launch_date): + sat = twoline2rv(tle[1], tle[2], whichconst=wgs84) + + # New Epoch + new_epoch = sat.epoch - launch_date + new_launch_date + + # New Right ascension of ascending node in radians + new_nodeo = (gmst(new_launch_date) - gmst(launch_date) + Longitude(sat.nodeo * u.radian)).rad + + return print_tle(tle, new_epoch, new_nodeo) + + +if __name__ == "__main__": + # Parse arguments + parser = argparse.ArgumentParser( + description="Adjust a TLE to a new launch time") + parser.add_argument('TLEFILE', help="reference tle file", type=str) + parser.add_argument("OLD", + help="Reference (old) launch time (YYYY-MM-DDTHH:MM:SS)", + type=str) + parser.add_argument("NEW", + help="New launch time (YYYY-MM-DDTHH:MM:SS) [default: now]", + default=datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S"), + type=str) + + args = parser.parse_args() + + with open(args.TLEFILE, 'r') as f: + tle = f.readlines() + tle = [l.strip() for l in tle] + + launch_date_ref = datetime.strptime(args.OLD, '%Y-%m-%dT%H:%M:%S') + new_launch_date = datetime.strptime(args.NEW, '%Y-%m-%dT%H:%M:%S') + + new_tle = launch_tle(tle, launch_date_ref, new_launch_date) + + print('New TLE for a launch delay of {}h :\n'.format(new_launch_date - launch_date_ref)) + print(new_tle[0].strip()+'-delayed') + print(new_tle[1]) + print(new_tle[2]) diff --git a/python/test_launchtle.py b/python/test_launchtle.py new file mode 100644 index 0000000..d27e252 --- /dev/null +++ b/python/test_launchtle.py @@ -0,0 +1,28 @@ +from datetime import datetime +from launchtle import launch_tle + + +launch_date_ref = datetime(2018, 11, 11, 3, 0) +tle_ref = ["1 70002U 18599A 18315.16151858 .00000000 00000-0 00000-0 0 07", + "2 70002 85.1205 90.1568 0012705 292.5520 107.9249 15.20792276 04"] + +# Testing the Implementation against 'launchtle' from sattools +# launchtle -c irvine.txt -i 70002 -t 2018-11-11T03:00:00 -T 2018-11-11T03:00:00 -I 70002 -d 18599A +fixtures = [(datetime(2018, 11, 11, 3, 0), + ["1 70002U 18599A 18315.16151858 .00000000 00000-0 00000-0 0 07", + "2 70002 85.1205 90.1568 0012705 292.5520 107.9249 15.20792276 04"]), + (datetime(2018, 11, 11, 3, 5), + ["1 70002U 18599A 18315.16499080 .00000000 00000-0 00000-0 0 09", + "2 70002 85.1205 91.4102 0012705 292.5520 107.9249 15.20792276 02"]), + (datetime(2018, 11, 11, 4, 0), + ["1 70002U 18599A 18315.20318525 .00000000 00000-0 00000-0 0 08", + "2 70002 85.1205 105.1979 0012705 292.5520 107.9249 15.20792276 07"]), + (datetime(2018, 11, 12, 3, 0), + ["1 70002U 18599A 18316.16151858 .00000000 00000-0 00000-0 0 08", + "2 70002 85.1205 91.1424 0012705 292.5520 107.9249 15.20792276 06"])] + +def test_launchtle(): + for new_launch_date, tle_correct in fixtures: + tle = launch_tle(['DUMMYSAT', *tle_ref], launch_date_ref, new_launch_date) + assert(tle_correct[1] == tle[2]) + assert(tle_correct[0] == tle[1])