Add vectorized version of df and typecode functions.
This commit is contained in:
parent
47de4d1163
commit
e53b51faa5
@ -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
48
pyModeS/common.py
Normal 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
0
pyModeS/vec/__init__.py
Normal file
34
pyModeS/vec/common.py
Normal file
34
pyModeS/vec/common.py
Normal 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
15
pyModeS/vec/ctor.py
Normal 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
9
pyModeS/vec/types.py
Normal 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
16
pyModeS/vec/util.py
Normal 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
0
tests/vec/__init__.py
Normal file
26
tests/vec/data.py
Normal file
26
tests/vec/data.py
Normal 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
20
tests/vec/test_common.py
Normal 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())
|
Loading…
Reference in New Issue
Block a user