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