示例#1
0
def callsign(msg):
    """Aircraft callsign

    Args:
        msg (string): 28 bytes hexadecimal message string

    Returns:
        string: callsign
    """

    if common.typecode(msg) < 1 or common.typecode(msg) > 4:
        raise RuntimeError("%s: Not a identification message" % msg)

    chars = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ#####_###############0123456789######'
    msgbin = common.hex2bin(msg)
    csbin = msgbin[40:96]

    cs = ''
    cs += chars[common.bin2int(csbin[0:6])]
    cs += chars[common.bin2int(csbin[6:12])]
    cs += chars[common.bin2int(csbin[12:18])]
    cs += chars[common.bin2int(csbin[18:24])]
    cs += chars[common.bin2int(csbin[24:30])]
    cs += chars[common.bin2int(csbin[30:36])]
    cs += chars[common.bin2int(csbin[36:42])]
    cs += chars[common.bin2int(csbin[42:48])]

    # clean string, remove spaces and marks, if any.
    # cs = cs.replace('_', '')
    cs = cs.replace('#', '')
    return cs
示例#2
0
def surface_velocity(msg, rtn_sources=False):
    """Decode surface velocity from from a surface position message
    Args:
        msg (string): 28 bytes hexadecimal message string
        rtn_source (boolean): If the function will return
            the sources for direction of travel and vertical
            rate. This will change the return value from a four
            element array to a six element array.

    Returns:
        (int, float, int, string, string, None): speed (kt),
            ground track (degree), None for rate of climb/descend (ft/min),
            and speed type ('GS' for ground speed), direction source
            ('true_north' for ground track / true north as reference),
            None rate of climb/descent source.
    """

    if common.typecode(msg) < 5 or common.typecode(msg) > 8:
        raise RuntimeError("%s: Not a surface message, expecting 5<TC<8" % msg)

    mb = common.hex2bin(msg)[32:]

    # ground track
    trk_status = int(mb[12])
    if trk_status == 1:
        trk = common.bin2int(mb[13:20]) * 360.0 / 128.0
        trk = round(trk, 1)
    else:
        trk = None

    # ground movement / speed
    mov = common.bin2int(mb[5:12])

    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
        spd = round(spd, 2)

    if rtn_sources:
        return spd, trk, 0, "GS", "true_north", None
    else:
        return spd, trk, 0, "GS"
示例#3
0
def category(msg):
    """Aircraft category number

    Args:
        msg (string): 28 bytes hexadecimal message string

    Returns:
        int: category number
    """

    if common.typecode(msg) < 1 or common.typecode(msg) > 4:
        raise RuntimeError("%s: Not a identification message" % msg)

    msgbin = common.hex2bin(msg)
    return common.bin2int(msgbin[5:8])
示例#4
0
文件: bds05.py 项目: zh199225/pyModeS
def altitude(msg):
    """Decode aircraft altitude

    Args:
        msg (string): 28 bytes hexadecimal message string

    Returns:
        int: altitude in feet
    """

    tc = common.typecode(msg)

    if tc < 9 or tc == 19 or tc > 22:
        raise RuntimeError("%s: Not a airborn position message" % msg)

    mb = common.hex2bin(msg)[32:]

    if tc < 19:
        # barometric altitude
        q = mb[15]
        if q:
            n = common.bin2int(mb[8:15] + mb[16:20])
            alt = n * 25 - 1000
        else:
            alt = None
    else:
        # GNSS altitude, meters -> feet
        alt = common.bin2int(mb[8:20]) * 3.28084

    return alt
示例#5
0
def infer(msg):
    """Estimate the most likely BDS code of an message

    Args:
        msg (String): 28 bytes hexadecimal message string

    Returns:
        String or None: BDS version, or possible versions, or None if nothing matches.
    """

    df = common.df(msg)

    if common.allzeros(msg):
        return 'EMPTY'

    # For ADS-B / Mode-S extended squitter
    if df == 17:
        tc = common.typecode(msg)

        if 1 <= tc <= 4:
            return 'BDS08'  # indentification and category
        if 5 <= tc <= 8:
            return 'BDS06'  # surface movement
        if 9 <= tc <= 18:
            return 'BDS05'  # airborne position, baro-alt
        if tc == 19:
            return 'BDS09'  # airborne velocity
        if 20 <= tc <= 22:
            return 'BDS05'  # airborne position, gnss-alt
        if tc == 28:
            return 'BDS61'  # aircraft status
        if tc == 29:
            return 'BDS62'  # target state and status
        if tc == 31:
            return 'BDS65'  # operational status

    # For Comm-B replies, ELS + EHS only
    IS10 = bds10.is10(msg)
    IS17 = bds17.is17(msg)
    IS20 = bds20.is20(msg)
    IS30 = bds30.is30(msg)
    IS40 = bds40.is40(msg)
    IS50 = bds50.is50(msg)
    IS60 = bds60.is60(msg)

    allbds = np.array(
        ["BDS10", "BDS17", "BDS20", "BDS30", "BDS40", "BDS50", "BDS60"])

    mask = [IS10, IS17, IS20, IS30, IS40, IS50, IS60]

    bds = ','.join(sorted(allbds[mask]))

    if len(bds) == 0:
        return None
    else:
        return bds
