149 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			149 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/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.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.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
 | |
| 
 | |
|             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]:
 | |
|                     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]
 | |
| 
 | |
|                 # calculate the models
 | |
|                 if 1 < len(altitudes):
 | |
|                     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:
 | |
|             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
 | |
| 
 | |
|         # calculate the ground speed based on the headwind component
 | |
|         return tas + speed * math.cos(math.radians(direction) - math.radians(heading))
 |