Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(a380/mfd): Various Fixes in fuel & load page #9540

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
1 change: 1 addition & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
1. [A380X/FMS] Added SURV Status & Switching page with TCAS fault indication - @Frenkii (Moritz)
1. [FMS] Fix T/D not showing in selected speed - @BlueberryKing (BlueberryKing)
1. [FMS] Fix Pause at T/D not working in selected speed - @BlueberryKing (BlueberryKing)
1. [A380X/MFD] Various Fuel & Load Fixes - @BravoMike99 (bruno_pt99)

## 0.12.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -619,9 +619,9 @@ export class FlightManagementComputer implements FmcInterface {
this.acInterface.updateThrustReductionAcceleration();
}

pd.taxiFuelPilotEntry.set(null);
pd.routeReserveFuelPercentagePilotEntry.set(0.00001);
pd.routeReserveFuelWeightPilotEntry.set(0.00001);
pd.routeReserveFuelWeightPilotEntry.set(null);
pd.routeReserveFuelPercentagePilotEntry.set(0);
pd.routeReserveFuelWeightCalculated.set(0);

this.fmgc.data.climbPredictionsReferenceAutomatic.set(
this.guidanceController.verticalProfileComputationParametersObserver.get().fcuAltitude,
Expand Down
21 changes: 14 additions & 7 deletions fbw-a380x/src/systems/instruments/src/MFD/FMC/fmgc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,21 @@ export class FmgcData {
/** in percent. null if not set. */
public readonly routeReserveFuelPercentagePilotEntry = Subject.create<number | null>(null);

public readonly routeReserveFuelPercentage = this.routeReserveFuelPercentagePilotEntry.map((it) =>
it === null ? AirlineModifiableInformation.EK.rteRsv : it,
); // in percent

public readonly routeReserveFuelIsPilotEntered = MappedSubject.create(
([fuel, time]) => fuel !== null || time !== null,
this.routeReserveFuelWeightPilotEntry,
public readonly routeReserveFuelIsPilotEntered = this.routeReserveFuelWeightPilotEntry.map((it) => it !== null);

public readonly routeReserveFuelPercentage = MappedSubject.create(
([percentagePilotEntry, reservePilotEntry]) =>
reservePilotEntry !== null
? null
: percentagePilotEntry === null
? AirlineModifiableInformation.EK.rteRsv
: percentagePilotEntry,
this.routeReserveFuelPercentagePilotEntry,
this.routeReserveFuelWeightPilotEntry,
);

public readonly routeReserveFuelPercentageIsPilotEntered = this.routeReserveFuelPercentagePilotEntry.map(
(v) => v !== null,
);

public readonly paxNumber = Subject.create<number | null>(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { MfdSimvars } from 'instruments/src/MFD/shared/MFDSimvarPublisher';
import { FmgcFlightPhase } from '@shared/flightphase';
import { AirlineModifiableInformation } from '@shared/AirlineModifiableInformation';
import { Units } from '@flybywiresim/fbw-sdk';
import { getEtaFromUtcOrPresent } from '../../shared/utils';

interface MfdFmsFuelLoadProps extends AbstractMfdPageProps {}

Expand All @@ -42,9 +43,13 @@ export class MfdFmsFuelLoad extends FmsPage<MfdFmsFuelLoadProps> {

private fuelPlanningIsDisabled = Subject.create<boolean>(true);

private DestinationAlternateTimeHeader = this.activeFlightPhase.map((v) =>
v === FmgcFlightPhase.Preflight ? 'TIME' : 'UTC',
);

private tripFuelWeight = Subject.create<number | null>(null);

private tripFuelTime = Subject.create<number | null>(null);
private tripFuelTime = Subject.create('--:--');

private costIndex = Subject.create<number | null>(null);

Expand Down Expand Up @@ -101,15 +106,12 @@ export class MfdFmsFuelLoad extends FmsPage<MfdFmsFuelLoadProps> {

if (this.loadedFlightPlan.destinationAirport) {
this.destIcao.set(this.loadedFlightPlan.destinationAirport.ident);

const destPred = this.props.fmcService.master.guidanceController.vnavDriver.getDestinationPrediction();
if (destPred) {
const utcTime = SimVar.GetGlobalVarValue('ZULU TIME', 'seconds');
const eta = new Date((utcTime + destPred.secondsFromPresent) * 1000);
this.destEta.set(
`${eta.getHours().toString().padStart(2, '0')}:${eta.getMinutes().toString().padStart(2, '0')}`,
);
}

// TODO Should display ETA if EET present
this.destEta.set(
getEtaFromUtcOrPresent(destPred?.secondsFromPresent, this.activeFlightPhase.get() == FmgcFlightPhase.Preflight),
);
const destEfob = this.props.fmcService.master.fmgc.getDestEFOB(true);
this.destEfob.set(destEfob !== null ? destEfob.toFixed(1) : '---.-');
this.destEfobBelowMin.set(
Expand Down Expand Up @@ -163,21 +165,25 @@ export class MfdFmsFuelLoad extends FmsPage<MfdFmsFuelLoadProps> {
this.fuelOnBoard.set(this.props.fmcService.master.fmgc.getFOB());
}

const destPred = this.props.fmcService.master.guidanceController.vnavDriver.getDestinationPrediction();
if (this.activeFlightPhase.get() === FmgcFlightPhase.Preflight) {
const destPred = this.props.fmcService.master.guidanceController.vnavDriver.getDestinationPrediction();
// EXTRA = BLOCK - TAXI - TRIP - MIN FUEL DEST - RTE RSV
const fob = this.props.fmcService.master.fmgc.getFOB() * 1_000;
const tripFuel =
fob - (destPred?.estimatedFuelOnBoard ? Units.poundToKilogram(destPred?.estimatedFuelOnBoard) : fob);
this.tripFuelWeight.set(tripFuel);
this.tripFuelTime.set(getEtaFromUtcOrPresent(destPred?.secondsFromPresent, true));

// Calculate Rte Rsv fuel for 5.0% reserve
// Calculate Rte Rsv fuel if not manually entered
const pilotEnteredReserveFuel = this.props.fmcService.master.fmgc.data.routeReserveFuelIsPilotEntered.get();
this.props.fmcService.master.fmgc.data.routeReserveFuelWeightCalculated.set(
tripFuel ? tripFuel * 0.05 : null,
);
this.props.fmcService.master.fmgc.data.routeReserveFuelWeightPilotEntry.set(
tripFuel ? tripFuel * 0.05 : null,
!pilotEnteredReserveFuel && tripFuel
? (tripFuel * this.props.fmcService.master.fmgc.data.routeReserveFuelPercentage.get()!) / 100
: null,
);
if (!pilotEnteredReserveFuel) {
this.props.fmcService.master.fmgc.data.routeReserveFuelWeightPilotEntry.set(null);
}

const block = this.props.fmcService.master.fmgc.data.blockFuel.get() ?? 0;
this.extraFuelWeight.set(
Expand All @@ -188,12 +194,16 @@ export class MfdFmsFuelLoad extends FmsPage<MfdFmsFuelLoadProps> {
(this.props.fmcService.master.fmgc.data.routeReserveFuelWeight.get() ?? 0),
);
} else {
// EXTRA = FOB - TRIP - MIN FUEL DEST
this.extraFuelWeight.set(
(this.fuelOnBoard.get() ?? 0) -
((this.tripFuelWeight.get() ?? 0) -
(this.props.fmcService.master.fmgc.data.minimumFuelAtDestination.get() ?? 0)),
);
if (destPred) {
const fobKg = this.props.fmcService.master.fmgc.getFOB() * 1000;
const destFuelKg = Units.poundToKilogram(destPred?.estimatedFuelOnBoard);
const remainingTripFuel = fobKg - destFuelKg;
this.tripFuelWeight.set(remainingTripFuel);
this.tripFuelTime.set(getEtaFromUtcOrPresent(destPred.secondsFromPresent, true));
this.extraFuelWeight.set(
destFuelKg - (this.props.fmcService.master.fmgc.data.minimumFuelAtDestination.get() ?? 0),
);
}
}

this.updateDestAndAltnPredictions();
Expand Down Expand Up @@ -231,7 +241,7 @@ export class MfdFmsFuelLoad extends FmsPage<MfdFmsFuelLoadProps> {
</div>
<div class="mfd-label-value-container">
<span class="mfd-label mfd-spacing-right">FOB</span>
<span class="mfd-value">{this.fuelOnBoard.map((it) => (it ? (it / 1000).toFixed(1) : '---.-'))}</span>
<span class="mfd-value">{this.fuelOnBoard.map((it) => (it ? it.toFixed(1) : '---.-'))}</span>
<span class="mfd-label-unit mfd-unit-trailing">T</span>
</div>
</div>
Expand Down Expand Up @@ -337,7 +347,7 @@ export class MfdFmsFuelLoad extends FmsPage<MfdFmsFuelLoadProps> {
<span class="mfd-label-unit mfd-unit-trailing">T</span>
</div>
<div style="display: flex; justify-content: center; margin-bottom: 20px;">
<span class="mfd-value">{this.tripFuelTime.map((it) => new TimeHHMMFormat().format(it ?? 0))}</span>
<span class="mfd-value">{this.tripFuelTime}</span>
</div>
<div class="mfd-label mfd-spacing-right middleGrid">CI</div>
<div style="margin-bottom: 20px;">
Expand All @@ -359,7 +369,7 @@ export class MfdFmsFuelLoad extends FmsPage<MfdFmsFuelLoadProps> {
<div class="mfd-label mfd-spacing-right middleGrid">RTE RSV</div>
<div style="margin-bottom: 20px;">
<InputField<number>
disabled={Subject.create(true)}
disabled={this.activeFlightPhase.map((it) => it >= FmgcFlightPhase.Takeoff)}
dataEntryFormat={
new WeightFormat(
Subject.create(AirlineModifiableInformation.EK.rsvMin),
Expand All @@ -371,7 +381,6 @@ export class MfdFmsFuelLoad extends FmsPage<MfdFmsFuelLoadProps> {
}
enteredByPilot={this.props.fmcService.master.fmgc.data.routeReserveFuelIsPilotEntered}
value={this.props.fmcService.master.fmgc.data.routeReserveFuelWeight}
inactive={this.activeFlightPhase.map((it) => it >= FmgcFlightPhase.Takeoff)}
alignText="flex-end"
containerStyle="width: 150px;"
errorHandler={(e) => this.props.fmcService.master?.showFmsErrorMessage(e)}
Expand All @@ -381,14 +390,14 @@ export class MfdFmsFuelLoad extends FmsPage<MfdFmsFuelLoadProps> {
</div>
<div style="margin-bottom: 20px; margin-left: 5px">
<InputField<number>
disabled={Subject.create(true)}
disabled={this.activeFlightPhase.map((it) => it >= FmgcFlightPhase.Takeoff)}
dataEntryFormat={new PercentageFormat(Subject.create(0), Subject.create(maxRteRsvFuelPerc))}
dataHandlerDuringValidation={async (v) =>
this.props.fmcService.master?.fmgc.data.routeReserveFuelPercentagePilotEntry.set(v)
}
enteredByPilot={this.props.fmcService.master.fmgc.data.routeReserveFuelIsPilotEntered}
dataHandlerDuringValidation={async (v) => {
this.props.fmcService.master?.fmgc.data.routeReserveFuelWeightPilotEntry.set(null);
this.props.fmcService.master?.fmgc.data.routeReserveFuelPercentagePilotEntry.set(v);
}}
enteredByPilot={this.props.fmcService.master.fmgc.data.routeReserveFuelPercentageIsPilotEntered}
value={this.props.fmcService.master.fmgc.data.routeReserveFuelPercentage}
inactive={this.activeFlightPhase.map((it) => it >= FmgcFlightPhase.Takeoff)}
alignText="center"
containerStyle="width: 120px;"
errorHandler={(e) => this.props.fmcService.master?.showFmsErrorMessage(e)}
Expand Down Expand Up @@ -476,7 +485,9 @@ export class MfdFmsFuelLoad extends FmsPage<MfdFmsFuelLoadProps> {
<div style="display: grid; grid-template-columns: auto auto auto auto;">
<div class="mfd-fms-fuel-load-dest-grid-top-cell" />
<div class="mfd-fms-fuel-load-dest-grid-top-cell" />
<div class="mfd-label mfd-fms-fuel-load-dest-grid-top-cell">UTC</div>
<div class="mfd-label mfd-fms-fuel-load-dest-grid-top-cell">
{this.DestinationAlternateTimeHeader}
</div>
<div class="mfd-label mfd-fms-fuel-load-dest-grid-top-cell">EFOB</div>
<div class="mfd-label mfd-fms-fuel-load-dest-grid-middle-cell">DEST</div>
<div class="mfd-label bigger green mfd-fms-fuel-load-dest-grid-middle-cell">{this.destIcao}</div>
Expand Down
7 changes: 5 additions & 2 deletions fbw-a380x/src/systems/instruments/src/MFD/shared/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@

import { Approach, ApproachType } from '@flybywiresim/fbw-sdk';

export function getEtaFromUtcOrPresent(seconds: number | null, fromPresent: boolean) {
if (seconds === null) {
export function getEtaFromUtcOrPresent(seconds: number | null | undefined, fromPresent: boolean) {
if (seconds === null || seconds === undefined) {
BravoMike99 marked this conversation as resolved.
Show resolved Hide resolved
return '--:--';
} else if (Number.isNaN(seconds)) {
console.error('[MFD] NaN input received for eta format');
return '--:--';
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ export const AirlineModifiableInformation: AmiCollection = {
perfFactor: 0, // %
idleFactor: 0, // %
perfCode: 'ARM',
taxiFuel: 200, // kg
taxiFuel: 1500, // kg
rteRsv: 5, // %
rsvMin: 0, // kg
rsvMax: 10_000, // kg
rsvMax: 50_000, // kg
rsvInflt: true, // YES / NO
rsvAltn: false, // YES / NO
finalTg: 30, // minutes
Expand Down