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(fms): move speed limit to performance data #9033

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ class CDUVerticalRevisionPage {

/** @type {BaseFlightPlan} */
const targetPlan = mcdu.flightPlan(forPlan, inAlternate);
// Use performance data of primary for waypoints in alternaten
const performanceData = mcdu.flightPlan(forPlan, false).performanceData;
const mainTargetPlan = mcdu.flightPlan(forPlan, false);
// Use performance data of primary for waypoints in alternate
const performanceData = mainTargetPlan.performanceData;

const confirmConstraint = Number.isFinite(confirmSpeed) || Number.isFinite(confirmAlt);
const constraintType = CDUVerticalRevisionPage.constraintType(mcdu, wpIndex, forPlan, inAlternate);
Expand All @@ -41,31 +42,34 @@ class CDUVerticalRevisionPage {
}
}

let coordinates = "---";
if (waypoint.isXF()) {
coordinates = CDUPilotsWaypoint.formatLatLong(waypoint.terminationWaypoint().location);
}

const showSpeedLim = mcdu._fuelPredDone || isOrigin || isDestination || constraintType !== WaypointConstraintType.Unknown;
// the conditions other than isDestination are a workaround for no ToC
const showDesSpeedLim = showSpeedLim && (isDestination ||
constraintType === WaypointConstraintType.DES ||
(mcdu.flightPhaseManager.phase > FmgcFlightPhases.CRUISE &&
mcdu.flightPhaseManager.phase < FmgcFlightPhases.GOAROUND));

const climbSpeedLimitSpeed = inAlternate ? performanceData.alternateClimbSpeedLimitSpeed : performanceData.climbSpeedLimitSpeed;
const climbSpeedLimitAltitude = inAlternate ? performanceData.alternateClimbSpeedLimitAltitude : performanceData.climbSpeedLimitAltitude;
const isClimbSpeedLimitPilotEntered = inAlternate ? performanceData.isAlternateClimbSpeedLimitPilotEntered : performanceData.isClimbSpeedLimitPilotEntered;

const descentSpeedLimitSpeed = inAlternate ? performanceData.alternateDescentSpeedLimitSpeed : performanceData.descentSpeedLimitSpeed;
const descentSpeedLimitAltitude = inAlternate ? performanceData.alternateDescentSpeedLimitAltitude : performanceData.descentSpeedLimitAltitude;
const isDescentSpeedLimitPilotEntered = inAlternate ? performanceData.isAlternateDescentSpeedLimitPilotEntered : performanceData.isDescentSpeedLimitPilotEntered;

