diff --git a/process.py b/process.py index a7ae779..5599700 100755 --- a/process.py +++ b/process.py @@ -21,6 +21,7 @@ from stvid.fourframe import FourFrame from stvid.fourframe import Observation from stvid.fourframe import AstrometricCatalog +from stvid.fourframe import format_satno from astropy.utils.exceptions import AstropyWarning @@ -143,8 +144,11 @@ def process_loop(args): "catalogname": ident.catalogname} # Save track - t.save(f"{ff.froot}_{ident.satno:05d}_{ident.catalogname}.csv", ff) - + t.save( + f"{ff.froot}_{format_satno(ident.satno)}_" + f"{ident.catalogname}.csv", + ff, + ) # Measure single position m = t.measure_single_position(ff) iod_line = m.to_iod_line(ff, ident) @@ -185,10 +189,16 @@ def process_loop(args): screenoutput_idents = [] for o in obs: # Open file - outfname = f"{ff.froot}_{o.satno:05d}_{o.catalogname}.dat" + outfname = ( + f"{ff.froot}_{format_satno(o.satno)}_" + f"{o.catalogname}.dat" + ) with open(outfname, "w") as fp: fp.write(f"{o.iod_line}\n") - outfname = f"{ff.froot}_{o.satno:05d}_{o.catalogname}_m.dat" + outfname = ( + f"{ff.froot}_{format_satno(o.satno)}_" + f"{o.catalogname}_m.dat" + ) with open(outfname, "w") as fp: for iod_line in o.iod_lines: fp.write(f"{iod_line}\n") diff --git a/stvid/fourframe.py b/stvid/fourframe.py index 693654b..3c4516f 100644 --- a/stvid/fourframe.py +++ b/stvid/fourframe.py @@ -134,8 +134,8 @@ def to_iod_line(self, ff, ident): tstr = ( nfd.replace("-", "").replace("T", "").replace(":", "").replace(".", "") ) - iod_line = "%05d %-9s %04d G %s 17 25 %s 37 S" % ( - ident.satno, + iod_line = "%s %-9s %04d G %s 17 25 %s 37 S" % ( + format_satno(ident.satno), ident.cospar, ff.site_id, tstr, @@ -749,7 +749,7 @@ def diagnostic_plot(self, predictions, track, obs, cfg): iod_line = obs.iod_line satno = obs.satno catalogname = obs.catalogname - outfname = f"{self.froot}_{satno:05d}_{catalogname}.png" + outfname = f"{self.froot}_{format_satno(satno)}_{catalogname}.png" else: iod_line = "" outfname = f"{self.froot}_0.png" @@ -807,7 +807,7 @@ def diagnostic_plot(self, predictions, track, obs, cfg): ax.text( track.x0, track.y0, - f" {satno:05d}", + f" {format_satno(satno)}", color=color_detected, ha="center", in_layout=False, @@ -890,7 +890,7 @@ def plot_prediction(self, p, ax, tlefiles, colors, dt=2.0, w=10.0): if self.in_frame(xs[0], ys[0]): ax.text( - xs[0], ys[0], f" {p.satno:05d} ", color=color, ha=ha, in_layout=False + xs[0], ys[0], f" {format_satno(p.satno)} ", color=color, ha=ha, in_layout=False ) for state, linestyle in zip( @@ -975,6 +975,43 @@ def decode_line(line): return ax, ay, az, bx, by, bz, n +# TLE/IOD Alpha-5 satellite-number alphabet. +# Positions 10 through 33 correspond to A-Z, omitting I and O. +_ALPHA5 = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ" + + +def format_satno(satno): + """ + Format a numeric NORAD catalogue number as a five-character field. + + Examples: + 25544 -> "25544" + 100000 -> "A0000" + 102554 -> "A2554" + 270438 -> "T0438" + + Satellite numbers remain integers internally. Alpha-5 is only used + when writing a fixed-width textual field. + """ + satno = int(satno) + + if satno < 0: + raise ValueError(f"Invalid satellite number: {satno}") + + if satno < 100000: + return f"{satno:05d}" + + prefix = satno // 10000 + suffix = satno % 10000 + + if prefix >= len(_ALPHA5): + raise ValueError( + f"Satellite number {satno} is outside the Alpha-5 range" + ) + + return f"{_ALPHA5[prefix]}{suffix:04d}" + + # IOD position format 2: RA/DEC = HHMMmmm+DDMMmm MX (MX in minutes of arc) def format_position(ra, de): # Right ascension