From 1f16d82017a1b163a6c4de4db6c7092d6b175ff8 Mon Sep 17 00:00:00 2001 From: Michael Corcoran Date: Wed, 3 Jan 2024 00:51:56 +1300 Subject: [PATCH] fix(apu/gpws/fms): stop using sim altimeters (#8314) * fix(apu): use inlet pressure for alti measurements * fix(egpws): use adr1 capt baro alt * fix(fms): use gps alt for gps monitor page * fix: used named var. uom doesn't support const --------- Co-authored-by: Benjamin Dupont <4503241+Benjozork@users.noreply.github.com> --- .../html_ui/Pages/A32NX_Core/A32NX_GPWS.js | 5 +++-- .../CDU/A320_Neo_CDU_GPSMonitor.js | 7 +++--- .../systems/src/apu/electronic_control_box.rs | 22 ++++++++++++++----- .../src/wasm/systems/systems/src/apu/mod.rs | 22 ++++++++++--------- 4 files changed, 36 insertions(+), 20 deletions(-) diff --git a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Core/A32NX_GPWS.js b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Core/A32NX_GPWS.js index e61fd8cbcc5..482de23a968 100644 --- a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Core/A32NX_GPWS.js +++ b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/A32NX_Core/A32NX_GPWS.js @@ -126,6 +126,8 @@ class A32NX_GPWS { this.gpws(deltaTime); } gpws(deltaTime) { + // EGPWS receives ADR1 only + const baroAlt = Arinc429Word.fromSimVarValue(`L:A32NX_ADIRS_ADR_1_BARO_CORRECTED_ALTITUDE_1`); const radioAlt1 = Arinc429Word.fromSimVarValue(`L:A32NX_RA_1_RADIO_ALTITUDE`); const radioAlt2 = Arinc429Word.fromSimVarValue(`L:A32NX_RA_2_RADIO_ALTITUDE`); const radioAlt = radioAlt1.isFailureWarning() || radioAlt1.isNoComputedData() ? radioAlt2 : radioAlt1; @@ -178,13 +180,12 @@ class A32NX_GPWS { if ((mda !== 0 || (dh !== -1 && dh !== -2) && phase === FmgcFlightPhases.APPROACH)) { let minimumsDA; //MDA or DH let minimumsIA; //radio or baro altitude - const baroAlt = SimVar.GetSimVarValue("INDICATED ALTITUDE", "feet"); if (dh >= 0) { minimumsDA = dh; minimumsIA = radioAlt.isNormalOperation() || radioAlt.isFunctionalTest() ? radioAlt.value : NaN; } else { minimumsDA = mda; - minimumsIA = baroAlt; + minimumsIA = baroAlt.isNormalOperation() || baroAlt.isFunctionalTest() ? baroAlt.value : NaN; } if (isFinite(minimumsDA) && isFinite(minimumsIA)) { this.gpws_minimums(minimumsDA, minimumsIA); diff --git a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_GPSMonitor.js b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_GPSMonitor.js index d9685583516..457aab403e3 100644 --- a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_GPSMonitor.js +++ b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_GPSMonitor.js @@ -12,9 +12,10 @@ class CDUGPSMonitor { const latStr = currPosSplit[0]; const lonStr = currPosSplit[1]; currPos = latStr + sep + lonStr; - const TTRK = SimVar.GetSimVarValue("GPS GROUND MAGNETIC TRACK", "radians") || "000"; - const GROUNDSPEED = SimVar.GetSimVarValue("GPS GROUND SPEED", "Knots") || "0"; - const ALTITUDE = SimVar.GetSimVarValue("INDICATED ALTITUDE", "Feet") || "0"; + const TTRK = SimVar.GetSimVarValue("GPS GROUND MAGNETIC TRACK", "radians"); + const GROUNDSPEED = SimVar.GetSimVarValue("GPS GROUND SPEED", "Knots"); + // Should be corrected from WGS84 to EGM96... when MMR GPS receiver is implemented + const ALTITUDE = Math.min(131072, Math.max(-131072, SimVar.GetSimVarValue("GPS POSITION ALT", "Feet"))); const UTC_SECONDS = Math.floor(SimVar.GetGlobalVarValue("ZULU TIME", "seconds")); const hours = Math.floor(UTC_SECONDS / 3600) || 0; diff --git a/fbw-common/src/wasm/systems/systems/src/apu/electronic_control_box.rs b/fbw-common/src/wasm/systems/systems/src/apu/electronic_control_box.rs index ef92e7a4817..5eb74728152 100644 --- a/fbw-common/src/wasm/systems/systems/src/apu/electronic_control_box.rs +++ b/fbw-common/src/wasm/systems/systems/src/apu/electronic_control_box.rs @@ -13,9 +13,9 @@ use crate::{ simulation::{SimulationElement, SimulatorWriter, UpdateContext, Write}, }; use std::time::Duration; +use uom::si::pressure::bar; use uom::si::{ - f64::*, length::foot, power::watt, pressure::psi, ratio::percent, - thermodynamic_temperature::degree_celsius, + f64::*, power::watt, pressure::psi, ratio::percent, thermodynamic_temperature::degree_celsius, }; pub(super) struct ElectronicControlBox { @@ -47,6 +47,8 @@ pub(super) struct ElectronicControlBox { egt_warning_temperature: ThermodynamicTemperature, n_above_95_duration: Duration, fire_button_is_released: bool, + /** Absolute air pressure sensor in the air intake assembly. */ + inlet_pressure: Pressure, } impl ElectronicControlBox { const RUNNING_WARNING_EGT: f64 = 682.; @@ -87,6 +89,7 @@ impl ElectronicControlBox { ), n_above_95_duration: Duration::from_secs(0), fire_button_is_released: false, + inlet_pressure: Pressure::new::(0.94), } } @@ -120,6 +123,11 @@ impl ElectronicControlBox { self.air_intake_flap_open_amount = air_intake_flap.open_amount(); } + pub fn update_air_intake_state(&mut self, context: &UpdateContext) { + // FIXME simulate sensor failure (with fallback value logic) + self.inlet_pressure = context.ambient_pressure(); + } + pub fn update_start_motor_state(&mut self, start_motor: &impl ApuStartMotor) { self.start_motor_is_powered = start_motor.is_powered(); @@ -133,12 +141,14 @@ impl ElectronicControlBox { } pub fn update(&mut self, context: &UpdateContext, turbine: &dyn Turbine) { + self.update_air_intake_state(context); + self.n = turbine.n(); self.egt = turbine.egt(); self.turbine_state = turbine.state(); self.bleed_air_pressure = turbine.bleed_air_pressure(); self.egt_warning_temperature = - ElectronicControlBox::calculate_egt_warning_temperature(context, &self.turbine_state); + ElectronicControlBox::calculate_egt_warning_temperature(self, &self.turbine_state); if self.n.get::() > 95. { self.n_above_95_duration += context.delta(); @@ -173,7 +183,7 @@ impl ElectronicControlBox { } fn calculate_egt_warning_temperature( - context: &UpdateContext, + &self, turbine_state: &TurbineState, ) -> ThermodynamicTemperature { let running_warning_temperature = ThermodynamicTemperature::new::( @@ -184,7 +194,9 @@ impl ElectronicControlBox { TurbineState::Starting => { const STARTING_WARNING_EGT_BELOW_25000_FEET: f64 = 900.; const STARTING_WARNING_EGT_AT_OR_ABOVE_25000_FEET: f64 = 982.; - if context.indicated_altitude().get::() < 25_000. { + let fl250_isa_pressure = Pressure::new::(5.45); + + if self.inlet_pressure > fl250_isa_pressure { ThermodynamicTemperature::new::( STARTING_WARNING_EGT_BELOW_25000_FEET, ) diff --git a/fbw-common/src/wasm/systems/systems/src/apu/mod.rs b/fbw-common/src/wasm/systems/systems/src/apu/mod.rs index 920a48ba60c..efee9b58312 100644 --- a/fbw-common/src/wasm/systems/systems/src/apu/mod.rs +++ b/fbw-common/src/wasm/systems/systems/src/apu/mod.rs @@ -388,7 +388,9 @@ mod tests { use crate::simulation::InitContext; use std::time::Duration; use uom::si::{ - length::foot, power::watt, pressure::psi, ratio::percent, + power::watt, + pressure::{bar, psi}, + ratio::percent, thermodynamic_temperature::degree_celsius, }; @@ -610,15 +612,15 @@ mod tests { } pub struct AuxiliaryPowerUnitTestBed { + ambient_pressure: Pressure, ambient_temperature: ThermodynamicTemperature, - indicated_altitude: Length, test_bed: SimulationTestBed, } impl AuxiliaryPowerUnitTestBed { fn new() -> Self { let mut apu_test_bed = Self { + ambient_pressure: Pressure::new::(1.), ambient_temperature: ThermodynamicTemperature::new::(0.), - indicated_altitude: Length::new::(5000.), test_bed: SimulationTestBed::new(AuxiliaryPowerUnitTestAircraft::new), }; @@ -749,13 +751,13 @@ mod tests { self.running_apu() } - fn ambient_temperature(mut self, ambient: ThermodynamicTemperature) -> Self { - self.ambient_temperature = ambient; + fn ambient_pressure(mut self, ambient: Pressure) -> Self { + self.ambient_pressure = ambient; self } - fn indicated_altitude(mut self, indicated_altitute: Length) -> Self { - self.indicated_altitude = indicated_altitute; + fn ambient_temperature(mut self, ambient: ThermodynamicTemperature) -> Self { + self.ambient_temperature = ambient; self } @@ -784,7 +786,7 @@ mod tests { pub fn run(mut self, delta: Duration) -> Self { self.set_ambient_temperature(self.ambient_temperature); - self.set_indicated_altitude(self.indicated_altitude); + self.set_ambient_pressure(self.ambient_pressure); // As the APU update executes before power is distributed throughout // the aircraft, not all elements have received power yet if only one run @@ -1454,7 +1456,7 @@ mod tests { let mut test_bed = test_bed_with() .starting_apu() .and() - .indicated_altitude(Length::new::(24999.)) + .ambient_pressure(Pressure::new::(5.46)) .run(Duration::from_secs(1)); assert_about_eq!( @@ -1474,7 +1476,7 @@ mod tests { let mut test_bed = test_bed_with() .starting_apu() .and() - .indicated_altitude(Length::new::(25000.00001)) + .ambient_pressure(Pressure::new::(5.44)) .run(Duration::from_secs(1)); assert_about_eq!(