Migrate pressure to a typed unit.

This commit is contained in:
Dan Albert 2021-07-16 22:38:41 -07:00
parent d11174da21
commit 28f98aed88
5 changed files with 44 additions and 33 deletions

View File

@ -16,6 +16,9 @@ KPH_TO_KNOTS = 1 / KNOTS_TO_KPH
MS_TO_KPH = 3.6 MS_TO_KPH = 3.6
KPH_TO_MS = 1 / MS_TO_KPH KPH_TO_MS = 1 / MS_TO_KPH
INHG_TO_HPA = 33.86389
INHG_TR_MMHG = 25.400002776728
def heading_sum(h: int, a: int) -> int: def heading_sum(h: int, a: int) -> int:
h += a h += a
@ -181,6 +184,27 @@ def mach(value: float, altitude: Distance) -> Speed:
SPEED_OF_SOUND_AT_SEA_LEVEL = knots(661.5) SPEED_OF_SOUND_AT_SEA_LEVEL = knots(661.5)
@dataclass(frozen=True, order=True)
class Pressure:
pressure_in_inches_hg: float
@property
def inches_hg(self) -> float:
return self.pressure_in_inches_hg
@property
def mm_hg(self) -> float:
return self.pressure_in_inches_hg * INHG_TR_MMHG
@property
def hecto_pascals(self) -> float:
return self.pressure_in_inches_hg * INHG_TO_HPA
def inches_hg(value: float) -> Pressure:
return Pressure(value)
def pairwise(iterable: Iterable[Any]) -> Iterable[tuple[Any, Any]]: def pairwise(iterable: Iterable[Any]) -> Iterable[tuple[Any, Any]]:
""" """
itertools recipe itertools recipe

View File

@ -5,13 +5,14 @@ import logging
import random import random
from dataclasses import dataclass, field from dataclasses import dataclass, field
from enum import Enum from enum import Enum
from typing import Optional, TYPE_CHECKING from typing import Optional, TYPE_CHECKING, Any
from dcs.cloud_presets import Clouds as PydcsClouds from dcs.cloud_presets import Clouds as PydcsClouds
from dcs.weather import CloudPreset, Weather as PydcsWeather, Wind from dcs.weather import CloudPreset, Weather as PydcsWeather, Wind
from game.savecompat import has_save_compat_for
from game.settings import Settings from game.settings import Settings
from game.utils import Distance, meters, interpolate from game.utils import Distance, meters, interpolate, Pressure, inches_hg
if TYPE_CHECKING: if TYPE_CHECKING:
from game.theater import ConflictTheater from game.theater import ConflictTheater
@ -27,11 +28,19 @@ class TimeOfDay(Enum):
@dataclass(frozen=True) @dataclass(frozen=True)
class AtmosphericConditions: class AtmosphericConditions:
#: Pressure at sea level in inches of mercury. #: Pressure at sea level.
qnh_inches_mercury: float qnh: Pressure
#: Temperature at sea level in Celcius. #: Temperature at sea level in Celcius.
temperature_celsius: float temperature_celsius: float
@has_save_compat_for(5)
def __setstate__(self, state: dict[str, Any]) -> None:
if "qnh" not in state:
state["qnh"] = inches_hg(state["qnh_inches_mercury"])
del state["qnh_inches_mercury"]
self.__dict__.update(state)
@dataclass(frozen=True) @dataclass(frozen=True)
class WindConditions: class WindConditions:
@ -111,7 +120,7 @@ class Weather:
pressure += self.pressure_adjustment pressure += self.pressure_adjustment
temperature += self.temperature_adjustment temperature += self.temperature_adjustment
conditions = AtmosphericConditions( conditions = AtmosphericConditions(
qnh_inches_mercury=self.random_pressure(pressure), qnh=self.random_pressure(pressure),
temperature_celsius=self.random_temperature(temperature), temperature_celsius=self.random_temperature(temperature),
) )
return conditions return conditions
@ -162,14 +171,14 @@ class Weather:
return random.randint(100, 400) return random.randint(100, 400)
@staticmethod @staticmethod
def random_pressure(average_pressure: float) -> float: def random_pressure(average_pressure: float) -> Pressure:
# "Safe" constants based roughly on ME and viper altimeter. # "Safe" constants based roughly on ME and viper altimeter.
# Units are inches of mercury. # Units are inches of mercury.
SAFE_MIN = 28.4 SAFE_MIN = 28.4
SAFE_MAX = 30.9 SAFE_MAX = 30.9
# Use normalvariate to get normal distribution, more realistic than uniform # Use normalvariate to get normal distribution, more realistic than uniform
pressure = random.normalvariate(average_pressure, 0.1) pressure = random.normalvariate(average_pressure, 0.1)
return max(SAFE_MIN, min(SAFE_MAX, pressure)) return inches_hg(max(SAFE_MIN, min(SAFE_MAX, pressure)))
@staticmethod @staticmethod
def random_temperature(average_temperature: float) -> float: def random_temperature(average_temperature: float) -> float:

