define member variables with capital letters

This commit is contained in:
Sven Czarnian
2021-10-13 12:52:29 +02:00
parent 9d69a60396
commit 1e043e2765
15 changed files with 229 additions and 223 deletions

View File

@@ -27,12 +27,11 @@ class AMAN:
def __init__(self):
# default initialization of members
self.systemConfig = None
self.aircraftPerformance = None
self.receiver = None
self.weather = None
self.workers = []
self.inbounds = {}
self.SystemConfig = None
self.AircraftPerformance = None
self.Receiver = None
self.Weather = None
self.Workers = []
def __del__(self):
self.release()
@@ -41,19 +40,19 @@ class AMAN:
configPath = AMAN.findConfigPath()
# read all system relevant configuration files
self.systemConfig = System(os.path.join(configPath, 'System.ini'))
self.SystemConfig = System(os.path.join(configPath, 'System.ini'))
print('Parsed System.ini')
# read the aircraft performance data
self.aircraftPerformance = AircraftPerformance(os.path.join(configPath, 'PerformanceData.ini'))
if None == self.aircraftPerformance:
self.AircraftPerformance = AircraftPerformance(os.path.join(configPath, 'PerformanceData.ini'))
if None == self.AircraftPerformance:
sys.stderr.write('No aircraft performance data found!')
sys.exit(-1)
else:
print('Parsed PerformanceData.ini. Extracted ' + str(len(self.aircraftPerformance.Aircrafts)) + ' aircrafts')
print('Parsed PerformanceData.ini. Extracted ' + str(len(self.AircraftPerformance.Aircrafts)) + ' aircrafts')
self.weather = Weather()
self.weather.acquire(self.systemConfig.Weather)
self.Weather = Weather()
self.Weather.acquire(self.SystemConfig.Weather)
# find the airport configurations and create the workers
airportsPath = os.path.join(os.path.join(configPath, 'airports'), '*.ini')
@@ -65,33 +64,33 @@ class AMAN:
# initialize the worker thread
worker = Worker()
worker.acquire(icao, airportConfig, self.weather, self.aircraftPerformance)
self.workers.append(worker)
worker.acquire(icao, airportConfig, self.Weather, self.AircraftPerformance)
self.Workers.append(worker)
print('Started worker for ' + icao)
# create the EuroScope receiver
self.receiver = Euroscope()
self.receiver.acquire(configPath, self.systemConfig.Server, self)
self.Receiver = Euroscope()
self.Receiver.acquire(configPath, self.SystemConfig.Server, self)
def release(self):
if None != self.receiver:
self.receiver.release()
self.receiver = None
if None != self.Receiver:
self.Receiver.release()
self.Receiver = None
if None != self.weather:
self.weather.release()
self.weather = None
if None != self.Weather:
self.Weather.release()
self.Weather = None
if None != self.workers:
for worker in self.workers:
if None != self.Workers:
for worker in self.Workers:
worker.release()
self.workers = None
self.Workers = None
def updateAircraftReport(self, report : AircraftReport_pb2.AircraftReport):
# find the correct worker for the inbound
for worker in self.workers:
if worker.icao == report.destination:
for worker in self.Workers:
if worker.Icao == report.destination:
worker.acquireLock()
worker.reportQueue[report.aircraft.callsign] = report
worker.ReportQueue[report.aircraft.callsign] = report
worker.releaseLock()
break

View File

@@ -19,8 +19,8 @@ from datetime import datetime as dt
# - third element of wind data tuple: wind speed (KT)
class DwdCrawler():
def __init__(self):
self.updateTime = None
self.windData = None
self.UpdateTime = None
self.WindData = None
def parseGaforAreas(areas : str):
areas = areas.replace(':', '')
@@ -125,8 +125,8 @@ class DwdCrawler():
return nextUpdate, windInformation
def receiveWindData(self):
self.updateTime = None
self.windData = None
self.UpdateTime = None
self.WindData = None
with urllib.request.urlopen('https://www.dwd.de/DE/fachnutzer/luftfahrt/teaser/luftsportberichte/luftsportberichte_node.html') as site:
data = site.read().decode('utf-8')
@@ -141,17 +141,17 @@ class DwdCrawler():
pages.append('https://www.dwd.de/' + link['href'].split(';')[0])
# receive the wind data
self.updateTime = None
self.windData = []
self.UpdateTime = None
self.WindData = []
for page in pages:
next, wind = self.parseGaforPage(page)
if None != next:
if None == self.updateTime or self.updateTime > next:
self.updateTime = next
self.windData.extend(wind)
if None == self.UpdateTime or self.UpdateTime > next:
self.UpdateTime = next
self.WindData.extend(wind)
# indicate that new wind data is available
if None != self.updateTime:
if None != self.UpdateTime:
return True
else:
return False

