4 Commits

Author SHA1 Message Date
junzis
cc66e2f4e4 version 1.0.9 2017-03-21 18:14:30 +01:00
junzis
128163b41d update BDS 4,4 decoder, default to revised version 2017-03-17 18:03:54 +01:00
Junzi Sun
8933afb1c1 Update ehs.py 2017-03-17 15:24:18 +01:00
junzis
15f2833aee add surface velocity decoding from msg TC:5-8 2017-03-07 13:41:07 +01:00
6 changed files with 171 additions and 46 deletions

View File

@@ -72,8 +72,12 @@ Core functions for ADS-B decoding:
pms.adsb.surface_position_with_ref(msg, lat_ref, lon_ref)
pms.adsb.altitude(msg)
pms.adsb.velocity(msg)
pms.adsb.speed_heading(msg)
pms.adsb.velocity(msg) # handles both surface & airborne messages
pms.adsb.speed_heading(msg) # handles both surface & airborne messages
pms.adsb.surface_velocity(msg)
pms.adsb.airborne_velocity(msg)
**Hint: When you have a fix position of the aircraft, it is convenient to
use `position_with_ref()` method to decode with only one position message

View File

@@ -534,6 +534,42 @@ def nic(msg):
def velocity(msg):
"""Calculate the speed, heading, and vertical rate
(handles both airborne or surface message)
Args:
msg (string): 28 bytes hexadecimal message string
Returns:
(int, float, int, string): speed (kt), heading (degree),
rate of climb/descend (ft/min), and speed type
('GS' for ground speed, 'AS' for airspeed)
"""
if 5 <= typecode(msg) <= 8:
return surface_velocity(msg)
elif typecode(msg) == 19:
return airborne_velocity(msg)
else:
raise RuntimeError("incorrect or inconsistant message types")
def speed_heading(msg):
"""Get speed and heading only from the velocity message
(handles both airborne or surface message)
Args:
msg (string): 28 bytes hexadecimal message string
Returns:
(int, float): speed (kt), heading (degree)
"""
spd, hdg, rocd, tag = velocity(msg)
return spd, hdg
def airborne_velocity(msg):
"""Calculate the speed, heading, and vertical rate
Args:
msg (string): 28 bytes hexadecimal message string
@@ -582,14 +618,43 @@ def velocity(msg):
return int(spd), round(hdg, 1), int(rocd), tag
def speed_heading(msg):
"""Get speed and heading only from the velocity message
def surface_velocity(msg):
"""Decode surface velocity from from a surface position message
Args:
msg (string): 28 bytes hexadecimal message string
Returns:
(int, float): speed (kt), heading (degree)
(int, float, int, string): speed (kt), heading (degree),
rate of climb/descend (ft/min), and speed type
('GS' for ground speed, 'AS' for airspeed)
"""
spd, hdg, rocd, tag = velocity(msg)
return spd, hdg
if typecode(msg) < 5 or typecode(msg) > 8:
raise RuntimeError("%s: Not a surface message" % msg)
msgbin = util.hex2bin(msg)
# heading
hdg_status = int(msgbin[44])
if hdg_status == 1:
hdg = util.bin2int(msgbin[45:52]) * 360.0 / 128.0
else:
hdg = None
# ground movment / speed
mov = util.bin2int(msgbin[37:44])
if mov == 0 or mov > 124:
spd = None
elif mov == 1:
spd = 0
elif mov == 124:
spd = 175
else:
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
return round(spd, 2), round(hdg, 1), 0, 'GS'

View File

