Skip to content

Commit

Permalink
fix(tcas): use correct altitudes (#9658)
Browse files Browse the repository at this point in the history
* fix: tcas altitude computation

* fix(tcas): use correct altitude for slant range
  • Loading branch information
tracernz authored and Saschl committed Jan 2, 2025
1 parent cdfba52 commit 62ad366
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 49 deletions.
2 changes: 2 additions & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
56 changes: 33 additions & 23 deletions fbw-a32nx/src/systems/tcas/src/components/TcasComputer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
NXDataStore,
UpdateThrottler,
LocalSimVar,
AirDataSwitchingKnob,
} from '@flybywiresim/fbw-sdk';
import { Coordinates } from 'msfs-geo';
import { TcasComponent } from '../lib/TcasComponent';
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -297,27 +294,31 @@ 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');
this.altRptgSwitchPos = SimVar.GetSimVarValue('L:A32NX_SWITCH_ATC_ALT', 'number');
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 =
(radioAlt1.isFailureWarning() || radioAlt1.isNoComputedData()) &&
!(!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');
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
NXDataStore,
LocalSimVar,
Arinc429Register,
AirDataSwitchingKnob,
} from '@flybywiresim/fbw-sdk';
import { Coordinates } from 'msfs-geo';
import {
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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 =
Expand All @@ -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');
Expand Down Expand Up @@ -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;
Expand All @@ -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();
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
23 changes: 23 additions & 0 deletions fbw-common/src/systems/shared/src/types/SwitchingKnobs.ts
Original file line number Diff line number Diff line change
@@ -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,
}
5 changes: 2 additions & 3 deletions fbw-common/src/systems/shared/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -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';

0 comments on commit 62ad366

Please sign in to comment.