#!/usr/bin/env python from aman.com.Weather import Weather import math import scipy.interpolate class WeatherModel: def __init__(self, gaforId, weather : Weather): self.Gafor = gaforId self.Weather = weather self.Altitudes = None self.Directions = None self.Windspeeds = None 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/ altitudes = [ 50000, 45000, 40000, 38000, 36000, 34000, 32000, 30000, 28000, 26000, 24000, 22000, 20000, 18000, 16000, 15000, 14000, 13000, 12000, 11000, 10000, 9000, 8000, 7000, 6000, 5000, 4000, 3000, 2000, 1000, 0 ] densities = [ 0.18648, 0.23714, 0.24617, 0.33199, 0.36518, 0.39444, 0.42546, 0.45831, 0.402506, 0.432497, 0.464169, 0.60954, 0.65269, 0.69815, 0.74598, 0.77082, 0.79628, 0.82238, 0.84914, 0.87655, 0.90464, 0.93341, 0.96287, 0.99304, 1.02393, 1.05555, 1.08791, 1.12102, 1.1549, 1.18955, 1.225 ] self.densityModel = scipy.interpolate.interp1d(altitudes, densities) def calculateTAS(self, altitude : int, ias : int): if altitude >= 50000: altitude = 49999 if altitude <= 0: altitude = 1 # calculation based on https://aerotoolbox.com/airspeed-conversions/ return ias * math.sqrt(1.225 / self.densityModel(altitude).item()) def updateWindModel(self): if None == self.Weather or None == self.Weather.Provider: return if None == self.LastWeatherUpdate or self.LastWeatherUpdate != self.Weather.Provider.UpdateTime: self.MinimumAltitude = 1000000 self.MaximumAltitude = -1 self.WindDirectionModel = None self.WindSpeedModel = None self.Altitudes = None self.Directions = None self.Windspeeds = None if None != self.Weather.Provider.WindData and self.Gafor in self.Weather.Provider.WindData: self.Altitudes = [] self.Directions = [] self.Windspeeds = [] # collect the data for the wind model for level in self.Weather.Provider.WindData[self.Gafor]: self.Altitudes.append(level[0]) self.Directions.append(level[1]) self.Windspeeds.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] # calculate the models if 1 < len(self.Altitudes): self.WindDirectionModel = scipy.interpolate.interp1d(self.Altitudes, self.Directions) self.WindSpeedModel = scipy.interpolate.interp1d(self.Altitudes, self.Windspeeds) self.LastWeatherUpdate = self.Weather.Provider.UpdateTime else: self.LastWeatherUpdate = None def interpolateWindData(self, altitude : int): self.updateWindModel() # initialized the wind data 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() else: speed = 0 direction = 0 return speed, direction def calculateGS(self, altitude : int, ias : int, heading : int): speed, direction = self.interpolateWindData(altitude) tas = self.calculateTAS(altitude, ias) return tas + speed * math.cos(math.radians(direction) - math.radians(heading)) def convertGSToTAS(self, altitude : int, gs : int, heading : int): speed, direction = self.interpolateWindData(altitude) return gs - speed * math.cos(math.radians(direction) - math.radians(heading)) def estimateCourse(self, altitude : int, gs : int, heading : int): tas = self.convertGSToTAS(altitude, gs, heading) speed, direction = self.interpolateWindData(altitude) aca = heading - direction wca = speed * aca / tas if 0 <= aca: course = heading + wca else: course = heading - wca while 0 > course: course += 360 while 360 < course: course -= 360 return course