From 5058687e18885b29f10e2a573fb2c9e598175ae1 Mon Sep 17 00:00:00 2001 From: Markus Ast Date: Sun, 2 May 2021 19:34:07 +0200 Subject: [PATCH] improve QNH temperature correction --- crates/datis-core/src/ipc.rs | 6 ++--- crates/datis-core/src/station.rs | 34 ++++++++++++++-------------- crates/datis-core/src/weather.rs | 38 +++++++++++++++----------------- 3 files changed, 38 insertions(+), 40 deletions(-) diff --git a/crates/datis-core/src/ipc.rs b/crates/datis-core/src/ipc.rs index 8104b55..309bedf 100644 --- a/crates/datis-core/src/ipc.rs +++ b/crates/datis-core/src/ipc.rs @@ -49,7 +49,7 @@ impl MissionRpc { ) .await?; // ... to retrieve the QNH - let pressure_qnh = data.pressure; + let pressure_sealevel = data.pressure; // then get weather at actual altitude let data: Data = self @@ -82,8 +82,8 @@ impl MissionRpc { wind_speed: data.wind_speed, wind_dir, temperature: data.temp, - pressure_qnh, - pressure_qfe: data.pressure, + pressure_sealevel, + pressure_groundlevel: data.pressure, fog_thickness: data.fog_thickness, fog_visibility: data.fog_visibility, dust_density: data.dust_density, diff --git a/crates/datis-core/src/station.rs b/crates/datis-core/src/station.rs index 0f09d0e..09e277e 100644 --- a/crates/datis-core/src/station.rs +++ b/crates/datis-core/src/station.rs @@ -198,12 +198,12 @@ fn hectopascal_report(weather: &WeatherInfo, alt: Length, spoken: bool) -> Strin ) } -fn qfe_report(weather: &WeatherInfo, alt: Length, spoken: bool) -> String { +fn qfe_report(weather: &WeatherInfo, spoken: bool) -> String { format!( "QFE {} {}or {}. {}", // times 100, because we don't want to speak the DECIMAL place pronounce_number( - (weather.get_qfe(alt).get::() * 100.0).round(), + (weather.get_qfe().get::() * 100.0).round(), spoken ), if spoken { @@ -212,7 +212,7 @@ fn qfe_report(weather: &WeatherInfo, alt: Length, spoken: bool) -> String { } else { "" }, - pronounce_number(weather.get_qfe(alt).get::().round(), spoken), + pronounce_number(weather.get_qfe().get::().round(), spoken), break_(spoken), ) } @@ -396,8 +396,8 @@ impl Station { wind_speed: Velocity::new::(5.0), wind_dir: Angle::new::(330.0), temperature: Temperature::new::(22.0), - pressure_qnh: Pressure::new::(101_500.0), - pressure_qfe: Pressure::new::(101_500.0), + pressure_sealevel: Pressure::new::(101_500.0), + pressure_groundlevel: Pressure::new::(101_500.0), position: Position::default(), ..Default::default() }; @@ -516,7 +516,7 @@ impl Airfield { report += &format!("REMARKS. {}", break_(spoken)); report += &hectopascal_report(weather, alt, spoken); - report += &qfe_report(weather, alt, spoken); + report += &qfe_report(weather, spoken); report += &format!("End information {}.", information_letter); @@ -653,7 +653,7 @@ impl WeatherTransmitter { report += &format!("REMARKS. {}", break_(spoken),); report += &hectopascal_report(weather, alt, spoken); - report += &qfe_report(weather, alt, spoken); + report += &qfe_report(weather, spoken); report += &format!("End information {}.", information_letter); @@ -752,8 +752,8 @@ mod test { }; let report = station.generate_report(26).await.unwrap().unwrap(); - assert_eq!(report.spoken, "\nThis is Kutaisi information Alpha. | Runway in use is ZERO 4. | Traffic frequency 2 4 NINER DECIMAL 5. | Wind 3 3 ZERO at 5 knots. | Temperature 2 2 celcius. | ALTIMETER 2 NINER NINER 7. | REMARKS. | 1 ZERO 1 5 hectopascal. | QFE 2 NINER NINER 7 or 1 ZERO 1 5. | End information Alpha.\n"); - assert_eq!(report.textual, "This is Kutaisi information Alpha. Runway in use is 04. Traffic frequency 249.5. Wind 330 at 5 knots. Temperature 22 celcius. ALTIMETER 2997. REMARKS. 1015 hectopascal. QFE 2997 or 1015. End information Alpha."); + assert_eq!(report.spoken, "\nThis is Kutaisi information Alpha. | Runway in use is ZERO 4. | Traffic frequency 2 4 NINER DECIMAL 5. | Wind 3 3 ZERO at 5 knots. | Temperature 2 2 celcius. | ALTIMETER 2 NINER NINER 5. | REMARKS. | 1 ZERO 1 4 hectopascal. | QFE 2 NINER NINER 5 or 1 ZERO 1 4. | End information Alpha.\n"); + assert_eq!(report.textual, "This is Kutaisi information Alpha. Runway in use is 04. Traffic frequency 249.5. Wind 330 at 5 knots. Temperature 22 celcius. ALTIMETER 2995. REMARKS. 1014 hectopascal. QFE 2995 or 1014. End information Alpha."); } #[tokio::test] @@ -775,8 +775,8 @@ mod test { }; let report = station.generate_report(26).await.unwrap().unwrap(); - assert_eq!(report.spoken, "\nThis is Kutaisi information Papa. | Runway in use is ZERO 4. | Traffic frequency 2 4 NINER DECIMAL 5. | Wind 3 3 ZERO at 5 knots. | Temperature 2 2 celcius. | ALTIMETER 2 NINER NINER 7. | REMARKS. | 1 ZERO 1 5 hectopascal. | QFE 2 NINER NINER 7 or 1 ZERO 1 5. | End information Papa.\n"); - assert_eq!(report.textual, "This is Kutaisi information Papa. Runway in use is 04. Traffic frequency 249.5. Wind 330 at 5 knots. Temperature 22 celcius. ALTIMETER 2997. REMARKS. 1015 hectopascal. QFE 2997 or 1015. End information Papa."); + assert_eq!(report.spoken, "\nThis is Kutaisi information Papa. | Runway in use is ZERO 4. | Traffic frequency 2 4 NINER DECIMAL 5. | Wind 3 3 ZERO at 5 knots. | Temperature 2 2 celcius. | ALTIMETER 2 NINER NINER 5. | REMARKS. | 1 ZERO 1 4 hectopascal. | QFE 2 NINER NINER 5 or 1 ZERO 1 4. | End information Papa.\n"); + assert_eq!(report.textual, "This is Kutaisi information Papa. Runway in use is 04. Traffic frequency 249.5. Wind 330 at 5 knots. Temperature 22 celcius. ALTIMETER 2995. REMARKS. 1014 hectopascal. QFE 2995 or 1014. End information Papa."); } #[tokio::test] @@ -798,8 +798,8 @@ mod test { }; let report = station.generate_report(26).await.unwrap().unwrap(); - assert_eq!(report.spoken, "\nThis is Kutaisi information Quebec. | Runway in use is ZERO 4. | Traffic frequency 2 4 NINER DECIMAL 5. | Wind 3 3 ZERO at 5 knots. | Temperature 2 2 celcius. | ALTIMETER 2 NINER NINER 7. | REMARKS. | 1 ZERO 1 5 hectopascal. | QFE 2 NINER NINER 7 or 1 ZERO 1 5. | End information Quebec.\n"); - assert_eq!(report.textual, "This is Kutaisi information Quebec. Runway in use is 04. Traffic frequency 249.5. Wind 330 at 5 knots. Temperature 22 celcius. ALTIMETER 2997. REMARKS. 1015 hectopascal. QFE 2997 or 1015. End information Quebec."); + assert_eq!(report.spoken, "\nThis is Kutaisi information Quebec. | Runway in use is ZERO 4. | Traffic frequency 2 4 NINER DECIMAL 5. | Wind 3 3 ZERO at 5 knots. | Temperature 2 2 celcius. | ALTIMETER 2 NINER NINER 5. | REMARKS. | 1 ZERO 1 4 hectopascal. | QFE 2 NINER NINER 5 or 1 ZERO 1 4. | End information Quebec.\n"); + assert_eq!(report.textual, "This is Kutaisi information Quebec. Runway in use is 04. Traffic frequency 249.5. Wind 330 at 5 knots. Temperature 22 celcius. ALTIMETER 2995. REMARKS. 1014 hectopascal. QFE 2995 or 1014. End information Quebec."); } #[test] @@ -828,8 +828,8 @@ mod test { }; let report = station.generate_report(26).await.unwrap().unwrap(); - assert_eq!(report.spoken, "\n99, | Stennis\'s wind 3 3 ZERO at 5 knots, | altimeter 2 NINER NINER 7, | CASE 1, | BRC 1 8 ZERO, | expected final heading 1 7 1, | report initial.\n"); - assert_eq!(report.textual, "99, Stennis\'s wind 330 at 5 knots, altimeter 2997, CASE 1, BRC 180, expected final heading 171, report initial."); + assert_eq!(report.spoken, "\n99, | Stennis\'s wind 3 3 ZERO at 5 knots, | altimeter 3 ZERO ZERO 3, | CASE 1, | BRC 1 8 ZERO, | expected final heading 1 7 1, | report initial.\n"); + assert_eq!(report.textual, "99, Stennis\'s wind 330 at 5 knots, altimeter 3003, CASE 1, BRC 180, expected final heading 171, report initial."); } #[tokio::test] @@ -873,7 +873,7 @@ mod test { }; let report = station.generate_report(26).await.unwrap().unwrap(); - assert_eq!(report.spoken, "\nThis is weather station Mountain Range information Papa. | Wind 3 3 ZERO at 5 knots. | Temperature 2 2 celcius. | ALTIMETER 2 NINER NINER 7. | REMARKS. | 1 ZERO 1 5 hectopascal. | QFE 2 NINER NINER 7 or 1 ZERO 1 5. | End information Papa.\n"); - assert_eq!(report.textual, "This is weather station Mountain Range information Papa. Wind 330 at 5 knots. Temperature 22 celcius. ALTIMETER 2997. REMARKS. 1015 hectopascal. QFE 2997 or 1015. End information Papa."); + assert_eq!(report.spoken, "\nThis is weather station Mountain Range information Papa. | Wind 3 3 ZERO at 5 knots. | Temperature 2 2 celcius. | ALTIMETER 2 NINER NINER 5. | REMARKS. | 1 ZERO 1 4 hectopascal. | QFE 2 NINER NINER 5 or 1 ZERO 1 4. | End information Papa.\n"); + assert_eq!(report.textual, "This is weather station Mountain Range information Papa. Wind 330 at 5 knots. Temperature 22 celcius. ALTIMETER 2995. REMARKS. 1014 hectopascal. QFE 2995 or 1014. End information Papa."); } } diff --git a/crates/datis-core/src/weather.rs b/crates/datis-core/src/weather.rs index fadfd6b..c6850f5 100644 --- a/crates/datis-core/src/weather.rs +++ b/crates/datis-core/src/weather.rs @@ -1,11 +1,11 @@ use crate::station::Position; use serde::Deserialize; use uom::num::Zero; +use uom::num_traits::Pow; use uom::si::f64::{Angle, Pressure, ThermodynamicTemperature as Temperature, Velocity}; use uom::si::i32::Length; use uom::si::length::{foot, meter}; -use uom::si::pressure::pascal; -use uom::si::thermodynamic_temperature::degree_celsius; +use uom::si::pressure::{inch_of_mercury, millibar, pascal}; #[derive(Debug, PartialEq, Clone, Default)] pub struct WeatherInfo { @@ -14,8 +14,8 @@ pub struct WeatherInfo { /// The direction the wind is coming from pub wind_dir: Angle, pub temperature: Temperature, - pub pressure_qnh: Pressure, - pub pressure_qfe: Pressure, + pub pressure_sealevel: Pressure, + pub pressure_groundlevel: Pressure, /// This basically determines how heigh the fog is, from 0 to `fog_thickness`. pub fog_thickness: Length, pub fog_visibility: Length, @@ -67,25 +67,23 @@ pub struct OldClouds { impl WeatherInfo { /// Get QNH correct for the current temperature (as far as possible in DCS) pub fn get_qnh(&self, alt: Length) -> Pressure { - self.pressure_qnh + self.pressure_correction(alt) - } + // see https://en.wikipedia.org/wiki/Pressure_altitude + let pressure_altitude: f64 = 14_5366.45 + * (1.0 + - (self.get_qfe().get::() / self.pressure_sealevel.get::()) + .pow(0.190284)); + let alt_diff = f64::from(alt.get::()) - pressure_altitude; - /// Get QFE correct for the current temperature (as far as possible in DCS) - pub fn get_qfe(&self, alt: Length) -> Pressure { - self.pressure_qfe + self.pressure_correction(alt) + // this corrects the pressure for the current temperature + let correction = Pressure::new::(alt_diff / 27.0 * 100.0); + + self.pressure_sealevel + correction } - fn pressure_correction(&self, alt: Length) -> Pressure { - let alt = alt.get::(); - let angels = f64::from(alt) / 1000.0; - // ISA at see level is 16 and not 15 in DCS, see - // https://forums.eagle.ru/topic/256057-altitude-qnh-error-bug/ - let isa_at_alt = 16.0 - 1.98 * angels; - let isa_diff = self.temperature.get::() - isa_at_alt; - let palt_diff = 4.0 * isa_diff * angels; - - // translate alt diff into a QNH diff - Pressure::new::((palt_diff / 27.0) * 100.0) + /// Get QFE correct for the current temperature (as far as possible in DCS) + pub fn get_qfe(&self) -> Pressure { + // offset ground level pressure by empirically derived offset (DCS specific) + self.pressure_groundlevel - Pressure::new::(0.02) } pub fn get_visibility(&self, alt: Length) -> Option {