Skip to content

Commit

Permalink
fix(fms): fix vnav crash on steep approaches (#8766)
Browse files Browse the repository at this point in the history
Handle steep approaches better
  • Loading branch information
BlueberryKing authored Jul 28, 2024
1 parent 6c7c3aa commit 7bd5b1d
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 16 deletions.
3 changes: 2 additions & 1 deletion .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,9 @@
1. [EFB] Added a takeoff performance calculator - @donstim (donbikes), @tracernz (Mike)
1. [MCDU] Removed V-speed auto-fill function - @tracernz (Mike)
1. [PFD] Implement alerts within artificial horizon (ROP, ROW, OANS, stall, windshear) @flogross89 (Flo)
1. [MCDU] Fixed ZFW Autofill with lbs during boarding @ShreyasKallingal
1. [MCDU] Fixed ZFW Autofill with lbs during boarding @ShreyasKallingal
1. [FWC] Fix NW STRG DISC turning amber too soon - @adoggman (Andrew)
1. [FMS] Fix VNAV crash for steep approaches - @BlueberryKing (BlueberryKing)

## 0.11.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,15 +348,14 @@ export class ApproachPathBuilder {
const decelerationSequence = new TemporaryCheckpointSequence(lastCheckpoint);

const parameters = this.observer.get();
const { managedDescentSpeedMach } = parameters;

for (
let i = 0;
i < 10 &&
decelerationSequence.lastCheckpoint.reason !== VerticalCheckpointReason.Decel &&
decelerationSequence.lastCheckpoint.distanceFromStart - targetDistanceFromStart > 1e-4; // We really only want to prevent floating point errors here
i++
) {

let lastAccelerationCheckpointIndex = 1;

const isDoneDeclerating = () =>
decelerationSequence.lastCheckpoint.reason === VerticalCheckpointReason.Decel ||
decelerationSequence.lastCheckpoint.distanceFromStart - targetDistanceFromStart <= 1e-4; // We really only want to prevent floating point errors here

for (let i = 0; i < 10 && !isDoneDeclerating(); i++) {
const { distanceFromStart, altitude, speed, remainingFuelOnBoard } = decelerationSequence.lastCheckpoint;

const speedConstraint = speedProfile.getMaxDescentSpeedConstraint(distanceFromStart - 1e-4);
Expand Down Expand Up @@ -387,16 +386,24 @@ export class ApproachPathBuilder {
altitude,
Math.max(speedConstraint.maxSpeed, speed), // If constraint speed is less than the current speed, don't try to decelerate to it (because we'll end up going the wrong way)
speed,
managedDescentSpeedMach,
parameters.managedDescentSpeedMach,
remainingFuelOnBoard,
windProfile.getHeadwindComponent(distanceFromStart, altitude),
AircraftConfigurationProfile.getBySpeed(speed, parameters),
);

if (decelerationStep.distanceTraveled > 0) {
throw new Error('[FMS/VNAV] Deceleration step distance should not be positive');
if (decelerationStep.error !== undefined || decelerationStep.distanceTraveled > 0) {
// Reset
decelerationSequence.checkpoints.splice(
lastAccelerationCheckpointIndex,
decelerationSequence.checkpoints.length,
);

break;
}

lastAccelerationCheckpointIndex = decelerationSequence.length;

if (decelerationStep.distanceTraveled < 1e-4) {
// We tried to declerate, but it took us beyond targetDistanceFromStart, so we scale down the step
const scaling = Math.min(1, remainingDistance / decelerationStep.distanceTraveled);
Expand All @@ -420,7 +427,7 @@ export class ApproachPathBuilder {
altitude,
-remainingDistanceToConstraint,
speedConstraint.maxSpeed,
managedDescentSpeedMach,
parameters.managedDescentSpeedMach,
remainingFuelOnBoard - decelerationStep.fuelBurned,
windProfile.getHeadwindComponent(distanceFromStart, altitude),
AircraftConfigurationProfile.getBySpeed(speedConstraint.maxSpeed, parameters),
Expand All @@ -442,17 +449,28 @@ export class ApproachPathBuilder {
const targetSpeed = Math.min(flapTargetSpeed, limitingSpeed);
const config = AircraftConfigurationProfile.getBySpeed(speed, parameters);

// TODO: Handle case where we need speedbrakes
const decelerationStep = this.fpaStrategy.predictToSpeed(
altitude,
targetSpeed,
speed,
managedDescentSpeedMach,
parameters.managedDescentSpeedMach,
remainingFuelOnBoard,
windProfile.getHeadwindComponent(distanceFromStart, altitude),
config,
);

if (decelerationStep.error !== undefined || decelerationStep.distanceTraveled > 0) {
// Reset
decelerationSequence.checkpoints.splice(
lastAccelerationCheckpointIndex,
decelerationSequence.checkpoints.length,
);

break;
}

lastAccelerationCheckpointIndex = decelerationSequence.length;

if (decelerationStep.distanceTraveled < remainingDistance) {
const scaling = Math.min(1, remainingDistance / decelerationStep.distanceTraveled);
this.scaleStepBasedOnLastCheckpoint(decelerationSequence.lastCheckpoint, decelerationStep, scaling);
Expand All @@ -469,6 +487,30 @@ export class ApproachPathBuilder {
}
}

if (!isDoneDeclerating()) {
const config = AircraftConfigurationProfile.getBySpeed(decelerationSequence.lastCheckpoint.speed, parameters);

// Fly constant speed instead
const constantSpeedStep = this.fpaStrategy.predictToDistance(
decelerationSequence.lastCheckpoint.altitude,
targetDistanceFromStart - decelerationSequence.lastCheckpoint.distanceFromStart,
decelerationSequence.lastCheckpoint.speed,
parameters.managedDescentSpeedMach,
decelerationSequence.lastCheckpoint.remainingFuelOnBoard,
windProfile.getHeadwindComponent(
decelerationSequence.lastCheckpoint.distanceFromStart,
decelerationSequence.lastCheckpoint.altitude,
),
config,
);

decelerationSequence.addDecelerationCheckpointFromStep(
constantSpeedStep,
FlapConfigurationProfile.getFlapCheckpointReasonByFlapConf(config.flapConfig),
FlapConfigurationProfile.getApproachPhaseTargetSpeed(config.flapConfig, parameters),
);
}

return decelerationSequence;
}
}

0 comments on commit 7bd5b1d

Please sign in to comment.