fix altitude decoding

This commit is contained in:
Junzi Sun 2020-05-23 19:17:58 +02:00
parent 7892aac4de
commit 4126dedd19
4 changed files with 99 additions and 70 deletions

View File

@ -19,6 +19,7 @@ cpdef int typecode(str msg)
cpdef int cprNL(double lat) cpdef int cprNL(double lat)
cpdef str idcode(str msg) cpdef str idcode(str msg)
cpdef int altcode(str msg) cpdef int altcode(str msg)
cpdef int altitude(str binstr)
cpdef str data(str msg) cpdef str data(str msg)
cpdef bint allzeros(str msg) cpdef bint allzeros(str msg)

View File

@ -256,7 +256,6 @@ cpdef str idcode(str msg):
"""Compute identity (squawk code). """Compute identity (squawk code).
Applicable only for DF5 or DF21 messages, bit 20-32. Applicable only for DF5 or DF21 messages, bit 20-32.
credit: @fbyrkjeland
Args: Args:
msg (String): 28 bytes hexadecimal message string msg (String): 28 bytes hexadecimal message string
@ -280,7 +279,7 @@ cpdef str idcode(str msg):
cdef unsigned char A2 = mbin[22] cdef unsigned char A2 = mbin[22]
cdef unsigned char C4 = mbin[23] cdef unsigned char C4 = mbin[23]
cdef unsigned char A4 = mbin[24] cdef unsigned char A4 = mbin[24]
# _ = mbin[25] # X = mbin[25]
cdef unsigned char B1 = mbin[26] cdef unsigned char B1 = mbin[26]
cdef unsigned char D1 = mbin[27] cdef unsigned char D1 = mbin[27]
cdef unsigned char B2 = mbin[28] cdef unsigned char B2 = mbin[28]
@ -288,11 +287,6 @@ cpdef str idcode(str msg):
cdef unsigned char B4 = mbin[30] cdef unsigned char B4 = mbin[30]
cdef unsigned char D4 = mbin[31] cdef unsigned char D4 = mbin[31]
# byte1 = int(A4 + A2 + A1, 2)
# byte2 = int(B4 + B2 + B1, 2)
# byte3 = int(C4 + C2 + C1, 2)
# byte4 = int(D4 + D2 + D1, 2)
idcode[0] = int_to_char((char_to_int(A4)*2 + char_to_int(A2))*2 + char_to_int(A1)) idcode[0] = int_to_char((char_to_int(A4)*2 + char_to_int(A2))*2 + char_to_int(A1))
idcode[1] = int_to_char((char_to_int(B4)*2 + char_to_int(B2))*2 + char_to_int(B1)) idcode[1] = int_to_char((char_to_int(B4)*2 + char_to_int(B2))*2 + char_to_int(B1))
idcode[2] = int_to_char((char_to_int(C4)*2 + char_to_int(C2))*2 + char_to_int(C1)) idcode[2] = int_to_char((char_to_int(C4)*2 + char_to_int(C2))*2 + char_to_int(C1))
@ -321,47 +315,62 @@ cpdef int altcode(str msg):
if df(msg) not in [0, 4, 16, 20]: if df(msg) not in [0, 4, 16, 20]:
raise RuntimeError("Message must be Downlink Format 0, 4, 16, or 20.") raise RuntimeError("Message must be Downlink Format 0, 4, 16, or 20.")
# Altitude code, bit 20-32 alt = altitude(hex2bin(msg)[19:32])
cdef bytearray _mbin = bytearray(hex2bin(msg).encode())
return alt
@cython.boundscheck(False)
@cython.wraparound(False)
cpdef int altitude(str binstr):
if len(binstr) != 13 or set(binstr) != set('01'):
raise RuntimeError("Input must be 13 bits binary string")
cdef bytearray _mbin = bytearray(binstr.encode())
cdef unsigned char[:] mbin = _mbin cdef unsigned char[:] mbin = _mbin
cdef char mbit = mbin[25] # M bit: 26 cdef char Mbit = binstr[6]
cdef char qbit = mbin[27] # Q bit: 28 cdef char Qbit = binstr[8]
cdef int alt = 0 cdef int alt = 0
cdef bytearray vbin cdef bytearray vbin
cdef bytearray _graybytes = bytearray(11) cdef bytearray _graybytes = bytearray(11)
cdef unsigned char[:] graybytes = _graybytes cdef unsigned char[:] graybytes = _graybytes
if mbit == 48: # unit in ft, "0" -> 48 if bin2int(binstr) == 0:
if qbit == 49: # 25ft interval, "1" -> 49 # altitude unknown or invalid
vbin = _mbin[19:25] + _mbin[26:27] + _mbin[28:32] alt = -9999
elif Mbit == 48: # unit in ft, "0" -> 48
if Qbit == 49: # 25ft interval, "1" -> 49
vbin = _mbin[:6] + _mbin[7:8] + _mbin[9:]
alt = bin2int(vbin.decode()) * 25 - 1000 alt = bin2int(vbin.decode()) * 25 - 1000
if qbit == 48: # 100ft interval, above 50175ft, "0" -> 48 if Qbit == 48: # 100ft interval, above 50175ft, "0" -> 48
graybytes[8] = mbin[19] graybytes[8] = mbin[0]
graybytes[2] = mbin[20] graybytes[2] = mbin[1]
graybytes[9] = mbin[21] graybytes[9] = mbin[2]
graybytes[3] = mbin[22] graybytes[3] = mbin[3]
graybytes[10] = mbin[23] graybytes[10] = mbin[4]
graybytes[4] = mbin[24] graybytes[4] = mbin[5]
# _ = mbin[25] # M = mbin[6]
graybytes[5] = mbin[26] graybytes[5] = mbin[7]
# cdef char D1 = mbin[27] # always zero # Q = mbin[8]
graybytes[6] = mbin[28] graybytes[6] = mbin[9]
graybytes[0] = mbin[29] graybytes[0] = mbin[10]
graybytes[7] = mbin[30] graybytes[7] = mbin[11]
graybytes[1] = mbin[31] graybytes[1] = mbin[12]
# graybytes = D2 + D4 + A1 + A2 + A4 + B1 + B2 + B4 + C1 + C2 + C4 # graybytes = D2 + D4 + A1 + A2 + A4 + B1 + B2 + B4 + C1 + C2 + C4
alt = gray2alt(_graybytes.decode()) alt = gray2alt(_graybytes.decode())
if mbit == 49: # unit in meter, "1" -> 49 elif Mbit == 49: # unit in meter, "1" -> 49
vbin = _mbin[19:25] + _mbin[26:31] vbin = _mbin[:6] + _mbin[7:]
alt = int(bin2int(vbin.decode()) * 3.28084) # convert to ft alt = int(bin2int(vbin.decode()) * 3.28084) # convert to ft
return alt return alt
cpdef int gray2alt(str codestr): cpdef int gray2alt(str codestr):
cdef str gc500 = codestr[:8] cdef str gc500 = codestr[:8]
cdef int n500 = gray2int(gc500) cdef int n500 = gray2int(gc500)