示例#6
0
def surface_velocity(msg):
    """Decode surface velocity from from a surface position message
    Args:
        msg (string): 28 bytes hexadecimal message string

    Returns:
        (int, float, int, string): speed (kt), ground track (degree),
            rate of climb/descend (ft/min), and speed type
            ('GS' for ground speed, 'AS' for airspeed)
    """

    if common.typecode(msg) < 5 or common.typecode(msg) > 8:
        raise RuntimeError("%s: Not a surface message, expecting 5<TC<8" % msg)

    mb = common.hex2bin(msg)[32:]

    # ground track
    trk_status = int(mb[12])
    if trk_status == 1:
        trk = common.bin2int(mb[13:20]) * 360.0 / 128.0
        trk = round(trk, 1)
    else:
        trk = None

    # ground movment / speed
    mov = common.bin2int(mb[5:12])

    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
        spd = round(spd, 2)

    return spd, trk, 0, 'GS'
示例#7
0
文件: bds09.py 项目: Seanhsp/pyModeS
def altitude_diff(msg):
    """Decode the differece between GNSS and barometric altitude

    Args:
        msg (string): 28 bytes hexadecimal message string, TC=19

    Returns:
        int: Altitude difference in ft. Negative value indicates GNSS altitude
            below barometric altitude.
    """
    tc = common.typecode(msg)

    if 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.
示例#8
0
def typecode(msg):
    return common.typecode(msg)