View File

@@ -16,20 +16,20 @@ from threading import Thread, _active
class ReceiverThread(Thread):
def __init__(self, socket, aman):
Thread.__init__(self)
self.socket = socket
self.aman = aman
self.Socket = socket
self.AMAN = aman
def run(self):
while True:
try:
msg = self.socket.recv(zmq.NOBLOCK)
msg = self.Socket.recv(zmq.NOBLOCK)
# parse the received message
report = AircraftReport_pb2.AircraftReport()
report.ParseFromString(msg)
# try to associate the received aircraft to an airport
self.aman.updateAircraftReport(report)
self.AMAN.updateAircraftReport(report)
except zmq.ZMQError as error:
if zmq.EAGAIN == error.errno:
@@ -54,10 +54,10 @@ class ReceiverThread(Thread):
# @brief Receives and sends messages to EuroScope plugins
class Euroscope:
def __init__(self):
self.context = None
self.receiverSocket = None
self.receiverThread = None
self.notificationSocket = None
self.Context = None
self.ReceiverSocket = None
self.ReceiverThread = None
self.NotificationSocket = None
def __del__(self):
self.release()
@@ -65,7 +65,7 @@ class Euroscope:
# @brief Initializes the ZMQ socket
# @param[in] config The server configuration
def acquire(self, configPath : str, config : Server, aman):
self.context = zmq.Context()
self.Context = zmq.Context()
# find the key directories
serverKeyPath = os.path.join(os.path.join(configPath, 'keys'), 'server')
@@ -88,34 +88,36 @@ class Euroscope:
keyPair = zmq.auth.load_certificate(keyPairPath[0])
# initialize the receiver
self.receiverSocket = zmq.Socket(self.context, zmq.SUB)
self.receiverSocket.setsockopt(zmq.CURVE_PUBLICKEY, keyPair[0])
self.receiverSocket.setsockopt(zmq.CURVE_SECRETKEY, keyPair[1])
self.receiverSocket.setsockopt(zmq.CURVE_SERVER, True)
self.receiverSocket.bind('tcp://' + config.Address + ':' + str(config.PortReceiver))
self.receiverSocket.setsockopt(zmq.SUBSCRIBE, b'')
self.receiverThread = ReceiverThread(self.receiverSocket, aman)
self.receiverThread.start()
self.ReceiverSocket = zmq.Socket(self.Context, zmq.SUB)
self.ReceiverSocket.setsockopt(zmq.CURVE_PUBLICKEY, keyPair[0])
self.ReceiverSocket.setsockopt(zmq.CURVE_SECRETKEY, keyPair[1])
self.ReceiverSocket.setsockopt(zmq.CURVE_SERVER, True)
self.ReceiverSocket.bind('tcp://' + config.Address + ':' + str(config.PortReceiver))
self.ReceiverSocket.setsockopt(zmq.SUBSCRIBE, b'')
self.ReceiverThread = ReceiverThread(self.ReceiverSocket, aman)
self.ReceiverThread.start()
print('Listening to tcp://' + config.Address + ':' + str(config.PortReceiver))
# initialize the notification
self.notificationSocket = zmq.Socket(self.context, zmq.PUB)
self.notificationSocket.setsockopt(zmq.CURVE_PUBLICKEY, keyPair[0])
self.notificationSocket.setsockopt(zmq.CURVE_SECRETKEY, keyPair[1])
self.notificationSocket.setsockopt(zmq.CURVE_SERVER, True)
self.notificationSocket.bind('tcp://' + config.Address + ':' + str(config.PortNotification))
self.NotificationSocket = zmq.Socket(self.Context, zmq.PUB)
self.NotificationSocket.setsockopt(zmq.CURVE_PUBLICKEY, keyPair[0])
self.NotificationSocket.setsockopt(zmq.CURVE_SECRETKEY, keyPair[1])
self.NotificationSocket.setsockopt(zmq.CURVE_SERVER, True)
self.NotificationSocket.bind('tcp://' + config.Address + ':' + str(config.PortNotification))
print('Publishing to tcp://' + config.Address + ':' + str(config.PortNotification))
def release(self):
if None != self.receiverThread:
self.receiverThread.stopThread()
self.receiverThread.join()
self.receiverThread = None
if None != self.ReceiverThread:
self.ReceiverThread.stopThread()
self.ReceiverThread.join()
self.ReceiverThread = None
if None != self.receiverSocket:
self.receiverSocket.close()
self.receiverSocket = None
if None != self.ReceiverSocket:
self.ReceiverSocket.close()
self.ReceiverSocket = None
if None != self.notificationSocket:
self.notificationSocket.close()
self.notificationSocket = None
if None != self.NotificationSocket:
self.NotificationSocket.close()
self.NotificationSocket = None
self.Context = None