let speedLimitTitle = "";
let speedLimitCell = "";
if (showDesSpeedLim) {
speedLimitTitle = "\xa0DES SPD LIM";
if (mcdu.descentSpeedLimit !== undefined) {
speedLimitCell = `{magenta}{${mcdu.descentSpeedLimitPilot ? 'big' : 'small'}}${mcdu.descentSpeedLimit.toFixed(0).padStart(3, "0")}/${this.formatFl(mcdu.descentSpeedLimitAlt, performanceData.transitionLevel * 100)}{end}{end}`;
if (descentSpeedLimitSpeed !== null) {
speedLimitCell = `{magenta}{${isDescentSpeedLimitPilotEntered ? 'big' : 'small'}}${descentSpeedLimitSpeed.toFixed(0).padStart(3, "0")}/${this.formatFl(descentSpeedLimitAltitude, performanceData.transitionLevel * 100)}{end}{end}`;
} else {
speedLimitCell = "{cyan}*[ ]/[ ]{end}";
}
} else if (showSpeedLim) {
speedLimitTitle = "\xa0CLB SPD LIM";
if (mcdu.climbSpeedLimit !== undefined) {
speedLimitCell = `{magenta}{${mcdu.climbSpeedLimitPilot ? 'big' : 'small'}}${mcdu.climbSpeedLimit.toFixed(0).padStart(3, "0")}/${this.formatFl(mcdu.climbSpeedLimitAlt, performanceData.transitionAltitude)}{end}{end}`;
if (climbSpeedLimitSpeed !== null) {
speedLimitCell = `{magenta}{${isClimbSpeedLimitPilotEntered ? 'big' : 'small'}}${climbSpeedLimitSpeed.toFixed(0).padStart(3, "0")}/${this.formatFl(climbSpeedLimitAltitude, performanceData.transitionAltitude)}{end}{end}`;
} else {
speedLimitCell = "{cyan}*[ ]/[ ]{end}";
}
Expand Down Expand Up @@ -162,23 +166,13 @@ class CDUVerticalRevisionPage {

if (value === FMCMainDisplay.clrValue) {
if (showDesSpeedLim) {
if (mcdu.descentSpeedLimitPilot) {
mcdu.descentSpeedLimit = 250;
mcdu.descentSpeedLimitAlt = 10000;
} else {
mcdu.descentSpeedLimit = undefined;
mcdu.descentSpeedLimitAlt = undefined;
}
mcdu.descentSpeedLimitPilot = false;
mainTargetPlan.setPerformanceData(inAlternate ? 'alternateDescentSpeedLimitSpeed' : 'descentSpeedLimitSpeed', null);
mainTargetPlan.setPerformanceData(inAlternate ? 'alternateDescentSpeedLimitAltitude' : 'descentSpeedLimitAltitude', null);
mainTargetPlan.setPerformanceData(inAlternate ? 'isAlternateDescentSpeedLimitPilotEntered' : 'isDescentSpeedLimitPilotEntered', false);
} else {
if (mcdu.climbSpeedLimitPilot) {
mcdu.climbSpeedLimit = 250;
mcdu.climbSpeedLimitAlt = 10000;
} else {
mcdu.climbSpeedLimit = undefined;
mcdu.climbSpeedLimitAlt = undefined;
}
mcdu.climbSpeedLimitPilot = false;
mainTargetPlan.setPerformanceData(inAlternate ? 'alternateClimbSpeedLimitSpeed' : 'climbSpeedLimitSpeed', null);
mainTargetPlan.setPerformanceData(inAlternate ? 'alternateClimbSpeedLimitAltitude' : 'climbSpeedLimitAltitude', null);
mainTargetPlan.setPerformanceData(inAlternate ? 'isAlternateClimbSpeedLimitPilotEntered' : 'isClimbSpeedLimitPilotEntered', false);
}
CDUVerticalRevisionPage.ShowPage(mcdu, waypoint, wpIndex, verticalWaypoint, undefined, undefined, undefined, forPlan, inAlternate);
return;
Expand All @@ -203,13 +197,13 @@ class CDUVerticalRevisionPage {
alt = Math.round(alt / 10) * 10;

if (showDesSpeedLim) {
mcdu.descentSpeedLimit = speed;
mcdu.descentSpeedLimitAlt = alt;
mcdu.descentSpeedLimitPilot = true;
mainTargetPlan.setPerformanceData(inAlternate ? 'alternateDescentSpeedLimitSpeed' : 'descentSpeedLimitSpeed', speed);
mainTargetPlan.setPerformanceData(inAlternate ? 'alternateDescentSpeedLimitAltitude' : 'descentSpeedLimitAltitude', alt);
mainTargetPlan.setPerformanceData(inAlternate ? 'isAlternateDescentSpeedLimitPilotEntered' : 'isDescentSpeedLimitPilotEntered', true);
} else {
mcdu.climbSpeedLimit = speed;
mcdu.climbSpeedLimitAlt = alt;
mcdu.climbSpeedLimitPilot = true;
mainTargetPlan.setPerformanceData(inAlternate ? 'alternateClimbSpeedLimitSpeed' : 'climbSpeedLimitSpeed', speed);
mainTargetPlan.setPerformanceData(inAlternate ? 'alternateClimbSpeedLimitAltitude' : 'climbSpeedLimitAltitude', alt);
mainTargetPlan.setPerformanceData(inAlternate ? 'isAlternateClimbSpeedLimitPilotEntered' : 'isClimbSpeedLimitPilotEntered', true);
}

CDUVerticalRevisionPage.ShowPage(mcdu, waypoint, wpIndex, verticalWaypoint, undefined, undefined, undefined, forPlan, inAlternate);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,6 @@ class FMCMainDisplay extends BaseAirliners {
this.preSelectedCrzSpeed = undefined;
this.managedSpeedTarget = undefined;
this.managedSpeedTargetIsMach = undefined;
this.climbSpeedLimit = undefined;
this.climbSpeedLimitAlt = undefined;
this.climbSpeedLimitPilot = undefined;
this.descentSpeedLimit = undefined;
this.descentSpeedLimitAlt = undefined;
this.descentSpeedLimitPilot = undefined;
this.managedSpeedClimb = undefined;
this.managedSpeedClimbIsPilotEntered = undefined;
this.managedSpeedClimbMach = undefined;
Expand Down Expand Up @@ -450,12 +444,6 @@ class FMCMainDisplay extends BaseAirliners {
this.preSelectedCrzSpeed = undefined;
this.managedSpeedTarget = NaN;
this.managedSpeedTargetIsMach = false;
this.climbSpeedLimit = 250;
this.climbSpeedLimitAlt = 10000;
this.climbSpeedLimitPilot = false;
this.descentSpeedLimit = 250;
this.descentSpeedLimitAlt = 10000;
this.descentSpeedLimitPilot = false;
this.managedSpeedClimb = 290;
this.managedSpeedClimbIsPilotEntered = false;
this.managedSpeedClimbMach = 0.78;
Expand Down Expand Up @@ -947,11 +935,11 @@ class FMCMainDisplay extends BaseAirliners {

// apply speed limit/alt
if (this.flightPhaseManager.phase <= FmgcFlightPhases.CRUISE) {
if (this.climbSpeedLimit !== undefined && alt <= this.climbSpeedLimitAlt) {
if (this.climbSpeedLimit !== null && alt <= this.climbSpeedLimitAlt) {
kcas = Math.min(this.climbSpeedLimit, kcas);
}
} else if (this.flightPhaseManager.phase < FmgcFlightPhases.GOAROUND) {
if (this.descentSpeedLimit !== undefined && alt <= this.descentSpeedLimitAlt) {
if (this.descentSpeedLimit !== null && alt <= this.descentSpeedLimitAlt) {
kcas = Math.min(this.descentSpeedLimit, kcas);
}
}
Expand Down Expand Up @@ -4759,6 +4747,116 @@ class FMCMainDisplay extends BaseAirliners {
}
}

/**
* The maximum speed imposed by the climb speed limit in the active flight plan or null if it is not set.
* @returns {number | null}
*/
get climbSpeedLimit() {
const plan = this.currFlightPlanService.active;

// The plane follows 250 below 10'000 even without a flight plan
return plan ? plan.performanceData.climbSpeedLimitSpeed : DefaultPerformanceData.ClimbSpeedLimitSpeed;
}

/**
* Set the maximum speed imposed by the climb speed limit in the active flight plan.
*/
set climbSpeedLimit(speed) {
const plan = this.currFlightPlanService.active;

if (plan) {
this.currFlightPlanService.setPerformanceData('climbSpeedLimitSpeed', speed);
}
}

/**
* The altitude below which the climb speed limit of the active flight plan applies or null if not set.
* @returns {number | null}
*/
get climbSpeedLimitAlt() {
const plan = this.currFlightPlanService.active;

// The plane follows 250 below 10'000 even without a flight plan
return plan ? plan.performanceData.climbSpeedLimitAltitude : DefaultPerformanceData.ClimbSpeedLimitAltitude;
}

/**
* Set the altitude below which the climb speed limit of the active flight plan applies.
*/
set climbSpeedLimitAlt(alt) {
const plan = this.currFlightPlanService.active;

if (plan) {
this.currFlightPlanService.setPerformanceData('climbSpeedLimitAltitude', alt);
}
}

get climbSpeedLimitPilot() {
const plan = this.currFlightPlanService.active;

return plan ? plan.performanceData.isClimbSpeedLimitPilotEntered : false;
}

set climbSpeedLimitPilot(isPilotEntered) {
const plan = this.currFlightPlanService.active;

if (plan) {
this.currFlightPlanService.setPerformanceData('isClimbSpeedLimitPilotEntered', isPilotEntered);
}
}

/**
* The maximum speed imposed by the descent speed limit in the active flight plan or null if it is not set.
* @returns {number | null}
*/
get descentSpeedLimit() {
const plan = this.currFlightPlanService.active;

// The plane follows 250 below 10'000 even without a flight plan
return plan ? plan.performanceData.descentSpeedLimitSpeed : DefaultPerformanceData.DescentSpeedLimitSpeed;
}

set descentSpeedLimit(speed) {
const plan = this.currFlightPlanService.active;

if (plan) {
this.currFlightPlanService.setPerformanceData('descentSpeedLimitSpeed', speed);
}
}

/**
* The altitude below which the descent speed limit of the active flight plan applies or null if not set.
* @returns {number | null}
*/
get descentSpeedLimitAlt() {
const plan = this.currFlightPlanService.active;

// The plane follows 250 below 10'000 even without a flight plan
return plan ? plan.performanceData.descentSpeedLimitAltitude : DefaultPerformanceData.DescentSpeedLimitAltitude;
}

set descentSpeedLimitAlt(alt) {
const plan = this.currFlightPlanService.active;

if (plan) {
this.currFlightPlanService.setPerformanceData('descentSpeedLimitAltitude', alt);
}
}

get descentSpeedLimitPilot() {
const plan = this.currFlightPlanService.active;

return plan ? plan.performanceData.isDescentSpeedLimitPilotEntered : false;
}

set descentSpeedLimitPilot(isPilotEntered) {
const plan = this.currFlightPlanService.active;

if (plan) {
this.currFlightPlanService.setPerformanceData('isDescentSpeedLimitPilotEntered', isPilotEntered);
}
}

getFlightPhase() {
return this.flightPhaseManager.phase;
}
Expand Down Expand Up @@ -5075,6 +5173,13 @@ const FlightPlans = Object.freeze({
Temporary: 1,
});

const DefaultPerformanceData = Object.freeze({
ClimbSpeedLimitSpeed: 250,
ClimbSpeedLimitAltitude: 10_000,
DescentSpeedLimitSpeed: 250,
DescentSpeedLimitAltitude: 10_000,
});

class FmArinc429OutputWord extends Arinc429Word {
constructor(name, value = 0) {
super(0);
Expand Down
25 changes: 25 additions & 0 deletions fbw-a32nx/src/systems/fmgc/src/flightplanning/plans/FlightPlan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { FlightArea } from '@fmgc/navigation/FlightArea';
import { CopyOptions } from '@fmgc/flightplanning/plans/CloningOptions';
import { ImportedPerformanceData } from '@fmgc/flightplanning/uplink/SimBriefUplinkAdapter';
import {
DefaultPerformanceData,
FlightPlanPerformanceData,
FlightPlanPerformanceDataProperties,
} from '@fmgc/flightplanning/plans/performance/FlightPlanPerformanceData';
Expand Down Expand Up @@ -128,9 +129,20 @@ export class FlightPlan<P extends FlightPlanPerformanceData = FlightPlanPerforma

this.alternateFlightPlan.allLegs.length = 0;

this.resetAlternatePerformanceData();

this.alternateFlightPlan.incrementVersion();
}

private resetAlternatePerformanceData() {
this.setPerformanceData('alternateClimbSpeedLimitSpeed', DefaultPerformanceData.ClimbSpeedLimitSpeed);
this.setPerformanceData('alternateClimbSpeedLimitAltitude', DefaultPerformanceData.ClimbSpeedLimitAltitude);
this.setPerformanceData('isAlternateClimbSpeedLimitPilotEntered', false);
this.setPerformanceData('alternateDescentSpeedLimitSpeed', DefaultPerformanceData.DescentSpeedLimitSpeed);
this.setPerformanceData('alternateDescentSpeedLimitAltitude', DefaultPerformanceData.DescentSpeedLimitAltitude);
this.setPerformanceData('isAlternateDescentSpeedLimitPilotEntered', false);
}

directToLeg(ppos: Coordinates, trueTrack: Degrees, targetLegIndex: number, _withAbeam = false) {
if (targetLegIndex >= this.firstMissedApproachLegIndex) {
throw new Error('[FPM] Cannot direct to a leg in the missed approach segment');
Expand Down Expand Up @@ -294,8 +306,21 @@ export class FlightPlan<P extends FlightPlanPerformanceData = FlightPlanPerforma

this.setPerformanceData('cruiseFlightLevel', cruiseLevel);
this.setPerformanceData('costIndex', 0);
this.setPerformanceData('climbSpeedLimitSpeed', this.performanceData.alternateClimbSpeedLimitSpeed);
this.setPerformanceData('climbSpeedLimitAltitude', this.performanceData.alternateClimbSpeedLimitAltitude);
this.setPerformanceData(
'isClimbSpeedLimitPilotEntered',
this.performanceData.isAlternateClimbSpeedLimitPilotEntered,
);
this.setPerformanceData('descentSpeedLimitSpeed', this.performanceData.alternateDescentSpeedLimitSpeed);
this.setPerformanceData('descentSpeedLimitAltitude', this.performanceData.alternateDescentSpeedLimitAltitude);
this.setPerformanceData(
'isDescentSpeedLimitPilotEntered',
this.performanceData.isAlternateDescentSpeedLimitPilotEntered,
);

this.deleteAlternateFlightPlan();
this.resetAlternatePerformanceData();

this.enqueueOperation(FlightPlanQueuedOperation.RebuildArrivalAndApproach);
this.enqueueOperation(FlightPlanQueuedOperation.Restring);
Expand Down
Loading