示例#9
0
def tell(msg):
    def _print(label, value, unit=None):
        print("%20s: " % label, end="")
        print("%s " % value, end="")
        if unit:
            print(unit)
        else:
            print()

    df = common.df(msg)
    icao = common.icao(msg)

    _print("Message", msg)
    _print("ICAO address", icao)
    _print("Downlink Format", df)

    if df == 17:
        _print("Protocol", "Mode-S Extended Squitter (ADS-B)")

        tc = common.typecode(msg)
        if 1 <= tc <= 4:  # callsign
            callsign = adsb.callsign(msg)
            _print("Type", "Identitification and category")
            _print("Callsign:", callsign)

        if 5 <= tc <= 8:  # surface position
            _print("Type", "Surface position")
            oe = adsb.oe_flag(msg)
            msgbin = common.hex2bin(msg)
            cprlat = common.bin2int(msgbin[54:71]) / 131072.0
            cprlon = common.bin2int(msgbin[71:88]) / 131072.0
            v = adsb.surface_velocity(msg)
            _print("CPR format", "Odd" if oe else "Even")
            _print("CPR Latitude", cprlat)
            _print("CPR Longitude", cprlon)
            _print("Speed", v[0], "knots")
            _print("Track", v[1], "degrees")

        if 9 <= tc <= 18:  # airborne position
            _print("Type", "Airborne position (with barometric altitude)")
            alt = adsb.altitude(msg)
            oe = adsb.oe_flag(msg)
            msgbin = common.hex2bin(msg)
            cprlat = common.bin2int(msgbin[54:71]) / 131072.0
            cprlon = common.bin2int(msgbin[71:88]) / 131072.0
            _print("CPR format", "Odd" if oe else "Even")
            _print("CPR Latitude", cprlat)
            _print("CPR Longitude", cprlon)
            _print("Altitude", alt, "feet")

        if tc == 19:
            _print("Type", "Airborne velocity")
            spd, trk, vr, t = adsb.velocity(msg)
            types = {"GS": "Ground speed", "TAS": "True airspeed"}
            _print("Speed", spd, "knots")
            _print("Track", trk, "degrees")
            _print("Vertical rate", vr, "feet/minute")
            _print("Type", types[t])

        if 20 <= tc <= 22:  # airborne position
            _print("Type", "Airborne position (with GNSS altitude)")
            alt = adsb.altitude(msg)
            oe = adsb.oe_flag(msg)
            msgbin = common.hex2bin(msg)
            cprlat = common.bin2int(msgbin[54:71]) / 131072.0
            cprlon = common.bin2int(msgbin[71:88]) / 131072.0
            _print("CPR format", "Odd" if oe else "Even")
            _print("CPR Latitude", cprlat)
            _print("CPR Longitude", cprlon)
            _print("Altitude", alt, "feet")

    if df == 20:
        _print("Protocol", "Mode-S Comm-B altitude reply")
        _print("Altitude", common.altcode(msg), "feet")

    if df == 21:
        _print("Protocol", "Mode-S Comm-B identity reply")
        _print("Squawk code", common.idcode(msg))

    if df == 20 or df == 21:
        labels = {
            "BDS10": "Data link capability",
            "BDS17": "GICB capability",
            "BDS20": "Aircraft identification",
            "BDS30": "ACAS resolution",
            "BDS40": "Vertical intention report",
            "BDS50": "Track and turn report",
            "BDS60": "Heading and speed report",
            "BDS44": "Meteorological routine air report",
            "BDS45": "Meteorological hazard report",
            "EMPTY": "[No information available]",
        }

        BDS = bds.infer(msg, mrar=True)
        if BDS in labels.keys():
            _print("BDS", "%s (%s)" % (BDS, labels[BDS]))
        else:
            _print("BDS", BDS)

        if BDS == "BDS20":
            callsign = commb.cs20(msg)
            _print("Callsign", callsign)

        if BDS == "BDS40":
            _print("MCP target alt", commb.selalt40mcp(msg), "feet")
            _print("FMS Target alt", commb.selalt40fms(msg), "feet")
            _print("Pressure", commb.p40baro(msg), "millibar")

        if BDS == "BDS50":
            _print("Roll angle", commb.roll50(msg), "degrees")
            _print("Track angle", commb.trk50(msg), "degrees")
            _print("Track rate", commb.rtrk50(msg), "degree/second")
            _print("Ground speed", commb.gs50(msg), "knots")
            _print("True airspeed", commb.tas50(msg), "knots")

        if BDS == "BDS60":
            _print("Megnatic Heading", commb.hdg60(msg), "degrees")
            _print("Indicated airspeed", commb.ias60(msg), "knots")
            _print("Mach number", commb.mach60(msg))
            _print("Vertical rate (Baro)", commb.vr60baro(msg), "feet/minute")
            _print("Vertical rate (INS)", commb.vr60ins(msg), "feet/minute")

        if BDS == "BDS44":
            _print("Wind speed", commb.wind44(msg)[0], "knots")
            _print("Wind direction", commb.wind44(msg)[1], "degrees")
            _print("Temperature 1", commb.temp44(msg)[0], "Celsius")
            _print("Temperature 2", commb.temp44(msg)[1], "Celsius")
            _print("Pressure", commb.p44(msg), "hPa")
            _print("Humidity", commb.hum44(msg), "%")
            _print("Turbulence", commb.turb44(msg))

        if BDS == "BDS45":
            _print("Turbulence", commb.turb45(msg))
            _print("Wind shear", commb.ws45(msg))
            _print("Microbust", commb.mb45(msg))
            _print("Icing", commb.ic45(msg))
            _print("Wake vortex", commb.wv45(msg))
            _print("Temperature", commb.temp45(msg), "Celsius")
            _print("Pressure", commb.p45(msg), "hPa")
            _print("Radio height", commb.rh45(msg), "feet")