View File

@@ -14,19 +14,19 @@ class Weather(Thread):
def __init__(self):
Thread.__init__(self)
self.nextUpdate = None
self.lastUpdateTried = None
self.stopThread = False
self.provider = None
self.NextUpdate = None
self.LastUpdateTried = None
self.StopThread = False
self.Provider = None
def acquire(self, config : aman.config.Weather.Weather):
self.nextUpdate = dt.utcfromtimestamp(int(time.time()))
self.lastUpdateTried = None
self.stopThread = False
self.provider = None
self.NextUpdate = dt.utcfromtimestamp(int(time.time()))
self.LastUpdateTried = None
self.StopThread = False
self.Provider = None
if 'DWD' == config.Provider.upper():
self.provider = DwdCrawler()
self.Provider = DwdCrawler()
else:
sys.stderr.write('Invalid or unknown weather-provider defined')
sys.exit(-1)
@@ -34,7 +34,7 @@ class Weather(Thread):
self.start()
def release(self):
self.stopThread = True
self.StopThread = True
self.join()
def currentClock():
@@ -42,15 +42,15 @@ class Weather(Thread):
return clock
def run(self):
while False == self.stopThread and None != self.provider:
while False == self.StopThread and None != self.Provider:
now = Weather.currentClock()
# check if an update is required
if None != self.provider.updateTime and self.provider.updateTime > now:
if None != self.Provider.UpdateTime and self.Provider.UpdateTime > now:
time.sleep(1)
continue
if None == self.lastUpdateTried or self.lastUpdateTried <= now:
if True == self.provider.receiveWindData():
self.nextUpdate = self.provider.updateTime
if None == self.LastUpdateTried or self.LastUpdateTried <= now:
if True == self.Provider.receiveWindData():
self.NextUpdate = self.Provider.UpdateTime
print('Received new wind data')

View File

@@ -17,12 +17,12 @@ class AircraftPerformance:
aircraft = PerformanceData(key)
aircraft.speedAboveFL240 = config[key]['speedabovefl240']
aircraft.rodAboveFL240 = config[key]['rodabovefl240']
aircraft.speedAboveFL100 = config[key]['speedabovefl100']
aircraft.rodAboveFL100 = config[key]['rodabovefl100']
aircraft.speedBelowFL100 = config[key]['speedbelowfl100']
aircraft.rodBelowFL100 = config[key]['rodbelowfl100']
aircraft.speedApproach = config[key]['speedapproach']
aircraft.SpeedAboveFL240 = config[key]['speedabovefl240']
aircraft.RodAboveFL240 = config[key]['rodabovefl240']
aircraft.SpeedAboveFL100 = config[key]['speedabovefl100']
aircraft.RodAboveFL100 = config[key]['rodabovefl100']
aircraft.SpeedBelowFL100 = config[key]['speedbelowfl100']
aircraft.RodBelowFL100 = config[key]['rodbelowfl100']
aircraft.SpeedApproach = config[key]['speedapproach']
self.Aircrafts[aircraft.icao] = aircraft
self.Aircrafts[aircraft.Icao] = aircraft

View File

