From 4911e69171f56b794b9d3c64a581aca8de64808d Mon Sep 17 00:00:00 2001 From: Junzi Sun Date: Tue, 13 Mar 2018 16:55:50 +0100 Subject: [PATCH] update EHS BDS identification, add isBDS50or60() function --- pyModeS/__init__.py | 2 + pyModeS/decoder/ehs.py | 140 ++++--- pyModeS/extra/__init__.py | 1 + pyModeS/{streamer => extra}/aero.py | 356 +++++++++--------- .../client.py => extra/beastclient.py} | 0 pyModeS/streamer/pmstream.py | 10 +- pyModeS/streamer/stream.py | 33 +- tests/test_ehs.py | 6 +- 8 files changed, 274 insertions(+), 274 deletions(-) create mode 100644 pyModeS/extra/__init__.py rename pyModeS/{streamer => extra}/aero.py (89%) rename pyModeS/{streamer/client.py => extra/beastclient.py} (100%) diff --git a/pyModeS/__init__.py b/pyModeS/__init__.py index fdfb2a5..10f17ac 100644 --- a/pyModeS/__init__.py +++ b/pyModeS/__init__.py @@ -6,3 +6,5 @@ from .decoder import ehs from .decoder import els from .decoder import util from .decoder import modes_common +from .extra import aero +from .extra import beastclient diff --git a/pyModeS/decoder/ehs.py b/pyModeS/decoder/ehs.py index a8dc26e..7804347 100644 --- a/pyModeS/decoder/ehs.py +++ b/pyModeS/decoder/ehs.py @@ -18,8 +18,9 @@ A python package for decoding ModeS (DF20, DF21) messages. """ from __future__ import absolute_import, print_function, division -from . import util, modes_common -from scipy.stats import multivariate_normal +import numpy as np +from pyModeS.decoder import util, modes_common +from pyModeS.extra import aero def icao(msg): return modes_common.icao(msg) @@ -972,6 +973,61 @@ def vr60ins(msg): return roc +def isBDS50or60(msg, spd_ref, trk_ref, alt_ref): + """Use reference ground speed and trk to determine BDS50 and DBS60 + + Args: + msg (String): 28 bytes hexadecimal message string + spd_ref (float): reference speed (ADS-B ground speed), kts + trk_ref (float): reference track (ADS-B track angle), deg + alt_ref (float): reference altitude (ADS-B altitude), ft + + Returns: + String or None: BDS version, or possible versions, or None if nothing matches. + """ + def vxy(v, angle): + vx = v * np.sin(np.deg2rad(angle)) + vy = v * np.cos(np.deg2rad(angle)) + return vx, vy + + if not (isBDS50(msg) and isBDS60(msg)): + return None + + h50 = trk50(msg) + v50 = gs50(msg) + h50 = np.nan if h50 is None else h50 + v50 = np.nan if v50 is None else v50 + + + h60 = hdg60(msg) + m60 = mach60(msg) + i60 = ias60(msg) + h60 = np.nan if h60 is None else h60 + m60 = np.nan if m60 is None else m60 + i60 = np.nan if i60 is None else i60 + + XY5 = vxy(v50*aero.kts, h50) + XY6m = vxy(aero.mach2tas(m60, alt_ref*aero.ft), h60) + XY6i = vxy(aero.cas2tas(i60*aero.kts, alt_ref*aero.ft), h60) + + allbds = ['BDS50', 'BDS60', 'BDS60'] + + X = np.array([XY5, XY6m, XY6i]) + Mu = np.array(vxy(spd_ref*aero.kts, trk_ref*aero.kts)) + + # compute Mahalanobis distance matrix + # Cov = [[20**2, 0], [0, 20**2]] + # mmatrix = np.sqrt(np.dot(np.dot(X-Mu, np.linalg.inv(Cov)), (X-Mu).T)) + # dist = np.diag(mmatrix) + + # since the covariance matrix is identity matrix, + # M-dist is same as eculidian distance + dist = np.linalg.norm(X-Mu, axis=1) + BDS = allbds[np.nanargmin(dist)] + + return BDS + + def BDS(msg): """Estimate the most likely BDS code of an message @@ -994,78 +1050,16 @@ def BDS(msg): is53 = isBDS53(msg) is60 = isBDS60(msg) - BDS = ["BDS17", "BDS20", "BDS40", "BDS44", "BDS44REV", "BDS50", "BDS53", "BDS60"] + allbds = np.array([ + "BDS17", "BDS20", "BDS40", "BDS44", "BDS44REV", + "BDS50", "BDS53", "BDS60" + ]) + isBDS = [is17, is20, is40, is44, is44rev, is50, is53, is60] - if sum(isBDS) == 0: + bds = ','.join(sorted(allbds[isBDS])) + + if len(bds) == 0: return None - elif sum(isBDS) == 1: - return BDS[isBDS.index(True)] else: - bds_ = [bds for (bds, i) in zip(BDS, isBDS) if i] - return ','.join(bds_) - -def Vxy(V, angle): - Vx = V*np.sin(np.deg2rad(angle)) - Vy = V*np.cos(np.deg2rad(angle)) - return Vx, Vy - -def BDSv2(msg, SPDref=np.nan, TRKref=np.nan, ALTref=np.nan): - """Use probabilistic method to determine the most likely BDS code of an message - - Args: - msg (String): 28 bytes hexadecimal message string - SPDref (float): reference speed (for example ADS-B GS) - TRKref (float): reference track (for example ADS-B TRK) - ALTref (float): reference altitude (for example ADS-B altitude) - - Returns: - String or None: BDS version, or possible versions, or None if nothing matches. - """ - - BDS = pms.ehs.BDS(msg) - - if type(BDS) != list: - return BDS - else: - if 'BDS53' in BDS: - BDS.remove('BDS53') - - if 'BDS40' in BDS: - fms = pms.ehs.alt40fms(msg) - mcp = pms.ehs.alt40mcp(msg) - baro = pms.ehs.p40baro(msg) - - if fms != None: - if (((fms % 100) <= 8) or ((fms % 100) >= 92)) and fms < 50500: - return 'BDS40' - if mcp != None: - if (((mcp % 100) <= 8) or ((mcp % 100) >= 92)) and mcp < 50500: - return 'BDS40' - if baro != None: - if (983 <= baro <= 1043): #1013 -+ 30 - return 'BDS40' - - if set(BDS).issubset(['BDS50', 'BDS60']): - if ~(np.isnan(SPDref) or np.isnan(TRKref) or np.isnan(ALTref)): - meanV = Vxy(SPDref, TRKref) - sigmaV = 20 - covV = [[sigmaV**2, 0], [0, sigmaV**2]] - - try: # Because register field is not available. - pBDS50 = multivariate_normal(meanV, covV).pdf(Vxy(pms.ehs.gs50(msg), pms.ehs.trk50(msg))) - pBDS60_1 = multivariate_normal(meanV, covV).pdf(Vxy(aero.mach2tas(pms.ehs.mach60(msg), ALTref*aero.ft)/aero.kts, pms.ehs.hdg60(msg))) - pBDS60_2 = multivariate_normal(meanV, covV).pdf(Vxy(aero.cas2tas(pms.ehs.ias60(msg)*aero.kts, ALTref*aero.ft)/aero.kts, pms.ehs.hdg60(msg))) - pBDS60 = max(pBDS60_1, pBDS60_2) - - except: - return BDS - - if pBDS50 + pBDS60 > 0: #Avoid None values - if pBDS50 > pBDS60: - return 'BDS50' - elif pBDS50 < pBDS60: - return 'BDS60' - - return BDS - + return bds diff --git a/pyModeS/extra/__init__.py b/pyModeS/extra/__init__.py new file mode 100644 index 0000000..f298a61 --- /dev/null +++ b/pyModeS/extra/__init__.py @@ -0,0 +1 @@ +from __future__ import absolute_import, print_function, division diff --git a/pyModeS/streamer/aero.py b/pyModeS/extra/aero.py similarity index 89% rename from pyModeS/streamer/aero.py rename to pyModeS/extra/aero.py index 5557813..8953712 100644 --- a/pyModeS/streamer/aero.py +++ b/pyModeS/extra/aero.py @@ -1,178 +1,178 @@ -""" -Functions for aeronautics in this module - - physical quantities always in SI units - - lat,lon,course and heading in degrees - -International Standard Atmosphere - p,rho,T = atmos(H) # atmos as function of geopotential altitude H [m] - a = vsound(H) # speed of sound [m/s] as function of H[m] - p = pressure(H) # calls atmos but retruns only pressure [Pa] - T = temperature(H) # calculates temperature [K] - rho = density(H) # calls atmos but retruns only pressure [Pa] - -Speed conversion at altitude H[m] in ISA: - Mach = tas2mach(Vtas,H) # true airspeed (Vtas) to mach number conversion - Vtas = mach2tas(Mach,H) # true airspeed (Vtas) to mach number conversion - Vtas = eas2tas(Veas,H) # equivalent airspeed to true airspeed, H in [m] - Veas = tas2eas(Vtas,H) # true airspeed to equivent airspeed, H in [m] - Vtas = cas2tas(Vcas,H) # Vcas to Vtas conversion both m/s, H in [m] - Vcas = tas2cas(Vtas,H) # Vtas to Vcas conversion both m/s, H in [m] - Vcas = mach2cas(Mach,H) # Mach to Vcas conversion Vcas in m/s, H in [m] - Mach = cas2mach(Vcas,H) # Vcas to mach copnversion Vcas in m/s, H in [m] -""" - -import numpy as np - -"""Aero and geo Constants """ -kts = 0.514444 # knot -> m/s -ft = 0.3048 # ft -> m -fpm = 0.00508 # ft/min -> m/s -inch = 0.0254 # inch -> m -sqft = 0.09290304 # 1 square foot -nm = 1852. # nautical mile -> m -lbs = 0.453592 # pound -> kg -g0 = 9.80665 # m/s2, Sea level gravity constant -R = 287.05287 # m2/(s2 x K), gas constant, sea level ISA -p0 = 101325. # Pa, air pressure, sea level ISA -rho0 = 1.225 # kg/m3, air density, sea level ISA -T0 = 288.15 # K, temperature, sea level ISA -gamma = 1.40 # cp/cv for air -gamma1 = 0.2 # (gamma-1)/2 for air -gamma2 = 3.5 # gamma/(gamma-1) for air -beta = -0.0065 # [K/m] ISA temp gradient below tropopause -r_earth = 6371000. # m, average earth radius -a0 = 340.293988 # m/s, sea level speed of sound ISA, sqrt(gamma*R*T0) - - -def atmos(H): - # H in metres - T = np.maximum(288.15 - 0.0065 * H, 216.65) - rhotrop = 1.225 * (T / 288.15)**4.256848030018761 - dhstrat = np.maximum(0., H - 11000.0) - rho = rhotrop * np.exp(-dhstrat / 6341.552161) - p = rho * R * T - return p, rho, T - - -def temperature(H): - p, r, T = atmos(H) - return T - - -def pressure(H): - p, r, T = atmos(H) - return p - - -def density(H): - p, r, T = atmos(H) - return r - - -def vsound(H): - """Speed of sound""" - T = temperature(H) - a = np.sqrt(gamma * R * T) - return a - - -def distance(lat1, lon1, lat2, lon2, H=0): - """ - Compute spherical distance from spherical coordinates. - - For two locations in spherical coordinates - (1, theta, phi) and (1, theta', phi') - cosine( arc length ) = - sin phi sin phi' cos(theta-theta') + cos phi cos phi' - distance = rho * arc length - """ - - # phi = 90 - latitude - phi1 = np.radians(90.0 - lat1) - phi2 = np.radians(90.0 - lat2) - - # theta = longitude - theta1 = np.radians(lon1) - theta2 = np.radians(lon2) - - cos = np.sin(phi1) * np.sin(phi2) * np.cos(theta1 - theta2) \ - + np.cos(phi1) * np.cos(phi2) - - arc = np.arccos(cos) - dist = arc * (r_earth + H) # meters, radius of earth - return dist - - -def bearing(lat1, lon1, lat2, lon2): - lat1 = np.radians(lat1) - lon1 = np.radians(lon1) - lat2 = np.radians(lat2) - lon2 = np.radians(lon2) - x = np.sin(lon2-lon1) * np.cos(lat2) - y = np.cos(lat1) * np.sin(lat2) \ - - np.sin(lat1) * np.cos(lat2) * np.cos(lon2-lon1) - initial_bearing = np.arctan2(x, y) - initial_bearing = np.degrees(initial_bearing) - bearing = (initial_bearing + 360) % 360 - return bearing - - -# ----------------------------------------------------- -# Speed conversions, altitude H all in meters -# ----------------------------------------------------- -def tas2mach(Vtas, H): - """True Airspeed to Mach number""" - a = vsound(H) - Mach = Vtas/a - return Mach - - -def mach2tas(Mach, H): - """Mach number to True Airspeed""" - a = vsound(H) - Vtas = Mach*a - return Vtas - - -def eas2tas(Veas, H): - """Equivalent Airspeed to True Airspeed""" - rho = density(H) - Vtas = Veas * np.sqrt(rho0/rho) - return Vtas - - -def tas2eas(Vtas, H): - """True Airspeed to Equivalent Airspeed""" - rho = density(H) - Veas = Vtas * np.sqrt(rho/rho0) - return Veas - - -def cas2tas(Vcas, H): - """Calibrated Airspeed to True Airspeed""" - p, rho, T = atmos(H) - qdyn = p0*((1.+rho0*Vcas*Vcas/(7.*p0))**3.5-1.) - Vtas = np.sqrt(7.*p/rho*((1.+qdyn/p)**(2./7.)-1.)) - return Vtas - - -def tas2cas(Vtas, H): - """True Airspeed to Calibrated Airspeed""" - p, rho, T = atmos(H) - qdyn = p*((1.+rho*Vtas*Vtas/(7.*p))**3.5-1.) - Vcas = np.sqrt(7.*p0/rho0*((qdyn/p0+1.)**(2./7.)-1.)) - return Vcas - - -def mach2cas(Mach, H): - """Mach number to Calibrated Airspeed""" - Vtas = mach2tas(Mach, H) - Vcas = tas2cas(Vtas, H) - return Vcas - - -def cas2mach(Vcas, H): - """Calibrated Airspeed to Mach number""" - Vtas = cas2tas(Vcas, H) - Mach = tas2mach(Vtas, H) - return Mach +""" +Functions for aeronautics in this module + - physical quantities always in SI units + - lat,lon,course and heading in degrees + +International Standard Atmosphere + p,rho,T = atmos(H) # atmos as function of geopotential altitude H [m] + a = vsound(H) # speed of sound [m/s] as function of H[m] + p = pressure(H) # calls atmos but retruns only pressure [Pa] + T = temperature(H) # calculates temperature [K] + rho = density(H) # calls atmos but retruns only pressure [Pa] + +Speed conversion at altitude H[m] in ISA: + Mach = tas2mach(Vtas,H) # true airspeed (Vtas) to mach number conversion + Vtas = mach2tas(Mach,H) # true airspeed (Vtas) to mach number conversion + Vtas = eas2tas(Veas,H) # equivalent airspeed to true airspeed, H in [m] + Veas = tas2eas(Vtas,H) # true airspeed to equivent airspeed, H in [m] + Vtas = cas2tas(Vcas,H) # Vcas to Vtas conversion both m/s, H in [m] + Vcas = tas2cas(Vtas,H) # Vtas to Vcas conversion both m/s, H in [m] + Vcas = mach2cas(Mach,H) # Mach to Vcas conversion Vcas in m/s, H in [m] + Mach = cas2mach(Vcas,H) # Vcas to mach copnversion Vcas in m/s, H in [m] +""" + +import numpy as np + +"""Aero and geo Constants """ +kts = 0.514444 # knot -> m/s +ft = 0.3048 # ft -> m +fpm = 0.00508 # ft/min -> m/s +inch = 0.0254 # inch -> m +sqft = 0.09290304 # 1 square foot +nm = 1852. # nautical mile -> m +lbs = 0.453592 # pound -> kg +g0 = 9.80665 # m/s2, Sea level gravity constant +R = 287.05287 # m2/(s2 x K), gas constant, sea level ISA +p0 = 101325. # Pa, air pressure, sea level ISA +rho0 = 1.225 # kg/m3, air density, sea level ISA +T0 = 288.15 # K, temperature, sea level ISA +gamma = 1.40 # cp/cv for air +gamma1 = 0.2 # (gamma-1)/2 for air +gamma2 = 3.5 # gamma/(gamma-1) for air +beta = -0.0065 # [K/m] ISA temp gradient below tropopause +r_earth = 6371000. # m, average earth radius +a0 = 340.293988 # m/s, sea level speed of sound ISA, sqrt(gamma*R*T0) + + +def atmos(H): + # H in metres + T = np.maximum(288.15 - 0.0065 * H, 216.65) + rhotrop = 1.225 * (T / 288.15)**4.256848030018761 + dhstrat = np.maximum(0., H - 11000.0) + rho = rhotrop * np.exp(-dhstrat / 6341.552161) + p = rho * R * T + return p, rho, T + + +def temperature(H): + p, r, T = atmos(H) + return T + + +def pressure(H): + p, r, T = atmos(H) + return p + + +def density(H): + p, r, T = atmos(H) + return r + + +def vsound(H): + """Speed of sound""" + T = temperature(H) + a = np.sqrt(gamma * R * T) + return a + + +def distance(lat1, lon1, lat2, lon2, H=0): + """ + Compute spherical distance from spherical coordinates. + + For two locations in spherical coordinates + (1, theta, phi) and (1, theta', phi') + cosine( arc length ) = + sin phi sin phi' cos(theta-theta') + cos phi cos phi' + distance = rho * arc length + """ + + # phi = 90 - latitude + phi1 = np.radians(90.0 - lat1) + phi2 = np.radians(90.0 - lat2) + + # theta = longitude + theta1 = np.radians(lon1) + theta2 = np.radians(lon2) + + cos = np.sin(phi1) * np.sin(phi2) * np.cos(theta1 - theta2) + np.cos(phi1) * np.cos(phi2) + cos = np.where(cos>1, 1, cos) + + arc = np.arccos(cos) + dist = arc * (r_earth + H) # meters, radius of earth + return dist + + +def bearing(lat1, lon1, lat2, lon2): + lat1 = np.radians(lat1) + lon1 = np.radians(lon1) + lat2 = np.radians(lat2) + lon2 = np.radians(lon2) + x = np.sin(lon2-lon1) * np.cos(lat2) + y = np.cos(lat1) * np.sin(lat2) \ + - np.sin(lat1) * np.cos(lat2) * np.cos(lon2-lon1) + initial_bearing = np.arctan2(x, y) + initial_bearing = np.degrees(initial_bearing) + bearing = (initial_bearing + 360) % 360 + return bearing + + +# ----------------------------------------------------- +# Speed conversions, altitude H all in meters +# ----------------------------------------------------- +def tas2mach(Vtas, H): + """True Airspeed to Mach number""" + a = vsound(H) + Mach = Vtas/a + return Mach + + +def mach2tas(Mach, H): + """Mach number to True Airspeed""" + a = vsound(H) + Vtas = Mach*a + return Vtas + + +def eas2tas(Veas, H): + """Equivalent Airspeed to True Airspeed""" + rho = density(H) + Vtas = Veas * np.sqrt(rho0/rho) + return Vtas + + +def tas2eas(Vtas, H): + """True Airspeed to Equivalent Airspeed""" + rho = density(H) + Veas = Vtas * np.sqrt(rho/rho0) + return Veas + + +def cas2tas(Vcas, H): + """Calibrated Airspeed to True Airspeed""" + p, rho, T = atmos(H) + qdyn = p0*((1.+rho0*Vcas*Vcas/(7.*p0))**3.5-1.) + Vtas = np.sqrt(7.*p/rho*((1.+qdyn/p)**(2./7.)-1.)) + return Vtas + + +def tas2cas(Vtas, H): + """True Airspeed to Calibrated Airspeed""" + p, rho, T = atmos(H) + qdyn = p*((1.+rho*Vtas*Vtas/(7.*p))**3.5-1.) + Vcas = np.sqrt(7.*p0/rho0*((qdyn/p0+1.)**(2./7.)-1.)) + return Vcas + + +def mach2cas(Mach, H): + """Mach number to Calibrated Airspeed""" + Vtas = mach2tas(Mach, H) + Vcas = tas2cas(Vtas, H) + return Vcas + + +def cas2mach(Vcas, H): + """Calibrated Airspeed to Mach number""" + Vtas = cas2tas(Vcas, H) + Mach = tas2mach(Vtas, H) + return Mach diff --git a/pyModeS/streamer/client.py b/pyModeS/extra/beastclient.py similarity index 100% rename from pyModeS/streamer/client.py rename to pyModeS/extra/beastclient.py diff --git a/pyModeS/streamer/pmstream.py b/pyModeS/streamer/pmstream.py index 4c56f7d..3e65a11 100644 --- a/pyModeS/streamer/pmstream.py +++ b/pyModeS/streamer/pmstream.py @@ -5,11 +5,11 @@ import argparse import curses import numpy as np import time -import pyModeS as pms from threading import Lock -from client import BaseClient -from stream import Stream -from screen import Screen +from pyModeS.decoder import util +from pyModeS.extra.beastclient import BaseClient +from pyModeS.streamer.stream import Stream +from pyModeS.streamer.screen import Screen LOCK = Lock() ADSB_MSG = [] @@ -43,7 +43,7 @@ class ModesClient(BaseClient): if len(msg) < 28: # only process long messages continue - df = pms.df(msg) + df = util.df(msg) if df == 17 or df == 18: local_buffer_adsb_msg.append(msg) diff --git a/pyModeS/streamer/stream.py b/pyModeS/streamer/stream.py index c2c62c2..947f4af 100644 --- a/pyModeS/streamer/stream.py +++ b/pyModeS/streamer/stream.py @@ -1,8 +1,7 @@ -from __future__ import print_function, division +from __future__ import absolute_import, print_function, division import numpy as np import time -import pyModeS as pms - +from pyModeS.decoder import adsb, ehs class Stream(): def __init__(self, lat0, lon0): @@ -32,8 +31,8 @@ class Stream(): # process adsb message for t, msg in zip(adsb_ts, adsb_msgs): - icao = pms.adsb.icao(msg) - tc = pms.adsb.typecode(msg) + icao = adsb.icao(msg) + tc = adsb.typecode(msg) if icao not in self.acs: self.acs[icao] = { @@ -52,10 +51,10 @@ class Stream(): self.acs[icao]['t'] = t if 1 <= tc <= 4: - self.acs[icao]['callsign'] = pms.adsb.callsign(msg) + self.acs[icao]['callsign'] = adsb.callsign(msg) if (5 <= tc <= 8) or (tc == 19): - vdata = pms.adsb.velocity(msg) + vdata = adsb.velocity(msg) if vdata is None: continue @@ -69,7 +68,7 @@ class Stream(): self.acs[icao]['tv'] = t if (5 <= tc <= 18): - oe = pms.adsb.oe_flag(msg) + oe = adsb.oe_flag(msg) self.acs[icao][oe] = msg self.acs[icao]['t'+str(oe)] = t @@ -77,12 +76,12 @@ class Stream(): # use single message decoding rlat = self.acs[icao]['lat'] rlon = self.acs[icao]['lon'] - latlon = pms.adsb.position_with_ref(msg, rlat, rlon) + latlon = adsb.position_with_ref(msg, rlat, rlon) elif ('t0' in self.acs[icao]) and ('t1' in self.acs[icao]) and \ (abs(self.acs[icao]['t0'] - self.acs[icao]['t1']) < 10): # use multi message decoding try: - latlon = pms.adsb.position( + latlon = adsb.position( self.acs[icao][0], self.acs[icao][1], self.acs[icao]['t0'], @@ -99,29 +98,29 @@ class Stream(): self.acs[icao]['tpos'] = t self.acs[icao]['lat'] = latlon[0] self.acs[icao]['lon'] = latlon[1] - self.acs[icao]['alt'] = pms.adsb.altitude(msg) + self.acs[icao]['alt'] = adsb.altitude(msg) local_updated_acs_buffer.append(icao) # process ehs message for t, msg in zip(ehs_ts, ehs_msgs): - icao = pms.ehs.icao(msg) + icao = ehs.icao(msg) if icao not in self.acs: continue - bds = pms.ehs.BDS(msg) + bds = ehs.BDS(msg) if bds == 'BDS50': - tas = pms.ehs.tas50(msg) + tas = ehs.tas50(msg) if tas: self.acs[icao]['t50'] = t self.acs[icao]['tas'] = tas elif bds == 'BDS60': - ias = pms.ehs.ias60(msg) - hdg = pms.ehs.hdg60(msg) - mach = pms.ehs.mach60(msg) + ias = ehs.ias60(msg) + hdg = ehs.hdg60(msg) + mach = ehs.mach60(msg) if ias or hdg or mach: self.acs[icao]['t60'] = t diff --git a/tests/test_ehs.py b/tests/test_ehs.py index 87e3a16..ab1b362 100644 --- a/tests/test_ehs.py +++ b/tests/test_ehs.py @@ -14,10 +14,14 @@ def test_df20alt(): def test_ehs_BDS(): assert ehs.BDS("A0001838201584F23468207CDFA5") == 'BDS20' assert ehs.BDS("A0001839CA3800315800007448D9") == 'BDS40' - # assert ehs.BDS("A000031DBAA9DD18622C441330E9") == 'BDS44' assert ehs.BDS("A000139381951536E024D4CCF6B5") == 'BDS50' assert ehs.BDS("A00004128F39F91A7E27C46ADC21") == 'BDS60' +def test_ehs_isBDS50or60(): + assert ehs.isBDS50or60("A0001838201584F23468207CDFA5", 0, 0, 0) == None + assert ehs.isBDS50or60("A0000000FFDA9517000464000000", 182, 237, 1250) == 'BDS50' + assert ehs.isBDS50or60("A0000000919A5927E23444000000", 413, 54, 18700) == 'BDS60' + def test_ehs_BDS20_callsign(): assert ehs.callsign("A000083E202CC371C31DE0AA1CCF") == 'KLM1017_' assert ehs.callsign("A0001993202422F2E37CE038738E") == 'IBK2873_'