Files
pyModeS/pyModeS/decoder/bds/bds09.py
Paul de Jong 50864b56aa Remove rounding in pyModeS (#147)
* Update bds50.py: round roll to 3 places instead of 1

Provide a bit more detail for smaller roll angles.

* remove rounding

* update poetry

* update poetry

* update test

* update bds06

* update workflow

---------

Co-authored-by: Junzi Sun <junzisun@gmail.com>
2023-05-22 17:00:58 +02:00

148 lines
3.9 KiB
Python

# ------------------------------------------
# BDS 0,9
# ADS-B TC=19
# Aircraft Airborne velocity
# ------------------------------------------
from __future__ import annotations
import math
from ... import common
def airborne_velocity(
msg: str, source: bool = False
) -> None | tuple[None | int, None | float, None | int, str]:
"""Decode airborne velocity.
Args:
msg (str): 28 hexdigits string
source (boolean): Include direction and vertical rate sources in return.
Default to False.
If set to True, the function will return six value instead of four.
Returns:
int, float, int, string, [string], [string]:
- Speed (kt)
- Angle (degree), either ground track or heading
- Vertical rate (ft/min)
- Speed type ('GS' for ground speed, 'AS' for airspeed)
- [Optional] Direction source ('TRUE_NORTH' or 'MAGNETIC_NORTH')
- [Optional] Vertical rate source ('BARO' or 'GNSS')
"""
if common.typecode(msg) != 19:
raise RuntimeError(
"%s: Not a airborne velocity message, expecting TC=19" % msg
)
mb = common.hex2bin(msg)[32:]
subtype = common.bin2int(mb[5:8])
if common.bin2int(mb[14:24]) == 0 or common.bin2int(mb[25:35]) == 0:
return None
trk_or_hdg: None | float
spd: None | float
if subtype in (1, 2):
v_ew = common.bin2int(mb[14:24])
v_ns = common.bin2int(mb[25:35])
if v_ew == 0 or v_ns == 0:
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
v_ns_sign = -1 if mb[24] == "1" else 1
v_ns = v_ns - 1 # north-south velocity
if subtype == 2: # Supersonic
v_ns *= 4
v_we = v_ew_sign * v_ew
v_sn = v_ns_sign * v_ns
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
trk_or_hdg = trk
spd_type = "GS"
dir_type = "TRUE_NORTH"
else:
if mb[13] == "0":
hdg = None
else:
hdg = common.bin2int(mb[14:24]) / 1024 * 360.0
trk_or_hdg = hdg
spd = common.bin2int(mb[25:35])
spd = None if spd == 0 else spd - 1
if subtype == 4 and spd is not None: # Supersonic
spd *= 4
if mb[24] == "0":
spd_type = "IAS"
else:
spd_type = "TAS"
dir_type = "MAGNETIC_NORTH"
vr_source = "GNSS" if mb[35] == "0" else "BARO"
vr_sign = -1 if mb[36] == "1" else 1
vr = common.bin2int(mb[37:46])
vs = None if vr == 0 else int(vr_sign * (vr - 1) * 64)
if source:
return ( # type: ignore
spd,
trk_or_hdg,
vs,
spd_type,
dir_type,
vr_source,
)
else:
return spd, trk_or_hdg, vs, spd_type
def altitude_diff(msg: str) -> None | float:
"""Decode the differece between GNSS and barometric altitude.
Args:
msg (str): 28 hexdigits string, TC=19
Returns:
int: Altitude difference in feet. Negative value indicates GNSS altitude
below barometric altitude.
"""
tc = common.typecode(msg)
if tc is None or tc != 19:
raise RuntimeError(
"%s: Not a airborne velocity message, expecting TC=19" % msg
)
msgbin = common.hex2bin(msg)
sign = -1 if int(msgbin[80]) else 1
value = common.bin2int(msgbin[81:88])
if value == 0 or value == 127:
return None
else:
return sign * (value - 1) * 25 # in ft.