Files
pyModeS/pyModeS/streamer/stream.py
2018-06-23 14:40:27 +02:00

202 lines
6.7 KiB
Python

from __future__ import absolute_import, print_function, division
import numpy as np
import time
import pyModeS as pms
class Stream():
def __init__(self, lat0, lon0):
self.acs = dict()
self.cache_new_acs = False
self.__new_acs = set()
self.lat0 = lat0
self.lon0 = lon0
self.t = 0
self.cache_timeout = 60 # seconds
def process_raw(self, adsb_ts, adsb_msgs, commb_ts, commb_msgs, tnow=None):
"""process a chunk of adsb and commb messages recieved in the same
time period.
"""
if tnow is None:
tnow = time.time()
self.t = tnow
local_updated_acs_buffer = []
# process adsb message
for t, msg in zip(adsb_ts, adsb_msgs):
icao = pms.icao(msg)
tc = pms.adsb.typecode(msg)
if icao not in self.acs:
self.acs[icao] = {
'live': None,
'lat': None,
'lon': None,
'alt': None,
'gs': None,
'trk': None,
'roc': None,
'tas': None,
'ias': None,
'mach': None,
'hdg': None,
'ver' : None,
'NIC' : None,
'NACp' : None,
'NACv' : None,
'SIL' : None
}
self.acs[icao]['live'] = int(t)
if 1 <= tc <= 4:
self.acs[icao]['callsign'] = pms.adsb.callsign(msg)
if (5 <= tc <= 8) or (tc == 19):
vdata = pms.adsb.velocity(msg)
if vdata is None:
continue
spd, trk, roc, tag = vdata
if tag != 'GS':
continue
if (spd is None) or (trk is None):
continue
self.acs[icao]['gs'] = spd
self.acs[icao]['trk'] = trk
self.acs[icao]['roc'] = roc
self.acs[icao]['tv'] = t
if (5 <= tc <= 18):
oe = pms.adsb.oe_flag(msg)
self.acs[icao][oe] = msg
self.acs[icao]['t'+str(oe)] = t
if ('tpos' in self.acs[icao]) and (t - self.acs[icao]['tpos'] < 180):
# use single message decoding
rlat = self.acs[icao]['lat']
rlon = self.acs[icao]['lon']
latlon = pms.adsb.position_with_ref(msg, rlat, rlon)
elif ('t0' in self.acs[icao]) and ('t1' in self.acs[icao]) and \
(abs(self.acs[icao]['t0'] - self.acs[icao]['t1']) < 10):
# use multi message decoding
# try:
latlon = pms.adsb.position(
self.acs[icao][0],
self.acs[icao][1],
self.acs[icao]['t0'],
self.acs[icao]['t1'],
self.lat0, self.lon0
)
# except:
# # mix of surface and airborne position message
# continue
else:
latlon = None
if latlon is not None:
self.acs[icao]['tpos'] = t
self.acs[icao]['lat'] = latlon[0]
self.acs[icao]['lon'] = latlon[1]
self.acs[icao]['alt'] = pms.adsb.altitude(msg)
local_updated_acs_buffer.append(icao)
# Uncertainty & accuracy
ac = self.acs[icao]
if (5 <= tc <= 8) or (9 <= tc <= 18) or (20 <= tc <= 22):
if (ac['ver'] == 1) and ('nic_s' in ac.keys()):
self.acs[icao]['NIC'] = pms.adsb.nic_v1(msg, ac['nic_s'])
elif (ac['ver'] == 2) and ('nic_a' in ac.keys()) and ('nic_b' in ac.keys()):
self.acs[icao]['NIC'] = pms.adsb.nic_v2(msg, ac['nic_a'], ac['nic_b'], ac['nic_c'])
if tc == 19:
if ac['ver'] in [1, 2]:
self.acs[icao]['NACv'] = pms.adsb.nac_v(msg)
if tc == 29:
if ac['ver'] != None:
self.acs[icao]['SIL'], self.acs[icao]['sil_s'] = pms.adsb.sil(msg, ac['ver'])
self.acs[icao]['NACp'] = pms.adsb.nac_p(msg)
if tc == 31:
self.acs[icao]['ver'] = pms.adsb.version(msg)
self.acs[icao]['SIL'] = pms.adsb.version(msg)
self.acs[icao]['NACp'] = pms.adsb.nac_p(msg)
if self.acs[icao]['ver'] == 1:
self.acs[icao]['nic_s'] = pms.adsb.nic_s(msg)
elif self.acs[icao]['ver'] == 2:
self.acs[icao]['nic_a'], self.acs[icao]['nic_c'] = pms.adsb.nic_a_c(msg)
# process commb message
for t, msg in zip(commb_ts, commb_msgs):
icao = pms.icao(msg)
if icao not in self.acs:
continue
bds = pms.bds.infer(msg)
if bds == 'BDS50':
tas = pms.commb.tas50(msg)
if tas:
self.acs[icao]['t50'] = t
self.acs[icao]['tas'] = tas
elif bds == 'BDS60':
ias = pms.commb.ias60(msg)
hdg = pms.commb.hdg60(msg)
mach = pms.commb.mach60(msg)
if ias or hdg or mach:
self.acs[icao]['t60'] = t
if ias:
self.acs[icao]['ias'] = ias
if hdg:
self.acs[icao]['hdg'] = hdg
if mach:
self.acs[icao]['mach'] = mach
# clear up old data
for icao in list(self.acs.keys()):
if self.t - self.acs[icao]['live'] > self.cache_timeout:
del self.acs[icao]
continue
if self.cache_new_acs:
self.add_new_aircraft(local_updated_acs_buffer)
return
def get_aircraft(self):
"""all aircraft that are stored in memeory"""
acs = self.acs
icaos = list(acs.keys())
for icao in icaos:
if acs[icao]['lat'] is None:
acs.pop(icao)
return acs
def add_new_aircraft(self, acs):
"""add new aircraft to the list"""
self.__new_acs.update(acs)
return
def get_new_aircraft(self):
"""update aircraft from last iteration"""
newacs = dict()
for ac in self.__new_acs:
newacs[ac] = self.acs[ac]
return newacs
def reset_new_aircraft(self):
"""reset the updated icao buffer once been read"""
self.__new_acs = set()