View File

@ -139,17 +139,13 @@ def altitude(msg):
raise RuntimeError("%s: Not a airborn position message" % msg) raise RuntimeError("%s: Not a airborn position message" % msg)
mb = common.hex2bin(msg)[32:] mb = common.hex2bin(msg)[32:]
altbin = mb[8:20]
if tc < 19: if tc < 19:
# barometric altitude altcode = altbin[0:6] + "0" + altbin[6:]
q = mb[15]
if q:
n = common.bin2int(mb[8:15] + mb[16:20])
alt = n * 25 - 1000
else: else:
alt = None altcode = altbin[0:6] + "0" + altbin[6:]
else:
# GNSS altitude, meters -> feet alt = common.altitude(altcode)
alt = common.bin2int(mb[8:20]) * 3.28084
return alt return alt

View File

@ -206,7 +206,6 @@ def idcode(msg):
"""Compute identity (squawk code). """Compute identity (squawk code).
Applicable only for DF5 or DF21 messages, bit 20-32. Applicable only for DF5 or DF21 messages, bit 20-32.
credit: @fbyrkjeland
Args: Args:
msg (String): 28 bytes hexadecimal message string msg (String): 28 bytes hexadecimal message string
@ -226,7 +225,7 @@ def idcode(msg):
A2 = mbin[22] A2 = mbin[22]
C4 = mbin[23] C4 = mbin[23]
A4 = mbin[24] A4 = mbin[24]
# _ = mbin[25] # X = mbin[25]
B1 = mbin[26] B1 = mbin[26]
D1 = mbin[27] D1 = mbin[27]
B2 = mbin[28] B2 = mbin[28]
@ -243,10 +242,9 @@ def idcode(msg):
def altcode(msg): def altcode(msg):
"""Compute the altitude. """Compute the altitude in DF 4 and 20.
Applicable only for DF4 or DF20 message, bit 20-32. Applicable only for DF4 or DF20 message, bit 20-32.
credit: @fbyrkjeland
Args: Args:
msg (String): 28 bytes hexadecimal message string msg (String): 28 bytes hexadecimal message string
@ -261,44 +259,69 @@ def altcode(msg):
# Altitude code, bit 20-32 # Altitude code, bit 20-32
mbin = hex2bin(msg) mbin = hex2bin(msg)
mbit = mbin[25] # M bit: 26 altitude_code = mbin[19:32]
qbit = mbin[27] # Q bit: 28
if mbit == "0": # unit in ft alt = altitude(altitude_code)
if qbit == "1": # 25ft interval
vbin = mbin[19:25] + mbin[26] + mbin[28:32] return alt
def altitude(binstr):
"""Decode 13 bits altitude code.
Args:
binstr (String): 13 bits binary string
Returns:
int: altitude in ft
"""
if len(binstr) != 13 or set(binstr) != set("01"):
raise RuntimeError("Input must be 13 bits binary string")
Mbit = binstr[6]
Qbit = binstr[8]
if bin2int(binstr) == 0:
# altitude unknown or invalid
alt = None
elif Mbit == "0": # unit in ft
if Qbit == "1": # 25ft interval
vbin = binstr[:6] + binstr[7] + binstr[9:]
alt = bin2int(vbin) * 25 - 1000 alt = bin2int(vbin) * 25 - 1000
if qbit == "0": # 100ft interval, above 50175ft if Qbit == "0": # 100ft interval, above 50187.5ft
C1 = mbin[19] C1 = binstr[0]
A1 = mbin[20] A1 = binstr[1]
C2 = mbin[21] C2 = binstr[2]
A2 = mbin[22] A2 = binstr[3]
C4 = mbin[23] C4 = binstr[4]
A4 = mbin[24] A4 = binstr[5]
# _ = mbin[25] # M = binstr[6]
B1 = mbin[26] B1 = binstr[7]
# D1 = mbin[27] # always zero # Q = binstr[8]
B2 = mbin[28] B2 = binstr[9]
D2 = mbin[29] D2 = binstr[10]
B4 = mbin[30] B4 = binstr[11]
D4 = mbin[31] D4 = binstr[12]
graystr = D2 + D4 + A1 + A2 + A4 + B1 + B2 + B4 + C1 + C2 + C4 graystr = D2 + D4 + A1 + A2 + A4 + B1 + B2 + B4 + C1 + C2 + C4
alt = gray2alt(graystr) alt = gray2alt(graystr)
if mbit == "1": # unit in meter if Mbit == "1": # unit in meter
vbin = mbin[19:25] + mbin[26:31] vbin = binstr[:6] + binstr[7:]
alt = int(bin2int(vbin) * 3.28084) # convert to ft alt = int(bin2int(vbin) * 3.28084) # convert to ft
return alt return alt
def gray2alt(codestr): def gray2alt(binstr):
gc500 = codestr[:8] gc500 = binstr[:8]
n500 = gray2int(gc500) n500 = gray2int(gc500)
# in 100-ft step must be converted first # in 100-ft step must be converted first
gc100 = codestr[8:] gc100 = binstr[8:]
n100 = gray2int(gc100) n100 = gray2int(gc100)
if n100 in [0, 5, 6]: if n100 in [0, 5, 6]:
@ -314,9 +337,9 @@ def gray2alt(codestr):
return alt return alt
def gray2int(graystr): def gray2int(binstr):
"""Convert greycode to binary.""" """Convert greycode to binary."""
num = bin2int(graystr) num = bin2int(binstr)
num ^= num >> 8 num ^= num >> 8
num ^= num >> 4 num ^= num >> 4
num ^= num >> 2 num ^= num >> 2