@@ -43,7 +43,7 @@ class Airport:
if None == planning.get('arrivalspacingdefault'):
sys.stderr.write('No "arrivalspacingdefault" entry found!')
sys.exit(-1)
if not icao in self.GngData.runways:
if not icao in self.GngData.Runways:
sys.stderr.write('Unable to find' + icao + 'in the SCT data!')
sys.exit(-1)
@@ -77,8 +77,8 @@ class Airport:
sys.exit(-1)
found = False
for runway in self.GngData.runways[icao]:
if ident == runway.name:
for runway in self.GngData.Runways[icao]:
if ident == runway.Name:
sequence = RunwaySequencing(runway)
sequence.Spacing = spacings[ident]
self.DefaultSequencing.activateRunway(sequence)
@@ -103,9 +103,13 @@ class Airport:
for i in range(0, len(dependencies), 2):
self.DefaultSequencing.addDependency(dependencies[i], dependencies[i + 1])
def __init__(self, filepath : str, icao : str):
self.arrivalRoutes = {}
def parseConstraints(self, icao : str, planning):
for key in planning:
if True == key.startswith('constraints'):
star = key.replace('constraints', '').upper()
#print(star)
def __init__(self, filepath : str, icao : str):
config = configparser.ConfigParser()
config.read(filepath)
@@ -153,5 +157,6 @@ class Airport:
sys.exit(-1)
self.GaforId = dataConfig['gaforid']
# get the default sequencing data
# get the default sequencing data and constraints
self.parseDefaultSequencingConfiguration(icao, planningConfig)
self.parseConstraints(icao, planningConfig)

View File

@@ -13,14 +13,14 @@ class AirportSequencing:
def activateRunway(self, runway : RunwaySequencing):
for active in self.ActiveArrivalRunways:
if active.Runway.name == runway.Runway.name:
self.ActiveArrivalRunways[runway.Runway.name] = runway
if active.Runway.Name == runway.Runway.Name:
self.ActiveArrivalRunways[runway.Runway.Name] = runway
return
self.ActiveArrivalRunways.append(runway)
def runwayIndex(self, identifier : str):
for i in range(0, len(self.ActiveArrivalRunways)):
if self.ActiveArrivalRunways[i].Runway.name == identifier:
if self.ActiveArrivalRunways[i].Runway.Name == identifier:
return i
return -1
@@ -70,7 +70,7 @@ class AirportSequencing:
def findRunway(self, identifier : str):
for runway in self.ActiveArrivalRunways:
if runway.Runway.name == identifier:
if runway.Runway.Name == identifier:
return runway
return None

View File

