Merge pull request #1 from junzis/master

Update
This commit is contained in:
TimA346
2021-01-23 02:52:40 +01:00
committed by GitHub
13 changed files with 111 additions and 75 deletions
+29
View File
@@ -0,0 +1,29 @@
# This workflows will upload a Python Package using Twine when a release is created
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
name: PyPI Publish
on:
release:
types: [created]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: "3.x"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
+1 -1
View File
@@ -228,7 +228,7 @@ cpdef int cprNL(double lat):
cdef int nz = 15 cdef int nz = 15
cdef double a = 1 - cos(pi / (2 * nz)) cdef double a = 1 - cos(pi / (2 * nz))
cdef double b = cos(pi / 180.0 * fabs(lat)) ** 2 cdef double b = cos(pi / 180 * fabs(lat)) ** 2
cdef double nl = 2 * pi / (acos(1 - a / b)) cdef double nl = 2 * pi / (acos(1 - a / b))
NL = floor(nl) NL = floor(nl)
return NL return NL
+15 -16
View File
@@ -34,13 +34,13 @@ def airborne_position(msg0, msg1, t0, t1):
raise RuntimeError("Both even and odd CPR frames are required.") raise RuntimeError("Both even and odd CPR frames are required.")
# 131072 is 2^17, since CPR lat and lon are 17 bits each. # 131072 is 2^17, since CPR lat and lon are 17 bits each.
cprlat_even = common.bin2int(mb0[22:39]) / 131072.0 cprlat_even = common.bin2int(mb0[22:39]) / 131072
cprlon_even = common.bin2int(mb0[39:56]) / 131072.0 cprlon_even = common.bin2int(mb0[39:56]) / 131072
cprlat_odd = common.bin2int(mb1[22:39]) / 131072.0 cprlat_odd = common.bin2int(mb1[22:39]) / 131072
cprlon_odd = common.bin2int(mb1[39:56]) / 131072.0 cprlon_odd = common.bin2int(mb1[39:56]) / 131072
air_d_lat_even = 360.0 / 60 air_d_lat_even = 360 / 60
air_d_lat_odd = 360.0 / 59 air_d_lat_odd = 360 / 59
# compute latitude index 'j' # compute latitude index 'j'
j = common.floor(59 * cprlat_even - 60 * cprlat_odd + 0.5) j = common.floor(59 * cprlat_even - 60 * cprlat_odd + 0.5)
@@ -64,13 +64,13 @@ def airborne_position(msg0, msg1, t0, t1):
nl = common.cprNL(lat) nl = common.cprNL(lat)
ni = max(common.cprNL(lat) - 0, 1) ni = max(common.cprNL(lat) - 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 = (360.0 / ni) * (m % ni + cprlon_even) lon = (360 / ni) * (m % ni + cprlon_even)
else: else:
lat = lat_odd lat = lat_odd
nl = common.cprNL(lat) nl = common.cprNL(lat)
ni = max(common.cprNL(lat) - 1, 1) ni = max(common.cprNL(lat) - 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 = (360.0 / ni) * (m % ni + cprlon_odd) lon = (360 / ni) * (m % ni + cprlon_odd)
if lon > 180: if lon > 180:
lon = lon - 360 lon = lon - 360
@@ -95,11 +95,11 @@ def airborne_position_with_ref(msg, lat_ref, lon_ref):
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
cprlon = common.bin2int(mb[39:56]) / 131072.0 cprlon = common.bin2int(mb[39:56]) / 131072
i = int(mb[21]) i = int(mb[21])
d_lat = 360.0 / 59 if i else 360.0 / 60 d_lat = 360 / 59 if i else 360 / 60
j = common.floor(lat_ref / d_lat) + common.floor( j = common.floor(lat_ref / d_lat) + common.floor(
0.5 + ((lat_ref % d_lat) / d_lat) - cprlat 0.5 + ((lat_ref % d_lat) / d_lat) - cprlat
@@ -110,9 +110,9 @@ def airborne_position_with_ref(msg, lat_ref, lon_ref):
ni = common.cprNL(lat) - i ni = common.cprNL(lat) - i
if ni > 0: if ni > 0:
d_lon = 360.0 / ni d_lon = 360 / ni
else: else:
d_lon = 360.0 d_lon = 360
m = common.floor(lon_ref / d_lon) + common.floor( m = common.floor(lon_ref / d_lon) + common.floor(
0.5 + ((lon_ref % d_lon) / d_lon) - cprlon 0.5 + ((lon_ref % d_lon) / d_lon) - cprlon
@@ -143,9 +143,8 @@ def altitude(msg):
if tc < 19: if tc < 19:
altcode = altbin[0:6] + "0" + altbin[6:] altcode = altbin[0:6] + "0" + altbin[6:]
alt = common.altitude(altcode)
else: else:
altcode = altbin[0:6] + "0" + altbin[6:] alt = common.bin2int(altbin) * 3.28084
alt = common.altitude(altcode)
return alt return alt
+17 -17
View File
@@ -27,13 +27,13 @@ def surface_position(msg0, msg1, t0, t1, lat_ref, lon_ref):
msgbin1 = common.hex2bin(msg1) msgbin1 = common.hex2bin(msg1)
# 131072 is 2^17, since CPR lat and lon are 17 bits each. # 131072 is 2^17, since CPR lat and lon are 17 bits each.
cprlat_even = common.bin2int(msgbin0[54:71]) / 131072.0 cprlat_even = common.bin2int(msgbin0[54:71]) / 131072
cprlon_even = common.bin2int(msgbin0[71:88]) / 131072.0 cprlon_even = common.bin2int(msgbin0[71:88]) / 131072
cprlat_odd = common.bin2int(msgbin1[54:71]) / 131072.0 cprlat_odd = common.bin2int(msgbin1[54:71]) / 131072
cprlon_odd = common.bin2int(msgbin1[71:88]) / 131072.0 cprlon_odd = common.bin2int(msgbin1[71:88]) / 131072
air_d_lat_even = 90.0 / 60 air_d_lat_even = 90 / 60
air_d_lat_odd = 90.0 / 59 air_d_lat_odd = 90 / 59
# compute latitude index 'j' # compute latitude index 'j'
j = common.floor(59 * cprlat_even - 60 * cprlat_odd + 0.5) j = common.floor(59 * cprlat_even - 60 * cprlat_odd + 0.5)
@@ -43,8 +43,8 @@ def surface_position(msg0, msg1, t0, t1, lat_ref, lon_ref):
lat_odd_n = float(air_d_lat_odd * (j % 59 + cprlat_odd)) lat_odd_n = float(air_d_lat_odd * (j % 59 + cprlat_odd))
# solution for north hemisphere # solution for north hemisphere
lat_even_s = lat_even_n - 90.0 lat_even_s = lat_even_n - 90
lat_odd_s = lat_odd_n - 90.0 lat_odd_s = lat_odd_n - 90
# chose which solution corrispondes to receiver location # chose which solution corrispondes to receiver location
lat_even = lat_even_n if lat_ref > 0 else lat_even_s lat_even = lat_even_n if lat_ref > 0 else lat_even_s
@@ -60,16 +60,16 @@ def surface_position(msg0, msg1, t0, t1, lat_ref, lon_ref):
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 / 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 / ni) * (m % ni + cprlon_odd)
# four possible longitude solutions # four possible longitude solutions
lons = [lon, lon + 90.0, lon + 180.0, lon + 270.0] lons = [lon, lon + 90, lon + 180, lon + 270]
# make sure lons are between -180 and 180 # make sure lons are between -180 and 180
lons = [(l + 180) % 360 - 180 for l in lons] lons = [(l + 180) % 360 - 180 for l in lons]
@@ -99,11 +99,11 @@ def surface_position_with_ref(msg, lat_ref, lon_ref):
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
cprlon = common.bin2int(mb[39:56]) / 131072.0 cprlon = common.bin2int(mb[39:56]) / 131072
i = int(mb[21]) i = int(mb[21])
d_lat = 90.0 / 59 if i else 90.0 / 60 d_lat = 90 / 59 if i else 90 / 60
j = common.floor(lat_ref / d_lat) + common.floor( j = common.floor(lat_ref / d_lat) + common.floor(
0.5 + ((lat_ref % d_lat) / d_lat) - cprlat 0.5 + ((lat_ref % d_lat) / d_lat) - cprlat
@@ -114,9 +114,9 @@ def surface_position_with_ref(msg, lat_ref, lon_ref):
ni = common.cprNL(lat) - i ni = common.cprNL(lat) - i
if ni > 0: if ni > 0:
d_lon = 90.0 / ni d_lon = 90 / ni
else: else:
d_lon = 90.0 d_lon = 90
m = common.floor(lon_ref / d_lon) + common.floor( m = common.floor(lon_ref / d_lon) + common.floor(
0.5 + ((lon_ref % d_lon) / d_lon) - cprlon 0.5 + ((lon_ref % d_lon) / d_lon) - cprlon
@@ -153,7 +153,7 @@ def surface_velocity(msg, source=False):
# ground track # ground track
trk_status = int(mb[12]) trk_status = int(mb[12])
if trk_status == 1: if trk_status == 1:
trk = common.bin2int(mb[13:20]) * 360.0 / 128.0 trk = common.bin2int(mb[13:20]) * 360 / 128
trk = round(trk, 1) trk = round(trk, 1)
else: else:
trk = None trk = None
+30 -22
View File
@@ -24,7 +24,7 @@ def airborne_velocity(msg, source=False):
- Angle (degree), either ground track or heading - Angle (degree), either ground track or heading
- Vertical rate (ft/min) - Vertical rate (ft/min)
- Speed type ('GS' for ground speed, 'AS' for airspeed) - Speed type ('GS' for ground speed, 'AS' for airspeed)
- [Optional] Direction source ('TRUE_NORTH' or 'MAGENTIC_NORTH') - [Optional] Direction source ('TRUE_NORTH' or 'MAGNETIC_NORTH')
- [Optional] Vertical rate source ('BARO' or 'GNSS') - [Optional] Vertical rate source ('BARO' or 'GNSS')
""" """
@@ -35,29 +35,35 @@ def airborne_velocity(msg, source=False):
subtype = common.bin2int(mb[5:8]) subtype = common.bin2int(mb[5:8])
if common.bin2int(mb[14:24]) == 0 or common.bin2int(mb[25:35]) == 0:
return None
if subtype in (1, 2): 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 *= 4
v_ns_sign = -1 if mb[24] == "1" else 1 v_ew = common.bin2int(mb[14:24])
v_ns = common.bin2int(mb[25:35]) - 1 # north-south velocity v_ns = common.bin2int(mb[25:35])
if subtype == 2: # Supersonic
v_ns *= 4
v_we = v_ew_sign * v_ew if v_ew == 0 or v_ns == 0:
v_sn = v_ns_sign * v_ns spd = None
trk_or_hdg = None
vs = None
else:
v_ew_sign = -1 if mb[13] == "1" else 1
v_ew = v_ew - 1 # east-west velocity
if subtype == 2: # Supersonic
v_ew *= 4
spd = math.sqrt(v_sn * v_sn + v_we * v_we) # unit in kts v_ns_sign = -1 if mb[24] == "1" else 1
spd = int(spd) v_ns = v_ns - 1 # north-south velocity
if subtype == 2: # Supersonic
v_ns *= 4
trk = math.atan2(v_we, v_sn) v_we = v_ew_sign * v_ew
trk = math.degrees(trk) # convert to degrees v_sn = v_ns_sign * v_ns
trk = trk if trk >= 0 else trk + 360 # no negative val
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
spd_type = "GS" spd_type = "GS"
trk_or_hdg = round(trk, 2) trk_or_hdg = round(trk, 2)
@@ -67,13 +73,15 @@ def airborne_velocity(msg, source=False):
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 * 360.0
hdg = round(hdg, 2) hdg = round(hdg, 2)
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
@@ -82,7 +90,7 @@ def airborne_velocity(msg, source=False):
else: else:
spd_type = "TAS" spd_type = "TAS"
dir_type = "MAGENTIC_NORTH" dir_type = "MAGNETIC_NORTH"
vr_source = "GNSS" if mb[35] == "0" else "BARO" vr_source = "GNSS" if mb[35] == "0" else "BARO"
vr_sign = -1 if mb[36] == "1" else 1 vr_sign = -1 if mb[36] == "1" else 1
@@ -96,7 +104,7 @@ def airborne_velocity(msg, source=False):
def altitude_diff(msg): def altitude_diff(msg):
"""Decode the differece between GNSS and barometric altitude. """Decode the difference between GNSS and barometric altitude.
Args: Args:
msg (str): 28 hexdigits string, TC=19 msg (str): 28 hexdigits string, TC=19
+2 -2
View File
@@ -68,7 +68,7 @@ def wind44(msg):
return None, None return None, None
speed = common.bin2int(d[5:14]) # knots speed = common.bin2int(d[5:14]) # knots
direction = common.bin2int(d[14:23]) * 180.0 / 256.0 # degree direction = common.bin2int(d[14:23]) * 180 / 256 # degree
return round(speed, 0), round(direction, 1) return round(speed, 0), round(direction, 1)
@@ -136,7 +136,7 @@ def hum44(msg):
if d[49] == "0": if d[49] == "0":
return None return None
hm = common.bin2int(d[50:56]) * 100.0 / 64 # % hm = common.bin2int(d[50:56]) * 100 / 64 # %
return round(hm, 1) return round(hm, 1)
+3 -3
View File
@@ -78,7 +78,7 @@ def roll50(msg):
if sign: if sign:
value = value - 512 value = value - 512
angle = value * 45.0 / 256.0 # degree angle = value * 45 / 256 # degree
return round(angle, 1) return round(angle, 1)
@@ -102,7 +102,7 @@ def trk50(msg):
if sign: if sign:
value = value - 1024 value = value - 1024
trk = value * 90.0 / 512.0 trk = value * 90 / 512.0
# convert from [-180, 180] to [0, 360] # convert from [-180, 180] to [0, 360]
if trk < 0: if trk < 0:
@@ -151,7 +151,7 @@ def rtrk50(msg):
if sign: if sign:
value = value - 512 value = value - 512
angle = value * 8.0 / 256.0 # degree / sec angle = value * 8 / 256 # degree / sec
return round(angle, 3) return round(angle, 3)
+1 -1
View File
@@ -78,7 +78,7 @@ def hdg53(msg):
if sign: if sign:
value = value - 1024 value = value - 1024
hdg = value * 90.0 / 512.0 # degree hdg = value * 90 / 512 # degree
# convert from [-180, 180] to [0, 360] # convert from [-180, 180] to [0, 360]
if hdg < 0: if hdg < 0:
+1 -1
View File
@@ -86,7 +86,7 @@ def hdg60(msg):
if sign: if sign:
value = value - 1024 value = value - 1024
hdg = value * 90 / 512.0 # degree hdg = value * 90 / 512 # degree
# convert from [-180, 180] to [0, 360] # convert from [-180, 180] to [0, 360]
if hdg < 0: if hdg < 0:
+9 -9
View File
@@ -35,18 +35,18 @@ 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.0 # nautical mile -> m nm = 1852 # 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.0 # Pa, air pressure, sea level ISA p0 = 101325 # 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.0 # m, average earth radius r_earth = 6371000 # 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)
@@ -94,8 +94,8 @@ def distance(lat1, lon1, lat2, lon2, H=0):
""" """
# phi = 90 - latitude # phi = 90 - latitude
phi1 = np.radians(90.0 - lat1) phi1 = np.radians(90 - lat1)
phi2 = np.radians(90.0 - lat2) phi2 = np.radians(90 - lat2)
# theta = longitude # theta = longitude
theta1 = np.radians(lon1) theta1 = np.radians(lon1)
@@ -158,16 +158,16 @@ def tas2eas(Vtas, H):
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.0 + rho0 * Vcas * Vcas / (7.0 * p0)) ** 3.5 - 1.0) qdyn = p0 * ((1 + rho0 * Vcas * Vcas / (7 * p0)) ** 3.5 - 1.0)
Vtas = np.sqrt(7.0 * p / rho * ((1.0 + qdyn / p) ** (2.0 / 7.0) - 1.0)) Vtas = np.sqrt(7 * p / rho * ((1 + qdyn / p) ** (2 / 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.0 + rho * Vtas * Vtas / (7.0 * p)) ** 3.5 - 1.0) qdyn = p * ((1 + rho * Vtas * Vtas / (7 * p)) ** 3.5 - 1.0)
Vcas = np.sqrt(7.0 * p0 / rho0 * ((qdyn / p0 + 1.0) ** (2.0 / 7.0) - 1.0)) Vcas = np.sqrt(7 * p0 / rho0 * ((qdyn / p0 + 1.0) ** (2 / 7.0) - 1.0))
return Vcas return Vcas
+1 -1
View File
@@ -199,7 +199,7 @@ def cprNL(lat: float) -> int:
nz = 15 nz = 15
a = 1 - np.cos(np.pi / (2 * nz)) a = 1 - np.cos(np.pi / (2 * nz))
b = np.cos(np.pi / 180.0 * abs(lat)) ** 2 b = np.cos(np.pi / 180 * abs(lat)) ** 2
nl = 2 * np.pi / (np.arccos(1 - a / b)) nl = 2 * np.pi / (np.arccos(1 - a / b))
NL = floor(nl) NL = floor(nl)
return NL return NL
+1 -1
View File
@@ -27,7 +27,7 @@ with open(path.join(here, "README.rst"), encoding="utf-8") as f:
details = dict( details = dict(
name="pyModeS", name="pyModeS",
version="2.8", version="2.9",
description="Python Mode-S and ADS-B Decoder", description="Python Mode-S and ADS-B Decoder",
long_description=long_description, long_description=long_description,
url="https://github.com/junzis/pyModeS", url="https://github.com/junzis/pyModeS",
+1 -1
View File
@@ -6,7 +6,7 @@ def test_icao():
def test_interrogator(): def test_interrogator():
assert allcall.interrogator("5D484FDEA248F5") == 22 assert allcall.interrogator("5D484FDEA248F5") == "SI6"
def test_capability(): def test_capability():