Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc66e2f4e4 | ||
|
|
128163b41d | ||
|
|
8933afb1c1 | ||
|
|
15f2833aee |
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
118
pyModeS/ehs.py
118
pyModeS/ehs.py
@@ -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:
|
||||
|
||||
9
setup.py
9
setup.py
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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():
|
||||
|
||||
Reference in New Issue
Block a user