@@ -82,32 +82,32 @@ class SctEseFormat:
# extract all waypoints
for waypoint in config['VOR']:
waypoint = SctEseFormat.parseWaypoint(waypoint, 0, 2, 3)
self.waypoints.setdefault(waypoint.name, []).append(waypoint)
self.Waypoints.setdefault(waypoint.Name, []).append(waypoint)
for waypoint in config['NDB']:
waypoint = SctEseFormat.parseWaypoint(waypoint, 0, 1, 2)
self.waypoints.setdefault(waypoint.name, []).append(waypoint)
self.Waypoints.setdefault(waypoint.Name, []).append(waypoint)
for waypoint in config['FIXES']:
waypoint = SctEseFormat.parseWaypoint(waypoint, 0, 1, 2)
self.waypoints.setdefault(waypoint.name, []).append(waypoint)
self.Waypoints.setdefault(waypoint.Name, []).append(waypoint)
# extract the airports
for airport in config['AIRPORT']:
airport = SctEseFormat.parseWaypoint(airport, 0, 2, 3)
self.airports.setdefault(airport.name, []).append(airport)
self.Airports.setdefault(airport.Name, []).append(airport)
# extract the runways
for runway in config['RUNWAY']:
airport, runway0, runway1 = SctEseFormat.parseRunway(runway)
if None != airport:
if not airport in self.runways:
self.runways.setdefault(airport, [])
self.runways[airport].append(runway0)
self.runways[airport].append(runway1)
if not airport in self.Runways:
self.Runways.setdefault(airport, [])
self.Runways[airport].append(runway0)
self.Runways[airport].append(runway1)
def parseArrivalRoute(self, route : str, airport : Waypoint):
# split the route and validate that it is a STAR for the airport
split = route.split(':')
if 5 != len(split) or 'STAR' != split[0] or split[1] != airport.name:
if 5 != len(split) or 'STAR' != split[0] or split[1] != airport.Name:
return None
# find all waypoints
@@ -115,7 +115,7 @@ class SctEseFormat:
route = list(filter(None, split[4].split(' ')))
for waypoint in route:
# find the waypoint in the route
coordinates = self.waypoints[waypoint]
coordinates = self.Waypoints[waypoint]
# no waypoint with this name defined
if None == coordinates:
sys.stderr.write('Unable to find waypoint ' + waypoint)
@@ -150,10 +150,10 @@ class SctEseFormat:
foundSidsStars = False
# search the airport in the extracted list
if not airport in self.airports:
sys.stderr.write(airport + 'in self.airports', 'Unable to find the requested airport')
if not airport in self.Airports:
sys.stderr.write('Unable to find the requested airport')
sys.exit(-1)
airport = self.airports[airport][0]
airport = self.Airports[airport][0]
for key in config:
if 'SIDSSTARS' == key:
@@ -166,14 +166,14 @@ class SctEseFormat:
# parse all arrival routes
for line in config['SIDSSTARS']:
route = self.parseArrivalRoute(line, airport)
if None != route and route.name in allowedRoutes:
self.arrivalRoutes.setdefault(route.runway, []).append(route)
if None != route and route.Name in allowedRoutes:
self.ArrivalRoutes.setdefault(route.Runway, []).append(route)
def __init__(self, sctFilepath : str, eseFilepath : str, airport : str, allowedRoutes : list):
self.arrivalRoutes = {}
self.waypoints = {}
self.airports = {}
self.runways = {}
self.ArrivalRoutes = {}
self.Waypoints = {}
self.Airports = {}
self.Runways = {}
self.extractSctInformation(sctFilepath)
self.extractArrivalRoutes(eseFilepath, airport, allowedRoutes)

View File

@@ -7,13 +7,13 @@ import scipy.interpolate
class WeatherModel:
def __init__(self, gaforId, weather : Weather):
self.gafor = gaforId
self.weather = weather
self.windDirectionModel = None
self.windSpeedModel = None
self.lastWeatherUpdate = None
self.minimumAltitude = 1000000
self.maximumAltitude = -1
self.Gafor = gaforId
self.Weather = weather
self.WindDirectionModel = None
self.WindSpeedModel = None
self.LastWeatherUpdate = None
self.MinimumAltitude = 1000000
self.MaximumAltitude = -1
# create the density interpolation model
# the density model is based on https://aerotoolbox.com/atmcalc/
@@ -95,51 +95,51 @@ class WeatherModel:
return ias * math.sqrt(1.225 / self.densityModel(altitude).item())
def updateWindModel(self):
if None == self.lastWeatherUpdate or self.lastWeatherUpdate != self.weather.provider.updateTime:
self.lastWeatherUpdate = self.weather.provider.updateTime
if None == self.LastWeatherUpdate or self.LastWeatherUpdate != self.Weather.Provider.UpdateTime:
self.LastWeatherUpdate = self.Weather.Provider.UpdateTime
self.minimumAltitude = 1000000
self.maximumAltitude = -1
self.windDirectionModel = None
self.windSpeedModel = None
self.MinimumAltitude = 1000000
self.MaximumAltitude = -1
self.WindDirectionModel = None
self.WindSpeedModel = None
if None != self.weather.provider.windData and self.gafor in self.weather.provider.windData:
if None != self.Weather.Provider.WindData and self.Gafor in self.Weather.Provider.WindData:
altitudes = []
directions = []
speeds = []
# collect the data for the wind model
for level in self.weather.provider.windData[self.gafor]:
for level in self.Weather.Provider.WindData[self.Gafor]:
altitudes.append(level[0])
directions.append(level[1])
speeds.append(level[2])
# define the thresholds for later boundary checks
if self.minimumAltitude > level[0]:
self.minimumAltitude = level[0]
if self.maximumAltitude < level[0]:
self.maximumAltitude = level[0]
if self.MinimumAltitude > level[0]:
self.MinimumAltitude = level[0]
if self.MaximumAltitude < level[0]:
self.MaximumAltitude = level[0]
# calculate the models
if 1 < len(altitudes):
self.windDirectionModel = scipy.interpolate.interp1d(altitudes, directions)
self.windSpeedModel = scipy.interpolate.interp1d(altitudes, speeds)
self.WindDirectionModel = scipy.interpolate.interp1d(altitudes, directions)
self.WindSpeedModel = scipy.interpolate.interp1d(altitudes, speeds)
def calculateGS(self, altitude : int, ias : int, heading : int):
self.updateWindModel()
tas = self.calculateTAS(altitude, ias)
# initialize the wind data
if None != self.windDirectionModel and None != self.windSpeedModel:
if None != self.WindDirectionModel and None != self.WindSpeedModel:
direction = 0.0
speed = 0.0
if None != self.windSpeedModel and None != self.windDirectionModel:
if self.maximumAltitude <= altitude:
altitude = self.maximumAltitude - 1
if self.minimumAltitude >= altitude:
altitude = self.minimumAltitude + 1
direction = self.windDirectionModel(altitude).item()
speed = self.windSpeedModel(altitude).item()
if None != self.WindSpeedModel and None != self.WindDirectionModel:
if self.MaximumAltitude <= altitude:
altitude = self.MaximumAltitude - 1
if self.MinimumAltitude >= altitude:
altitude = self.MinimumAltitude + 1
direction = self.WindDirectionModel(altitude).item()
speed = self.WindSpeedModel(altitude).item()
else:
speed = 0
direction = 0

