diff --git a/fbw-a32nx/src/systems/instruments/src/SD/Pages/Press/Press.tsx b/fbw-a32nx/src/systems/instruments/src/SD/Pages/Press/Press.tsx index 14f20746014..e69ad36c16e 100644 --- a/fbw-a32nx/src/systems/instruments/src/SD/Pages/Press/Press.tsx +++ b/fbw-a32nx/src/systems/instruments/src/SD/Pages/Press/Press.tsx @@ -54,6 +54,10 @@ export const PressPage: FC = () => { }, [cabinAlt]); const deltaPress = splitDecimals(MathUtils.clamp(deltaPsi, -9.9, 9.9)); + // TODO: SDAC logic missing. Delta pressure is not available when the SDAC indication is not valid. + // This happens when both the CPCs and ADRs are not sending pressure information. Here we only check + // for CPC no computed data. + const deltaPressNotAvail = arincDeltaPsi.isNoComputedData(); const cax = 455; const dpx = 110; const y = 165; @@ -77,19 +81,30 @@ export const PressPage: FC = () => { PSI - = 8.5 ? 'Amber' : 'Green'}`} x={dpx + 38} y={y + 25}> + = 8.5 ? 'Amber' : 'Green'} ${deltaPressNotAvail ? 'hide' : 'show'}`} + x={dpx + 38} + y={y + 25} + > {deltaPress[0]} - = 8.5 ? 'Amber' : 'Green'}`} x={dpx + 53} y={y + 25}> + = 8.5 ? 'Amber' : 'Green'} ${deltaPressNotAvail ? 'hide' : 'show'}`} + x={dpx + 53} + y={y + 25} + > . = 8.5 ? 'Amber' : 'Green'}`} + className={`Standard End ${deltaPsi < -0.4 || deltaPsi >= 8.5 ? 'Amber' : 'Green'} ${deltaPressNotAvail ? 'hide' : 'show'}`} x={dpx + 63} y={y + 25} > {deltaPress[1]} + + XX + { radius={radius} startAngle={210} endAngle={50} - className={`GaugeIndicator ${deltaPsi < -0.4 || deltaPsi >= 8.5 ? 'Amber' : ''}`} + className={`GaugeIndicator ${deltaPsi < -0.4 || deltaPsi >= 8.5 ? 'Amber' : ''} ${deltaPressNotAvail ? 'hide' : 'show'}`} indicator /> diff --git a/fbw-a32nx/src/wasm/systems/a320_systems/src/air_conditioning.rs b/fbw-a32nx/src/wasm/systems/a320_systems/src/air_conditioning.rs index 8a807fc97da..c210bb4bf4a 100644 --- a/fbw-a32nx/src/wasm/systems/a320_systems/src/air_conditioning.rs +++ b/fbw-a32nx/src/wasm/systems/a320_systems/src/air_conditioning.rs @@ -4,7 +4,7 @@ use systems::{ acs_controller::{AcscId, AirConditioningSystemController, Pack}, cabin_air::CabinAirSimulation, cabin_pressure_controller::{CabinPressureController, CpcId}, - pressure_valve::{OutflowValve, SafetyValve}, + pressure_valve::{OutflowValve, SafetyValve, SafetyValveSignal}, AdirsToAirCondInterface, Air, AirConditioningOverheadShared, AirConditioningPack, CabinFan, Channel, DuctTemperature, MixerUnit, OutflowValveSignal, OutletAir, OverheadFlowSelector, PackFlowControllers, PressurizationConstants, PressurizationOverheadShared, TrimAirSystem, @@ -696,6 +696,7 @@ struct A320PressurizationSystem { cpc_interface: [PressurizationSystemInterfaceUnit; 2], outflow_valve: [OutflowValve; 1], // Array to prepare for more than 1 outflow valve in A380 safety_valve: SafetyValve, + safety_valve_signal: SafetyValveSignal, residual_pressure_controller: ResidualPressureController, active_system: usize, @@ -725,6 +726,7 @@ impl A320PressurizationSystem { vec![ElectricalBusType::DirectCurrentBattery], )], safety_valve: SafetyValve::new(), + safety_valve_signal: SafetyValveSignal::new(), residual_pressure_controller: ResidualPressureController::new(), active_system: active as usize, @@ -794,8 +796,12 @@ impl A320PressurizationSystem { }); } - self.safety_valve - .update(context, &self.cpc[self.active_system - 1]); + self.safety_valve_signal.update( + context, + cabin_simulation.cabin_pressure(), + self.safety_valve.open_amount(), + ); + self.safety_valve.update(context, &self.safety_valve_signal); self.switch_active_system(); @@ -2628,7 +2634,7 @@ mod tests { InternationalStandardAtmosphere::pressure_at_altitude(Length::default()) - Pressure::new::(10.), ) - .iterate(10); + .iterate(2); assert!(test_bed.safety_valve_open_amount() > Ratio::default()); } diff --git a/fbw-a380x/src/wasm/systems/a380_systems/src/air_conditioning/local_controllers/outflow_valve_control_module.rs b/fbw-a380x/src/wasm/systems/a380_systems/src/air_conditioning/local_controllers/outflow_valve_control_module.rs index c77b1bff707..0b4233ba99f 100644 --- a/fbw-a380x/src/wasm/systems/a380_systems/src/air_conditioning/local_controllers/outflow_valve_control_module.rs +++ b/fbw-a380x/src/wasm/systems/a380_systems/src/air_conditioning/local_controllers/outflow_valve_control_module.rs @@ -1,12 +1,11 @@ use systems::{ air_conditioning::{ - cabin_pressure_controller::OutflowValveController, - pressure_valve::{OutflowValve, PressureValveSignal}, + cabin_pressure_controller::OutflowValveController, pressure_valve::OutflowValve, AdirsToAirCondInterface, Air, OperatingChannel, PressurizationConstants, PressurizationOverheadShared, }, shared::{ - low_pass_filter::LowPassFilter, CabinSimulation, ControllerSignal, ElectricalBusType, + low_pass_filter::LowPassFilter, CabinSimulation, ElectricalBusType, InternationalStandardAtmosphere, }, simulation::{ @@ -21,7 +20,6 @@ use uom::si::{ f64::*, length::foot, pressure::{hectopascal, psi}, - ratio::percent, velocity::foot_per_minute, }; @@ -139,10 +137,6 @@ impl OutflowValveControlModule { fn switch_active_channel(&mut self) { std::mem::swap(&mut self.stand_by_channel, &mut self.active_channel); } - - pub fn negative_relief_valve_trigger(&self) -> &impl ControllerSignal { - &self.epp - } } impl OcsmShared for OutflowValveControlModule { @@ -449,32 +443,3 @@ impl EmergencyPressurizationPartition { &self.outflow_valve_controller } } - -/// Negative relieve valves signal. This returns a controller signal, but the valves are mechanical assemblies -impl ControllerSignal for EmergencyPressurizationPartition { - fn signal(&self) -> Option { - let open = Some(PressureValveSignal::Open( - Ratio::new::(100.), - Duration::from_secs(1), - )); - let closed = Some(PressureValveSignal::Close( - Ratio::new::(0.), - Duration::from_secs(1), - )); - if self.differential_pressure.get::() - < A380PressurizationConstants::MIN_SAFETY_DELTA_P + 0.2 - { - if self.differential_pressure.get::() - < A380PressurizationConstants::MIN_SAFETY_DELTA_P - { - open - } else { - Some(PressureValveSignal::Neutral) - } - } else if self.safety_valve_open_amount.get::() > 0. { - closed - } else { - Some(PressureValveSignal::Neutral) - } - } -} diff --git a/fbw-a380x/src/wasm/systems/a380_systems/src/air_conditioning/mod.rs b/fbw-a380x/src/wasm/systems/a380_systems/src/air_conditioning/mod.rs index 7ee26151b3f..f1427bcc236 100644 --- a/fbw-a380x/src/wasm/systems/a380_systems/src/air_conditioning/mod.rs +++ b/fbw-a380x/src/wasm/systems/a380_systems/src/air_conditioning/mod.rs @@ -1,7 +1,9 @@ use systems::{ accept_iterable, air_conditioning::{ - acs_controller::Pack, cabin_air::CabinAirSimulation, pressure_valve::SafetyValve, + acs_controller::Pack, + cabin_air::CabinAirSimulation, + pressure_valve::{NegativeRelieveValveSignal, SafetyValve}, AdirsToAirCondInterface, Air, AirConditioningOverheadShared, AirConditioningPack, AirHeater, CabinFan, DuctTemperature, MixerUnit, OutletAir, OverheadFlowSelector, PackFlow, PackFlowControllers, PressurizationConstants, PressurizationOverheadShared, TrimAirSystem, @@ -861,6 +863,7 @@ struct A380PressurizationSystem { negative_relief_valves_id: VariableIdentifier, negative_relief_valves: SafetyValve, + negative_relief_valves_signal: NegativeRelieveValveSignal, } impl A380PressurizationSystem { @@ -904,6 +907,7 @@ impl A380PressurizationSystem { negative_relief_valves_id: context .get_identifier("PRESS_SAFETY_VALVE_OPEN_PERCENTAGE".to_owned()), negative_relief_valves: SafetyValve::new(), + negative_relief_valves_signal: NegativeRelieveValveSignal::new(), } } @@ -926,9 +930,14 @@ impl A380PressurizationSystem { ); } + self.negative_relief_valves_signal.update( + context, + cabin_simulation.cabin_pressure(), + self.negative_relief_valves.open_amount(), + ); // TODO Add check for failure self.negative_relief_valves - .update(context, self.ocsm[0].negative_relief_valve_trigger()); + .update(context, &self.negative_relief_valves_signal); } fn safety_valve_open_amount(&self) -> Ratio { diff --git a/fbw-common/src/wasm/systems/systems/src/air_conditioning/cabin_pressure_controller.rs b/fbw-common/src/wasm/systems/systems/src/air_conditioning/cabin_pressure_controller.rs index 6526e275782..a0c2ad6c007 100644 --- a/fbw-common/src/wasm/systems/systems/src/air_conditioning/cabin_pressure_controller.rs +++ b/fbw-common/src/wasm/systems/systems/src/air_conditioning/cabin_pressure_controller.rs @@ -13,8 +13,8 @@ use crate::{ }; use super::{ - pressure_valve::{OutflowValve, PressureValveSignal, SafetyValve}, - AdirsToAirCondInterface, OutflowValveSignal, PressurizationConstants, + pressure_valve::{OutflowValve, SafetyValve}, + AdirsToAirCondInterface, Air, OutflowValveSignal, PressurizationConstants, PressurizationOverheadShared, }; @@ -56,6 +56,7 @@ pub struct CabinPressureController { pressure_schedule_manager: Option, manual_partition: Option, outflow_valve_controller: OutflowValveController, + adirs_data_is_valid: bool, exterior_pressure: LowPassFilter, exterior_flight_altitude: Length, exterior_vertical_speed: LowPassFilter, @@ -124,6 +125,7 @@ impl CabinPressureController { Self::OFV_CONTROLLER_KP, Self::OFV_CONTROLLER_KI, ), + adirs_data_is_valid: false, exterior_pressure: LowPassFilter::new_with_init_value( Self::AMBIENT_CONDITIONS_FILTER_TIME_CONSTANT, Pressure::new::(Self::P_0), @@ -172,6 +174,9 @@ impl CabinPressureController { safety_valve: &SafetyValve, is_active: bool, ) { + self.adirs_data_is_valid = [1, 2, 3] + .iter() + .any(|&adr| adirs.ambient_static_pressure(adr).is_normal_operation()); let (adirs_airspeed, _) = self.adirs_values_calculation(adirs); self.cabin_pressure = cabin_simulation.cabin_pressure(); @@ -255,9 +260,9 @@ impl CabinPressureController { let (_, adirs_ambient_pressure) = self.adirs_values_calculation(adirs); let new_exterior_altitude: Length; - if !self.is_initialised { + if !self.is_initialised && adirs_ambient_pressure.is_some() { self.exterior_pressure.reset( - adirs_ambient_pressure.unwrap_or_else(|| Pressure::new::(Self::P_0)), + adirs_ambient_pressure.unwrap_or_else(|| Pressure::new::(Air::P_0)), ); new_exterior_altitude = self.calculate_altitude(self.exterior_pressure.output(), self.reference_pressure); @@ -265,7 +270,7 @@ impl CabinPressureController { } else { self.exterior_pressure.update( context.delta(), - adirs_ambient_pressure.unwrap_or_else(|| Pressure::new::(Self::P_0)), + adirs_ambient_pressure.unwrap_or_else(|| Pressure::new::(Air::P_0)), ); new_exterior_altitude = @@ -641,39 +646,6 @@ impl ControllerSignal } } -// Safety valve signal -impl ControllerSignal - for CabinPressureController -{ - fn signal(&self) -> Option { - let open = Some(PressureValveSignal::Open( - Ratio::new::(100.), - Duration::from_secs(1), - )); - let closed = Some(PressureValveSignal::Close( - Ratio::new::(0.), - Duration::from_secs(1), - )); - if self.cabin_delta_p() > Pressure::new::(8.1) { - if self.cabin_delta_p() > Pressure::new::(8.6) { - open - } else { - Some(PressureValveSignal::Neutral) - } - } else if self.cabin_delta_p() < Pressure::new::(-0.5) { - if self.cabin_delta_p() < Pressure::new::(-1.) { - open - } else { - Some(PressureValveSignal::Neutral) - } - } else if self.safety_valve_open_amount > Ratio::new::(0.) { - closed - } else { - Some(PressureValveSignal::Neutral) - } - } -} - impl SimulationElement for CabinPressureController { fn write(&self, writer: &mut SimulatorWriter) { let ssm = if self.failure.is_active() { @@ -682,13 +654,26 @@ impl SimulationElement for CabinPressureController { + ambient_pressure: Pressure, + cabin_pressure: Pressure, + safety_valve_open_amount: Ratio, + + constants: PhantomData, +} + +impl SafetyValveSignal { + pub fn new() -> Self { + Self { + ambient_pressure: Pressure::new::(Air::P_0), + cabin_pressure: Pressure::new::(Air::P_0), + safety_valve_open_amount: Ratio::default(), + + constants: PhantomData, + } + } + + pub fn update( + &mut self, + context: &UpdateContext, + cabin_pressure: Pressure, + safety_valve_open_amount: Ratio, + ) { + self.ambient_pressure = context.ambient_pressure(); + self.cabin_pressure = cabin_pressure; + self.safety_valve_open_amount = safety_valve_open_amount; + } +} + +// Safety valve signal +impl ControllerSignal for SafetyValveSignal { + fn signal(&self) -> Option { + let cabin_delta_p = self.cabin_pressure - self.ambient_pressure; + let open = Some(PressureValveSignal::Open( + Ratio::new::(100.), + Duration::from_secs(1), + )); + let closed = Some(PressureValveSignal::Close( + Ratio::new::(0.), + Duration::from_secs(1), + )); + if cabin_delta_p.get::() > C::MAX_SAFETY_DELTA_P { + if cabin_delta_p.get::() > C::MAX_SAFETY_DELTA_P + 0.5 { + open + } else { + Some(PressureValveSignal::Neutral) + } + } else if cabin_delta_p.get::() < C::MIN_SAFETY_DELTA_P { + if cabin_delta_p.get::() < C::MIN_SAFETY_DELTA_P - 0.5 { + open + } else { + Some(PressureValveSignal::Neutral) + } + } else if self.safety_valve_open_amount > Ratio::default() { + closed + } else { + Some(PressureValveSignal::Neutral) + } + } +} + +impl Default for SafetyValveSignal { + fn default() -> Self { + Self::new() + } +} + +pub struct NegativeRelieveValveSignal { + ambient_pressure: Pressure, + cabin_pressure: Pressure, + safety_valve_open_amount: Ratio, + + constants: PhantomData, +} + +impl NegativeRelieveValveSignal { + pub fn new() -> Self { + Self { + ambient_pressure: Pressure::new::(Air::P_0), + cabin_pressure: Pressure::new::(Air::P_0), + safety_valve_open_amount: Ratio::default(), + + constants: PhantomData, + } + } + + pub fn update( + &mut self, + context: &UpdateContext, + cabin_pressure: Pressure, + safety_valve_open_amount: Ratio, + ) { + self.ambient_pressure = context.ambient_pressure(); + self.cabin_pressure = cabin_pressure; + self.safety_valve_open_amount = safety_valve_open_amount; + } +} + +// Negative relieve valves signal +impl ControllerSignal + for NegativeRelieveValveSignal +{ + fn signal(&self) -> Option { + let cabin_delta_p = self.cabin_pressure - self.ambient_pressure; + let open = Some(PressureValveSignal::Open( + Ratio::new::(100.), + Duration::from_secs(1), + )); + let closed = Some(PressureValveSignal::Close( + Ratio::new::(0.), + Duration::from_secs(1), + )); + if cabin_delta_p.get::() < C::MIN_SAFETY_DELTA_P + 0.2 { + if cabin_delta_p.get::() < C::MIN_SAFETY_DELTA_P { + open + } else { + Some(PressureValveSignal::Neutral) + } + } else if self.safety_valve_open_amount.get::() > 0. { + closed + } else { + Some(PressureValveSignal::Neutral) + } + } +} + +impl Default for NegativeRelieveValveSignal { + fn default() -> Self { + Self::new() + } +} + pub struct PressureValve { open_amount: Ratio, }