WeatherModel.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #!/usr/bin/env python
  2. from aman.com.Weather import Weather
  3. import math
  4. import scipy.interpolate
  5. class WeatherModel:
  6. def __init__(self, gaforId, weather : Weather):
  7. self.gafor = gaforId
  8. self.weather = weather
  9. self.windDirectionModel = None
  10. self.windSpeedModel = None
  11. self.lastWeatherUpdate = None
  12. self.minimumAltitude = 1000000
  13. self.maximumAltitude = -1
  14. # create the density interpolation model
  15. # the density model is based on https://aerotoolbox.com/atmcalc/
  16. altitudes = [
  17. 50000,
  18. 45000,
  19. 40000,
  20. 38000,
  21. 36000,
  22. 34000,
  23. 32000,
  24. 30000,
  25. 28000,
  26. 26000,
  27. 24000,
  28. 22000,
  29. 20000,
  30. 18000,
  31. 16000,
  32. 15000,
  33. 14000,
  34. 13000,
  35. 12000,
  36. 11000,
  37. 10000,
  38. 9000,
  39. 8000,
  40. 7000,
  41. 6000,
  42. 5000,
  43. 4000,
  44. 3000,
  45. 2000,
  46. 1000,
  47. 0
  48. ]
  49. densities = [
  50. 0.18648,
  51. 0.23714,
  52. 0.24617,
  53. 0.33199,
  54. 0.36518,
  55. 0.39444,
  56. 0.42546,
  57. 0.45831,
  58. 0.402506,
  59. 0.432497,
  60. 0.464169,
  61. 0.60954,
  62. 0.65269,
  63. 0.69815,
  64. 0.74598,
  65. 0.77082,
  66. 0.79628,
  67. 0.82238,
  68. 0.84914,
  69. 0.87655,
  70. 0.90464,
  71. 0.93341,
  72. 0.96287,
  73. 0.99304,
  74. 1.02393,
  75. 1.05555,
  76. 1.08791,
  77. 1.12102,
  78. 1.1549,
  79. 1.18955,
  80. 1.225
  81. ]
  82. self.densityModel = scipy.interpolate.interp1d(altitudes, densities)
  83. def calculateTAS(self, altitude : int, ias : int):
  84. if altitude >= 50000:
  85. altitude = 49999
  86. if altitude <= 0:
  87. altitude = 1
  88. # calculation based on https://aerotoolbox.com/airspeed-conversions/
  89. return ias * math.sqrt(1.225 / self.densityModel(altitude).item())
  90. def updateWindModel(self):
  91. if None == self.lastWeatherUpdate or self.lastWeatherUpdate != self.weather.provider.updateTime:
  92. self.lastWeatherUpdate = self.weather.provider.updateTime
  93. self.minimumAltitude = 1000000
  94. self.maximumAltitude = -1
  95. self.windDirectionModel = None
  96. self.windSpeedModel = None
  97. if None != self.weather.provider.windData and self.gafor in self.weather.provider.windData:
  98. altitudes = []
  99. directions = []
  100. speeds = []
  101. # collect the data for the wind model
  102. for level in self.weather.provider.windData[self.gafor]:
  103. altitudes.append(level[0])
  104. directions.append(level[1])
  105. speeds.append(level[2])
  106. # define the thresholds for later boundary checks
  107. if self.minimumAltitude > level[0]:
  108. self.minimumAltitude = level[0]
  109. if self.maximumAltitude < level[0]:
  110. self.maximumAltitude = level[0]
  111. # calculate the models
  112. if 1 < len(altitudes):
  113. self.windDirectionModel = scipy.interpolate.interp1d(altitudes, directions)
  114. self.windSpeedModel = scipy.interpolate.interp1d(altitudes, speeds)
  115. def calculateGS(self, altitude : int, ias : int, heading : int):
  116. self.updateWindModel()
  117. tas = self.calculateTAS(altitude, ias)
  118. # initialize the wind data
  119. if None != self.windDirectionModel and None != self.windSpeedModel:
  120. direction = 0.0
  121. speed = 0.0
  122. if None != self.windSpeedModel and None != self.windDirectionModel:
  123. if self.maximumAltitude <= altitude:
  124. altitude = self.maximumAltitude - 1
  125. if self.minimumAltitude >= altitude:
  126. altitude = self.minimumAltitude + 1
  127. direction = self.windDirectionModel(altitude).item()
  128. speed = self.windSpeedModel(altitude).item()
  129. else:
  130. speed = 0
  131. direction = 0
  132. # calculate the ground speed based on the headwind component
  133. return tas + speed * math.cos(math.radians(direction) - math.radians(heading))