View File

@@ -14,48 +14,46 @@ from aman.types.PerformanceData import PerformanceData
class Worker(Thread):
def __init__(self):
Thread.__init__(self)
self.stopThread = None
self.icao = None
self.configuration = None
self.arrivalRoutes = None
self.performanceData = None
self.updateLock = None
self.reportQueue = {}
self.weatherModel = None
self.StopThread = None
self.Icao = None
self.Configuration = None
self.PerformanceData = None
self.UpdateLock = None
self.ReportQueue = {}
self.WeatherModel = None
self.RecedingHorizonControl = None
def __del__(self):
self.release()
def acquire(self, icao : str, configuration : Airport, weather : Weather, performance : PerformanceData):
self.stopThread = None
self.icao = icao
self.configuration = configuration
self.sequencingConfiguration = self.configuration.DefaultSequencing
self.performanceData = performance
self.arrivalRoutes = configuration.GngData.arrivalRoutes
self.updateLock = Lock()
self.reportQueue = {}
self.weatherModel = WeatherModel(self.configuration.GaforId, weather)
self.RecedingHorizonControl = RecedingHorizonControl(self.configuration.RecedingHorizonControl)
self.StopThread = None
self.Icao = icao
self.Configuration = configuration
self.sequencingConfiguration = configuration.DefaultSequencing
self.PerformanceData = performance
self.UpdateLock = Lock()
self.ReportQueue = {}
self.WeatherModel = WeatherModel(configuration.GaforId, weather)
self.RecedingHorizonControl = RecedingHorizonControl(configuration.RecedingHorizonControl)
self.start()
def acquireLock(self):
if None != self.updateLock:
self.updateLock.acquire()
if None != self.UpdateLock:
self.UpdateLock.acquire()
def release(self):
self.stopThread = True
self.StopThread = True
self.join()
def releaseLock(self):
if None != self.updateLock:
self.updateLock.release()
if None != self.UpdateLock:
self.UpdateLock.release()
def run(self):
counter = 0
while None == self.stopThread:
while None == self.StopThread:
time.sleep(1)
counter += 1
if 0 != (counter % 10):
@@ -67,17 +65,17 @@ class Worker(Thread):
self.RecedingHorizonControl.cleanupWindows()
# update the aircraft information in RHC
for callsign in self.reportQueue:
report = self.reportQueue[callsign]
for callsign in self.ReportQueue:
report = self.ReportQueue[callsign]
if 0 != report.distanceToIAF and '' != report.initialApproachFix:
inbound = Inbound(report, self.sequencingConfiguration, self.configuration.GngData, self.performanceData, self.weatherModel)
inbound = Inbound(report, self.sequencingConfiguration, self.Configuration.GngData, self.PerformanceData, self.WeatherModel)
if None != inbound.PlannedRunway and None != inbound.PlannedStar:
self.RecedingHorizonControl.update(inbound)
else:
print('Unable to find all data of ' + report.aircraft.callsign)
self.reportQueue.clear()
self.ReportQueue.clear()
if 0 != len(self.RecedingHorizonControl.Windows):
print('FCFS run:')
@@ -89,9 +87,9 @@ class Worker(Thread):
# this is required to handle the overlap between windows
preceedingInbounds = {}
for runway in self.sequencingConfiguration.ActiveArrivalRunways:
inbound = self.RecedingHorizonControl.lastFixedInboundOnRunway(runway.Runway.name)
inbound = self.RecedingHorizonControl.lastFixedInboundOnRunway(runway.Runway.Name)
if None != inbound:
preceedingInbounds[runway.Runway.name] = inbound
preceedingInbounds[runway.Runway.Name] = inbound
# search the ACO relevant aircrafts
relevantInbounds = self.RecedingHorizonControl.optimizationRelevantInbounds()
@@ -106,6 +104,6 @@ class Worker(Thread):
# TODO perform the ACO run
# TODO update the RHC stages based on the ACO run result
else:
print('No relevant inbounds found for the optimization in ' + self.icao)
print('No relevant inbounds found for the optimization in ' + self.Icao)
self.releaseLock()

