In [1]:
import json
import urllib.request
import pickle
import collections
import pathlib
import yaml
In [2]:
GR_SATELLITES_PATH = '/home/daniel/debian_testing_chroot/home/daniel/gr-satellites'
OUTPUT_DIR = '/tmp/satyamls'
In [3]:
satellites = json.load(urllib.request.urlopen('https://db.satnogs.org/api/satellites/?format=json'))
transmitters = json.load(urllib.request.urlopen('https://db.satnogs.org/api/transmitters/?format=json'))
In [4]:
modes = {'AFSK1k2' : ('AFSK', False, 1200), 'FSK19k2' : ('FSK', True, 19200), 'FSK1k2' : None, 'FSK2k4' : None, 'FSK4k8' : ('FSK', True, 4800),\
'FSK9k6' : ('FSK', True, 9600), 'GFSK19k2' : ('FSK', True, 19200), 'GFSK1k2' : None, 'GFSK2k4' : None, 'GFSK4k8' : ('FSK', True, 4800),\
'GFSK9k6' : ('FSK', True, 9600), 'GMSK19k2' : ('FSK', True, 19200), 'GMSK1k2' : None, 'GMSK2k4' : None, 'GMSK4k8' : ('FSK', True, 4800),\
'GMSK9k6' : ('FSK', True, 9600), 'MSK19k2' : ('FSK', True, 19200), 'MSK1k2' : None, 'MSK2k4' : None, 'MSK4k8' : ('FSK', True, 4800),\
'MSK9k6' : ('FSK', True, 9600),}
In [5]:
norad_list = set([t['norad_cat_id'] for t in transmitters if t['mode'] in modes.keys() and t['type'] == 'Transmitter'])
In [6]:
def get_ax25_headers(norad):
tlm = json.load(urllib.request.urlopen(f'https://db.satnogs.org/api/telemetry/?format=json&satellite={norad}'))
headers = [bytes.fromhex(t['frame'][:16*2]) for t in tlm]
return collections.Counter(headers)
def to_address(header):
return bytes([a >> 1 for a in header[:14]])
def load_info(file):
with open(file, 'rb') as f:
info = pickle.load(f)
return info
def addresses(frames):
return {to_address(a[0]):a[1] for a in frames.items()}
def sat_from_name(name):
return [s for s in satellites if s['name'] == name][0]
def name(norad):
return [s['name'] for s in satellites if s['norad_cat_id'] == norad][0]
def norad(name):
return [s['norad_cat_id'] for s in satellites if s['name'] == name][0]
def addresses_look_ok(frame):
if frame is None:
return False
addr = str(to_address(frame), encoding = 'ascii')
return addr[:6].isprintable() and addr[7:7+6].isprintable()
def get_most_popular_header(headers):
s = sorted(headers.items(), key = lambda a: a[1], reverse = True)
if len(s) == 1:
return s[0][0]
if len(s) == 0:
return None
# the most popular needs to be 4 times more popular than the rest
if s[0][1] > s[1][1] * 4:
return s[0][0]
else:
return None
def baudrate_str(baud):
return f'{baud//1000}k{(baud-baud//1000*1000)//100}'
def norad_from_satyaml(path):
with open(path) as f:
y = yaml.safe_load(f)
return y['norad']
def good_filename(name):
return name.replace('/', '_').replace(' ', '_').replace('.', '_') + '.yml'
def satyaml(sat):
names = [s.strip() for s in sat['names'].replace('\r\n',',').split(',') if len(s.strip()) > 0]
alternatives = '\nalternative_names:\n' + '\n'.join([' - ' + s for s in names]) if len(names) else ''
return f"""name: {sat['name']}{alternatives}
norad: {sat['norad_cat_id']}
data:
&tlm Telemetry:
telemetry: ax25
transmitters:
""" + '\n'.join([f""" {baudrate_str(modes[t['mode']][2])} {modes[t['mode']][0]} downlink:
frequency: {t['downlink_low']*1e-6:.03f}e+6
modulation: {modes[t['mode']][0]}
baudrate: {modes[t['mode']][2]}
framing: AX.25{' G3RUH' if modes[t['mode']][1] else ''}
data:
- *tlm""" for t in transmitters if t['norad_cat_id'] == sat['norad_cat_id'] and t['mode'] in modes]) + '\n'
In [7]:
#for norad in norad_list:
# with open(f'satnogsdb/ax25_addresses/{norad}', 'wb') as f:
# try:
# headers = get_ax25_headers(norad)
# except:
# print(f'{name(norad)} {norad} failed')
# pickle.dump(headers, f)
In [8]:
frames = {int(f.name) : load_info(f) for f in pathlib.Path('satnogsdb/ax25_addresses/').glob('*')}
In [9]:
headers = {name(f[0]) : get_most_popular_header(f[1]) for f in frames.items()}
suspicious_addresses = {h[0] : to_address(h[1]) for h in headers.items() if h[1] is not None and not addresses_look_ok(h[1])}
ok_addresses = {h[0] : to_address(h[1]) for h in headers.items() if h[1] is not None and addresses_look_ok(h[1])}
In [10]:
suspicious_addresses
Out[10]:
In [11]:
ok_addresses
Out[11]:
In [12]:
blacklist = {'RANGE A' # LY0LS is another spacecraft
}
suspicious_good = {'BUGSAT-1', 'ENDUROSAT ONE', 'IRVINE-01', 'QBEE', 'SNUGLITE'}
In [13]:
good_addresses = (ok_addresses.keys() - blacklist) | suspicious_good
In [14]:
gr_satellites_norads = {norad_from_satyaml(f) for f in (pathlib.Path(GR_SATELLITES_PATH) / 'python' / 'satyaml').glob('*.yml')}
In [21]:
gr_satellites_names = {n for n in good_addresses if norad(n) in gr_satellites_norads}
gr_satellites_names
Out[21]:
In [23]:
for name in good_addresses - gr_satellites_names:
with open(pathlib.Path(OUTPUT_DIR) / good_filename(name), 'w') as f:
try:
y = satyaml(sat_from_name(name))
except:
print('Error with', name)
else:
f.write(y)