View File

@ -3,7 +3,6 @@ from typing import Optional
from dcs.mission import Mission from dcs.mission import Mission
from game.weather import Clouds, Fog, Conditions, WindConditions, AtmosphericConditions from game.weather import Clouds, Fog, Conditions, WindConditions, AtmosphericConditions
from .units import inches_hg_to_mm_hg
class EnvironmentGenerator: class EnvironmentGenerator:
@ -12,7 +11,7 @@ class EnvironmentGenerator:
self.conditions = conditions self.conditions = conditions
def set_atmospheric(self, atmospheric: AtmosphericConditions) -> None: def set_atmospheric(self, atmospheric: AtmosphericConditions) -> None:
self.mission.weather.qnh = inches_hg_to_mm_hg(atmospheric.qnh_inches_mercury) self.mission.weather.qnh = atmospheric.qnh.mm_hg
self.mission.weather.season_temperature = atmospheric.temperature_celsius self.mission.weather.season_temperature = atmospheric.temperature_celsius
def set_clouds(self, clouds: Optional[Clouds]) -> None: def set_clouds(self, clouds: Optional[Clouds]) -> None:

View File

@ -47,7 +47,6 @@ from .briefinggen import CommInfo, JtacInfo, MissionInfoGenerator
from .flights.flight import FlightWaypoint, FlightWaypointType, FlightType from .flights.flight import FlightWaypoint, FlightWaypointType, FlightType
from .radios import RadioFrequency from .radios import RadioFrequency
from .runways import RunwayData from .runways import RunwayData
from .units import inches_hg_to_mm_hg, inches_hg_to_hpa
if TYPE_CHECKING: if TYPE_CHECKING:
from game import Game from game import Game
@ -308,13 +307,9 @@ class BriefingPage(KneeboardPage):
writer.text(f"Bullseye: {self.bullseye.to_lat_lon(self.theater).format_dms()}") writer.text(f"Bullseye: {self.bullseye.to_lat_lon(self.theater).format_dms()}")
qnh_in_hg = "{:.2f}".format(self.weather.atmospheric.qnh_inches_mercury) qnh_in_hg = f"{self.weather.atmospheric.qnh.inches_hg:.2f}"
qnh_mm_hg = "{:.1f}".format( qnh_mm_hg = f"{self.weather.atmospheric.qnh.mm_hg:.1f}"
inches_hg_to_mm_hg(self.weather.atmospheric.qnh_inches_mercury) qnh_hpa = f"{self.weather.atmospheric.qnh.hecto_pascals:.1f}"
)
qnh_hpa = "{:.1f}".format(
inches_hg_to_hpa(self.weather.atmospheric.qnh_inches_mercury)
)
writer.text( writer.text(
f"Temperature: {round(self.weather.atmospheric.temperature_celsius)} °C at sea level" f"Temperature: {round(self.weather.atmospheric.temperature_celsius)} °C at sea level"
) )

View File

@ -1,16 +0,0 @@
"""Unit conversions."""
def meters_to_feet(meters: float) -> float:
"""Converts meters to feet."""
return meters * 3.28084
def inches_hg_to_mm_hg(inches_hg: float) -> float:
"""Converts inches mercury to millimeters mercury."""
return inches_hg * 25.400002776728
def inches_hg_to_hpa(inches_hg: float) -> float:
"""Converts inches mercury to hectopascal."""
return inches_hg * 33.86389