View File

@@ -2,10 +2,10 @@
class ArrivalRoute:
def __init__(self, name : str, runway : str, waypoints : list):
self.name = name
self.runway = runway
self.iaf = waypoints[0]
self.route = waypoints
self.Name = name
self.Runway = runway
self.Iaf = waypoints[0]
self.Route = waypoints
def __str__(self):
return 'Name: ' + self.name + ', IAF: ' + self.iaf.name + ', RWY: ' + self.runway
return 'Name: ' + self.Name + ', IAF: ' + self.Iaf.name + ', RWY: ' + self.Runway

View File

@@ -39,7 +39,7 @@ class Inbound:
distance = 100000.0
currentPosition = Waypoint('', self.Report.position.latitude, self.Report.position.longitude)
for runway in sequencingConfig.ActiveArrivalRunways:
candidateDistance = runway.Runway.start.haversine(currentPosition)
candidateDistance = runway.Runway.Start.haversine(currentPosition)
if distance > candidateDistance:
self.PlannedRunway = runway
distance = candidateDistance
@@ -49,11 +49,11 @@ class Inbound:
if None == self.PlannedRunway:
return
for arrivalRunway in navData.arrivalRoutes:
if arrivalRunway == self.PlannedRunway.Runway.name:
stars = navData.arrivalRoutes[arrivalRunway]
for arrivalRunway in navData.ArrivalRoutes:
if arrivalRunway == self.PlannedRunway.Runway.Name:
stars = navData.ArrivalRoutes[arrivalRunway]
for star in stars:
if 0 != len(star.route) and self.Report.initialApproachFix == star.iaf.name:
if 0 != len(star.Route) and self.Report.initialApproachFix == star.Iaf.Name:
self.PlannedStar = star
return
@@ -63,14 +63,14 @@ class Inbound:
# calculate remaining trackmiles
remainingDistanceNM = self.Report.distanceToIAF
start = self.PlannedStar.route[0]
for i in range(1, len(self.PlannedStar.route)):
remainingDistanceNM += start.haversine(self.PlannedStar.route[i]) * 0.539957
start = self.PlannedStar.route[i]
start = self.PlannedStar.Route[0]
for i in range(1, len(self.PlannedStar.Route)):
remainingDistanceNM += start.haversine(self.PlannedStar.Route[i]) * 0.539957
start = self.PlannedStar.Route[i]
# calculate descend profile
flightTimeSeconds = 0
currentHeading = Waypoint('', self.Report.position.latitude, self.Report.position.longitude).bearing(self.PlannedStar.route[0])
currentHeading = Waypoint('', self.Report.position.latitude, self.Report.position.longitude).bearing(self.PlannedStar.Route[0])
distanceToWaypoint = self.Report.distanceToIAF
nextWaypointIndex = 0
currentPosition = [ self.Report.dynamics.altitude, self.Report.dynamics.groundSpeed ]
@@ -105,7 +105,7 @@ class Inbound:
distanceToWaypoint -= abs(lastDistance - remainingDistanceNM)
if 0 >= distanceToWaypoint:
nextWaypointIndex += 1
if nextWaypointIndex < len(self.PlannedStar.route):
currentHeading = self.PlannedStar.route[nextWaypointIndex - 1].bearing(self.PlannedStar.route[nextWaypointIndex])
if nextWaypointIndex < len(self.PlannedStar.Route):
currentHeading = self.PlannedStar.Route[nextWaypointIndex - 1].bearing(self.PlannedStar.Route[nextWaypointIndex])
return timedelta(seconds = flightTimeSeconds)

