Skip to content

Commit

Permalink
Feat/RT/Weather/METAR: CAVOK etc., clouds, weather phenomena, rwy fric
Browse files Browse the repository at this point in the history
Stability fixes
  • Loading branch information
TwinFan committed Jul 24, 2024
1 parent 1023587 commit ce2e1a8
Show file tree
Hide file tree
Showing 6 changed files with 340 additions and 103 deletions.
2 changes: 1 addition & 1 deletion Include/LTRealTraffic.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ constexpr std::chrono::seconds RT_DRCT_ERR_WAIT = std::chrono::seconds(5); ///<
constexpr std::chrono::minutes RT_DRCT_WX_WAIT = std::chrono::minutes(1); ///< How often to update weather?
constexpr long RT_DRCT_WX_DIST = 10L * M_per_NM; ///< Distance for which weather is considered valid, greater than that and we re-request
constexpr int RT_DRCT_MAX_WX_ERR = 5; ///< Max number of consecutive errors during initial weather requests we wait for...before not asking for weather any longer
constexpr double RT_DRCT_MAX_METAR_DIST_NM = 50.0; ///< Max distance a METAR station is considered valid...otherwise we rather use no METAR (for clouds, for example)
constexpr double RT_DRCT_MAX_METAR_DIST_NM = 10.0; ///< Max distance a METAR station is considered valid...otherwise we rather use no METAR (for clouds, for example)

/// Fields in a response of a direct connection's request
enum RT_DIRECT_FIELDS_TY {
Expand Down
39 changes: 29 additions & 10 deletions Include/LTWeather.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,10 @@ std::string WeatherGetSource ();

/// Distance when next weather is set to update immediately instead of gradually
constexpr double WEATHER_MAX_DIST_M = 50 * M_per_NM;
/// Minimum thickness of a METAR cloud layer [m]
constexpr float WEATHER_MIN_CLOUD_HEIGHT_M = 300;
/// Thickness of a METAR cloud layer [m]
constexpr float WEATHER_METAR_CLOUD_HEIGHT_M = 500;
/// Thickness of a METAR Cumulo-nimbus cloud layer [m]
constexpr float WEATHER_METAR_CB_CLOUD_HEIGHT_M = 5000;
/// May height AGL up to which we weigh METAR higher than other weather data
constexpr double PREFER_METAR_MAX_AGL_M = 5000.0 * M_per_FT;

Expand Down Expand Up @@ -97,9 +99,12 @@ class LTWeather
float thermal_rate_ms = NAN; ///< float y m/s >= 0 The climb rate for thermals.
float wave_amplitude = NAN; ///< float y meters Amplitude of waves in the water (height of waves)
float wave_dir = NAN; ///< float y degrees Direction of waves.
int runway_friction = 0; ///< int y enum The friction constant for runways (how wet they are). Dry = 0, wet(1-3), puddly(4-6), snowy(7-9), icy(10-12), snowy/icy(13-15)
int runway_friction = -1; ///< int y enum The friction constant for runways (how wet they are). Dry = 0, wet(1-3), puddly(4-6), snowy(7-9), icy(10-12), snowy/icy(13-15)
float variability_pct = 0; ///< float y ratio How randomly variable the weather is over distance. Range 0 - 1.
bool update_immediately = false; ///< int y bool If this is true, any weather region changes EXCEPT CLOUDS will take place immediately instead of at the next update interval (currently 60 seconds).
int change_mode = -1; ///< int y enum How the weather is changing. 0 = Rapidly Improving, 1 = Improving, 2 = Gradually Improving, 3 = Static, 4 = Gradually Deteriorating, 5 = Deteriorating, 6 = Rapidly Deteriorating, 7 = Using Real Weather
int weather_source = -1; ///< int n enum What system is currently controlling the weather. 0 = Preset, 1 = Real Weather, 2 = Controlpad, 3 = Plugin.
int weather_preset = -1; ///< int y enum Read the UI weather preset that is closest to the current conditions, or set an UI preset. Clear(0), VFR Few(1), VFR Scattered(2), VFR Broken(3), VFR Marginal(4), IFR Non-precision(5), IFR Precision(6), Convective(7), Large-cell Storms(8)
std::string metar; ///< METAR, if filled combine METAR data into weather generation

public:
Expand All @@ -112,15 +117,28 @@ class LTWeather
static std::array<InterpolSet,13> ComputeInterpol (const std::vector<float>& from,
const std::array<float,13>& to);
/// Fill values from a differently sized input vector based on interpolation
void Interpolate (const std::array<InterpolSet,13>& aInterpol,
const std::vector<float>& from,
std::array<float,13>& to);
static void Interpolate (const std::array<InterpolSet,13>& aInterpol,
const std::vector<float>& from,
std::array<float,13>& to);
/// @brief Fill directions/headings from a differently sized input vector based on interpolation
/// @details Headings need to be interpolate separately as the average of 359 and 001 is 000 rather than 180...
void InterpolateDir (const std::array<InterpolSet,13>& aInterpol,
const std::vector<float>& from,
std::array<float,13>& to);
/// @details Headings need to be interpolated separately as the average of 359 and 001 is 000 rather than 180...
static void InterpolateDir (const std::array<InterpolSet,13>& aInterpol,
const std::vector<float>& from,
std::array<float,13>& to);

/// Fill value equally up to given altitude
static void FillUp (const std::array<float,13>& levels_m,
std::array<float,13>& to,
float alt_m,
float val,
bool bInterpolateNext);
/// Fill value equally to the given minimum up to given altitude (ie. don't overwrite values that are already larger)
static void FillUpMin (const std::array<float,13>& levels_m,
std::array<float,13>& to,
float alt_m,
float valMin,
bool bInterpolateNext);

protected:
static positionTy lastPos; ///< last position for which weather was set (to check if next one is "far" awar and deserves to be updated immedlately

Expand All @@ -134,6 +152,7 @@ class LTWeather
// Some global functions require access
friend void WeatherSet (const LTWeather& w);
friend void WeatherUpdate ();
friend void WeatherReset ();
friend void WeatherLogCurrent (const std::string& msg);
};

