Use weibull distribution for wind generation.

Wind speeds should not be uniformly distributed. This switches to a
Weibull distribution which allegedly (see the bug) is good enough.
Experimentally that seems true as well, though I know nothing about how
wind works irl. This at least looks like it'll generate reasonable
variation in missions while keeping the 1st through 3rd quartile
behaviors from getting out of hand.

I'm very uncertain about the scaling factor aspect of this. Naively the
wind speeds at different altitudes ought to be somewhat correlated, but
I'm not sure how much, and whether this kind of scaling is at all the
right way to do it. As before, meh, close enough?

Fixes https://github.com/dcs-liberation/dcs_liberation/issues/2861.
This commit is contained in:
Dan Albert
2023-05-15 20:54:49 -07:00
committed by Raffson
parent b750099b16
commit 73e0cbe182
2 changed files with 24 additions and 39 deletions

View File

@@ -21,6 +21,7 @@ from game.utils import (
interpolate,
knots,
meters,
Speed,
)
if TYPE_CHECKING:
@@ -185,56 +186,39 @@ class Weather:
raise NotImplementedError
@staticmethod
def random_wind(minimum: int, maximum: int) -> WindConditions:
def random_wind(
weibull_shape: float,
weibull_scale_speed: Speed,
at_2000m_factor_range: tuple[float, float],
at_8000m_factor_range: tuple[float, float],
) -> WindConditions:
"""Generates random wind."""
wind_direction = Heading.random()
wind_direction_2000m = wind_direction + Heading.random(-90, 90)
wind_direction_8000m = wind_direction + Heading.random(-90, 90)
at_0m_factor = 1
at_2000m_factor = 3 + random.choice([0, 0, 0, 0, 0, 1, 1])
high_alt_variation = random.choice(
[
-3,
-3,
-2,
-2,
-2,
-2,
-2,
-2,
-1,
-1,
-1,
-1,
-1,
-1,
-1,
0,
0,
0,
1,
1,
2,
3,
]
# The first parameter is the scale. 63.2% of all results will fall below that
# value.
# https://www.itl.nist.gov/div898/handbook/eda/section3/weibplot.htm
msl = random.weibullvariate(
weibull_scale_speed.meters_per_second, weibull_shape
)
at_8000m_factor = at_2000m_factor + 5 + high_alt_variation
base_wind = random.randint(minimum, maximum)
at_2000m_factor = random.uniform(*at_2000m_factor_range)
at_8000m_factor = random.uniform(*at_8000m_factor_range)
# DCS is limited to 97 knots wind speed.
max_supported_wind_speed = knots(97).meters_per_second
return WindConditions(
# Always some wind to make the smoke move a bit.
at_0m=Wind(wind_direction.degrees, max(1, base_wind * at_0m_factor)),
at_0m=Wind(wind_direction.degrees, max(1.0, msl)),
at_2000m=Wind(
wind_direction_2000m.degrees,
min(max_supported_wind_speed, base_wind * at_2000m_factor),
min(max_supported_wind_speed, msl * at_2000m_factor),
),
at_8000m=Wind(
wind_direction_8000m.degrees,
min(max_supported_wind_speed, base_wind * at_8000m_factor),
min(max_supported_wind_speed, msl * at_8000m_factor),
),
)
@@ -334,7 +318,7 @@ class ClearSkies(Weather):
return None
def generate_wind(self) -> WindConditions:
return self.random_wind(1, 4)
return self.random_wind(1.5, knots(5), (1, 1.8), (1.5, 2.5))
class Cloudy(Weather):
@@ -358,7 +342,7 @@ class Cloudy(Weather):
return None
def generate_wind(self) -> WindConditions:
return self.random_wind(1, 5)
return self.random_wind(1.6, knots(6.5), (1, 1.8), (1.5, 2.5))
class Raining(Weather):
@@ -382,7 +366,7 @@ class Raining(Weather):
return None
def generate_wind(self) -> WindConditions:
return self.random_wind(2, 6)
return self.random_wind(2.6, knots(12), (1, 1.7), (2.2, 2.8))
class Thunderstorm(Weather):
@@ -407,7 +391,7 @@ class Thunderstorm(Weather):
)
def generate_wind(self) -> WindConditions:
return self.random_wind(2, 8)
return self.random_wind(6, knots(20), (1, 2), (2.5, 3.5))
@dataclass