View File

@@ -2,27 +2,29 @@
class PerformanceData:
def __init__(self, icao : str):
self.icao = icao
self.speedAboveFL240 = 0.0
self.speedAboveFL100 = 0.0
self.speedBelowFL100 = 0.0
self.speedApproach = 0.0
self.rodAboveFL240 = 0.0
self.rodAboveFL100 = 0.0
self.rodBelowFL100 = 2000.0
self.Icao = icao
self.SpeedAboveFL240 = 0.0
self.SpeedAboveFL100 = 0.0
self.SpeedBelowFL100 = 0.0
self.SpeedApproach = 0.0
self.RodAboveFL240 = 0.0
self.RodAboveFL100 = 0.0
self.RodBelowFL100 = 2000.0
def ias(self, altitude, distance):
if 24000 >= altitude:
return self.speedAboveFL240
return self.SpeedAboveFL240
elif 10000 >= altitude:
return self.speedAboveFL100
return self.SpeedAboveFL100
elif 10000 < altitude and 5 < distance:
return self.SpeedBelowFL100
elif 5 >= distance:
return self.speedApproach
return self.SpeedApproach
else:
return 220
def __str__(self):
return 'ICAO: ' + self.icao + ', FL240: ' + str(self.rodAboveFL240) + '@' + str(self.speedAboveFL240) + \
', +FL100: ' + str(self.rodAboveFL100) + '@' + str(self.speedAboveFL100) + \
', -FL100: ' + str(self.rodBelowFL100) + '@' + str(self.speedBelowFL100) + \
', Vapp: ' + str(self.speedApproach)
return 'ICAO: ' + self.icao + ', FL240: ' + str(self.RodAboveFL240) + '@' + str(self.SpeedAboveFL240) + \
', +FL100: ' + str(self.RodAboveFL100) + '@' + str(self.SpeedAboveFL100) + \
', -FL100: ' + str(self.RodBelowFL100) + '@' + str(self.SpeedBelowFL100) + \
', Vapp: ' + str(self.SpeedApproach)

View File

@@ -4,9 +4,9 @@ from aman.types.Waypoint import Waypoint
class Runway:
def __init__(self, start : Waypoint, end : Waypoint):
self.name = start.name
self.start = start
self.end = end
self.Name = start.Name
self.Start = start
self.End = end
def heading(self):
return self.start.bearing(self.end)
return self.Start.bearing(self.End)

View File

@@ -21,18 +21,18 @@ class Waypoint:
return dd
def __init__(self, name : str, latitude : float, longitude : float):
self.name = name
self.coordinate = np.array([ latitude, longitude ])
self.Name = name
self.Coordinate = np.array([ latitude, longitude ])
def __str__(self):
return 'Name: ' + self.name + ', Lat: ' + str(self.coordinate[0]) + ', Lon: ' + str(self.coordinate[1])
return 'Name: ' + self.Name + ', Lat: ' + str(self.Coordinate[0]) + ', Lon: ' + str(self.Coordinate[1])
def haversine(self, other):
geodesic = pyproj.Geod(ellps='WGS84')
forward, backward, distance = geodesic.inv(self.coordinate[1], self.coordinate[0], other.coordinate[1], other.coordinate[0])
forward, backward, distance = geodesic.inv(self.Coordinate[1], self.Coordinate[0], other.Coordinate[1], other.Coordinate[0])
return distance / 1000.0
def bearing(self, other):
geodesic = pyproj.Geod(ellps='WGS84')
forward, backward, distance = geodesic.inv(self.coordinate[1], self.coordinate[0], other.coordinate[1], other.coordinate[0])
forward, backward, distance = geodesic.inv(self.Coordinate[1], self.Coordinate[0], other.Coordinate[1], other.Coordinate[0])
return forward