示例#10
0
文件: bds09.py 项目: Seanhsp/pyModeS
def airborne_velocity(msg, rtn_sources=False):
    """Calculate the speed, track (or heading), and vertical rate

    Args:
        msg (string): 28 bytes hexadecimal message string
        rtn_source (boolean): If the function will return
            the sources for direction of travel and vertical
            rate. This will change the return value from a four
            element array to a six element array.

    Returns:
        (int, float, int, string, string, string): speed (kt),
            ground track or heading (degree),
            rate of climb/descent (ft/min), speed type
            ('GS' for ground speed, 'AS' for airspeed),
            direction source ('true_north' for ground track / true north
            as refrence, 'mag_north' for magnetic north as reference),
            rate of climb/descent source ('Baro' for barometer, 'GNSS'
            for GNSS constellation).
    """

    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

    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_ns = common.bin2int(mb[25:35]) - 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

        tag = "GS"
        trk_or_hdg = round(trk, 2)
        dir_type = "true_north"

    else:
        if mb[13] == "0":
            hdg = None
        else:
            hdg = common.bin2int(mb[14:24]) / 1024.0 * 360.0
            hdg = round(hdg, 2)

        trk_or_hdg = hdg

        spd = common.bin2int(mb[25:35])
        spd = None if spd == 0 else spd - 1
        if subtype == 4:  # Supersonic
            spd *= 4

        if mb[24] == "0":
            tag = "IAS"
        else:
            tag = "TAS"

        dir_type = "mag_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])
    rocd = None if vr == 0 else int(vr_sign * (vr - 1) * 64)

    if rtn_sources:
        return spd, trk_or_hdg, rocd, tag, dir_type, vr_source
    else:
        return spd, trk_or_hdg, rocd, tag
示例#11
0
文件: bds09.py 项目: yzyGavin/pyModeS
def airborne_velocity(msg):
    """Calculate the speed, track (or heading), and vertical rate

    Args:
        msg (string): 28 bytes hexadecimal message string

    Returns:
        (int, float, int, string): speed (kt), ground track or heading (degree),
            rate of climb/descend (ft/min), and speed type
            ('GS' for ground speed, 'AS' for airspeed)
    """

    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

    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

        v_ns_sign = -1 if mb[24]=='1' else 1
        v_ns = common.bin2int(mb[25:35]) - 1       # north-south velocity

        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

        tag = 'GS'
        trk_or_hdg = round(trk, 2)

    else:
        if mb[13] == '0':
            hdg = None
        else:
            hdg = common.bin2int(mb[14:24]) / 1024.0 * 360.0
            hdg = round(hdg, 2)

        trk_or_hdg = hdg

        spd = common.bin2int(mb[25:35])
        spd = None if spd==0 else spd-1

        if mb[24]=='0':
            tag = 'IAS'
        else:
            tag = 'TAS'

    vr_sign = -1 if mb[36]=='1' else 1
    vr = common.bin2int(mb[37:46])
    rocd = None if vr==0 else int(vr_sign*(vr-1)*64)

    return spd, trk_or_hdg, rocd, tag
示例#12
0
def infer(msg, mrar=False):
    """Estimate the most likely BDS code of an message.

    Args:
        msg (String): 28 bytes hexadecimal message string
        mrar (bool): Also infer MRAR (BDS 44) and MHR (BDS 45). Defaults to False.

    Returns:
        String or None: BDS version, or possible versions, or None if nothing matches.

    """
    df = common.df(msg)

    if common.allzeros(msg):
        return "EMPTY"

    # For ADS-B / Mode-S extended squitter
    if df == 17:
        tc = common.typecode(msg)

        if 1 <= tc <= 4:
            return "BDS08"  # identification and category
        if 5 <= tc <= 8:
            return "BDS06"  # surface movement
        if 9 <= tc <= 18:
            return "BDS05"  # airborne position, baro-alt
        if tc == 19:
            return "BDS09"  # airborne velocity
        if 20 <= tc <= 22:
            return "BDS05"  # airborne position, gnss-alt
        if tc == 28:
            return "BDS61"  # aircraft status
        if tc == 29:
            return "BDS62"  # target state and status
        if tc == 31:
            return "BDS65"  # operational status

    # For Comm-B replies
    IS10 = bds10.is10(msg)
    IS17 = bds17.is17(msg)
    IS20 = bds20.is20(msg)
    IS30 = bds30.is30(msg)
    IS40 = bds40.is40(msg)
    IS50 = bds50.is50(msg)
    IS60 = bds60.is60(msg)
    IS44 = bds44.is44(msg)
    IS45 = bds45.is45(msg)

    if mrar:
        allbds = np.array([
            "BDS10",
            "BDS17",
            "BDS20",
            "BDS30",
            "BDS40",
            "BDS44",
            "BDS45",
            "BDS50",
            "BDS60",
        ])
        mask = [IS10, IS17, IS20, IS30, IS40, IS44, IS45, IS50, IS60]
    else:
        allbds = np.array(
            ["BDS10", "BDS17", "BDS20", "BDS30", "BDS40", "BDS50", "BDS60"])
        mask = [IS10, IS17, IS20, IS30, IS40, IS50, IS60]

    bds = ",".join(sorted(allbds[mask]))

    if len(bds) == 0:
        return None
    else:
        return bds