From ce500c1393bdff14af5130d58087633d0e4257b3 Mon Sep 17 00:00:00 2001 From: Michael Corcoran Date: Sun, 19 Jan 2025 00:54:49 +1300 Subject: [PATCH 1/3] fix(fms): more robust navdata error handling and sorting (#9774) * fix(fms): improve nav database error handling * fix(a32nx/fms): sort procedures --- .github/CHANGELOG.md | 2 + .../CDU/A320_Neo_CDU_AvailableArrivalsPage.js | 6 +- .../A320_Neo_CDU_AvailableDeparturesPage.js | 2 +- .../navdata/client/backends/Msfs/Mapping.ts | 248 ++++++++++-------- 4 files changed, 150 insertions(+), 108 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index 49a4b41a2cd..afc7d66fb82 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -126,6 +126,8 @@ 1. [A380X/EFB] Adds PRIM/SEC/FCDC failures to EFB - @flogross89 (floridude) 1. [A380X/PFD] Fix precision of pitch trim indicator - @flogross89 (floridude) 1. [A380X/MFD] Add leading zero to altitude prediction and track from last waypoint on FPLN page - @bulenteroglu (senolitam) +1. [FMS] Improved nav database error handling, preserving as much valid data as possible - @tracernz (Mike) +1. [A32NX/FMS] Sort instrument procedures for display on the MCDU - @tracernz (Mike) ## 0.12.0 diff --git a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_AvailableArrivalsPage.js b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_AvailableArrivalsPage.js index cb9fd4cc103..a10fe135818 100644 --- a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_AvailableArrivalsPage.js +++ b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_AvailableArrivalsPage.js @@ -143,8 +143,8 @@ class CDUAvailableArrivalsPage { // Filter out approaches with no matching runway // Approaches not going to a specific runway (i.e circling approaches are filtered out at DB level) .filter((a) => !!runways.find((rw) => rw.ident === a.runwayIdent)) - // Sort the approaches in Honeywell's documented order - .sort((a, b) => ApproachTypeOrder[a.type] - ApproachTypeOrder[b.type]) + // Sort the approaches in Honeywell's documented order, and alphabetical in between + .sort((a, b) => a.type != b.type ? ApproachTypeOrder[a.type] - ApproachTypeOrder[b.type] : a.ident.localeCompare(b.ident)) .map((approach) => ({ approach })) .concat( // Runway-by-itself approaches @@ -252,7 +252,7 @@ class CDUAvailableArrivalsPage { const destinationRunway = targetPlan.destinationRunway; if (destinationRunway) { - const arrivals = targetPlan.availableArrivals; + const arrivals = [...targetPlan.availableArrivals].sort((a, b) => a.ident.localeCompare(b.ident)); for (let i = 0; i < arrivals.length; i++) { const arrival = arrivals[i]; diff --git a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_AvailableDeparturesPage.js b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_AvailableDeparturesPage.js index 8c3e264e9cd..e28a3093c56 100644 --- a/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_AvailableDeparturesPage.js +++ b/fbw-a32nx/src/base/flybywire-aircraft-a320-neo/html_ui/Pages/VCockpit/Instruments/Airliners/FlyByWire_A320_Neo/CDU/A320_Neo_CDU_AvailableDeparturesPage.js @@ -47,7 +47,7 @@ class CDUAvailableDeparturesPage { /** @type {import('msfs-navdata').Runway[]} */ const availableRunways = [...targetPlan.availableOriginRunways]; - let availableSids = [...targetPlan.availableDepartures]; + let availableSids = [...targetPlan.availableDepartures].sort((a, b) => a.ident.localeCompare(b.ident)); let availableTransitions = []; if (selectedRunway) { diff --git a/fbw-common/src/systems/navdata/client/backends/Msfs/Mapping.ts b/fbw-common/src/systems/navdata/client/backends/Msfs/Mapping.ts index 3acfefc74b0..66519246fd9 100644 --- a/fbw-common/src/systems/navdata/client/backends/Msfs/Mapping.ts +++ b/fbw-common/src/systems/navdata/client/backends/Msfs/Mapping.ts @@ -671,46 +671,54 @@ export class MsfsMapping { // Filter out circling approaches .filter((approach) => approach.runwayNumber !== 0) .map((approach) => { - const approachName = this.mapApproachName(approach); - const suffix = approach.approachSuffix.length > 0 ? approach.approachSuffix : undefined; - - // The AR flag is only available from MSFS2024, so fall back to a heuristic based on analysing the MSFS2020 data if not available. - const authorisationRequired = - approach.rnpAr !== undefined - ? approach.rnpAr - : approach.approachType === MSApproachType.Rnav && approach.rnavTypeFlags === 0; - const rnp = authorisationRequired ? 0.3 : undefined; - const missedApproachAuthorisationRequired = - approach.rnpArMissed !== undefined ? approach.rnpArMissed : authorisationRequired; - - const runwayIdent = `${airportIdent}${approach.runwayNumber.toString().padStart(2, '0')}${this.mapRunwayDesignator(approach.runwayDesignator)}`; - - const levelOfService = this.mapRnavTypeFlags(approach.rnavTypeFlags); - - const transitions = this.mapApproachTransitions(approach, facilities, msAirport, approachName); - - return { - sectionCode: SectionCode.Airport, - subSectionCode: AirportSubsectionCode.ApproachProcedures, - databaseId: `P${icaoCode}${airportIdent}${approach.name}`, - icaoCode, - ident: approachName, - suffix, - runwayIdent, - multipleIndicator: approach.approachSuffix, - type: this.mapApproachType(approach.approachType), - authorisationRequired, - missedApproachAuthorisationRequired, - levelOfService, - transitions, - legs: approach.finalLegs.map((leg, legIndex) => - this.mapLeg(leg, legIndex, facilities, msAirport, approachName, approach.approachType, rnp), - ), - missedLegs: approach.missedLegs.map((leg, legIndex) => - this.mapLeg(leg, legIndex, facilities, msAirport, approachName), - ), - }; + try { + const approachName = this.mapApproachName(approach); + const suffix = approach.approachSuffix.length > 0 ? approach.approachSuffix : undefined; + + // The AR flag is only available from MSFS2024, so fall back to a heuristic based on analysing the MSFS2020 data if not available. + const authorisationRequired = + approach.rnpAr !== undefined + ? approach.rnpAr + : approach.approachType === MSApproachType.Rnav && approach.rnavTypeFlags === 0; + const rnp = authorisationRequired ? 0.3 : undefined; + const missedApproachAuthorisationRequired = + approach.rnpArMissed !== undefined ? approach.rnpArMissed : authorisationRequired; + + const runwayIdent = `${airportIdent}${approach.runwayNumber.toString().padStart(2, '0')}${this.mapRunwayDesignator(approach.runwayDesignator)}`; + + const levelOfService = this.mapRnavTypeFlags(approach.rnavTypeFlags); + + const transitions = this.mapApproachTransitions(approach, facilities, msAirport, approachName); + + const ret: Approach = { + sectionCode: SectionCode.Airport, + subSectionCode: AirportSubsectionCode.ApproachProcedures, + databaseId: `P${icaoCode}${airportIdent}${approach.name}`, + icaoCode, + ident: approachName, + suffix, + runwayIdent, + multipleIndicator: approach.approachSuffix, + type: this.mapApproachType(approach.approachType), + authorisationRequired, + missedApproachAuthorisationRequired, + levelOfService, + transitions, + legs: approach.finalLegs.map((leg, legIndex) => + this.mapLeg(leg, legIndex, facilities, msAirport, approachName, approach.approachType, rnp), + ), + missedLegs: approach.missedLegs.map((leg, legIndex) => + this.mapLeg(leg, legIndex, facilities, msAirport, approachName), + ), + }; + + return ret; + } catch (e) { + console.error(`Error mapping approach ${msAirport.icao} ${approach.name}`, e); + } + return null; }) + .filter((v) => v !== null) ); } @@ -720,23 +728,33 @@ export class MsfsMapping { const facilities = await this.loadFacilitiesFromProcedures(msAirport.arrivals); - return msAirport.arrivals.map((arrival) => ({ - sectionCode: SectionCode.Airport, - subSectionCode: AirportSubsectionCode.STARs, - databaseId: `P${icaoCode}${airportIdent}${arrival.name}`, - icaoCode, - ident: arrival.name, - authorisationRequired: arrival.rnpAr ?? false, - commonLegs: arrival.commonLegs.map((leg, legIndex) => - this.mapLeg(leg, legIndex, facilities, msAirport, arrival.name), - ), - enrouteTransitions: arrival.enRouteTransitions.map((trans, idx) => - this.mapEnrouteTransition(trans, facilities, msAirport, arrival.name, arrival.name + idx), - ), - runwayTransitions: arrival.runwayTransitions.map((trans, idx) => - this.mapRunwayTransition(trans, facilities, msAirport, arrival.name, arrival.name + idx), - ), - })); + return msAirport.arrivals + .map((arrival) => { + try { + const ret: Arrival = { + sectionCode: SectionCode.Airport, + subSectionCode: AirportSubsectionCode.STARs, + databaseId: `P${icaoCode}${airportIdent}${arrival.name}`, + icaoCode, + ident: arrival.name, + authorisationRequired: arrival.rnpAr ?? false, + commonLegs: arrival.commonLegs.map((leg, legIndex) => + this.mapLeg(leg, legIndex, facilities, msAirport, arrival.name), + ), + enrouteTransitions: arrival.enRouteTransitions.map((trans, idx) => + this.mapEnrouteTransition(trans, facilities, msAirport, arrival.name, arrival.name + idx), + ), + runwayTransitions: arrival.runwayTransitions.map((trans, idx) => + this.mapRunwayTransition(trans, facilities, msAirport, arrival.name, arrival.name + idx), + ), + }; + return ret; + } catch (e) { + console.error(`Error mapping arrival ${msAirport.icao} ${arrival.name}`, e); + } + return null; + }) + .filter((v) => v !== null); } public async mapDepartures(msAirport: JS_FacilityAirport): Promise { @@ -745,37 +763,45 @@ export class MsfsMapping { const facilities = await this.loadFacilitiesFromProcedures(msAirport.departures); - return msAirport.departures.map((departure) => { - let authorisationRequired = departure.rnpAr; - if (authorisationRequired === undefined) { - // fallback heuristic for MSFS2020 - authorisationRequired = - this.isAnyRfLegPresent(departure.commonLegs) || - this.isAnyRfLegPresent(departure.runwayTransitions) || - this.isAnyRfLegPresent(departure.enRouteTransitions); - } + return msAirport.departures + .map((departure) => { + try { + let authorisationRequired = departure.rnpAr; + if (authorisationRequired === undefined) { + // fallback heuristic for MSFS2020 + authorisationRequired = + this.isAnyRfLegPresent(departure.commonLegs) || + this.isAnyRfLegPresent(departure.runwayTransitions) || + this.isAnyRfLegPresent(departure.enRouteTransitions); + } - const commonLegsRnp = authorisationRequired ? 0.3 : undefined; + const commonLegsRnp = authorisationRequired ? 0.3 : undefined; - return { - sectionCode: SectionCode.Airport, - subSectionCode: AirportSubsectionCode.SIDs, - databaseId: `P${icaoCode}${airportIdent}${departure.name}`, - icaoCode, - ident: departure.name, - authorisationRequired, - commonLegs: departure.commonLegs.map((leg, legIndex) => - this.mapLeg(leg, legIndex, facilities, msAirport, departure.name, undefined, commonLegsRnp), - ), - engineOutLegs: [], - enrouteTransitions: departure.enRouteTransitions.map((trans, idx) => - this.mapEnrouteTransition(trans, facilities, msAirport, departure.name, departure.name + idx), - ), - runwayTransitions: departure.runwayTransitions.map((trans, idx) => - this.mapRunwayTransition(trans, facilities, msAirport, departure.name, departure.name + idx), - ), - }; - }); + const ret: Departure = { + sectionCode: SectionCode.Airport, + subSectionCode: AirportSubsectionCode.SIDs, + databaseId: `P${icaoCode}${airportIdent}${departure.name}`, + icaoCode, + ident: departure.name, + authorisationRequired, + commonLegs: departure.commonLegs.map((leg, legIndex) => + this.mapLeg(leg, legIndex, facilities, msAirport, departure.name, undefined, commonLegsRnp), + ), + engineOutLegs: [], + enrouteTransitions: departure.enRouteTransitions.map((trans, idx) => + this.mapEnrouteTransition(trans, facilities, msAirport, departure.name, departure.name + idx), + ), + runwayTransitions: departure.runwayTransitions.map((trans, idx) => + this.mapRunwayTransition(trans, facilities, msAirport, departure.name, departure.name + idx), + ), + }; + return ret; + } catch (e) { + console.error(`Error mapping departure ${msAirport.icao} ${departure.name}`, e); + } + return null; + }) + .filter((v) => v !== null); } public async mapGates(msAirport: JS_FacilityAirport): Promise { @@ -1037,6 +1063,31 @@ export class MsfsMapping { }; } + private tryGetWaypointFromIcao( + airport: JS_FacilityAirport, + facilities: Map, + icao: string, + ): ReturnType | undefined { + const isRunway = icao.charAt(0) === 'R'; + if (!FacilityCache.validFacilityIcao(icao) && !isRunway) { + return undefined; + } + + let ret: ReturnType | undefined; + + if (isRunway) { + ret = this.mapRunwayWaypoint(airport, icao); + } else { + const facility = facilities.get(icao); + ret = facility ? this.mapFacilityToWaypoint(facility) : undefined; + } + + if (!ret) { + throw new Error(`Missing fix ${icao} for procedure leg!`); + } + return ret; + } + private mapLeg( leg: JS_Leg, legIndex: number, @@ -1046,28 +1097,17 @@ export class MsfsMapping { approachType?: MSApproachType, fallbackRnp?: number, ): ProcedureLeg { - const arcCentreFixFacility = FacilityCache.validFacilityIcao(leg.arcCenterFixIcao) - ? facilities.get(leg.arcCenterFixIcao) - : undefined; - const arcCentreFix = arcCentreFixFacility ? this.mapFacilityToWaypoint(arcCentreFixFacility) : undefined; - let waypoint; - if (leg.fixIcao.charAt(0) === 'R') { - waypoint = this.mapRunwayWaypoint(airport, leg.fixIcao); - } else { - const waypointFacility = FacilityCache.validFacilityIcao(leg.fixIcao) ? facilities.get(leg.fixIcao) : undefined; - waypoint = waypointFacility ? this.mapFacilityToWaypoint(waypointFacility) : undefined; - } - const recommendedNavaidFacility = FacilityCache.validFacilityIcao(leg.originIcao) - ? facilities.get(leg.originIcao) - : undefined; - const recommendedNavaid = recommendedNavaidFacility - ? this.mapFacilityToWaypoint(recommendedNavaidFacility) - : undefined; + const arcCentreFix = this.tryGetWaypointFromIcao(airport, facilities, leg.arcCenterFixIcao); + const waypoint = this.tryGetWaypointFromIcao(airport, facilities, leg.fixIcao); + const recommendedNavaid = this.tryGetWaypointFromIcao(airport, facilities, leg.originIcao); let arcRadius: number | undefined; if (leg.type === MsLegType.RF) { - if (!arcCentreFix || !waypoint) { - throw new Error('Missing data for RF leg!'); + if (!arcCentreFix) { + throw new Error(`No arc centre fix for RF leg!`); + } + if (!waypoint) { + throw new Error(`No waypoint fix for RF leg!`); } arcRadius = distanceTo(arcCentreFix.location, waypoint.location); } From c837ab18a6170b108312fa77c96eb09cfc4815a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20St=C3=B6rzbach?= Date: Sat, 18 Jan 2025 16:24:10 +0100 Subject: [PATCH 2/3] feat(elec): a380 electrical improvements (#9683) * feat(elec): more accurate simulation of BCRU behavior * feat: add missing EBHA for spoiler 5 * fix ac gnd service bus * fix tests * fix battery voltage indicator battery mapping * Revert "feat: add missing EBHA for spoiler 5" This reverts commit a7dbce2cb691802f460febf53c4dd44aaf747141. * add changelog --- .github/CHANGELOG.md | 1 + fbw-a380x/docs/a380-simvars.md | 2 +- .../src/systems/instruments/src/BAT/index.tsx | 2 +- .../src/electrical/alternating_current.rs | 9 ++ .../src/electrical/direct_current.rs | 18 ++-- .../a380_systems/src/electrical/mod.rs | 98 ++++++++++++++----- .../battery_charge_rectifier_unit.rs | 30 ++---- 7 files changed, 101 insertions(+), 59 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index afc7d66fb82..b4d780da680 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -128,6 +128,7 @@ 1. [A380X/MFD] Add leading zero to altitude prediction and track from last waypoint on FPLN page - @bulenteroglu (senolitam) 1. [FMS] Improved nav database error handling, preserving as much valid data as possible - @tracernz (Mike) 1. [A32NX/FMS] Sort instrument procedures for display on the MCDU - @tracernz (Mike) +1. [A380X/ELEC] Various fixes in the electrical system (battery voltage indicator switchup, AC GND SVC BUS and correct behavior of battery contactors) - @Gurgel100 (Pascal) ## 0.12.0 diff --git a/fbw-a380x/docs/a380-simvars.md b/fbw-a380x/docs/a380-simvars.md index bbbed6ee669..32ea45db184 100644 --- a/fbw-a380x/docs/a380-simvars.md +++ b/fbw-a380x/docs/a380-simvars.md @@ -105,7 +105,7 @@ - Number - The position of the battery display knob from left to right - ESS=0, APU=1, OFF=2, BAT1=3, BAT2=4 - - Mapped to battery voltage indexes: {bat_index} = ESS=4 | APU=3 | OFF=0 | BAT1=1 | BAT2=2 + - Mapped to battery voltage indexes: {bat_index} = ESS=3 | APU=4 | OFF=0 | BAT1=1 | BAT2=2 - A32NX_ELEC_BAT_{bat_index}_POTENTIAL is used to get the voltage - A32NX_NOSE_WHEEL_LEFT_ANIM_ANGLE diff --git a/fbw-a380x/src/systems/instruments/src/BAT/index.tsx b/fbw-a380x/src/systems/instruments/src/BAT/index.tsx index 59e79d27206..05accc1a8fd 100644 --- a/fbw-a380x/src/systems/instruments/src/BAT/index.tsx +++ b/fbw-a380x/src/systems/instruments/src/BAT/index.tsx @@ -16,7 +16,7 @@ const BatRoot = () => { } // mapping of knob (lvar) values to battery numbers to allow easy lvar and model values - const batteryMap = [4, 3, 0, 1, 2]; // ESS, APU, OFF, BAT1, BAT2 + const batteryMap = [3, 4, 0, 1, 2]; // ESS, APU, OFF, BAT1, BAT2 return ( diff --git a/fbw-a380x/src/wasm/systems/a380_systems/src/electrical/alternating_current.rs b/fbw-a380x/src/wasm/systems/a380_systems/src/electrical/alternating_current.rs index dbbd7e89f91..796c0f63370 100644 --- a/fbw-a380x/src/wasm/systems/a380_systems/src/electrical/alternating_current.rs +++ b/fbw-a380x/src/wasm/systems/a380_systems/src/electrical/alternating_current.rs @@ -143,6 +143,10 @@ impl A380AlternatingCurrentElectrical { &self.ext_pwr_to_ac_gnd_flt_service_bus_and_tr_2_contactor, ); electricity.flow(&self.ac_bus_3_to_tr_2_contactor, &self.ac_buses[2]); + electricity.flow( + &self.ac_bus_3_to_tr_2_contactor, + &self.ac_gnd_flt_service_bus, + ); electricity.flow( &self.ext_pwr_to_ac_gnd_flt_service_bus_and_tr_2_contactor, &self.ac_gnd_flt_service_bus, @@ -276,6 +280,11 @@ impl SimulationElement for A380AlternatingCurrentElectrical { self.ac_emer_bus.accept(visitor); self.ac_eha_bus.accept(visitor); + self.ac_bus_3_to_tr_2_contactor.accept(visitor); + self.ext_pwr_to_ac_gnd_flt_service_bus_and_tr_2_contactor + .accept(visitor); + self.ac_gnd_flt_service_bus.accept(visitor); + visitor.visit(self); } } diff --git a/fbw-a380x/src/wasm/systems/a380_systems/src/electrical/direct_current.rs b/fbw-a380x/src/wasm/systems/a380_systems/src/electrical/direct_current.rs index caea58bc718..89a0880d28c 100644 --- a/fbw-a380x/src/wasm/systems/a380_systems/src/electrical/direct_current.rs +++ b/fbw-a380x/src/wasm/systems/a380_systems/src/electrical/direct_current.rs @@ -91,19 +91,16 @@ impl A380DirectCurrentElectrical { tr_1: BatteryChargeRectifierUnit::new( context, 1, - ElectricalBusType::DirectCurrent(1), ElectricalBusType::DirectCurrentHot(1), ), tr_2: BatteryChargeRectifierUnit::new( context, 2, - ElectricalBusType::DirectCurrent(2), ElectricalBusType::DirectCurrentHot(2), ), tr_ess: BatteryChargeRectifierUnit::new( context, 3, - ElectricalBusType::DirectCurrentEssential, ElectricalBusType::DirectCurrentHot(3), ), tr_1_contactor: Contactor::new(context, "990PU1"), @@ -214,7 +211,7 @@ impl A380DirectCurrentElectrical { && !self.tr_1.battery_nearly_empty() && !ac_state.any_non_essential_bus_powered(electricity) || rat.should_deploy(); - self.tr_1.update(electricity, should_close_elc, false); + self.tr_1.update(should_close_elc); self.battery_1_contactor .close_when(self.tr_1.should_close_battery_connector()); self.battery_1_emergency_contactor @@ -226,20 +223,27 @@ impl A380DirectCurrentElectrical { electricity.flow(&self.battery_1_emergency_contactor, &self.dc_ess_bus); electricity.supplied_by(&self.battery_2); - self.tr_2.update(electricity, false, false); + self.tr_2.update(false); self.battery_2_contactor .close_when(self.tr_2.should_close_battery_connector()); electricity.flow(&self.battery_2_contactor, &self.battery_2); electricity.flow(&self.hot_bus_2, &self.battery_2); electricity.flow(&self.battery_2_contactor, &self.dc_bus_2); + // TODO: should not close when battery failed (signal from BCRU) + // TODO: complete logic + let should_close_ess_bat_lc = overhead.bat_is_auto(1) + && overhead.bat_is_auto(3) + && !self.tr_ess.battery_nearly_empty() + && !ac_state.any_non_essential_bus_powered(electricity) + || rat.should_deploy(); let emergency_config = !electricity.is_powered(&self.dc_bus_1) && emergency_config.is_active() || rat.should_deploy(); electricity.supplied_by(&self.battery_ess); - self.tr_ess.update(electricity, false, emergency_config); + self.tr_ess.update(emergency_config); self.battery_ess_contactor - .close_when(self.tr_ess.should_close_battery_connector()); + .close_when(self.tr_ess.should_close_battery_connector() || should_close_ess_bat_lc); electricity.flow(&self.battery_ess_contactor, &self.battery_ess); electricity.flow(&self.hot_bus_ess, &self.battery_ess); electricity.flow(&self.battery_ess_contactor, &self.dc_ess_bus); diff --git a/fbw-a380x/src/wasm/systems/a380_systems/src/electrical/mod.rs b/fbw-a380x/src/wasm/systems/a380_systems/src/electrical/mod.rs index e3a4d609282..d7c98463fad 100644 --- a/fbw-a380x/src/wasm/systems/a380_systems/src/electrical/mod.rs +++ b/fbw-a380x/src/wasm/systems/a380_systems/src/electrical/mod.rs @@ -870,7 +870,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::ApuGenerator(2))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::ApuGenerator(2))); assert!(test_bed.tr_1_input().is_single(PotentialOrigin::External)); assert!(test_bed .tr_2_input() @@ -942,7 +944,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::External)); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::External)); assert!(test_bed.tr_1_input().is_single(PotentialOrigin::External)); assert!(test_bed.tr_2_input().is_single(PotentialOrigin::External)); assert!(test_bed.tr_ess_input().is_single(PotentialOrigin::External)); @@ -1016,7 +1020,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::External)); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::External)); assert!(test_bed.tr_1_input().is_single(PotentialOrigin::External)); assert!(test_bed.tr_2_input().is_single(PotentialOrigin::External)); assert!(test_bed @@ -1091,7 +1097,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::ApuGenerator(2))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::ApuGenerator(2))); assert!(test_bed .tr_1_input() .is_single(PotentialOrigin::ApuGenerator(1))); @@ -1171,7 +1179,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::ApuGenerator(2))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::ApuGenerator(2))); assert!(test_bed .tr_1_input() .is_single(PotentialOrigin::ApuGenerator(1))); @@ -1253,7 +1263,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::External)); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::External)); assert!(test_bed.tr_1_input().is_single(PotentialOrigin::External)); assert!(test_bed.tr_2_input().is_single(PotentialOrigin::External)); assert!(test_bed @@ -1321,7 +1333,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::ApuGenerator(2))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::ApuGenerator(2))); assert!(test_bed .tr_1_input() .is_single(PotentialOrigin::ApuGenerator(2))); @@ -1397,7 +1411,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::EngineGenerator(4))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::EngineGenerator(4))); assert!(test_bed .tr_1_input() .is_single(PotentialOrigin::ApuGenerator(1))); @@ -1467,7 +1483,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed .tr_1_input() .is_single(PotentialOrigin::EngineGenerator(2))); @@ -1546,7 +1564,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed .tr_1_input() .is_single(PotentialOrigin::EngineGenerator(2))); @@ -1624,7 +1644,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed .tr_1_input() .is_single(PotentialOrigin::EngineGenerator(3))); @@ -1702,7 +1724,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed .tr_1_input() .is_single(PotentialOrigin::EngineGenerator(2))); @@ -1781,7 +1805,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed .tr_1_input() .is_single(PotentialOrigin::ApuGenerator(1))); @@ -1861,7 +1887,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::ApuGenerator(1))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::ApuGenerator(1))); assert!(test_bed .tr_1_input() .is_single(PotentialOrigin::EngineGenerator(2))); @@ -1930,7 +1958,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed.tr_1_input().is_unpowered()); assert!(test_bed .tr_2_input() @@ -1958,7 +1988,7 @@ mod a380_electrical_circuit_tests { .is_single(PotentialOrigin::TransformerRectifier(4))); assert!(test_bed .hot_bus_output(1) - .is_single(PotentialOrigin::TransformerRectifier(2))); + .is_single(PotentialOrigin::Battery(1))); assert!(test_bed .hot_bus_output(2) .is_single(PotentialOrigin::TransformerRectifier(2))); @@ -2006,7 +2036,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed .tr_1_input() .is_single(PotentialOrigin::ApuGenerator(1))); @@ -2188,7 +2220,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed .tr_1_input() .is_single(PotentialOrigin::EngineGenerator(2))); @@ -2218,7 +2252,7 @@ mod a380_electrical_circuit_tests { .is_single(PotentialOrigin::TransformerRectifier(4))); assert!(test_bed .hot_bus_output(1) - .is_single(PotentialOrigin::TransformerRectifier(2))); + .is_single(PotentialOrigin::Battery(1))); assert!(test_bed .hot_bus_output(2) .is_single(PotentialOrigin::TransformerRectifier(2))); @@ -2259,7 +2293,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed .tr_1_input() .is_single(PotentialOrigin::EngineGenerator(2))); @@ -2292,7 +2328,7 @@ mod a380_electrical_circuit_tests { .is_single(PotentialOrigin::TransformerRectifier(1))); assert!(test_bed .hot_bus_output(2) - .is_single(PotentialOrigin::TransformerRectifier(1))); + .is_single(PotentialOrigin::Battery(2))); assert!(test_bed .hot_bus_output(3) .is_single(PotentialOrigin::TransformerRectifier(3))); @@ -2330,7 +2366,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed .tr_1_input() .is_single(PotentialOrigin::EngineGenerator(2))); @@ -2366,7 +2404,7 @@ mod a380_electrical_circuit_tests { .is_single(PotentialOrigin::TransformerRectifier(2))); assert!(test_bed .hot_bus_output(3) - .is_single(PotentialOrigin::TransformerRectifier(1))); + .is_single(PotentialOrigin::Battery(3))); assert!(test_bed .hot_bus_output(4) .is_single(PotentialOrigin::Battery(4))); @@ -2399,7 +2437,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed .tr_1_input() .is_single(PotentialOrigin::EngineGenerator(2))); @@ -2471,7 +2511,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed .tr_1_input() .is_single(PotentialOrigin::EngineGenerator(2))); @@ -2537,7 +2579,9 @@ mod a380_electrical_circuit_tests { .ac_eha_bus_output() .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed.static_inverter_input().is_unpowered()); - assert!(test_bed.ac_gnd_flt_service_bus_output().is_unpowered()); + assert!(test_bed + .ac_gnd_flt_service_bus_output() + .is_single(PotentialOrigin::EngineGenerator(3))); assert!(test_bed .tr_1_input() .is_single(PotentialOrigin::EngineGenerator(2))); @@ -2568,7 +2612,7 @@ mod a380_electrical_circuit_tests { .is_single(PotentialOrigin::TransformerRectifier(1))); assert!(test_bed .hot_bus_output(2) - .is_single(PotentialOrigin::TransformerRectifier(1))); + .is_single(PotentialOrigin::Battery(2))); assert!(test_bed .hot_bus_output(3) .is_single(PotentialOrigin::Battery(3))); diff --git a/fbw-common/src/wasm/systems/systems/src/electrical/battery_charge_rectifier_unit.rs b/fbw-common/src/wasm/systems/systems/src/electrical/battery_charge_rectifier_unit.rs index 2e243ec88ae..32a74ea8e8e 100644 --- a/fbw-common/src/wasm/systems/systems/src/electrical/battery_charge_rectifier_unit.rs +++ b/fbw-common/src/wasm/systems/systems/src/electrical/battery_charge_rectifier_unit.rs @@ -22,7 +22,6 @@ pub struct BatteryChargeRectifierUnit { output_potential: ElectricPotential, output_current: ElectricCurrent, number: usize, - dc_bus: ElectricalBusType, battery_hot_bus: ElectricalBusType, failure: Failure, battery_soc_20: bool, @@ -40,7 +39,6 @@ impl BatteryChargeRectifierUnit { pub fn new( context: &mut InitContext, number: usize, - dc_bus: ElectricalBusType, battery_hot_bus: ElectricalBusType, ) -> Self { Self { @@ -50,7 +48,6 @@ impl BatteryChargeRectifierUnit { output_potential: ElectricPotential::default(), output_current: ElectricCurrent::default(), number, - dc_bus, battery_hot_bus, failure: Failure::new(FailureType::TransformerRectifier(number)), battery_soc_20: false, @@ -99,16 +96,9 @@ impl BatteryChargeRectifierUnit { self.battery_soc_20 = battery.potential().get::() < 24.5; } - pub fn update( - &mut self, - electricity: &Electricity, - battery_inhibited: bool, - emergency_config: bool, - ) { + pub fn update(&mut self, emergency_config: bool) { self.state = self.state.update( - battery_inhibited, self.battery_pb_is_auto, - electricity.bus_is_powered(self.dc_bus), emergency_config, self.loss_of_ac_duration, ); @@ -229,9 +219,7 @@ impl State { fn update( self, - battery_inhibited: bool, battery_is_auto: bool, - dc_bus_powered: bool, emergency_config: bool, loss_of_ac_duration: Duration, ) -> Self { @@ -245,25 +233,22 @@ impl State { } Self::Open => { if emergency_config { - Self::Closed + Self::Open } else if !battery_is_auto { Self::BatOff - } else if !battery_inhibited && dc_bus_powered { + } else if loss_of_ac_duration.is_zero() { Self::Closed } else { Self::Open } } Self::Closed => { - if emergency_config { - Self::Closed - } else if !battery_is_auto { - Self::BatOff - } else if battery_inhibited - || !dc_bus_powered - && loss_of_ac_duration >= Self::OPEN_BAT_LC_AFTER_AC_LOST_DURATION + if emergency_config + || loss_of_ac_duration >= Self::OPEN_BAT_LC_AFTER_AC_LOST_DURATION { Self::Open + } else if !battery_is_auto { + Self::BatOff } else { Self::Closed } @@ -359,7 +344,6 @@ mod battery_charger_rectifier_tests { transformer_rectifier: BatteryChargeRectifierUnit::new( context, 1, - ElectricalBusType::DirectCurrent(1), ElectricalBusType::DirectCurrentHot(1), ), bus: ElectricalBus::new(context, ElectricalBusType::DirectCurrent(1)), From 886180bafb48d69bf4935be3c9f946f45ab48de3 Mon Sep 17 00:00:00 2001 From: floridude <63071941+flogross89@users.noreply.github.com> Date: Sat, 18 Jan 2025 19:47:34 +0200 Subject: [PATCH 3/3] fix(a380x/fms): Fix mach crossover altitude & T/O perf characteristic speeds (#9769) * use FL300 as crossover altitude * fixes * review comments * fix(mathutils): remove machToKCas temperature dependency (cherry picked from commit 3f77cd546183db6a9d1ae779af412bb3ed1b7cf7) * some updates * remove comment * Update CHANGELOG.md --------- Co-authored-by: Michael Corcoran --- .github/CHANGELOG.md | 1 + .../src/MFD/FMC/FmcAircraftInterface.ts | 30 +++++++---- .../systems/instruments/src/MFD/FMC/fmgc.ts | 15 ++++-- .../src/MFD/pages/FMS/MfdFmsPerf.tsx | 54 +++++++++++++------ .../instruments/src/MFD/shared/Adirs.ts | 17 ++++++ .../systems/shared/src/OperatingSpeeds.tsx | 6 ++- .../src/systems/shared/src/MathUtils.ts | 1 - 7 files changed, 91 insertions(+), 33 deletions(-) diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index b4d780da680..c9586f56c19 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -129,6 +129,7 @@ 1. [FMS] Improved nav database error handling, preserving as much valid data as possible - @tracernz (Mike) 1. [A32NX/FMS] Sort instrument procedures for display on the MCDU - @tracernz (Mike) 1. [A380X/ELEC] Various fixes in the electrical system (battery voltage indicator switchup, AC GND SVC BUS and correct behavior of battery contactors) - @Gurgel100 (Pascal) +1. [A380X/FMS] Use cruise mach above crossover altitude - @flogross89 (floridude) ## 0.12.0 diff --git a/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcAircraftInterface.ts b/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcAircraftInterface.ts index e2d1092e4d3..d2e09fa33e5 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcAircraftInterface.ts +++ b/fbw-a380x/src/systems/instruments/src/MFD/FMC/FmcAircraftInterface.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: GPL-3.0 import { ConsumerValue, EventBus, GameStateProvider, SimVarValueType, Subject, UnitType } from '@microsoft/msfs-sdk'; -import { Arinc429SignStatusMatrix, Arinc429Word, FmsOansData } from '@flybywiresim/fbw-sdk'; +import { Arinc429SignStatusMatrix, Arinc429Word, FmsOansData, MathUtils } from '@flybywiresim/fbw-sdk'; import { FlapConf } from '@fmgc/guidance/vnav/common'; import { FlightPlanService } from '@fmgc/index'; import { MmrRadioTuningStatus } from '@fmgc/navigation/NavaidTuner'; @@ -1170,17 +1170,16 @@ export class FmcAircraftInterface { this.fmgc.data.approachFlapRetractionSpeed.set(Math.ceil(approachSpeeds.f3)); this.speedVapp.set(Math.round(approachSpeeds.vapp)); - // Retrieve CAS and altitude from ADRs - const cas = this.fmc.navigation.getComputedAirspeed(); + // Retrieve altitude from ADRs const alt = this.fmc.navigation.getPressureAltitude(); - if (cas !== null && alt !== null) { - // Only update speeds if ADR data valid + if (alt !== null) { + // Only update speeds if ADR altitude data valid. const flapLever = SimVar.GetSimVarValue('L:A32NX_FLAPS_HANDLE_INDEX', 'Enum'); const speeds = new A380OperatingSpeeds( grossWeight, - cas, + this.fmc.navigation.getComputedAirspeed() ?? 0, // CAS is NCD for low speeds/standstill, leading to null here flapLever, this.flightPhase.get(), this.fmgc.getV2Speed(), @@ -1612,10 +1611,21 @@ export class FmcAircraftInterface { return SimVar.GetSimVarValue('AUTOPILOT ALTITUDE SLOT INDEX', 'number') === 2; } - getManagedTargets(v: number, m: number) { - const alt = ADIRS.getBaroCorrectedAltitude(); - const vM = SimVar.GetGameVarValue('FROM MACH TO KIAS', 'number', m); - return alt && alt.isNormalOperation() && alt.value > 20_000 && v > vM ? [vM, true] : [v, false]; + getManagedTargets(v: number, m: number): [number, boolean] { + const sat = ADIRS.getStaticAirTemperature(); + const press = ADIRS.getCorrectedAverageStaticPressure(); + + if ( + sat !== undefined && + (sat.isNormalOperation() || sat.isFunctionalTest()) && + press !== undefined && + (press.isNormalOperation() || press.isFunctionalTest()) + ) { + const vM = MathUtils.convertMachToKCas(m, press.value); + return v > vM ? [vM, true] : [v, false]; + } else { + return [v, false]; + } } // TODO/VNAV: Speed constraint diff --git a/fbw-a380x/src/systems/instruments/src/MFD/FMC/fmgc.ts b/fbw-a380x/src/systems/instruments/src/MFD/FMC/fmgc.ts index 72d56a99eb2..1207cbaa2d7 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/FMC/fmgc.ts +++ b/fbw-a380x/src/systems/instruments/src/MFD/FMC/fmgc.ts @@ -53,6 +53,10 @@ export enum ClimbDerated { * Temporary place for data which is found nowhere else. Not associated to flight plans right now, which should be the case for some of these values */ export class FmgcData { + static fmcFormatSpeed(sub: Subscribable) { + return sub.map((it) => (it !== null ? it.toFixed(0) : '---')); + } + public readonly cpnyFplnAvailable = Subject.create(false); public readonly cpnyFplnUplinkInProgress = Subject.create(false); @@ -217,11 +221,11 @@ export class FmgcData { public readonly takeoffFlapsSetting = Subject.create(FlapConf.CONF_1); - public readonly flapRetractionSpeed = Subject.create(141); + public readonly flapRetractionSpeed = Subject.create(null); - public readonly slatRetractionSpeed = Subject.create(159); + public readonly slatRetractionSpeed = Subject.create(null); - public readonly greenDotSpeed = Subject.create(190); + public readonly greenDotSpeed = Subject.create(null); public readonly approachSpeed = Subject.create(null); @@ -454,10 +458,11 @@ export class FmgcDataService implements Fmgc { return preSel; } - if (this.flightPlanService.has(FlightPlanIndex.Active)) { + // FIXME need to rework the cost index based speed calculations + /* if (this.flightPlanService.has(FlightPlanIndex.Active)) { const dCI = ((this.flightPlanService.active.performanceData.costIndex ?? 100) / 999) ** 2; return 290 * (1 - dCI) + 330 * dCI; - } + }*/ return 310; } diff --git a/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/MfdFmsPerf.tsx b/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/MfdFmsPerf.tsx index 7baa4383e7d..3b5ed636ac7 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/MfdFmsPerf.tsx +++ b/fbw-a380x/src/systems/instruments/src/MFD/pages/FMS/MfdFmsPerf.tsx @@ -29,7 +29,7 @@ import { maxCertifiedAlt, Mmo, Vmo } from '@shared/PerformanceConstants'; import { ConfirmationDialog } from 'instruments/src/MFD/pages/common/ConfirmationDialog'; import { FmsPage } from 'instruments/src/MFD/pages/common/FmsPage'; import { FmgcFlightPhase } from '@shared/flightphase'; -import { TakeoffDerated, TakeoffPowerSetting } from 'instruments/src/MFD/FMC/fmgc'; +import { FmgcData, TakeoffDerated, TakeoffPowerSetting } from 'instruments/src/MFD/FMC/fmgc'; import { ConditionalComponent } from 'instruments/src/MFD/pages/common/ConditionalComponent'; import { MfdSimvars } from 'instruments/src/MFD/shared/MFDSimvarPublisher'; import { VerticalCheckpointReason } from '@fmgc/guidance/vnav/profile/NavGeometryProfile'; @@ -1055,7 +1055,9 @@ export class MfdFmsPerf extends FmsPage {
- {this.props.fmcService.master.fmgc.data.v1ToBeConfirmed} + + {FmgcData.fmcFormatSpeed(this.props.fmcService.master.fmgc.data.v1ToBeConfirmed)} + KT
@@ -1093,7 +1095,9 @@ export class MfdFmsPerf extends FmsPage {
F - {this.props.fmcService.master.fmgc.data.flapRetractionSpeed} + + {FmgcData.fmcFormatSpeed(this.props.fmcService.master.fmgc.data.flapRetractionSpeed)} + KT
@@ -1115,13 +1119,17 @@ export class MfdFmsPerf extends FmsPage {
- {this.props.fmcService.master.fmgc.data.vrToBeConfirmed} + + {FmgcData.fmcFormatSpeed(this.props.fmcService.master.fmgc.data.vrToBeConfirmed)} + KT
S - {this.props.fmcService.master.fmgc.data.slatRetractionSpeed} + + {FmgcData.fmcFormatSpeed(this.props.fmcService.master.fmgc.data.slatRetractionSpeed)} + KT
@@ -1143,7 +1151,9 @@ export class MfdFmsPerf extends FmsPage {
- {this.props.fmcService.master.fmgc.data.v2ToBeConfirmed} + + {FmgcData.fmcFormatSpeed(this.props.fmcService.master.fmgc.data.v2ToBeConfirmed)} + KT
@@ -1153,7 +1163,9 @@ export class MfdFmsPerf extends FmsPage { - {this.props.fmcService.master.fmgc.data.greenDotSpeed} + + {FmgcData.fmcFormatSpeed(this.props.fmcService.master.fmgc.data.greenDotSpeed)} + KT @@ -2557,26 +2569,30 @@ export class MfdFmsPerf extends FmsPage { - {this.props.fmcService.master.fmgc.data.approachGreenDotSpeed} + + {FmgcData.fmcFormatSpeed(this.props.fmcService.master.fmgc.data.approachGreenDotSpeed)} + KT
S - {this.props.fmcService.master.fmgc.data.approachSlatRetractionSpeed} + {FmgcData.fmcFormatSpeed(this.props.fmcService.master.fmgc.data.approachSlatRetractionSpeed)} KT
F - {this.props.fmcService.master.fmgc.data.approachFlapRetractionSpeed} + {FmgcData.fmcFormatSpeed(this.props.fmcService.master.fmgc.data.approachFlapRetractionSpeed)} KT
VREF - {this.props.fmcService.master.fmgc.data.approachVref} + + {FmgcData.fmcFormatSpeed(this.props.fmcService.master.fmgc.data.approachVref)} + KT
@@ -2594,7 +2610,9 @@ export class MfdFmsPerf extends FmsPage { />
VLS - {this.props.fmcService.master.fmgc.data.approachVls} + + {FmgcData.fmcFormatSpeed(this.props.fmcService.master.fmgc.data.approachVls)} + KT
@@ -2653,12 +2671,16 @@ export class MfdFmsPerf extends FmsPage {
F - {this.props.fmcService.master.fmgc.data.approachFlapRetractionSpeed} + + {FmgcData.fmcFormatSpeed(this.props.fmcService.master.fmgc.data.approachFlapRetractionSpeed)} + KT
S - {this.props.fmcService.master.fmgc.data.approachSlatRetractionSpeed} + + {FmgcData.fmcFormatSpeed(this.props.fmcService.master.fmgc.data.approachSlatRetractionSpeed)} + KT
@@ -2667,7 +2689,9 @@ export class MfdFmsPerf extends FmsPage { - {this.props.fmcService.master.fmgc.data.approachGreenDotSpeed} + + {FmgcData.fmcFormatSpeed(this.props.fmcService.master.fmgc.data.approachGreenDotSpeed)} + KT
diff --git a/fbw-a380x/src/systems/instruments/src/MFD/shared/Adirs.ts b/fbw-a380x/src/systems/instruments/src/MFD/shared/Adirs.ts index fe2a04b023a..6f3dde15515 100644 --- a/fbw-a380x/src/systems/instruments/src/MFD/shared/Adirs.ts +++ b/fbw-a380x/src/systems/instruments/src/MFD/shared/Adirs.ts @@ -31,35 +31,52 @@ export class ADIRS { ); } + /** in degrees */ static getLatitude() { return ADIRS.getFromAnyAdiru('IR', 'LATITUDE'); } + /** in degrees */ static getLongitude() { return ADIRS.getFromAnyAdiru('IR', 'LONGITUDE'); } + /** in degrees */ static getTrueTrack() { return ADIRS.getFromAnyAdiru('IR', 'TRUE_TRACK'); } + /** in knots */ static getTrueAirspeed() { return ADIRS.getFromAnyAdiru('ADR', 'TRUE_AIRSPEED'); } + /** in knots */ static getCalibratedAirspeed() { return ADIRS.getFromAnyAdiru('ADR', 'COMPUTED_AIRSPEED'); } + /** in knots */ static getGroundSpeed() { return ADIRS.getFromAnyAdiru('IR', 'GROUND_SPEED'); } // FIXME there should be baro corrected altitude 1 (capt) and 2 (f/o) + /** in feet */ static getBaroCorrectedAltitude() { return ADIRS.getFromAnyAdiru('ADR', 'ALTITUDE'); } + /** in degrees celsius */ + static getStaticAirTemperature() { + return ADIRS.getFromAnyAdiru('ADR', 'STATIC_AIR_TEMPERATURE'); + } + + /** in hPa */ + static getCorrectedAverageStaticPressure() { + return ADIRS.getFromAnyAdiru('ADR', 'CORRECTED_AVERAGE_STATIC_PRESSURE'); + } + /** * * @param type IR or ADR diff --git a/fbw-a380x/src/systems/shared/src/OperatingSpeeds.tsx b/fbw-a380x/src/systems/shared/src/OperatingSpeeds.tsx index c8fd7d26b9a..373c06c8af5 100644 --- a/fbw-a380x/src/systems/shared/src/OperatingSpeeds.tsx +++ b/fbw-a380x/src/systems/shared/src/OperatingSpeeds.tsx @@ -11,6 +11,7 @@ import { MathUtils } from '@flybywiresim/fbw-sdk'; import { Mmo, VfeF1, VfeF1F, VfeF2, VfeF3, VfeFF, Vmcl, Vmo } from '@shared/PerformanceConstants'; import { FmgcFlightPhase } from '@shared/flightphase'; import { LerpLookupTable } from '@microsoft/msfs-sdk'; +import { ADIRS } from 'instruments/src/MFD/shared/Adirs'; export enum ApproachConf { CONF_1 = 1, @@ -408,8 +409,9 @@ function getVfeNIdx(fi: number): number { * @private */ function getVmo() { - // FIXME use ADR corrected average static pressure - return Math.min(Vmo, MathUtils.convertMachToKCas(Mmo, SimVar.GetSimVarValue('AMBIENT PRESSURE', 'millibar'))); + const adrPressure = ADIRS.getCorrectedAverageStaticPressure(); + const ambientPressure = adrPressure !== undefined ? adrPressure.valueOr(1013.25) : 1013.25; + return Math.min(Vmo, MathUtils.convertMachToKCas(Mmo, ambientPressure)); } export class A380OperatingSpeeds { diff --git a/fbw-common/src/systems/shared/src/MathUtils.ts b/fbw-common/src/systems/shared/src/MathUtils.ts index 1ecf06db53a..091fbbc14be 100644 --- a/fbw-common/src/systems/shared/src/MathUtils.ts +++ b/fbw-common/src/systems/shared/src/MathUtils.ts @@ -314,7 +314,6 @@ export class MathUtils { /** * Convert Mach to Calibrated Air Speed * @param mach Mach - * @param oat Kelvin * @param pressure current pressure hpa * @returns Calibrated Air Speed */