Expand Down
16 changes: 7 additions & 9 deletions Src/LTRealTraffic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -877,13 +877,15 @@ void RealTrafficConnection::ProcessWeather(const JSON_Object* pData)
}

rtWx.w.pos = curr.pos;
// Forward METAR for weather processing, too
rtWx.w.metar = rtWx.nearestMETAR.METAR;

rtWx.w.visibility_reported_sm = float(jog_n_nan(pLocWX, "SVis") / M_per_SM);
rtWx.w.sealevel_pressure_pas = float(jog_n_nan(pLocWX, "SLP") * 100.0);
if (pTEMPs && json_array_get_count(pTEMPs) >= 1) // use temperature of lowest level, adjusted per temperature lapse rate
rtWx.w.sealevel_temperature_c = float(jag_n_nan(pTEMPs, 0)) - RT_ATMOS_LAYERS.front() * float(TEMP_LAPS_R);
rtWx.w.qnh_base_elevation = 0; // TODO: Verify if using qnh_base this way makes any sense
rtWx.w.qnh_pas = rtWx.w.sealevel_pressure_pas;
// rtWx.w.qnh_base_elevation = 0; // TODO: Verify if using qnh_base this way makes any sense
// rtWx.w.qnh_pas = rtWx.w.sealevel_pressure_pas;
rtWx.w.rain_percent = std::min(float(jog_n_nan(pLocWX, "PRR")) / 9.0f, 1.0f); // RT sends mm/h and says ">7.5 is heavy", XP wants a 0..1 scale

// Wind
Expand Down Expand Up @@ -947,13 +949,9 @@ void RealTrafficConnection::ProcessWeather(const JSON_Object* pData)
// rtWx.w.thermal_rate_ms;

// TODO: Improve Rwy_Friction (Snow, Ice)
rtWx.w.runway_friction =
rtWx.w.rain_percent <= 5.0f ? 0 :
rtWx.w.rain_percent <= 33.3f ? 1 :
rtWx.w.rain_percent <= 66.6f ? 2 : 3;

// Forward METAR for weather processing, too
rtWx.w.metar = rtWx.nearestMETAR.METAR;
if (rtWx.w.metar.empty()) // ideally set later based on METAR
// Rain causes wet status [0..7]
rtWx.w.runway_friction = (int)std::lround(rtWx.w.rain_percent * 7.f);

// Have the weather set (force immediate update on first weather data)
rtWx.w.update_immediately = !rtWx.pos.isNormal();
Expand Down
Loading

0 comments on commit ce2e1a8

Please sign in to comment.