From 62ad366312fde52a2868014a999012ea566a1d50 Mon Sep 17 00:00:00 2001 From: Michael Corcoran Date: Wed, 1 Jan 2025 23:05:53 +1300 Subject: [PATCH] fix(tcas): use correct altitudes (#9658) * fix: tcas altitude computation * fix(tcas): use correct altitude for slant range --- .github/CHANGELOG.md | 2 + .../tcas/src/components/TcasComputer.ts | 56 +++++++++++-------- .../tcas/components/LegacyTcasComputer.ts | 56 +++++++++++-------- .../shared/src/types/SwitchingKnobs.ts | 23 ++++++++ .../src/systems/shared/src/types/index.ts | 5 +- 5 files changed, 93 insertions(+), 49 deletions(-) create mode 100644 fbw-common/src/systems/shared/src/types/SwitchingKnobs.ts diff --git a/.github/CHANGELOG.md b/.github/CHANGELOG.md index e6fcd8ae2f6..ed5143b4776 100644 --- a/.github/CHANGELOG.md +++ b/.github/CHANGELOG.md @@ -107,6 +107,8 @@ 1. [A380X/ENGINES] Adjust climb thrust to be more accurate - @BlueberryKing (BlueberryKing) 1. [A380X/EWD] Show THR limit in EWD instead of N1 - @flogross89 (floridude) 1. [A380X/FLIGHT MODEL] Fix pitchup and unrecoverable stall - - @donstim (donbikes#4084) +1. [ATC/TCAS] Fixed TCAS failure on baro corrected altitude going invalid - @tracernz (Mike) +1. [ATC/TCAS] Fixed TCAS slant range computation - @tracernz (Mike) ## 0.12.0 diff --git a/fbw-a32nx/src/systems/tcas/src/components/TcasComputer.ts b/fbw-a32nx/src/systems/tcas/src/components/TcasComputer.ts index 5bf1c332c77..d2f3c0d3fb2 100644 --- a/fbw-a32nx/src/systems/tcas/src/components/TcasComputer.ts +++ b/fbw-a32nx/src/systems/tcas/src/components/TcasComputer.ts @@ -14,6 +14,7 @@ import { NXDataStore, UpdateThrottler, LocalSimVar, + AirDataSwitchingKnob, } from '@flybywiresim/fbw-sdk'; import { Coordinates } from 'msfs-geo'; import { TcasComponent } from '../lib/TcasComponent'; @@ -221,11 +222,7 @@ export class TcasComputer implements TcasComponent { private ppos: LatLongData; // Plane PPOS - private baroCorrectedAltitude1: Arinc429Word | null; // ADR1/2 Altitude - - private adr3BaroCorrectedAltitude1: Arinc429Word | null; // ADR3 Altitude - - private pressureAlt: number | null; // Pressure Altitude + private pressureAlt: Arinc429Word | null; // Pressure Altitude private planeAlt: number | null; // Plane Altitude @@ -297,6 +294,7 @@ export class TcasComputer implements TcasComponent { this.verticalSpeed = SimVar.GetSimVarValue('VERTICAL SPEED', 'feet per minute'); this.ppos.lat = SimVar.GetSimVarValue('PLANE LATITUDE', 'degree latitude'); this.ppos.long = SimVar.GetSimVarValue('PLANE LONGITUDE', 'degree longitude'); + this.planeAlt = SimVar.GetSimVarValue('PLANE ALTITUDE', 'feet'); this.tcasPower = !!SimVar.GetSimVarValue('L:A32NX_ELEC_DC_1_BUS_IS_POWERED', 'boolean'); this.tcasSwitchPos = SimVar.GetSimVarValue('L:A32NX_SWITCH_TCAS_Position', 'number'); @@ -304,9 +302,16 @@ export class TcasComputer implements TcasComponent { this.tcasThreat = SimVar.GetSimVarValue('L:A32NX_SWITCH_TCAS_Traffic_Position', 'number'); this.xpdrStatus = SimVar.GetSimVarValue('TRANSPONDER STATE:1', 'number'); this.activeXpdr = SimVar.GetSimVarValue('L:A32NX_TRANSPONDER_SYSTEM', 'number'); - // workaround for altitude issues due to MSFS bug, needs to be changed to PRESSURE ALTITUDE again when solved - this.pressureAlt = SimVar.GetSimVarValue('INDICATED ALTITUDE:3', 'feet'); - this.planeAlt = SimVar.GetSimVarValue('PLANE ALTITUDE', 'feet'); + + const alternateAirDataSourceSelect = + SimVar.GetSimVarValue('L:A32NX_AIR_DATA_SWITCHING_KNOB', 'enum') === + (this.activeXpdr === 0 ? AirDataSwitchingKnob.Capt : AirDataSwitchingKnob.Fo); + this.pressureAlt = Arinc429Word.fromSimVarValue( + alternateAirDataSourceSelect + ? `L:A32NX_ADIRS_ADR_3_ALTITUDE` + : `L:A32NX_ADIRS_ADR_${this.activeXpdr + 1}_ALTITUDE`, + ); + const radioAlt1 = Arinc429Word.fromSimVarValue('L:A32NX_RA_1_RADIO_ALTITUDE'); const radioAlt2 = Arinc429Word.fromSimVarValue('L:A32NX_RA_2_RADIO_ALTITUDE'); this.radioAlt = @@ -314,10 +319,6 @@ export class TcasComputer implements TcasComponent { !(!radioAlt1.isNoComputedData() && radioAlt2.isFailureWarning()) ? radioAlt2 : radioAlt1; - this.baroCorrectedAltitude1 = Arinc429Word.fromSimVarValue( - `L:A32NX_ADIRS_ADR_${this.activeXpdr + 1}_BARO_CORRECTED_ALTITUDE_1`, - ); - this.adr3BaroCorrectedAltitude1 = Arinc429Word.fromSimVarValue('L:A32NX_ADIRS_ADR_3_BARO_CORRECTED_ALTITUDE_1'); this.trueHeading = SimVar.GetSimVarValue('PLANE HEADING DEGREES TRUE', 'degrees'); this.isSlewActive = !!SimVar.GetSimVarValue('IS SLEW ACTIVE', 'boolean'); this.simRate = SimVar.GetGlobalVarValue('SIMULATION RATE', 'number'); @@ -355,7 +356,7 @@ export class TcasComputer implements TcasComponent { this.inhibitions = Inhibit.ALL_DESC_RA; } else if (!this.radioAlt.isNoComputedData() && this.radioAlt.value < 1550) { this.inhibitions = Inhibit.ALL_INCR_DESC_RA; - } else if (this.pressureAlt > 39000) { + } else if (this.pressureAlt.value > 39000) { this.inhibitions = Inhibit.ALL_CLIMB_RA; } else { this.inhibitions = Inhibit.NONE; @@ -393,12 +394,9 @@ export class TcasComputer implements TcasComponent { // Amber TCAS warning on fault (and on PFD) - 34-43-00:A24/34-43-010 if ( - !this.baroCorrectedAltitude1 || - !this.adr3BaroCorrectedAltitude1 || - !this.baroCorrectedAltitude1.isNormalOperation() || - !this.adr3BaroCorrectedAltitude1.isNormalOperation() || + !this.pressureAlt || + (!this.pressureAlt.isNormalOperation() && !this.pressureAlt.isFunctionalTest()) || this.radioAlt.isFailureWarning() || - this.baroCorrectedAltitude1.value - this.adr3BaroCorrectedAltitude1.value > 300 || !this.tcasPower ) { this.tcasFault.setVar(true); @@ -417,13 +415,25 @@ export class TcasComputer implements TcasComponent { this.radioAlt.value <= TCAS.SENSE[3][Limits.MAX] ) { this.sensitivity.setVar(3); - } else if (this.pressureAlt > TCAS.SENSE[4][Limits.MIN] && this.pressureAlt <= TCAS.SENSE[4][Limits.MAX]) { + } else if ( + this.pressureAlt.value > TCAS.SENSE[4][Limits.MIN] && + this.pressureAlt.value <= TCAS.SENSE[4][Limits.MAX] + ) { this.sensitivity.setVar(4); - } else if (this.pressureAlt > TCAS.SENSE[5][Limits.MIN] && this.pressureAlt <= TCAS.SENSE[5][Limits.MAX]) { + } else if ( + this.pressureAlt.value > TCAS.SENSE[5][Limits.MIN] && + this.pressureAlt.value <= TCAS.SENSE[5][Limits.MAX] + ) { this.sensitivity.setVar(5); - } else if (this.pressureAlt > TCAS.SENSE[6][Limits.MIN] && this.pressureAlt <= TCAS.SENSE[6][Limits.MAX]) { + } else if ( + this.pressureAlt.value > TCAS.SENSE[6][Limits.MIN] && + this.pressureAlt.value <= TCAS.SENSE[6][Limits.MAX] + ) { this.sensitivity.setVar(6); - } else if (this.pressureAlt > TCAS.SENSE[7][Limits.MIN] && this.pressureAlt <= TCAS.SENSE[7][Limits.MAX]) { + } else if ( + this.pressureAlt.value > TCAS.SENSE[7][Limits.MIN] && + this.pressureAlt.value <= TCAS.SENSE[7][Limits.MAX] + ) { this.sensitivity.setVar(7); } else { this.sensitivity.setVar(8); @@ -479,7 +489,7 @@ export class TcasComputer implements TcasComponent { traffic.alt, this.ppos.lat, this.ppos.long, - this.pressureAlt, + this.planeAlt, ); const newClosureRate = ((traffic.slantDistance - newSlantDist) / (_deltaTime / 1000)) * 3600; // knots = nautical miles per hour traffic.closureAccel = (newClosureRate - traffic.closureRate) / (_deltaTime / 1000); diff --git a/fbw-a380x/src/systems/systems-host/systems/tcas/components/LegacyTcasComputer.ts b/fbw-a380x/src/systems/systems-host/systems/tcas/components/LegacyTcasComputer.ts index 48758408c74..037adf83ab3 100644 --- a/fbw-a380x/src/systems/systems-host/systems/tcas/components/LegacyTcasComputer.ts +++ b/fbw-a380x/src/systems/systems-host/systems/tcas/components/LegacyTcasComputer.ts @@ -14,6 +14,7 @@ import { NXDataStore, LocalSimVar, Arinc429Register, + AirDataSwitchingKnob, } from '@flybywiresim/fbw-sdk'; import { Coordinates } from 'msfs-geo'; import { @@ -215,11 +216,7 @@ export class LegacyTcasComputer implements Instrument { private ppos: LatLongData; // Plane PPOS - private baroCorrectedAltitude1: Arinc429Word | null; // ADR1/2 Altitude - - private adr3BaroCorrectedAltitude1: Arinc429Word | null; // ADR3 Altitude - - private pressureAlt: number | null; // Pressure Altitude + private pressureAlt: Arinc429Word | null; // Pressure Altitude private planeAlt: number | null; // Plane Altitude @@ -318,15 +315,23 @@ export class LegacyTcasComputer implements Instrument { this.verticalSpeed = SimVar.GetSimVarValue('VERTICAL SPEED', 'feet per minute'); this.ppos.lat = SimVar.GetSimVarValue('PLANE LATITUDE', 'degree latitude'); this.ppos.long = SimVar.GetSimVarValue('PLANE LONGITUDE', 'degree longitude'); + this.planeAlt = SimVar.GetSimVarValue('PLANE ALTITUDE', 'feet'); this.tcasPower = SimVar.GetSimVarValue('L:A32NX_ELEC_AC_ESS_BUS_IS_POWERED', 'boolean') || SimVar.GetSimVarValue('L:A32NX_ELEC_AC_2_BUS_IS_POWERED', 'boolean'); this.activeXpdr = SimVar.GetSimVarValue('L:A32NX_TRANSPONDER_SYSTEM', 'number'); this.xpdrStatus = SimVar.GetSimVarValue(`TRANSPONDER STATE:${this.activeXpdr + 1}`, 'number'); - // workaround for altitude issues due to MSFS bug, needs to be changed to PRESSURE ALTITUDE again when solved - this.pressureAlt = SimVar.GetSimVarValue('INDICATED ALTITUDE:3', 'feet'); - this.planeAlt = SimVar.GetSimVarValue('PLANE ALTITUDE', 'feet'); + + const alternateAirDataSourceSelect = + SimVar.GetSimVarValue('L:A32NX_AIR_DATA_SWITCHING_KNOB', 'enum') === + (this.activeXpdr === 0 ? AirDataSwitchingKnob.Capt : AirDataSwitchingKnob.Fo); + this.pressureAlt = Arinc429Word.fromSimVarValue( + alternateAirDataSourceSelect + ? `L:A32NX_ADIRS_ADR_3_ALTITUDE` + : `L:A32NX_ADIRS_ADR_${this.activeXpdr + 1}_ALTITUDE`, + ); + const radioAlt1 = Arinc429Word.fromSimVarValue('L:A32NX_RA_1_RADIO_ALTITUDE'); const radioAlt2 = Arinc429Word.fromSimVarValue('L:A32NX_RA_2_RADIO_ALTITUDE'); this.radioAlt = @@ -335,12 +340,8 @@ export class LegacyTcasComputer implements Instrument { ? radioAlt2 : radioAlt1; - this.baroCorrectedAltitude1 = Arinc429Word.fromSimVarValue( - `L:A32NX_ADIRS_ADR_${this.activeXpdr + 1}_BARO_CORRECTED_ALTITUDE_1`, - ); const irSwitchingKnob = SimVar.GetSimVarValue('L:A32NX_ATT_HDG_SWITCHING_KNOB', 'enum'); const irToUse = irSwitchingKnob === 1 ? this.activeXpdr + 1 : 3; - this.adr3BaroCorrectedAltitude1 = Arinc429Word.fromSimVarValue('L:A32NX_ADIRS_ADR_3_BARO_CORRECTED_ALTITUDE_1'); this.irTrueheading.setFromSimVar(`L:A32NX_ADIRS_IR_${irToUse}_TRUE_HEADING`); this.isSlewActive = !!SimVar.GetSimVarValue('IS SLEW ACTIVE', 'boolean'); this.simRate = SimVar.GetGlobalVarValue('SIMULATION RATE', 'number'); @@ -381,7 +382,7 @@ export class LegacyTcasComputer implements Instrument { this.inhibitions = Inhibit.ALL_DESC_RA; } else if (!this.radioAlt.isNoComputedData() && this.radioAlt.value < 1550) { this.inhibitions = Inhibit.ALL_INCR_DESC_RA; - } else if (this.pressureAlt > 39000) { + } else if (this.pressureAlt.value > 39000) { this.inhibitions = Inhibit.ALL_CLIMB_RA; } else { this.inhibitions = Inhibit.NONE; @@ -397,12 +398,9 @@ export class LegacyTcasComputer implements Instrument { !this.irTrueheading || !this.irTrueheading.isNormalOperation() || this.irTrueheading.isNoComputedData() || - !this.baroCorrectedAltitude1 || - !this.adr3BaroCorrectedAltitude1 || - !this.baroCorrectedAltitude1.isNormalOperation() || - !this.adr3BaroCorrectedAltitude1.isNormalOperation() || + !this.pressureAlt || + (!this.pressureAlt.isNormalOperation() && !this.pressureAlt.isFunctionalTest()) || this.radioAlt.isFailureWarning() || - this.baroCorrectedAltitude1.value - this.adr3BaroCorrectedAltitude1.value > 300 || !this.tcasPower ) { this.resetDisplay(); @@ -448,13 +446,25 @@ export class LegacyTcasComputer implements Instrument { this.radioAlt.value <= TCAS.SENSE[3][Limits.MAX] ) { this.sensitivity.setVar(3); - } else if (this.pressureAlt > TCAS.SENSE[4][Limits.MIN] && this.pressureAlt <= TCAS.SENSE[4][Limits.MAX]) { + } else if ( + this.pressureAlt.value > TCAS.SENSE[4][Limits.MIN] && + this.pressureAlt.value <= TCAS.SENSE[4][Limits.MAX] + ) { this.sensitivity.setVar(4); - } else if (this.pressureAlt > TCAS.SENSE[5][Limits.MIN] && this.pressureAlt <= TCAS.SENSE[5][Limits.MAX]) { + } else if ( + this.pressureAlt.value > TCAS.SENSE[5][Limits.MIN] && + this.pressureAlt.value <= TCAS.SENSE[5][Limits.MAX] + ) { this.sensitivity.setVar(5); - } else if (this.pressureAlt > TCAS.SENSE[6][Limits.MIN] && this.pressureAlt <= TCAS.SENSE[6][Limits.MAX]) { + } else if ( + this.pressureAlt.value > TCAS.SENSE[6][Limits.MIN] && + this.pressureAlt.value <= TCAS.SENSE[6][Limits.MAX] + ) { this.sensitivity.setVar(6); - } else if (this.pressureAlt > TCAS.SENSE[7][Limits.MIN] && this.pressureAlt <= TCAS.SENSE[7][Limits.MAX]) { + } else if ( + this.pressureAlt.value > TCAS.SENSE[7][Limits.MIN] && + this.pressureAlt.value <= TCAS.SENSE[7][Limits.MAX] + ) { this.sensitivity.setVar(7); } else { this.sensitivity.setVar(8); @@ -510,7 +520,7 @@ export class LegacyTcasComputer implements Instrument { traffic.alt, this.ppos.lat, this.ppos.long, - this.pressureAlt, + this.planeAlt, ); const newClosureRate = ((traffic.slantDistance - newSlantDist) / (_deltaTime / 1000)) * 3600; // knots = nautical miles per hour traffic.closureAccel = (newClosureRate - traffic.closureRate) / (_deltaTime / 1000); diff --git a/fbw-common/src/systems/shared/src/types/SwitchingKnobs.ts b/fbw-common/src/systems/shared/src/types/SwitchingKnobs.ts new file mode 100644 index 00000000000..664e83e4462 --- /dev/null +++ b/fbw-common/src/systems/shared/src/types/SwitchingKnobs.ts @@ -0,0 +1,23 @@ +export enum DmcSwitchingKnob { + Capt, + Norm, + Fo, +} + +export enum EcamNdSwitchingKnob { + Capt, + Norm, + Fo, +} + +export enum AttHdgSwitchingKnob { + Capt, + Norm, + Fo, +} + +export enum AirDataSwitchingKnob { + Capt, + Norm, + Fo, +} diff --git a/fbw-common/src/systems/shared/src/types/index.ts b/fbw-common/src/systems/shared/src/types/index.ts index bea48047998..f4975ddd481 100644 --- a/fbw-common/src/systems/shared/src/types/index.ts +++ b/fbw-common/src/systems/shared/src/types/index.ts @@ -1,6 +1,5 @@ // Copyright (c) 2024 FlyByWire Simulations // SPDX-License-Identifier: GPL-3.0 -import { GenericAdirsEvents } from './GenericAdirsEvents'; - -export { GenericAdirsEvents }; +export * from './GenericAdirsEvents'; +export * from './SwitchingKnobs';