@@ -209,36 +209,37 @@ def pbaro(msg):
# DF 20/21, BDS 4,4
# ------------------------------------------
def isBDS44(msg):
def isBDS44(msg, rev=True):
"""Check if a message is likely to be BDS code 4,4
Meteorological routine air report
WARNING: there is two different definition for BDS4,4. This part of the
decoder is likely to be wrong...
Args:
msg (String): 28 bytes hexadecimal message string
rev (bool): using revised version
Returns:
bool: True or False
"""
# status bit 5, 15, 24, 36, 49
d = util.hex2bin(data(msg))
result = True
# --- current version ---
result = result & checkbits(d, 5, 6, 23) \
& checkbits(d, 35, 36, 46) & checkbits(d, 47, 48, 49) \
& checkbits(d, 50, 51, 56)
if not rev:
# status bit 5, 35, 47, 50
result = result & checkbits(d, 5, 6, 23) \
& checkbits(d, 35, 36, 46) & checkbits(d, 47, 48, 49) \
& checkbits(d, 50, 51, 56)
# # --- revised future version ---
# result = result & checkbits(d, 5, 6, 14) \
# & checkbits(d, 15, 16, 23) & checkbits(d, 24, 25, 35) \
# & checkbits(d, 36, 37, 47) & checkbits(d, 49, 50, 56)
if wind(msg) and wind(msg)[0] > 250:
else:
# status bit 5, 15, 24, 36, 49
result = result & checkbits(d, 5, 6, 14) \
& checkbits(d, 15, 16, 23) & checkbits(d, 24, 25, 35) \
& checkbits(d, 36, 37, 47) & checkbits(d, 49, 50, 56)
vw = wind(msg, rev=rev)
if vw and vw[0] > 250:
result &= False
# if temperature(msg):
@@ -248,78 +249,123 @@ def isBDS44(msg):
return result
def wind(msg):
def wind(msg, rev=True):
"""reported wind speed and direction
Args:
msg (String): 28 bytes hexadecimal message (BDS44) string
rev (bool): using revised version
Returns:
(int, float): speed (kt), direction (degree)
"""
d = util.hex2bin(data(msg))
status = int(d[4])
if not status:
return None
if not rev:
status = int(d[4])
if not status:
return None
speed = util.bin2int(d[5:14]) # knots
direction = util.bin2int(d[14:23]) * 180.0 / 256.0 # degree
else:
spd_status = int(d[4])
dir_status = int(d[14])
if (not spd_status) or (not dir_status):
return None
speed = util.bin2int(d[5:14]) # knots
direction = util.bin2int(d[15:23]) * 180.0 / 128.0 # degree
speed = util.bin2int(d[5:14]) # knots
direction = util.bin2int(d[14:23]) * 180.0 / 256.0 # degree
return round(speed, 0), round(direction, 1)
def temperature(msg):
def temperature(msg, rev=True):
"""reported air temperature
Args:
msg (String): 28 bytes hexadecimal message (BDS44) string
rev (bool): using revised version
Returns:
float: tmeperature in Celsius degree
"""
d = util.hex2bin(data(msg))
sign = int(d[23]) # 1 -> minus
temp = util.bin2int(d[24:34]) * 0.25 # celsius
temp = round(temp, 1)
return -1 * temp if sign else temp
if not rev:
sign = int(d[23])
temp = util.bin2int(d[24:34]) * 0.125 # celsius
temp = round(temp, 1)
else:
status = int(d[23])
if not status:
return None
sign = int(d[24])
temp = util.bin2int(d[25:35]) * 0.125 # celsius
temp = round(temp, 1)
return temp if sign else -1*temp
def pressure(msg):
def pressure(msg, rev=True):
"""reported average static pressure
Args:
msg (String): 28 bytes hexadecimal message (BDS44) string
rev (bool): using revised version
Returns:
int: static pressure in hPa
"""
d = util.hex2bin(data(msg))
status = int(d[34])
if not status:
return None
if not rev:
status = int(d[34])
if not status:
return None
p = util.bin2int(d[35:46]) # hPa
else:
status = int(d[35])
if not status:
return None
p = util.bin2int(d[36:47]) # hPa
p = util.bin2int(d[35:46]) # hPa
return p
def humidity(msg):
def humidity(msg, rev=True):
"""reported humidity
Args:
msg (String): 28 bytes hexadecimal message (BDS44) string
rev (bool): using revised version
Returns:
float: percentage of humidity, [0 - 100] %
"""
d = util.hex2bin(data(msg))
status = int(d[49])
if not status:
return None
if not rev:
status = int(d[49])
if not status:
return None
hm = util.bin2int(d[50:56]) * 100.0 / 64 # %
else:
status = int(d[48])
if not status:
return None
hm = util.bin2int(d[49:56]) # %
hm = util.bin2int(d[50:56]) * 100.0 / 64 # %
return round(hm, 1)
@@ -352,7 +398,7 @@ def isBDS50(msg):
if abs(roll(msg)) > 30:
result &= False
if gs(msg) > 500:
if gs(msg) > 600:
result &= False
if tas(msg) > 500:

View File

@@ -3,6 +3,13 @@
See:
https://packaging.python.org/en/latest/distributing.html
https://github.com/pypa/sampleproject
Steps for deploying a new verison:
1. Increase the version number
2. remove the old deployment under [dist] folder
3. run: python setup.py sdist
run: python setup.py bdist_wheel --universal
4. twine upload dist/*
"""
# Always prefer setuptools over distutils
@@ -23,7 +30,7 @@ setup(
# Versions should comply with PEP440. For a discussion on single-sourcing
# the version across setup.py and the project code, see
# https://packaging.python.org/en/latest/single_source_version.html
version='1.0.8',
version='1.0.9',
description='Python Mode-S Decoder',
long_description=long_description,

View File

@@ -62,7 +62,8 @@ def ehs_decode_all(n=None):
ehs.alt_fms(m), ehs.pbaro(m))
if vBDS == "BDS44":
print(ts, m, icao, vBDS, ehs.wind(m))
print(ts, m, icao, vBDS, ehs.wind(m),
ehs.temperature(m), ehs.pressure(m))
if vBDS == "BDS50":
print(ts, m, icao, vBDS, ehs.roll(m), ehs.track(m),

View File

@@ -58,8 +58,10 @@ def test_adsb_alt():
def test_adsb_velocity():
vgs = adsb.velocity("8D485020994409940838175B284F")
vas = adsb.velocity("8DA05F219B06B6AF189400CBC33F")
vgs_surface = adsb.velocity("8FC8200A3AB8F5F893096B000000")
assert vgs == (159, 182.9, -832, 'GS')
assert vas == (376, 244.0, -2304, 'AS')
assert vgs_surface == (19.0, 42.2, 0 , 'GS')
def test_nic():