reformat code with Black

This commit is contained in:
Junzi Sun
2019-09-10 23:25:21 +02:00
parent 695fc34988
commit 2c1db13122
29 changed files with 535 additions and 417 deletions
+1
View File
@@ -12,4 +12,5 @@ from .extra import tcpclient
# from .decoder import ehs # depricated # from .decoder import ehs # depricated
import os import os
dirpath = os.path.dirname(os.path.realpath(__file__)) dirpath = os.path.dirname(os.path.realpath(__file__))
+80 -45
View File
@@ -35,20 +35,32 @@ from pyModeS.decoder import common
from pyModeS.decoder import uncertainty from pyModeS.decoder import uncertainty
# from pyModeS.decoder.bds import bds05, bds06, bds09 # from pyModeS.decoder.bds import bds05, bds06, bds09
from pyModeS.decoder.bds.bds05 import airborne_position, airborne_position_with_ref, altitude from pyModeS.decoder.bds.bds05 import (
from pyModeS.decoder.bds.bds06 import surface_position, surface_position_with_ref, surface_velocity airborne_position,
airborne_position_with_ref,
altitude,
)
from pyModeS.decoder.bds.bds06 import (
surface_position,
surface_position_with_ref,
surface_velocity,
)
from pyModeS.decoder.bds.bds08 import category, callsign from pyModeS.decoder.bds.bds08 import category, callsign
from pyModeS.decoder.bds.bds09 import airborne_velocity, altitude_diff from pyModeS.decoder.bds.bds09 import airborne_velocity, altitude_diff
def df(msg): def df(msg):
return common.df(msg) return common.df(msg)
def icao(msg): def icao(msg):
return common.icao(msg) return common.icao(msg)
def typecode(msg): def typecode(msg):
return common.typecode(msg) return common.typecode(msg)
def position(msg0, msg1, t0, t1, lat_ref=None, lon_ref=None): def position(msg0, msg1, t0, t1, lat_ref=None, lon_ref=None):
"""Decode position from a pair of even and odd position message """Decode position from a pair of even and odd position message
(works with both airborne and surface position messages) (works with both airborne and surface position messages)
@@ -65,19 +77,21 @@ def position(msg0, msg1, t0, t1, lat_ref=None, lon_ref=None):
tc0 = typecode(msg0) tc0 = typecode(msg0)
tc1 = typecode(msg1) tc1 = typecode(msg1)
if (5<=tc0<=8 and 5<=tc1<=8): if 5 <= tc0 <= 8 and 5 <= tc1 <= 8:
if (not lat_ref) or (not lon_ref): if (not lat_ref) or (not lon_ref):
raise RuntimeError("Surface position encountered, a reference \ raise RuntimeError(
"Surface position encountered, a reference \
position lat/lon required. Location of \ position lat/lon required. Location of \
receiver can be used.") receiver can be used."
)
else: else:
return surface_position(msg0, msg1, t0, t1, lat_ref, lon_ref) return surface_position(msg0, msg1, t0, t1, lat_ref, lon_ref)
elif (9<=tc0<=18 and 9<=tc1<=18): elif 9 <= tc0 <= 18 and 9 <= tc1 <= 18:
# Airborne position with barometric height # Airborne position with barometric height
return airborne_position(msg0, msg1, t0, t1) return airborne_position(msg0, msg1, t0, t1)
elif (20<=tc0<=22 and 20<=tc1<=22): elif 20 <= tc0 <= 22 and 20 <= tc1 <= 22:
# Airborne position with GNSS height # Airborne position with GNSS height
return airborne_position(msg0, msg1, t0, t1) return airborne_position(msg0, msg1, t0, t1)
@@ -104,10 +118,10 @@ def position_with_ref(msg, lat_ref, lon_ref):
tc = typecode(msg) tc = typecode(msg)
if 5<=tc<=8: if 5 <= tc <= 8:
return surface_position_with_ref(msg, lat_ref, lon_ref) return surface_position_with_ref(msg, lat_ref, lon_ref)
elif 9<=tc<=18 or 20<=tc<=22: elif 9 <= tc <= 18 or 20 <= tc <= 22:
return airborne_position_with_ref(msg, lat_ref, lon_ref) return airborne_position_with_ref(msg, lat_ref, lon_ref)
else: else:
@@ -126,17 +140,17 @@ def altitude(msg):
tc = typecode(msg) tc = typecode(msg)
if tc<5 or tc==19 or tc>22: if tc < 5 or tc == 19 or tc > 22:
raise RuntimeError("%s: Not a position message" % msg) raise RuntimeError("%s: Not a position message" % msg)
if tc>=5 and tc<=8: if tc >= 5 and tc <= 8:
# surface position, altitude 0 # surface position, altitude 0
return 0 return 0
msgbin = common.hex2bin(msg) msgbin = common.hex2bin(msg)
q = msgbin[47] q = msgbin[47]
if q: if q:
n = common.bin2int(msgbin[40:47]+msgbin[48:52]) n = common.bin2int(msgbin[40:47] + msgbin[48:52])
alt = n * 25 - 1000 alt = n * 25 - 1000
return alt return alt
else: else:
@@ -175,7 +189,9 @@ def velocity(msg, rtn_sources=False):
return airborne_velocity(msg, rtn_sources) return airborne_velocity(msg, rtn_sources)
else: else:
raise RuntimeError("incorrect or inconsistant message types, expecting 4<TC<9 or TC=19") raise RuntimeError(
"incorrect or inconsistant message types, expecting 4<TC<9 or TC=19"
)
def speed_heading(msg): def speed_heading(msg):
@@ -215,7 +231,9 @@ def version(msg):
tc = typecode(msg) tc = typecode(msg)
if tc != 31: if tc != 31:
raise RuntimeError("%s: Not a status operation message, expecting TC = 31" % msg) raise RuntimeError(
"%s: Not a status operation message, expecting TC = 31" % msg
)
msgbin = common.hex2bin(msg) msgbin = common.hex2bin(msg)
version = common.bin2int(msgbin[72:75]) version = common.bin2int(msgbin[72:75])
@@ -241,18 +259,18 @@ def nuc_p(msg):
raise RuntimeError( raise RuntimeError(
"%s: Not a surface position message (5<TC<8), \ "%s: Not a surface position message (5<TC<8), \
airborne position message (8<TC<19), \ airborne position message (8<TC<19), \
or airborne position with GNSS height (20<TC<22)" % msg or airborne position with GNSS height (20<TC<22)"
% msg
) )
try: try:
NUCp = uncertainty.TC_NUCp_lookup[tc] NUCp = uncertainty.TC_NUCp_lookup[tc]
HPL = uncertainty.NUCp[NUCp]['HPL'] HPL = uncertainty.NUCp[NUCp]["HPL"]
RCu = uncertainty.NUCp[NUCp]['RCu'] RCu = uncertainty.NUCp[NUCp]["RCu"]
RCv = uncertainty.NUCp[NUCp]['RCv'] RCv = uncertainty.NUCp[NUCp]["RCv"]
except KeyError: except KeyError:
HPL, RCu, RCv = uncertainty.NA, uncertainty.NA, uncertainty.NA HPL, RCu, RCv = uncertainty.NA, uncertainty.NA, uncertainty.NA
if tc in [20, 21]: if tc in [20, 21]:
RCv = uncertainty.NA RCv = uncertainty.NA
@@ -272,15 +290,16 @@ def nuc_v(msg):
tc = typecode(msg) tc = typecode(msg)
if tc != 19: if tc != 19:
raise RuntimeError("%s: Not an airborne velocity message, expecting TC = 19" % msg) raise RuntimeError(
"%s: Not an airborne velocity message, expecting TC = 19" % msg
)
msgbin = common.hex2bin(msg) msgbin = common.hex2bin(msg)
NUCv = common.bin2int(msgbin[42:45]) NUCv = common.bin2int(msgbin[42:45])
try: try:
HVE = uncertainty.NUCv[NUCv]['HVE'] HVE = uncertainty.NUCv[NUCv]["HVE"]
VVE = uncertainty.NUCv[NUCv]['VVE'] VVE = uncertainty.NUCv[NUCv]["VVE"]
except KeyError: except KeyError:
HVE, VVE = uncertainty.NA, uncertainty.NA HVE, VVE = uncertainty.NA, uncertainty.NA
@@ -302,7 +321,8 @@ def nic_v1(msg, NICs):
raise RuntimeError( raise RuntimeError(
"%s: Not a surface position message (5<TC<8), \ "%s: Not a surface position message (5<TC<8), \
airborne position message (8<TC<19), \ airborne position message (8<TC<19), \
or airborne position with GNSS height (20<TC<22)" % msg or airborne position with GNSS height (20<TC<22)"
% msg
) )
tc = typecode(msg) tc = typecode(msg)
@@ -312,8 +332,8 @@ def nic_v1(msg, NICs):
NIC = NIC[NICs] NIC = NIC[NICs]
try: try:
Rc = uncertainty.NICv1[NIC][NICs]['Rc'] Rc = uncertainty.NICv1[NIC][NICs]["Rc"]
VPL = uncertainty.NICv1[NIC][NICs]['VPL'] VPL = uncertainty.NICv1[NIC][NICs]["VPL"]
except KeyError: except KeyError:
Rc, VPL = uncertainty.NA, uncertainty.NA Rc, VPL = uncertainty.NA, uncertainty.NA
@@ -335,22 +355,23 @@ def nic_v2(msg, NICa, NICbc):
raise RuntimeError( raise RuntimeError(
"%s: Not a surface position message (5<TC<8), \ "%s: Not a surface position message (5<TC<8), \
airborne position message (8<TC<19), \ airborne position message (8<TC<19), \
or airborne position with GNSS height (20<TC<22)" % msg or airborne position with GNSS height (20<TC<22)"
% msg
) )
tc = typecode(msg) tc = typecode(msg)
NIC = uncertainty.TC_NICv2_lookup[tc] NIC = uncertainty.TC_NICv2_lookup[tc]
if 20<=tc<=22: if 20 <= tc <= 22:
NICs = 0 NICs = 0
else: else:
NICs = NICa*2 + NICbc NICs = NICa * 2 + NICbc
try: try:
if isinstance(NIC, dict): if isinstance(NIC, dict):
NIC = NIC[NICs] NIC = NIC[NICs]
Rc = uncertainty.NICv2[NIC][NICs]['Rc'] Rc = uncertainty.NICv2[NIC][NICs]["Rc"]
except KeyError: except KeyError:
Rc = uncertainty.NA Rc = uncertainty.NA
@@ -369,7 +390,9 @@ def nic_s(msg):
tc = typecode(msg) tc = typecode(msg)
if tc != 31: if tc != 31:
raise RuntimeError("%s: Not a status operation message, expecting TC = 31" % msg) raise RuntimeError(
"%s: Not a status operation message, expecting TC = 31" % msg
)
msgbin = common.hex2bin(msg) msgbin = common.hex2bin(msg)
nic_s = int(msgbin[75]) nic_s = int(msgbin[75])
@@ -389,7 +412,9 @@ def nic_a_c(msg):
tc = typecode(msg) tc = typecode(msg)
if tc != 31: if tc != 31:
raise RuntimeError("%s: Not a status operation message, expecting TC = 31" % msg) raise RuntimeError(
"%s: Not a status operation message, expecting TC = 31" % msg
)
msgbin = common.hex2bin(msg) msgbin = common.hex2bin(msg)
nic_a = int(msgbin[75]) nic_a = int(msgbin[75])
@@ -410,7 +435,9 @@ def nic_b(msg):
tc = typecode(msg) tc = typecode(msg)
if tc < 9 or tc > 18: if tc < 9 or tc > 18:
raise RuntimeError("%s: Not a airborne position message, expecting 8<TC<19" % msg) raise RuntimeError(
"%s: Not a airborne position message, expecting 8<TC<19" % msg
)
msgbin = common.hex2bin(msg) msgbin = common.hex2bin(msg)
nic_b = int(msgbin[39]) nic_b = int(msgbin[39])
@@ -431,8 +458,11 @@ def nac_p(msg):
tc = typecode(msg) tc = typecode(msg)
if tc not in [29, 31]: if tc not in [29, 31]:
raise RuntimeError("%s: Not a target state and status message, \ raise RuntimeError(
or operation status message, expecting TC = 29 or 31" % msg) "%s: Not a target state and status message, \
or operation status message, expecting TC = 29 or 31"
% msg
)
msgbin = common.hex2bin(msg) msgbin = common.hex2bin(msg)
@@ -442,8 +472,8 @@ def nac_p(msg):
NACp = common.bin2int(msgbin[76:80]) NACp = common.bin2int(msgbin[76:80])
try: try:
EPU = uncertainty.NACp[NACp]['EPU'] EPU = uncertainty.NACp[NACp]["EPU"]
VEPU = uncertainty.NACp[NACp]['VEPU'] VEPU = uncertainty.NACp[NACp]["VEPU"]
except KeyError: except KeyError:
EPU, VEPU = uncertainty.NA, uncertainty.NA EPU, VEPU = uncertainty.NA, uncertainty.NA
@@ -463,14 +493,16 @@ def nac_v(msg):
tc = typecode(msg) tc = typecode(msg)
if tc != 19: if tc != 19:
raise RuntimeError("%s: Not an airborne velocity message, expecting TC = 19" % msg) raise RuntimeError(
"%s: Not an airborne velocity message, expecting TC = 19" % msg
)
msgbin = common.hex2bin(msg) msgbin = common.hex2bin(msg)
NACv = common.bin2int(msgbin[42:45]) NACv = common.bin2int(msgbin[42:45])
try: try:
HFOMr = uncertainty.NACv[NACv]['HFOMr'] HFOMr = uncertainty.NACv[NACv]["HFOMr"]
VFOMr = uncertainty.NACv[NACv]['VFOMr'] VFOMr = uncertainty.NACv[NACv]["VFOMr"]
except KeyError: except KeyError:
HFOMr, VFOMr = uncertainty.NA, uncertainty.NA HFOMr, VFOMr = uncertainty.NA, uncertainty.NA
@@ -491,8 +523,11 @@ def sil(msg, version):
tc = typecode(msg) tc = typecode(msg)
if tc not in [29, 31]: if tc not in [29, 31]:
raise RuntimeError("%s: Not a target state and status messag, \ raise RuntimeError(
or operation status message, expecting TC = 29 or 31" % msg) "%s: Not a target state and status messag, \
or operation status message, expecting TC = 29 or 31"
% msg
)
msgbin = common.hex2bin(msg) msgbin = common.hex2bin(msg)
@@ -502,12 +537,12 @@ def sil(msg, version):
SIL = common.bin2int(msgbin[82:84]) SIL = common.bin2int(msgbin[82:84])
try: try:
PE_RCu = uncertainty.SIL[SIL]['PE_RCu'] PE_RCu = uncertainty.SIL[SIL]["PE_RCu"]
PE_VPL = uncertainty.SIL[SIL]['PE_VPL'] PE_VPL = uncertainty.SIL[SIL]["PE_VPL"]
except KeyError: except KeyError:
PE_RCu, PE_VPL = uncertainty.NA, uncertainty.NA PE_RCu, PE_VPL = uncertainty.NA, uncertainty.NA
base = 'unknown' base = "unknown"
if version == 2: if version == 2:
if tc == 29: if tc == 29:
+52 -25
View File
@@ -23,8 +23,22 @@ import numpy as np
from pyModeS.extra import aero from pyModeS.extra import aero
from pyModeS.decoder import common from pyModeS.decoder import common
from pyModeS.decoder.bds import bds05, bds06, bds08, bds09, \ from pyModeS.decoder.bds import (
bds10, bds17, bds20, bds30, bds40, bds44, bds45, bds50, bds53, bds60 bds05,
bds06,
bds08,
bds09,
bds10,
bds17,
bds20,
bds30,
bds40,
bds44,
bds45,
bds50,
bds53,
bds60,
)
def is50or60(msg, spd_ref, trk_ref, alt_ref): def is50or60(msg, spd_ref, trk_ref, alt_ref):
@@ -40,6 +54,7 @@ def is50or60(msg, spd_ref, trk_ref, alt_ref):
String or None: BDS version, or possible versions, or None if nothing matches. String or None: BDS version, or possible versions, or None if nothing matches.
""" """
def vxy(v, angle): def vxy(v, angle):
vx = v * np.sin(np.radians(angle)) vx = v * np.sin(np.radians(angle))
vy = v * np.cos(np.radians(angle)) vy = v * np.cos(np.radians(angle))
@@ -52,26 +67,26 @@ def is50or60(msg, spd_ref, trk_ref, alt_ref):
v50 = bds50.gs50(msg) v50 = bds50.gs50(msg)
if h50 is None or v50 is None: if h50 is None or v50 is None:
return 'BDS50,BDS60' return "BDS50,BDS60"
h60 = bds60.hdg60(msg) h60 = bds60.hdg60(msg)
m60 = bds60.mach60(msg) m60 = bds60.mach60(msg)
i60 = bds60.ias60(msg) i60 = bds60.ias60(msg)
if h60 is None or (m60 is None and i60 is None): if h60 is None or (m60 is None and i60 is None):
return 'BDS50,BDS60' return "BDS50,BDS60"
m60 = np.nan if m60 is None else m60 m60 = np.nan if m60 is None else m60
i60 = np.nan if i60 is None else i60 i60 = np.nan if i60 is None else i60
XY5 = vxy(v50*aero.kts, h50) XY5 = vxy(v50 * aero.kts, h50)
XY6m = vxy(aero.mach2tas(m60, alt_ref*aero.ft), h60) XY6m = vxy(aero.mach2tas(m60, alt_ref * aero.ft), h60)
XY6i = vxy(aero.cas2tas(i60*aero.kts, alt_ref*aero.ft), h60) XY6i = vxy(aero.cas2tas(i60 * aero.kts, alt_ref * aero.ft), h60)
allbds = ['BDS50', 'BDS60', 'BDS60'] allbds = ["BDS50", "BDS60", "BDS60"]
X = np.array([XY5, XY6m, XY6i]) X = np.array([XY5, XY6m, XY6i])
Mu = np.array(vxy(spd_ref*aero.kts, trk_ref)) Mu = np.array(vxy(spd_ref * aero.kts, trk_ref))
# compute Mahalanobis distance matrix # compute Mahalanobis distance matrix
# Cov = [[20**2, 0], [0, 20**2]] # Cov = [[20**2, 0], [0, 20**2]]
@@ -81,10 +96,10 @@ def is50or60(msg, spd_ref, trk_ref, alt_ref):
# since the covariance matrix is identity matrix, # since the covariance matrix is identity matrix,
# M-dist is same as eculidian distance # M-dist is same as eculidian distance
try: try:
dist = np.linalg.norm(X-Mu, axis=1) dist = np.linalg.norm(X - Mu, axis=1)
BDS = allbds[np.nanargmin(dist)] BDS = allbds[np.nanargmin(dist)]
except ValueError: except ValueError:
return 'BDS50,BDS60' return "BDS50,BDS60"
return BDS return BDS
@@ -103,28 +118,28 @@ def infer(msg, mrar=False):
df = common.df(msg) df = common.df(msg)
if common.allzeros(msg): if common.allzeros(msg):
return 'EMPTY' return "EMPTY"
# For ADS-B / Mode-S extended squitter # For ADS-B / Mode-S extended squitter
if df == 17: if df == 17:
tc = common.typecode(msg) tc = common.typecode(msg)
if 1 <= tc <= 4: if 1 <= tc <= 4:
return 'BDS08' # indentification and category return "BDS08" # indentification and category
if 5 <= tc <= 8: if 5 <= tc <= 8:
return 'BDS06' # surface movement return "BDS06" # surface movement
if 9 <= tc <= 18: if 9 <= tc <= 18:
return 'BDS05' # airborne position, baro-alt return "BDS05" # airborne position, baro-alt
if tc == 19: if tc == 19:
return 'BDS09' # airborne velocity return "BDS09" # airborne velocity
if 20 <= tc <= 22: if 20 <= tc <= 22:
return 'BDS05' # airborne position, gnss-alt return "BDS05" # airborne position, gnss-alt
if tc == 28: if tc == 28:
return 'BDS61' # aircraft status return "BDS61" # aircraft status
if tc == 29: if tc == 29:
return 'BDS62' # target state and status return "BDS62" # target state and status
if tc == 31: if tc == 31:
return 'BDS65' # operational status return "BDS65" # operational status
# For Comm-B replies # For Comm-B replies
IS10 = bds10.is10(msg) IS10 = bds10.is10(msg)
@@ -138,15 +153,27 @@ def infer(msg, mrar=False):
IS45 = bds45.is45(msg) IS45 = bds45.is45(msg)
if mrar: if mrar:
allbds = np.array(["BDS10", "BDS17", "BDS20", "BDS30", "BDS40", allbds = np.array(
"BDS44", "BDS45", "BDS50", "BDS60"]) [
"BDS10",
"BDS17",
"BDS20",
"BDS30",
"BDS40",
"BDS44",
"BDS45",
"BDS50",
"BDS60",
]
)
mask = [IS10, IS17, IS20, IS30, IS40, IS44, IS45, IS50, IS60] mask = [IS10, IS17, IS20, IS30, IS40, IS44, IS45, IS50, IS60]
else: else:
allbds = np.array(["BDS10", "BDS17", "BDS20", "BDS30", "BDS40", allbds = np.array(
"BDS50", "BDS60"]) ["BDS10", "BDS17", "BDS20", "BDS30", "BDS40", "BDS50", "BDS60"]
)
mask = [IS10, IS17, IS20, IS30, IS40, IS50, IS60] mask = [IS10, IS17, IS20, IS30, IS40, IS50, IS60]
bds = ','.join(sorted(allbds[mask])) bds = ",".join(sorted(allbds[mask]))
if len(bds) == 0: if len(bds) == 0:
return None return None
+14 -13
View File
@@ -73,17 +73,17 @@ def surface_position(msg0, msg1, t0, t1, lat_ref, lon_ref):
return None return None
# compute ni, longitude index m, and longitude # compute ni, longitude index m, and longitude
if (t0 > t1): if t0 > t1:
lat = lat_even lat = lat_even
nl = common.cprNL(lat_even) nl = common.cprNL(lat_even)
ni = max(common.cprNL(lat_even) - 0, 1) ni = max(common.cprNL(lat_even) - 0, 1)
m = common.floor(cprlon_even * (nl-1) - cprlon_odd * nl + 0.5) m = common.floor(cprlon_even * (nl - 1) - cprlon_odd * nl + 0.5)
lon = (90.0 / ni) * (m % ni + cprlon_even) lon = (90.0 / ni) * (m % ni + cprlon_even)
else: else:
lat = lat_odd lat = lat_odd
nl = common.cprNL(lat_odd) nl = common.cprNL(lat_odd)
ni = max(common.cprNL(lat_odd) - 1, 1) ni = max(common.cprNL(lat_odd) - 1, 1)
m = common.floor(cprlon_even * (nl-1) - cprlon_odd * nl + 0.5) m = common.floor(cprlon_even * (nl - 1) - cprlon_odd * nl + 0.5)
lon = (90.0 / ni) * (m % ni + cprlon_odd) lon = (90.0 / ni) * (m % ni + cprlon_odd)
# four possible longitude solutions # four possible longitude solutions
@@ -112,17 +112,17 @@ def surface_position_with_ref(msg, lat_ref, lon_ref):
(float, float): (latitude, longitude) of the aircraft (float, float): (latitude, longitude) of the aircraft
""" """
mb = common.hex2bin(msg)[32:] mb = common.hex2bin(msg)[32:]
cprlat = common.bin2int(mb[22:39]) / 131072.0 cprlat = common.bin2int(mb[22:39]) / 131072.0
cprlon = common.bin2int(mb[39:56]) / 131072.0 cprlon = common.bin2int(mb[39:56]) / 131072.0
i = int(mb[21]) i = int(mb[21])
d_lat = 90.0/59 if i else 90.0/60 d_lat = 90.0 / 59 if i else 90.0 / 60
j = common.floor(lat_ref / d_lat) \ j = common.floor(lat_ref / d_lat) + common.floor(
+ common.floor(0.5 + ((lat_ref % d_lat) / d_lat) - cprlat) 0.5 + ((lat_ref % d_lat) / d_lat) - cprlat
)
lat = d_lat * (j + cprlat) lat = d_lat * (j + cprlat)
@@ -133,8 +133,9 @@ def surface_position_with_ref(msg, lat_ref, lon_ref):
else: else:
d_lon = 90.0 d_lon = 90.0
m = common.floor(lon_ref / d_lon) \ m = common.floor(lon_ref / d_lon) + common.floor(
+ common.floor(0.5 + ((lon_ref % d_lon) / d_lon) - cprlon) 0.5 + ((lon_ref % d_lon) / d_lon) - cprlon
)
lon = d_lon * (m + cprlon) lon = d_lon * (m + cprlon)
@@ -184,11 +185,11 @@ def surface_velocity(msg, rtn_sources=False):
movs = [2, 9, 13, 39, 94, 109, 124] movs = [2, 9, 13, 39, 94, 109, 124]
kts = [0.125, 1, 2, 15, 70, 100, 175] kts = [0.125, 1, 2, 15, 70, 100, 175]
i = next(m[0] for m in enumerate(movs) if m[1] > mov) i = next(m[0] for m in enumerate(movs) if m[1] > mov)
step = (kts[i] - kts[i-1]) * 1.0 / (movs[i]-movs[i-1]) step = (kts[i] - kts[i - 1]) * 1.0 / (movs[i] - movs[i - 1])
spd = kts[i-1] + (mov-movs[i-1]) * step spd = kts[i - 1] + (mov - movs[i - 1]) * step
spd = round(spd, 2) spd = round(spd, 2)
if rtn_sources: if rtn_sources:
return spd, trk, 0, 'GS', 'true_north', None return spd, trk, 0, "GS", "true_north", None
else: else:
return spd, trk, 0, 'GS' return spd, trk, 0, "GS"
+6 -5
View File
@@ -23,6 +23,7 @@
from __future__ import absolute_import, print_function, division from __future__ import absolute_import, print_function, division
from pyModeS.decoder import common from pyModeS.decoder import common
def category(msg): def category(msg):
"""Aircraft category number """Aircraft category number
@@ -36,8 +37,8 @@ def category(msg):
if common.typecode(msg) < 1 or common.typecode(msg) > 4: if common.typecode(msg) < 1 or common.typecode(msg) > 4:
raise RuntimeError("%s: Not a identification message" % msg) raise RuntimeError("%s: Not a identification message" % msg)
msgbin = common.hex2bin(msg) msgbin = common.hex2bin(msg)
mebin = msgbin[32:87] mebin = msgbin[32:87]
return common.bin2int(mebin[5:8]) return common.bin2int(mebin[5:8])
@@ -54,11 +55,11 @@ def callsign(msg):
if common.typecode(msg) < 1 or common.typecode(msg) > 4: if common.typecode(msg) < 1 or common.typecode(msg) > 4:
raise RuntimeError("%s: Not a identification message" % msg) raise RuntimeError("%s: Not a identification message" % msg)
chars = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ#####_###############0123456789######' chars = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ#####_###############0123456789######"
msgbin = common.hex2bin(msg) msgbin = common.hex2bin(msg)
csbin = msgbin[40:96] csbin = msgbin[40:96]
cs = '' cs = ""
cs += chars[common.bin2int(csbin[0:6])] cs += chars[common.bin2int(csbin[0:6])]
cs += chars[common.bin2int(csbin[6:12])] cs += chars[common.bin2int(csbin[6:12])]
cs += chars[common.bin2int(csbin[12:18])] cs += chars[common.bin2int(csbin[12:18])]
@@ -70,5 +71,5 @@ def callsign(msg):
# clean string, remove spaces and marks, if any. # clean string, remove spaces and marks, if any.
# cs = cs.replace('_', '') # cs = cs.replace('_', '')
cs = cs.replace('#', '') cs = cs.replace("#", "")
return cs return cs
+24 -24
View File
@@ -57,32 +57,32 @@ def airborne_velocity(msg, rtn_sources=False):
return None return None
if subtype in (1, 2): if subtype in (1, 2):
v_ew_sign = -1 if mb[13]=='1' else 1 v_ew_sign = -1 if mb[13] == "1" else 1
v_ew = common.bin2int(mb[14:24]) - 1 # east-west velocity v_ew = common.bin2int(mb[14:24]) - 1 # east-west velocity
if subtype == 2: # Supersonic if subtype == 2: # Supersonic
v_ew *= 4 v_ew *= 4
v_ns_sign = -1 if mb[24]=='1' else 1 v_ns_sign = -1 if mb[24] == "1" else 1
v_ns = common.bin2int(mb[25:35]) - 1 # north-south velocity v_ns = common.bin2int(mb[25:35]) - 1 # north-south velocity
if subtype == 2: # Supersonic if subtype == 2: # Supersonic
v_ns *= 4 v_ns *= 4
v_we = v_ew_sign * v_ew v_we = v_ew_sign * v_ew
v_sn = v_ns_sign * v_ns v_sn = v_ns_sign * v_ns
spd = math.sqrt(v_sn*v_sn + v_we*v_we) # unit in kts spd = math.sqrt(v_sn * v_sn + v_we * v_we) # unit in kts
spd = int(spd) spd = int(spd)
trk = math.atan2(v_we, v_sn) trk = math.atan2(v_we, v_sn)
trk = math.degrees(trk) # convert to degrees trk = math.degrees(trk) # convert to degrees
trk = trk if trk >= 0 else trk + 360 # no negative val trk = trk if trk >= 0 else trk + 360 # no negative val
tag = 'GS' tag = "GS"
trk_or_hdg = round(trk, 2) trk_or_hdg = round(trk, 2)
dir_type = 'true_north' dir_type = "true_north"
else: else:
if mb[13] == '0': if mb[13] == "0":
hdg = None hdg = None
else: else:
hdg = common.bin2int(mb[14:24]) / 1024.0 * 360.0 hdg = common.bin2int(mb[14:24]) / 1024.0 * 360.0
@@ -91,27 +91,27 @@ def airborne_velocity(msg, rtn_sources=False):
trk_or_hdg = hdg trk_or_hdg = hdg
spd = common.bin2int(mb[25:35]) spd = common.bin2int(mb[25:35])
spd = None if spd==0 else spd-1 spd = None if spd == 0 else spd - 1
if subtype == 4: # Supersonic if subtype == 4: # Supersonic
spd *= 4 spd *= 4
if mb[24]=='0': if mb[24] == "0":
tag = 'IAS' tag = "IAS"
else: else:
tag = 'TAS' tag = "TAS"
dir_type = 'mag_north'
vr_source = 'GNSS' if mb[35]=='0' else 'Baro' dir_type = "mag_north"
vr_sign = -1 if mb[36]=='1' else 1
vr_source = "GNSS" if mb[35] == "0" else "Baro"
vr_sign = -1 if mb[36] == "1" else 1
vr = common.bin2int(mb[37:46]) vr = common.bin2int(mb[37:46])
rocd = None if vr==0 else int(vr_sign*(vr-1)*64) rocd = None if vr == 0 else int(vr_sign * (vr - 1) * 64)
if rtn_sources: if rtn_sources:
return spd, trk_or_hdg, rocd, tag, dir_type, vr_source return spd, trk_or_hdg, rocd, tag, dir_type, vr_source
else: else:
return spd, trk_or_hdg, rocd, tag return spd, trk_or_hdg, rocd, tag
def altitude_diff(msg): def altitude_diff(msg):
"""Decode the differece between GNSS and barometric altitude """Decode the differece between GNSS and barometric altitude
@@ -135,4 +135,4 @@ def altitude_diff(msg):
if value == 0 or value == 127: if value == 0 or value == 127:
return None return None
else: else:
return sign * (value - 1) * 25 # in ft. return sign * (value - 1) * 25 # in ft.
+5 -3
View File
@@ -21,6 +21,7 @@
from __future__ import absolute_import, print_function, division from __future__ import absolute_import, print_function, division
from pyModeS.decoder.common import hex2bin, bin2int, data, allzeros from pyModeS.decoder.common import hex2bin, bin2int, data, allzeros
def is10(msg): def is10(msg):
"""Check if a message is likely to be BDS code 1,0 """Check if a message is likely to be BDS code 1,0
@@ -37,7 +38,7 @@ def is10(msg):
d = hex2bin(data(msg)) d = hex2bin(data(msg))
# first 8 bits must be 0x10 # first 8 bits must be 0x10
if d[0:8] != '00010000': if d[0:8] != "00010000":
return False return False
# bit 10 to 14 are reserved # bit 10 to 14 are reserved
@@ -45,13 +46,14 @@ def is10(msg):
return False return False
# overlay capabilty conflict # overlay capabilty conflict
if d[14] == '1' and bin2int(d[16:23]) < 5: if d[14] == "1" and bin2int(d[16:23]) < 5:
return False return False
if d[14] == '0' and bin2int(d[16:23]) > 4: if d[14] == "0" and bin2int(d[16:23]) > 4:
return False return False
return True return True
def ovc10(msg): def ovc10(msg):
"""Return the overlay control capability """Return the overlay control capability
+34 -6
View File
@@ -50,11 +50,12 @@ def is17(msg):
# return False # return False
# at least you can respond who you are # at least you can respond who you are
if 'BDS20' not in caps: if "BDS20" not in caps:
return False return False
return True return True
def cap17(msg): def cap17(msg):
"""Extract capacities from BDS 1,7 message """Extract capacities from BDS 1,7 message
@@ -64,12 +65,39 @@ def cap17(msg):
Returns: Returns:
list: list of suport BDS codes list: list of suport BDS codes
""" """
allbds = ['05', '06', '07', '08', '09', '0A', '20', '21', '40', '41', allbds = [
'42', '43', '44', '45', '48', '50', '51', '52', '53', '54', "05",
'55', '56', '5F', '60', 'NA', 'NA', 'E1', 'E2'] "06",
"07",
"08",
"09",
"0A",
"20",
"21",
"40",
"41",
"42",
"43",
"44",
"45",
"48",
"50",
"51",
"52",
"53",
"54",
"55",
"56",
"5F",
"60",
"NA",
"NA",
"E1",
"E2",
]
d = hex2bin(data(msg)) d = hex2bin(data(msg))
idx = [i for i, v in enumerate(d[:28]) if v=='1'] idx = [i for i, v in enumerate(d[:28]) if v == "1"]
capacity = ['BDS'+allbds[i] for i in idx if allbds[i] is not 'NA'] capacity = ["BDS" + allbds[i] for i in idx if allbds[i] is not "NA"]
return capacity return capacity
+5 -4
View File
@@ -21,6 +21,7 @@
from __future__ import absolute_import, print_function, division from __future__ import absolute_import, print_function, division
from pyModeS.decoder.common import hex2bin, bin2int, data, allzeros from pyModeS.decoder.common import hex2bin, bin2int, data, allzeros
def is20(msg): def is20(msg):
"""Check if a message is likely to be BDS code 2,0 """Check if a message is likely to be BDS code 2,0
@@ -36,12 +37,12 @@ def is20(msg):
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[0:8] != '00100000': if d[0:8] != "00100000":
return False return False
cs = cs20(msg) cs = cs20(msg)
if '#' in cs: if "#" in cs:
return False return False
return True return True
@@ -56,11 +57,11 @@ def cs20(msg):
Returns: Returns:
string: callsign, max. 8 chars string: callsign, max. 8 chars
""" """
chars = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ#####_###############0123456789######' chars = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ#####_###############0123456789######"
d = hex2bin(data(msg)) d = hex2bin(data(msg))
cs = '' cs = ""
cs += chars[bin2int(d[8:14])] cs += chars[bin2int(d[8:14])]
cs += chars[bin2int(d[14:20])] cs += chars[bin2int(d[14:20])]
cs += chars[bin2int(d[20:26])] cs += chars[bin2int(d[20:26])]
+3 -2
View File
@@ -21,6 +21,7 @@
from __future__ import absolute_import, print_function, division from __future__ import absolute_import, print_function, division
from pyModeS.decoder.common import hex2bin, bin2int, data, allzeros from pyModeS.decoder.common import hex2bin, bin2int, data, allzeros
def is30(msg): def is30(msg):
"""Check if a message is likely to be BDS code 2,0 """Check if a message is likely to be BDS code 2,0
@@ -36,11 +37,11 @@ def is30(msg):
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[0:8] != '00110000': if d[0:8] != "00110000":
return False return False
# threat type 3 not assigned # threat type 3 not assigned
if d[28:30] == '11': if d[28:30] == "11":
return False return False
# reserved for ACAS III, in far future # reserved for ACAS III, in far future
+1 -7
View File
@@ -19,13 +19,7 @@
# ------------------------------------------ # ------------------------------------------
from __future__ import absolute_import, print_function, division from __future__ import absolute_import, print_function, division
from pyModeS.decoder.common import ( from pyModeS.decoder.common import hex2bin, bin2int, data, allzeros, wrongstatus
hex2bin,
bin2int,
data,
allzeros,
wrongstatus,
)
def is44(msg): def is44(msg):
+9 -9
View File
@@ -87,7 +87,7 @@ def turb45(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[0] == '0': if d[0] == "0":
return None return None
turb = bin2int(d[1:3]) turb = bin2int(d[1:3])
@@ -105,7 +105,7 @@ def ws45(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[3] == '0': if d[3] == "0":
return None return None
ws = bin2int(d[4:6]) ws = bin2int(d[4:6])
@@ -123,7 +123,7 @@ def mb45(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[6] == '0': if d[6] == "0":
return None return None
mb = bin2int(d[7:9]) mb = bin2int(d[7:9])
@@ -141,7 +141,7 @@ def ic45(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[9] == '0': if d[9] == "0":
return None return None
ic = bin2int(d[10:12]) ic = bin2int(d[10:12])
@@ -159,7 +159,7 @@ def wv45(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[12] == '0': if d[12] == "0":
return None return None
ws = bin2int(d[13:15]) ws = bin2int(d[13:15])
@@ -184,7 +184,7 @@ def temp45(msg):
if sign: if sign:
value = value - 512 value = value - 512
temp = value * 0.25 # celsius temp = value * 0.25 # celsius
temp = round(temp, 1) temp = round(temp, 1)
return temp return temp
@@ -201,9 +201,9 @@ def p45(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[26] == '0': if d[26] == "0":
return None return None
p = bin2int(d[27:38]) # hPa p = bin2int(d[27:38]) # hPa
return p return p
@@ -218,7 +218,7 @@ def rh45(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[38] == '0': if d[38] == "0":
return None return None
rh = bin2int(d[39:51]) * 16 rh = bin2int(d[39:51]) * 16
return rh return rh
+12 -12
View File
@@ -85,16 +85,16 @@ def roll50(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[0] == '0': if d[0] == "0":
return None return None
sign = int(d[1]) # 1 -> left wing down sign = int(d[1]) # 1 -> left wing down
value = bin2int(d[2:11]) value = bin2int(d[2:11])
if sign: if sign:
value = value - 512 value = value - 512
angle = value * 45.0 / 256.0 # degree angle = value * 45.0 / 256.0 # degree
return round(angle, 1) return round(angle, 1)
@@ -109,10 +109,10 @@ def trk50(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[11] == '0': if d[11] == "0":
return None return None
sign = int(d[12]) # 1 -> west sign = int(d[12]) # 1 -> west
value = bin2int(d[13:23]) value = bin2int(d[13:23])
if sign: if sign:
@@ -138,10 +138,10 @@ def gs50(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[23] == '0': if d[23] == "0":
return None return None
spd = bin2int(d[24:34]) * 2 # kts spd = bin2int(d[24:34]) * 2 # kts
return spd return spd
@@ -156,18 +156,18 @@ def rtrk50(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[34] == '0': if d[34] == "0":
return None return None
if d[36:45] == "111111111": if d[36:45] == "111111111":
return None return None
sign = int(d[35]) # 1 -> negative value, two's complement sign = int(d[35]) # 1 -> negative value, two's complement
value = bin2int(d[36:45]) value = bin2int(d[36:45])
if sign: if sign:
value = value - 512 value = value - 512
angle = value * 8.0 / 256.0 # degree / sec angle = value * 8.0 / 256.0 # degree / sec
return round(angle, 3) return round(angle, 3)
@@ -182,8 +182,8 @@ def tas50(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[45] == '0': if d[45] == "0":
return None return None
tas = bin2int(d[46:56]) * 2 # kts tas = bin2int(d[46:56]) * 2 # kts
return tas return tas
+12 -11
View File
@@ -85,16 +85,16 @@ def hdg53(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[0] == '0': if d[0] == "0":
return None return None
sign = int(d[1]) # 1 -> west sign = int(d[1]) # 1 -> west
value = bin2int(d[2:12]) value = bin2int(d[2:12])
if sign: if sign:
value = value - 1024 value = value - 1024
hdg = value * 90.0 / 512.0 # degree hdg = value * 90.0 / 512.0 # degree
# convert from [-180, 180] to [0, 360] # convert from [-180, 180] to [0, 360]
if hdg < 0: if hdg < 0:
@@ -114,10 +114,10 @@ def ias53(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[12] == '0': if d[12] == "0":
return None return None
ias = bin2int(d[13:23]) # knots ias = bin2int(d[13:23]) # knots
return ias return ias
@@ -132,7 +132,7 @@ def mach53(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[23] == '0': if d[23] == "0":
return None return None
mach = bin2int(d[24:33]) * 0.008 mach = bin2int(d[24:33]) * 0.008
@@ -150,12 +150,13 @@ def tas53(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[33] == '0': if d[33] == "0":
return None return None
tas = bin2int(d[34:46]) * 0.5 # kts tas = bin2int(d[34:46]) * 0.5 # kts
return round(tas, 1) return round(tas, 1)
def vr53(msg): def vr53(msg):
"""Vertical rate """Vertical rate
@@ -167,16 +168,16 @@ def vr53(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[46] == '0': if d[46] == "0":
return None return None
sign = int(d[47]) # 1 -> negative value, two's complement sign = int(d[47]) # 1 -> negative value, two's complement
value = bin2int(d[48:56]) value = bin2int(d[48:56])
if value == 0 or value == 255: # all zeros or all ones if value == 0 or value == 255: # all zeros or all ones
return 0 return 0
value = value - 256 if sign else value value = value - 256 if sign else value
roc = value * 64 # feet/min roc = value * 64 # feet/min
return roc return roc
+12 -11
View File
@@ -21,6 +21,7 @@
from __future__ import absolute_import, print_function, division from __future__ import absolute_import, print_function, division
from pyModeS.decoder.common import hex2bin, bin2int, data, allzeros, wrongstatus from pyModeS.decoder.common import hex2bin, bin2int, data, allzeros, wrongstatus
def is60(msg): def is60(msg):
"""Check if a message is likely to be BDS code 6,0 """Check if a message is likely to be BDS code 6,0
@@ -83,10 +84,10 @@ def hdg60(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[0] == '0': if d[0] == "0":
return None return None
sign = int(d[1]) # 1 -> west sign = int(d[1]) # 1 -> west
value = bin2int(d[2:12]) value = bin2int(d[2:12])
if sign: if sign:
@@ -112,10 +113,10 @@ def ias60(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[12] == '0': if d[12] == "0":
return None return None
ias = bin2int(d[13:23]) # kts ias = bin2int(d[13:23]) # kts
return ias return ias
@@ -130,7 +131,7 @@ def mach60(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[23] == '0': if d[23] == "0":
return None return None
mach = bin2int(d[24:34]) * 2.048 / 512.0 mach = bin2int(d[24:34]) * 2.048 / 512.0
@@ -148,10 +149,10 @@ def vr60baro(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[34] == '0': if d[34] == "0":
return None return None
sign = int(d[35]) # 1 -> negative value, two's complement sign = int(d[35]) # 1 -> negative value, two's complement
value = bin2int(d[36:45]) value = bin2int(d[36:45])
if value == 0 or value == 511: # all zeros or all ones if value == 0 or value == 511: # all zeros or all ones
@@ -159,7 +160,7 @@ def vr60baro(msg):
value = value - 512 if sign else value value = value - 512 if sign else value
roc = value * 32 # feet/min roc = value * 32 # feet/min
return roc return roc
@@ -174,10 +175,10 @@ def vr60ins(msg):
""" """
d = hex2bin(data(msg)) d = hex2bin(data(msg))
if d[45] == '0': if d[45] == "0":
return None return None
sign = int(d[46]) # 1 -> negative value, two's complement sign = int(d[46]) # 1 -> negative value, two's complement
value = bin2int(d[47:56]) value = bin2int(d[47:56])
if value == 0 or value == 511: # all zeros or all ones if value == 0 or value == 511: # all zeros or all ones
@@ -185,5 +186,5 @@ def vr60ins(msg):
value = value - 512 if sign else value value = value - 512 if sign else value
roc = value * 32 # feet/min roc = value * 32 # feet/min
return roc return roc
+2 -33
View File
@@ -61,12 +61,7 @@ def crc(msg, encode=False):
""" """
# the CRC generator # the CRC generator
G = [ G = [int("11111111", 2), int("11111010", 2), int("00000100", 2), int("10000000", 2)]
int("11111111", 2),
int("11111010", 2),
int("00000100", 2),
int("10000000", 2),
]
if encode: if encode:
msg = msg[:-6] + "000000" msg = msg[:-6] + "000000"
@@ -101,33 +96,7 @@ def crc_legacy(msg, encode=False):
"""Mode-S Cyclic Redundancy Check. (Legacy code, 2x slow).""" """Mode-S Cyclic Redundancy Check. (Legacy code, 2x slow)."""
# the polynominal generattor code for CRC [1111111111111010000001001] # the polynominal generattor code for CRC [1111111111111010000001001]
generator = np.array( generator = np.array(
[ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1]
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
0,
1,
0,
0,
0,
0,
0,
0,
1,
0,
0,
1,
]
) )
ng = len(generator) ng = len(generator)
+1
View File
@@ -0,0 +1 @@
import pyModeS as pms
+10 -3
View File
@@ -17,13 +17,20 @@ from pyModeS.decoder.bds.bds50 import *
from pyModeS.decoder.bds.bds60 import * from pyModeS.decoder.bds.bds60 import *
from pyModeS.decoder.bds import infer from pyModeS.decoder.bds import infer
warnings.simplefilter('once', DeprecationWarning) warnings.simplefilter("once", DeprecationWarning)
warnings.warn("pms.ehs module is deprecated. Please use pms.commb instead.", DeprecationWarning) warnings.warn(
"pms.ehs module is deprecated. Please use pms.commb instead.", DeprecationWarning
)
def BDS(msg): def BDS(msg):
warnings.warn("pms.ehs.BDS() is deprecated, use pms.bds.infer() instead.", DeprecationWarning) warnings.warn(
"pms.ehs.BDS() is deprecated, use pms.bds.infer() instead.", DeprecationWarning
)
return infer(msg) return infer(msg)
def icao(msg): def icao(msg):
from pyModeS.decoder.common import icao from pyModeS.decoder.common import icao
return icao(msg) return icao(msg)
+5 -2
View File
@@ -18,5 +18,8 @@ from pyModeS.decoder.bds.bds20 import *
from pyModeS.decoder.bds.bds30 import * from pyModeS.decoder.bds.bds30 import *
import warnings import warnings
warnings.simplefilter('once', DeprecationWarning)
warnings.warn("pms.els module is deprecated. Please use pms.commb instead.", DeprecationWarning) warnings.simplefilter("once", DeprecationWarning)
warnings.warn(
"pms.els module is deprecated. Please use pms.commb instead.", DeprecationWarning
)
+112 -85
View File
@@ -6,120 +6,147 @@ See source code at: https://github.com/junzis/pyModeS/blob/master/pyModeS/decode
NA = None NA = None
TC_NUCp_lookup = { TC_NUCp_lookup = {
0:0, 5:9, 6:8, 7:7, 8:6, 0: 0,
9:9, 10:8, 11:7, 12:6, 13:5, 14:4, 15:3, 16:2, 17:1, 18:0, 5: 9,
20:9, 21:8, 22:0 6: 8,
7: 7,
8: 6,
9: 9,
10: 8,
11: 7,
12: 6,
13: 5,
14: 4,
15: 3,
16: 2,
17: 1,
18: 0,
20: 9,
21: 8,
22: 0,
} }
TC_NICv1_lookup = { TC_NICv1_lookup = {
5:11, 6:10, 7:9, 8:0, 5: 11,
9:11, 10:10, 11:{1:9, 0:8}, 12:7, 13:6, 14:5, 15:4, 16:{1:3, 0:2}, 17:1, 18:0, 6: 10,
20:11, 21:10, 22:0 7: 9,
8: 0,
9: 11,
10: 10,
11: {1: 9, 0: 8},
12: 7,
13: 6,
14: 5,
15: 4,
16: {1: 3, 0: 2},
17: 1,
18: 0,
20: 11,
21: 10,
22: 0,
} }
TC_NICv2_lookup = { TC_NICv2_lookup = {
5:11, 6:10, 7:{2:9, 0:8}, 8:{3:7, 2:6, 1:6, 0:0}, 5: 11,
9:11, 10:10, 11:{3:9, 0:8}, 12:7, 13:6, 14:5, 15:4, 16:{3:3, 0:2}, 17:1, 18:0, 6: 10,
20:11, 21:10, 22:0 7: {2: 9, 0: 8},
8: {3: 7, 2: 6, 1: 6, 0: 0},
9: 11,
10: 10,
11: {3: 9, 0: 8},
12: 7,
13: 6,
14: 5,
15: 4,
16: {3: 3, 0: 2},
17: 1,
18: 0,
20: 11,
21: 10,
22: 0,
} }
NUCp = { NUCp = {
9: {'HPL':7.5, 'RCu':3, 'RCv':4}, 9: {"HPL": 7.5, "RCu": 3, "RCv": 4},
8: {'HPL':25, 'RCu':10, 'RCv':15}, 8: {"HPL": 25, "RCu": 10, "RCv": 15},
7: {'HPL':185, 'RCu':93, 'RCv':NA}, 7: {"HPL": 185, "RCu": 93, "RCv": NA},
6: {'HPL':370, 'RCu':185, 'RCv':NA}, 6: {"HPL": 370, "RCu": 185, "RCv": NA},
5: {'HPL':926, 'RCu':463, 'RCv':NA}, 5: {"HPL": 926, "RCu": 463, "RCv": NA},
4: {'HPL':1852, 'RCu':926, 'RCv':NA}, 4: {"HPL": 1852, "RCu": 926, "RCv": NA},
3: {'HPL':3704, 'RCu':1852, 'RCv':NA}, 3: {"HPL": 3704, "RCu": 1852, "RCv": NA},
2: {'HPL':18520, 'RCu':9260, 'RCv':NA}, 2: {"HPL": 18520, "RCu": 9260, "RCv": NA},
1: {'HPL':37040, 'RCu':18520, 'RCv':NA}, 1: {"HPL": 37040, "RCu": 18520, "RCv": NA},
0: {'HPL':NA, 'RCu':NA, 'RCv':NA}, 0: {"HPL": NA, "RCu": NA, "RCv": NA},
} }
NUCv = { NUCv = {
0: {'HVE':NA, 'VVE':NA}, 0: {"HVE": NA, "VVE": NA},
1: {'HVE':10, 'VVE':15.2}, 1: {"HVE": 10, "VVE": 15.2},
2: {'HVE':3, 'VVE':4.5}, 2: {"HVE": 3, "VVE": 4.5},
3: {'HVE':1, 'VVE':1.5}, 3: {"HVE": 1, "VVE": 1.5},
4: {'HVE':0.3, 'VVE':0.46}, 4: {"HVE": 0.3, "VVE": 0.46},
} }
NACp = { NACp = {
11: {'EPU': 3, 'VEPU': 4}, 11: {"EPU": 3, "VEPU": 4},
10: {'EPU': 10, 'VEPU': 15}, 10: {"EPU": 10, "VEPU": 15},
9: {'EPU': 30, 'VEPU': 45}, 9: {"EPU": 30, "VEPU": 45},
8: {'EPU': 93, 'VEPU': NA}, 8: {"EPU": 93, "VEPU": NA},
7: {'EPU': 185, 'VEPU': NA}, 7: {"EPU": 185, "VEPU": NA},
6: {'EPU': 556, 'VEPU': NA}, 6: {"EPU": 556, "VEPU": NA},
5: {'EPU': 926, 'VEPU': NA}, 5: {"EPU": 926, "VEPU": NA},
4: {'EPU': 1852, 'VEPU': NA}, 4: {"EPU": 1852, "VEPU": NA},
3: {'EPU': 3704, 'VEPU': NA}, 3: {"EPU": 3704, "VEPU": NA},
2: {'EPU': 7408, 'VEPU': NA}, 2: {"EPU": 7408, "VEPU": NA},
1: {'EPU': 18520, 'VEPU': NA}, 1: {"EPU": 18520, "VEPU": NA},
0: {'EPU': NA, 'VEPU': NA}, 0: {"EPU": NA, "VEPU": NA},
} }
NACv = { NACv = {
0: {'HFOMr':NA, 'VFOMr':NA}, 0: {"HFOMr": NA, "VFOMr": NA},
1: {'HFOMr':10, 'VFOMr':15.2}, 1: {"HFOMr": 10, "VFOMr": 15.2},
2: {'HFOMr':3, 'VFOMr':4.5}, 2: {"HFOMr": 3, "VFOMr": 4.5},
3: {'HFOMr':1, 'VFOMr':1.5}, 3: {"HFOMr": 1, "VFOMr": 1.5},
4: {'HFOMr':0.3, 'VFOMr':0.46}, 4: {"HFOMr": 0.3, "VFOMr": 0.46},
} }
SIL = { SIL = {
3: {'PE_RCu': 1e-7, 'PE_VPL': 2e-7}, 3: {"PE_RCu": 1e-7, "PE_VPL": 2e-7},
2: {'PE_RCu': 1e-5, 'PE_VPL': 1e-5}, 2: {"PE_RCu": 1e-5, "PE_VPL": 1e-5},
1: {'PE_RCu': 1e-3, 'PE_VPL': 1e-3}, 1: {"PE_RCu": 1e-3, "PE_VPL": 1e-3},
0: {'PE_RCu': NA, 'PE_VPL': NA}, 0: {"PE_RCu": NA, "PE_VPL": NA},
} }
NICv1 = { NICv1 = {
# NIC is used as the index at second Level # NIC is used as the index at second Level
11: {0: {"Rc": 7.5, "VPL": 11}},
11: {0: {'Rc': 7.5, 'VPL': 11}}, 10: {0: {"Rc": 25, "VPL": 37.5}},
10: {0: {'Rc': 25, 'VPL': 37.5}}, 9: {1: {"Rc": 75, "VPL": 112}},
9: {1: {'Rc': 75, 'VPL': 112}}, 8: {0: {"Rc": 185, "VPL": NA}},
8: {0: {'Rc': 185, 'VPL': NA}}, 7: {0: {"Rc": 370, "VPL": NA}},
7: {0: {'Rc': 370, 'VPL': NA}}, 6: {0: {"Rc": 926, "VPL": NA}, 1: {"Rc": 1111, "VPL": NA}},
6: { 5: {0: {"Rc": 1852, "VPL": NA}},
0: {'Rc': 926, 'VPL': NA}, 4: {0: {"Rc": 3702, "VPL": NA}},
1: {'Rc': 1111, 'VPL': NA}, 3: {1: {"Rc": 7408, "VPL": NA}},
}, 2: {0: {"Rc": 14008, "VPL": NA}},
5: {0: {'Rc': 1852, 'VPL': NA}}, 1: {0: {"Rc": 37000, "VPL": NA}},
4: {0: {'Rc': 3702, 'VPL': NA}}, 0: {0: {"Rc": NA, "VPL": NA}},
3: {1: {'Rc': 7408, 'VPL': NA}},
2: {0: {'Rc': 14008, 'VPL': NA}},
1: {0: {'Rc': 37000, 'VPL': NA}},
0: {0: {'Rc': NA, 'VPL': NA}},
} }
NICv2 = { NICv2 = {
# Decimal value of [NICa NICb/NICc] is used as the index at second Level # Decimal value of [NICa NICb/NICc] is used as the index at second Level
11: {0: {"Rc": 7.5}},
11: {0: {'Rc': 7.5}}, 10: {0: {"Rc": 25}},
10: {0: {'Rc': 25}}, 9: {2: {"Rc": 75}, 3: {"Rc": 75}},
9: { 8: {0: {"Rc": 185}},
2: {'Rc': 75}, 7: {0: {"Rc": 370}, 3: {"Rc": 370}},
3: {'Rc': 75}, 6: {0: {"Rc": 926}, 1: {"Rc": 556}, 2: {"Rc": 556}, 3: {"Rc": 1111}},
}, 5: {0: {"Rc": 1852}},
8: {0: {'Rc': 185}}, 4: {0: {"Rc": 3702}},
7: { 3: {3: {"Rc": 7408}},
0: {'Rc': 370}, 2: {0: {"Rc": 14008}},
3: {'Rc': 370}, 1: {0: {"Rc": 37000}},
}, 0: {0: {"Rc": NA}},
6: {
0: {'Rc': 926},
1: {'Rc': 556},
2: {'Rc': 556},
3: {'Rc': 1111},
},
5: {0: {'Rc': 1852}},
4: {0: {'Rc': 3702}},
3: {3: {'Rc': 7408}},
2: {0: {'Rc': 14008}},
1: {0: {'Rc': 37000}},
0: {0: {'Rc': NA}},
} }
+35 -34
View File
@@ -30,31 +30,31 @@ Speed conversion at altitude H[m] in ISA
import numpy as np import numpy as np
"""Aero and geo Constants """ """Aero and geo Constants """
kts = 0.514444 # knot -> m/s kts = 0.514444 # knot -> m/s
ft = 0.3048 # ft -> m ft = 0.3048 # ft -> m
fpm = 0.00508 # ft/min -> m/s fpm = 0.00508 # ft/min -> m/s
inch = 0.0254 # inch -> m inch = 0.0254 # inch -> m
sqft = 0.09290304 # 1 square foot sqft = 0.09290304 # 1 square foot
nm = 1852. # nautical mile -> m nm = 1852.0 # nautical mile -> m
lbs = 0.453592 # pound -> kg lbs = 0.453592 # pound -> kg
g0 = 9.80665 # m/s2, Sea level gravity constant g0 = 9.80665 # m/s2, Sea level gravity constant
R = 287.05287 # m2/(s2 x K), gas constant, sea level ISA R = 287.05287 # m2/(s2 x K), gas constant, sea level ISA
p0 = 101325. # Pa, air pressure, sea level ISA p0 = 101325.0 # Pa, air pressure, sea level ISA
rho0 = 1.225 # kg/m3, air density, sea level ISA rho0 = 1.225 # kg/m3, air density, sea level ISA
T0 = 288.15 # K, temperature, sea level ISA T0 = 288.15 # K, temperature, sea level ISA
gamma = 1.40 # cp/cv for air gamma = 1.40 # cp/cv for air
gamma1 = 0.2 # (gamma-1)/2 for air gamma1 = 0.2 # (gamma-1)/2 for air
gamma2 = 3.5 # gamma/(gamma-1) for air gamma2 = 3.5 # gamma/(gamma-1) for air
beta = -0.0065 # [K/m] ISA temp gradient below tropopause beta = -0.0065 # [K/m] ISA temp gradient below tropopause
r_earth = 6371000. # m, average earth radius r_earth = 6371000.0 # m, average earth radius
a0 = 340.293988 # m/s, sea level speed of sound ISA, sqrt(gamma*R*T0) a0 = 340.293988 # m/s, sea level speed of sound ISA, sqrt(gamma*R*T0)
def atmos(H): def atmos(H):
# H in metres # H in metres
T = np.maximum(288.15 - 0.0065 * H, 216.65) T = np.maximum(288.15 - 0.0065 * H, 216.65)
rhotrop = 1.225 * (T / 288.15)**4.256848030018761 rhotrop = 1.225 * (T / 288.15) ** 4.256848030018761
dhstrat = np.maximum(0., H - 11000.0) dhstrat = np.maximum(0.0, H - 11000.0)
rho = rhotrop * np.exp(-dhstrat / 6341.552161) rho = rhotrop * np.exp(-dhstrat / 6341.552161)
p = rho * R * T p = rho * R * T
return p, rho, T return p, rho, T
@@ -101,11 +101,13 @@ def distance(lat1, lon1, lat2, lon2, H=0):
theta1 = np.radians(lon1) theta1 = np.radians(lon1)
theta2 = np.radians(lon2) theta2 = np.radians(lon2)
cos = np.sin(phi1) * np.sin(phi2) * np.cos(theta1 - theta2) + np.cos(phi1) * np.cos(phi2) cos = np.sin(phi1) * np.sin(phi2) * np.cos(theta1 - theta2) + np.cos(phi1) * np.cos(
cos = np.where(cos>1, 1, cos) phi2
)
cos = np.where(cos > 1, 1, cos)
arc = np.arccos(cos) arc = np.arccos(cos)
dist = arc * (r_earth + H) # meters, radius of earth dist = arc * (r_earth + H) # meters, radius of earth
return dist return dist
@@ -114,9 +116,8 @@ def bearing(lat1, lon1, lat2, lon2):
lon1 = np.radians(lon1) lon1 = np.radians(lon1)
lat2 = np.radians(lat2) lat2 = np.radians(lat2)
lon2 = np.radians(lon2) lon2 = np.radians(lon2)
x = np.sin(lon2-lon1) * np.cos(lat2) x = np.sin(lon2 - lon1) * np.cos(lat2)
y = np.cos(lat1) * np.sin(lat2) \ y = np.cos(lat1) * np.sin(lat2) - np.sin(lat1) * np.cos(lat2) * np.cos(lon2 - lon1)
- np.sin(lat1) * np.cos(lat2) * np.cos(lon2-lon1)
initial_bearing = np.arctan2(x, y) initial_bearing = np.arctan2(x, y)
initial_bearing = np.degrees(initial_bearing) initial_bearing = np.degrees(initial_bearing)
bearing = (initial_bearing + 360) % 360 bearing = (initial_bearing + 360) % 360
@@ -129,44 +130,44 @@ def bearing(lat1, lon1, lat2, lon2):
def tas2mach(Vtas, H): def tas2mach(Vtas, H):
"""True Airspeed to Mach number""" """True Airspeed to Mach number"""
a = vsound(H) a = vsound(H)
Mach = Vtas/a Mach = Vtas / a
return Mach return Mach
def mach2tas(Mach, H): def mach2tas(Mach, H):
"""Mach number to True Airspeed""" """Mach number to True Airspeed"""
a = vsound(H) a = vsound(H)
Vtas = Mach*a Vtas = Mach * a
return Vtas return Vtas
def eas2tas(Veas, H): def eas2tas(Veas, H):
"""Equivalent Airspeed to True Airspeed""" """Equivalent Airspeed to True Airspeed"""
rho = density(H) rho = density(H)
Vtas = Veas * np.sqrt(rho0/rho) Vtas = Veas * np.sqrt(rho0 / rho)
return Vtas return Vtas
def tas2eas(Vtas, H): def tas2eas(Vtas, H):
"""True Airspeed to Equivalent Airspeed""" """True Airspeed to Equivalent Airspeed"""
rho = density(H) rho = density(H)
Veas = Vtas * np.sqrt(rho/rho0) Veas = Vtas * np.sqrt(rho / rho0)
return Veas return Veas
def cas2tas(Vcas, H): def cas2tas(Vcas, H):
"""Calibrated Airspeed to True Airspeed""" """Calibrated Airspeed to True Airspeed"""
p, rho, T = atmos(H) p, rho, T = atmos(H)
qdyn = p0*((1.+rho0*Vcas*Vcas/(7.*p0))**3.5-1.) qdyn = p0 * ((1.0 + rho0 * Vcas * Vcas / (7.0 * p0)) ** 3.5 - 1.0)
Vtas = np.sqrt(7.*p/rho*((1.+qdyn/p)**(2./7.)-1.)) Vtas = np.sqrt(7.0 * p / rho * ((1.0 + qdyn / p) ** (2.0 / 7.0) - 1.0))
return Vtas return Vtas
def tas2cas(Vtas, H): def tas2cas(Vtas, H):
"""True Airspeed to Calibrated Airspeed""" """True Airspeed to Calibrated Airspeed"""
p, rho, T = atmos(H) p, rho, T = atmos(H)
qdyn = p*((1.+rho*Vtas*Vtas/(7.*p))**3.5-1.) qdyn = p * ((1.0 + rho * Vtas * Vtas / (7.0 * p)) ** 3.5 - 1.0)
Vcas = np.sqrt(7.*p0/rho0*((qdyn/p0+1.)**(2./7.)-1.)) Vcas = np.sqrt(7.0 * p0 / rho0 * ((qdyn / p0 + 1.0) ** (2.0 / 7.0) - 1.0))
return Vcas return Vcas
+2 -8
View File
@@ -59,9 +59,7 @@ class TcpClient(object):
msg_stop = False msg_stop = False
self.current_msg = "" self.current_msg = ""
if (not msg_stop) and ( if (not msg_stop) and (48 <= b <= 57 or 65 <= b <= 70 or 97 <= b <= 102):
48 <= b <= 57 or 65 <= b <= 70 or 97 <= b <= 102
):
self.current_msg = self.current_msg + chr(b) self.current_msg = self.current_msg + chr(b)
self.buffer = [] self.buffer = []
@@ -234,11 +232,7 @@ class TcpClient(object):
msg = "".join("%02X" % j for j in payload) msg = "".join("%02X" % j for j in payload)
i += 14 # Both message types use 14 bytes i += 14 # Both message types use 14 bytes
tsbin = self.buffer[i : i + 6] tsbin = self.buffer[i : i + 6]
sec = ( sec = ((tsbin[0] & 0x7F) << 10) | (tsbin[1] << 2) | (tsbin[2] >> 6)
((tsbin[0] & 0x7F) << 10)
| (tsbin[1] << 2)
| (tsbin[2] >> 6)
)
nano = ( nano = (
((tsbin[2] & 0x3F) << 24) ((tsbin[2] & 0x3F) << 24)
| (tsbin[3] << 16) | (tsbin[3] << 16)
+2 -6
View File
@@ -108,9 +108,7 @@ class Decode:
self.acs[icao][oe] = msg self.acs[icao][oe] = msg
self.acs[icao]["t" + str(oe)] = t self.acs[icao]["t" + str(oe)] = t
if ("tpos" in self.acs[icao]) and ( if ("tpos" in self.acs[icao]) and (t - self.acs[icao]["tpos"] < 180):
t - self.acs[icao]["tpos"] < 180
):
# use single message decoding # use single message decoding
rlat = self.acs[icao]["lat"] rlat = self.acs[icao]["lat"]
rlon = self.acs[icao]["lon"] rlon = self.acs[icao]["lon"]
@@ -174,9 +172,7 @@ class Decode:
ac["HFOMr"], ac["VFOMr"] = pms.adsb.nac_v(msg) ac["HFOMr"], ac["VFOMr"] = pms.adsb.nac_v(msg)
if tc == 29: if tc == 29:
ac["PE_RCu"], ac["PE_VPL"], ac["base"] = pms.adsb.sil( ac["PE_RCu"], ac["PE_VPL"], ac["base"] = pms.adsb.sil(msg, ac["ver"])
msg, ac["ver"]
)
ac["EPU"], ac["VEPU"] = pms.adsb.nac_p(msg) ac["EPU"], ac["VEPU"] = pms.adsb.nac_p(msg)
if tc == 31: if tc == 31:
+1 -3
View File
@@ -147,9 +147,7 @@ class Screen(object):
total_page = len(icaos) // (self.scr_h - 4) + 1 total_page = len(icaos) // (self.scr_h - 4) + 1
current_page = self.offset // (self.scr_h - 4) + 1 current_page = self.offset // (self.scr_h - 4) + 1
self.screen.addstr( self.screen.addstr(self.scr_h - 2, 1, "(%d / %d)" % (current_page, total_page))
self.scr_h - 2, 1, "(%d / %d)" % (current_page, total_page)
)
self.reset_cursor_pos() self.reset_cursor_pos()
+5 -2
View File
@@ -4,10 +4,12 @@ from pyModeS import adsb, ehs
# === Decode sample data file === # === Decode sample data file ===
def adsb_decode_all(n=None): def adsb_decode_all(n=None):
print("===== Decode ADS-B sample data=====") print("===== Decode ADS-B sample data=====")
import csv import csv
f = open('tests/data/sample_data_adsb.csv', 'rt')
f = open("tests/data/sample_data_adsb.csv", "rt")
msg0 = None msg0 = None
msg1 = None msg1 = None
@@ -37,5 +39,6 @@ def adsb_decode_all(n=None):
alt = adsb.altitude(m) alt = adsb.altitude(m)
print(ts, m, icao, tc, pos, alt) print(ts, m, icao, tc, pos, alt)
if __name__ == '__main__':
if __name__ == "__main__":
adsb_decode_all(n=100) adsb_decode_all(n=100)
+28 -11
View File
@@ -3,12 +3,13 @@ from pyModeS import commb, common, bds
# === Decode sample data file === # === Decode sample data file ===
def bds_info(BDS, m): def bds_info(BDS, m):
if BDS == "BDS10": if BDS == "BDS10":
info = [commb.ovc10(m)] info = [commb.ovc10(m)]
elif BDS == "BDS17": elif BDS == "BDS17":
info = ([i[-2:] for i in commb.cap17(m)]) info = [i[-2:] for i in commb.cap17(m)]
elif BDS == "BDS20": elif BDS == "BDS20":
info = [commb.cs20(m)] info = [commb.cs20(m)]
@@ -20,13 +21,30 @@ def bds_info(BDS, m):
info = (commb.wind44(m), commb.temp44(m), commb.p44(m), commb.hum44(m)) info = (commb.wind44(m), commb.temp44(m), commb.p44(m), commb.hum44(m))
elif BDS == "BDS44REV": elif BDS == "BDS44REV":
info = (commb.wind44(m, rev=True), commb.temp44(m, rev=True), commb.p44(m, rev=True), commb.hum44(m, rev=True)) info = (
commb.wind44(m, rev=True),
commb.temp44(m, rev=True),
commb.p44(m, rev=True),
commb.hum44(m, rev=True),
)
elif BDS == "BDS50": elif BDS == "BDS50":
info = (commb.roll50(m), commb.trk50(m), commb.gs50(m), commb.rtrk50(m), commb.tas50(m)) info = (
commb.roll50(m),
commb.trk50(m),
commb.gs50(m),
commb.rtrk50(m),
commb.tas50(m),
)
elif BDS == "BDS60": elif BDS == "BDS60":
info = (commb.hdg60(m), commb.ias60(m), commb.mach60(m), commb.vr60baro(m), commb.vr60ins(m)) info = (
commb.hdg60(m),
commb.ias60(m),
commb.mach60(m),
commb.vr60baro(m),
commb.vr60ins(m),
)
else: else:
info = None info = None
@@ -39,8 +57,7 @@ def commb_decode_all(df, n=None):
print("===== Decode Comm-B sample data (DF=%s)=====" % df) print("===== Decode Comm-B sample data (DF=%s)=====" % df)
f = open('tests/data/sample_data_commb_df%s.csv' % df, 'rt') f = open("tests/data/sample_data_commb_df%s.csv" % df, "rt")
for i, r in enumerate(csv.reader(f)): for i, r in enumerate(csv.reader(f)):
if n and i > n: if n and i > n:
@@ -55,21 +72,21 @@ def commb_decode_all(df, n=None):
code = common.altcode(m) if df == 20 else common.idcode(m) code = common.altcode(m) if df == 20 else common.idcode(m)
if not BDS: if not BDS:
print(ts, m, icao, df, '%5s'%code, 'UNKNOWN') print(ts, m, icao, df, "%5s" % code, "UNKNOWN")
continue continue
if len(BDS.split(",")) > 1: if len(BDS.split(",")) > 1:
print(ts, m, icao, df, '%5s' % code, end=' ') print(ts, m, icao, df, "%5s" % code, end=" ")
for i, _bds in enumerate(BDS.split(",")): for i, _bds in enumerate(BDS.split(",")):
if i == 0: if i == 0:
print(_bds, *bds_info(_bds, m)) print(_bds, *bds_info(_bds, m))
else: else:
print(' ' * 55, _bds, *bds_info(_bds, m)) print(" " * 55, _bds, *bds_info(_bds, m))
else: else:
print(ts, m, icao, df, '%5s'%code, BDS, *bds_info(BDS, m)) print(ts, m, icao, df, "%5s" % code, BDS, *bds_info(BDS, m))
if __name__ == '__main__': if __name__ == "__main__":
commb_decode_all(df=20, n=100) commb_decode_all(df=20, n=100)
commb_decode_all(df=21, n=100) commb_decode_all(df=21, n=100)
+14 -13
View File
@@ -1,20 +1,21 @@
from pyModeS import bds from pyModeS import bds
def test_bds_infer():
assert bds.infer("8D406B902015A678D4D220AA4BDA") == 'BDS08'
assert bds.infer("8FC8200A3AB8F5F893096B000000") == 'BDS06'
assert bds.infer("8D40058B58C901375147EFD09357") == 'BDS05'
assert bds.infer("8D485020994409940838175B284F") == 'BDS09'
assert bds.infer("A800178D10010080F50000D5893C") == 'BDS10' def test_bds_infer():
assert bds.infer("A0000638FA81C10000000081A92F") == 'BDS17' assert bds.infer("8D406B902015A678D4D220AA4BDA") == "BDS08"
assert bds.infer("A0001838201584F23468207CDFA5") == 'BDS20' assert bds.infer("8FC8200A3AB8F5F893096B000000") == "BDS06"
assert bds.infer("A0001839CA3800315800007448D9") == 'BDS40' assert bds.infer("8D40058B58C901375147EFD09357") == "BDS05"
assert bds.infer("A000139381951536E024D4CCF6B5") == 'BDS50' assert bds.infer("8D485020994409940838175B284F") == "BDS09"
assert bds.infer("A00004128F39F91A7E27C46ADC21") == 'BDS60'
assert bds.infer("A800178D10010080F50000D5893C") == "BDS10"
assert bds.infer("A0000638FA81C10000000081A92F") == "BDS17"
assert bds.infer("A0001838201584F23468207CDFA5") == "BDS20"
assert bds.infer("A0001839CA3800315800007448D9") == "BDS40"
assert bds.infer("A000139381951536E024D4CCF6B5") == "BDS50"
assert bds.infer("A00004128F39F91A7E27C46ADC21") == "BDS60"
def test_bds_is50or60(): def test_bds_is50or60():
assert bds.is50or60("A0001838201584F23468207CDFA5", 0, 0, 0) == None assert bds.is50or60("A0001838201584F23468207CDFA5", 0, 0, 0) == None
assert bds.is50or60("A0000000FFDA9517000464000000", 182, 237, 1250) == 'BDS50' assert bds.is50or60("A0000000FFDA9517000464000000", 182, 237, 1250) == "BDS50"
assert bds.is50or60("A0000000919A5927E23444000000", 413, 54, 18700) == 'BDS60' assert bds.is50or60("A0000000919A5927E23444000000", 413, 54, 18700) == "BDS60"
+9 -7
View File
@@ -1,12 +1,14 @@
from pyModeS import bds, commb from pyModeS import bds, commb
# from pyModeS import ehs, els # deprecated # from pyModeS import ehs, els # deprecated
def test_bds20_callsign():
assert bds.bds20.cs20("A000083E202CC371C31DE0AA1CCF") == 'KLM1017_'
assert bds.bds20.cs20("A0001993202422F2E37CE038738E") == 'IBK2873_'
assert commb.cs20("A000083E202CC371C31DE0AA1CCF") == 'KLM1017_' def test_bds20_callsign():
assert commb.cs20("A0001993202422F2E37CE038738E") == 'IBK2873_' assert bds.bds20.cs20("A000083E202CC371C31DE0AA1CCF") == "KLM1017_"
assert bds.bds20.cs20("A0001993202422F2E37CE038738E") == "IBK2873_"
assert commb.cs20("A000083E202CC371C31DE0AA1CCF") == "KLM1017_"
assert commb.cs20("A0001993202422F2E37CE038738E") == "IBK2873_"
def test_bds40_functions(): def test_bds40_functions():
@@ -21,14 +23,14 @@ def test_bds40_functions():
def test_bds50_functions(): def test_bds50_functions():
assert bds.bds50.roll50("A000139381951536E024D4CCF6B5") == 2.1 assert bds.bds50.roll50("A000139381951536E024D4CCF6B5") == 2.1
assert bds.bds50.roll50("A0001691FFD263377FFCE02B2BF9") == -0.4 # signed value assert bds.bds50.roll50("A0001691FFD263377FFCE02B2BF9") == -0.4 # signed value
assert bds.bds50.trk50("A000139381951536E024D4CCF6B5") == 114.258 assert bds.bds50.trk50("A000139381951536E024D4CCF6B5") == 114.258
assert bds.bds50.gs50("A000139381951536E024D4CCF6B5") == 438 assert bds.bds50.gs50("A000139381951536E024D4CCF6B5") == 438
assert bds.bds50.rtrk50("A000139381951536E024D4CCF6B5") == 0.125 assert bds.bds50.rtrk50("A000139381951536E024D4CCF6B5") == 0.125
assert bds.bds50.tas50("A000139381951536E024D4CCF6B5") == 424 assert bds.bds50.tas50("A000139381951536E024D4CCF6B5") == 424
assert commb.roll50("A000139381951536E024D4CCF6B5") == 2.1 assert commb.roll50("A000139381951536E024D4CCF6B5") == 2.1
assert commb.roll50("A0001691FFD263377FFCE02B2BF9") == -0.4 # signed value assert commb.roll50("A0001691FFD263377FFCE02B2BF9") == -0.4 # signed value
assert commb.trk50("A000139381951536E024D4CCF6B5") == 114.258 assert commb.trk50("A000139381951536E024D4CCF6B5") == 114.258
assert commb.gs50("A000139381951536E024D4CCF6B5") == 438 assert commb.gs50("A000139381951536E024D4CCF6B5") == 438
assert commb.rtrk50("A000139381951536E024D4CCF6B5") == 0.125 assert commb.rtrk50("A000139381951536E024D4CCF6B5") == 0.125
+39 -33
View File
@@ -2,57 +2,63 @@ from pyModeS import common
def test_conversions(): def test_conversions():
assert common.hex2bin('6E406B') == "011011100100000001101011" assert common.hex2bin("6E406B") == "011011100100000001101011"
assert common.bin2hex('011011100100000001101011') == "6E406B" assert common.bin2hex("011011100100000001101011") == "6E406B"
assert common.int2hex(11160538) == "AA4BDA" assert common.int2hex(11160538) == "AA4BDA"
def test_crc_decode(): def test_crc_decode():
assert common.crc_legacy("8D406B902015A678D4D220AA4BDA") == 0 assert common.crc_legacy("8D406B902015A678D4D220AA4BDA") == 0
assert common.crc("8D406B902015A678D4D220AA4BDA") == 0 assert common.crc("8D406B902015A678D4D220AA4BDA") == 0
assert common.crc('8d8960ed58bf053cf11bc5932b7d') == 0 assert common.crc("8d8960ed58bf053cf11bc5932b7d") == 0
assert common.crc('8d45cab390c39509496ca9a32912') == 0 assert common.crc("8d45cab390c39509496ca9a32912") == 0
assert common.crc('8d49d3d4e1089d00000000744c3b') == 0 assert common.crc("8d49d3d4e1089d00000000744c3b") == 0
assert common.crc('8d74802958c904e6ef4ba0184d5c') == 0 assert common.crc("8d74802958c904e6ef4ba0184d5c") == 0
assert common.crc('8d4400cd9b0000b4f87000e71a10') == 0 assert common.crc("8d4400cd9b0000b4f87000e71a10") == 0
assert common.crc('8d4065de58a1054a7ef0218e226a') == 0 assert common.crc("8d4065de58a1054a7ef0218e226a") == 0
assert common.crc("c80b2dca34aa21dd821a04cb64d4") == 10719924
assert common.crc("a800089d8094e33a6004e4b8a522") == 4805588
assert common.crc("a8000614a50b6d32bed000bbe0ed") == 5659991
assert common.crc("a0000410bc900010a40000f5f477") == 11727682
assert common.crc("8d4ca251204994b1c36e60a5343d") == 16
assert common.crc("b0001718c65632b0a82040715b65") == 353333
assert common.crc('c80b2dca34aa21dd821a04cb64d4') == 10719924
assert common.crc('a800089d8094e33a6004e4b8a522') == 4805588
assert common.crc('a8000614a50b6d32bed000bbe0ed') == 5659991
assert common.crc('a0000410bc900010a40000f5f477') == 11727682
assert common.crc('8d4ca251204994b1c36e60a5343d') == 16
assert common.crc('b0001718c65632b0a82040715b65') == 353333
def test_crc_encode(): def test_crc_encode():
parity = common.crc("8D406B902015A678D4D220AA4BDA", encode=True) parity = common.crc("8D406B902015A678D4D220AA4BDA", encode=True)
assert common.int2hex(parity) == "AA4BDA" assert common.int2hex(parity) == "AA4BDA"
def test_icao(): def test_icao():
assert common.icao("8D406B902015A678D4D220AA4BDA") == "406B90" assert common.icao("8D406B902015A678D4D220AA4BDA") == "406B90"
assert common.icao("A0001839CA3800315800007448D9") == '400940' assert common.icao("A0001839CA3800315800007448D9") == "400940"
assert common.icao("A000139381951536E024D4CCF6B5") == '3C4DD2' assert common.icao("A000139381951536E024D4CCF6B5") == "3C4DD2"
assert common.icao("A000029CFFBAA11E2004727281F1") == '4243D0' assert common.icao("A000029CFFBAA11E2004727281F1") == "4243D0"
def test_modes_altcode(): def test_modes_altcode():
assert common.altcode("A02014B400000000000000F9D514") == 32300 assert common.altcode("A02014B400000000000000F9D514") == 32300
def test_modes_idcode(): def test_modes_idcode():
assert common.idcode("A800292DFFBBA9383FFCEB903D01") == '1346' assert common.idcode("A800292DFFBBA9383FFCEB903D01") == "1346"
def test_graycode_to_altitude(): def test_graycode_to_altitude():
assert common.gray2alt('00000000010') == -1000 assert common.gray2alt("00000000010") == -1000
assert common.gray2alt('00000001010') == -500 assert common.gray2alt("00000001010") == -500
assert common.gray2alt('00000011011') == -100 assert common.gray2alt("00000011011") == -100
assert common.gray2alt('00000011010') == 0 assert common.gray2alt("00000011010") == 0
assert common.gray2alt('00000011110') == 100 assert common.gray2alt("00000011110") == 100
assert common.gray2alt('00000010011') == 600 assert common.gray2alt("00000010011") == 600
assert common.gray2alt('00000110010') == 1000 assert common.gray2alt("00000110010") == 1000
assert common.gray2alt('00001001001') == 5800 assert common.gray2alt("00001001001") == 5800
assert common.gray2alt('00011100100') == 10300 assert common.gray2alt("00011100100") == 10300
assert common.gray2alt('01100011010') == 32000 assert common.gray2alt("01100011010") == 32000
assert common.gray2alt('01110000100') == 46300 assert common.gray2alt("01110000100") == 46300
assert common.gray2alt('01010101100') == 50200 assert common.gray2alt("01010101100") == 50200
assert common.gray2alt('11011110100') == 73200 assert common.gray2alt("11011110100") == 73200
assert common.gray2alt('10000000011') == 126600 assert common.gray2alt("10000000011") == 126600
assert common.gray2alt('10000000001') == 126700 assert common.gray2alt("10000000001") == 126700