Add vectorized version of df and typecode functions.

This commit is contained in:
wrobell 2020-12-30 23:57:25 +00:00
parent 47de4d1163
commit e53b51faa5
10 changed files with 169 additions and 7 deletions

View File

@ -1,13 +1,7 @@
import os import os
import warnings import warnings
try: from .common import *
from . import c_common as common
from .c_common import *
except:
from . import py_common as common
from .py_common import *
from .decoder import tell from .decoder import tell
from .decoder import adsb from .decoder import adsb
from .decoder import commb from .decoder import commb

48
pyModeS/common.py Normal file
View File

@ -0,0 +1,48 @@
import typing as tp
from functools import singledispatch
from .vec import common as common_vec
from .vec.types import InputData
try:
from . import c_common as common_str
except:
from . import py_common as common_str
@singledispatch
def df(msg: tp.Any) -> int:
raise NotImplementedError('Only string and NumPy arrays supported')
@df.register
def _df_str(msg: str) -> int:
return common_str.df(msg)
@df.register
def _df_vec(msg: InputData) -> int:
return common_vec.df(msg)
@singledispatch
def typecode(msg: tp.Any) -> int:
raise NotImplementedError('Only string and NumPy arrays supported')
@typecode.register
def _tc_str(msg: str) -> int:
return common_str.typecode(msg)
@typecode.register
def _tc_vec(msg: InputData) -> int:
return common_vec.typecode(msg)
icao = common_str.icao
altitude = common_str.altitude
altcode = common_str.altcode
allzeros = common_str.allzeros
data = common_str.data
wrongstatus = common_str.wrongstatus
idcode = common_str.idcode
floor = common_str.floor
cprNL = common_str.cprNL
crc = common_str.crc
squawk = common_str.squawk
hex2bin = common_str.hex2bin
hex2bin = common_str.hex2bin
bin2int = common_str.bin2int

0
pyModeS/vec/__init__.py Normal file
View File

34
pyModeS/vec/common.py Normal file
View File

@ -0,0 +1,34 @@
import numpy as np
import typing as tp
from .util import create_array
from .types import InputData, DownlinkFormat, TypeCode
def df(data: InputData) -> DownlinkFormat:
"""
Parse downlink format address from ADS-B messages.
:param data: ADS-B messages.
..seealso:: `Message structure <https://mode-s.org/decode/content/ads-b/1-basics.html>`_
"""
result = (data[:, 0] & 0xf8) >> 3
result[result > 24] = 24
return result
def typecode(data: InputData, df_data: tp.Optional[DownlinkFormat]=None) -> TypeCode:
"""
Parse type code information from ADS-B messages.
:param data: ADS-B messages.
:param df_data: Optional downlink format information for each ADS-B
message.
..seealso:: `ADS-B message types <https://mode-s.org/decode/content/ads-b/1-basics.html>`_
"""
result = np.zeros(len(data), dtype=np.uint8)
df_v = df(data) if df_data is None else df_data
idx = (df_v == 17) | (df_v == 18)
result[idx] = data[idx, 4] >> 3
return create_array(result, idx)

15
pyModeS/vec/ctor.py Normal file
View File

@ -0,0 +1,15 @@
import numpy as np
import typing as tp
from .types import InputData
def array(data: tp.Sequence[bytes]) -> InputData:
"""
Create Numpy array, which is input for parsing functions.
:param data: Collection of ADS-B messages.
"""
vec = np.array(data)
result = vec.view(dtype=np.uint8)
return result.reshape(-1, 14)

9
pyModeS/vec/types.py Normal file
View File

@ -0,0 +1,9 @@
import numpy as np
# define aliases for basic types to support static type analysis; these for
# convenience
# NOTE: more specific types can be defined when numpy 1.20 is released,
# i.e. use of np.ndarray[dtype, shape] shall be possible
InputData = np.ndarray
DownlinkFormat = np.ndarray
TypeCode = np.ndarray

16
pyModeS/vec/util.py Normal file
View File

@ -0,0 +1,16 @@
import numpy as np
def create_array(data, idx):
"""
Create NumPy masked array.
Note, that this function differes from NumPy constructor semantics. The
index indicates the valid values (not the invalid as in the default
masked array in NumPy).
:param data: Input data.
:param idx: Index of valid values.
"""
return np.ma.array(data, mask=~idx)
# vim: sw=4:et:ai

0
tests/vec/__init__.py Normal file
View File

26
tests/vec/data.py Normal file
View File

@ -0,0 +1,26 @@
import numpy as np
from binascii import unhexlify
from pyModeS.vec.ctor import array
from pyModeS.vec.common import df
import pytest
@pytest.fixture
def message():
data = [
'904ca3a33219741c85465ae1b4c3', # df = 18
'a8281d3030000000000000850d4a', # df = 21
'8d406b902015a678d4d220000000', # example from https://mode-s.org/decode/content/ads-b/8-error-control.html
'904ca3da121010603d04f5df3ecf', # df = 18, tc = 2
'977ba7ca0daa3e1915d83237c86e', # df = 18, tc = 1
'8d4ca2d4234994b5452820e5b7ab', # df = 17, tc = 4
]
return array(np.array([unhexlify(v) for v in data]))
@pytest.fixture
def df_message(message):
return df(message)
# vim: sw=4:et:ai

20
tests/vec/test_common.py Normal file
View File

@ -0,0 +1,20 @@
import numpy as np
from pyModeS.common import df, typecode
from .data import message
def test_df(message):
"""
Test parsing of ADS-B downlink format.
"""
result = df(message)
assert np.array_equal([18, 21, 17, 18, 18, 17], result)
def test_typecode(message):
"""
Test ADS-B type code parsing.
"""
result = typecode(message)
assert np.array_equal([6, 0, 4, 2, 1, 4], result)
assert np.array_equal([6, 4, 2, 1, 4], result.compressed())