Migration
Diese Seite wurde aus der AirSimTech MediaWiki migriert.
PERF1 Performance Engine
Overview
Perf1Engine is a direct port of the VB6 PREF.ctl COM control. It provides MDB-based performance data (vertical speed and fuel flow) for trajectory computation. The engine decrypts the PERF table from FMGCPERF1.MDB, builds 5 in-memory 3D grids (Weight x IAS x Altitude), and provides tri-linear interpolated lookups matching VB6 behavior exactly.
Before Phase 20, PerfDataStore used a hardcoded linear approximation (e.g., climb V/S = 2000 - altitude/1000 * 40). Now, LoadFromDatabase instantiates Perf1Engine, wires a lambda to _lookupFunction, and all trajectory computation uses real MDB-derived data.
Data Flow
FMGCPERF1.MDB
|
v
Perf1Engine.LoadAndDecrypt()
|-- reads EXTENDED table -> PRO or ADV version (PublicKey)
|-- reads PERF table -> decrypts each row
|-- routes by Mode field -> 5 grids
v
PerfDataStore.LoadFromDatabase()
|-- creates Perf1Engine, calls LoadAndDecrypt
|-- wires _lookupFunction lambda (phase -> VSCLB/FFCLB/FFCRZ/VSDES/FFDES)
|-- updates PerfLimits from actual grid bounds
v
TrajectoryActor.ComputeClimbProfile / ComputeDescentProfile / ComputeCruiseProfile
|-- calls _perfData.GetPerformanceCached(alt, weight, phase, ias)
|-- receives PerfResult(FuelFlow, VerticalSpeed) from tri-linear interpolation
PERF Table Field Mapping
The PERF table uses string-encoded columns N1 through N18:
| Column | Field | Description |
|---|---|---|
N1 |
GW | Gross Weight (kg) |
N2 |
IAS | Indicated Airspeed (kt) |
N3 |
ALT | Altitude (ft) |
N4 |
VS | Vertical Speed (ft/min) |
N5 |
FF | Fuel Flow (kg/h) |
N9 |
Mode | Flight phase (determines grid assignment) |
N13 |
Stime | Time field |
N16 |
CODECHECK | Checksum (sum of N1-N12) |
N17 |
Keynum | Decryption key number (1, 2, 3, or 4) |
N18 |
ID | Sequential ID (ORDER BY) |
Decryption Algorithm
Each string-encoded field value follows the format EEMMMMMMMMMMM where:
- First 2 characters = exponent (E)
- Remaining characters = mantissa (M)
Step 1: Decode
temp2 = Val(Left(fieldValue, 2)) ' exponent
temp1 = CDbl(Right(fieldValue, Len - 2)) ' mantissa
decodedValue = temp1 / (10 ^ (Len - 2 - temp2))
Step 2: Key-based scaling
PublicKey = 4532535 ' PRO version (or 4465230 for ADV)
cKey = PublicKey / (10000000 * Keynum)
finalValue = Int(decodedValue * cKey + 0.5)
The version (PRO vs ADV) is determined by the EXTENDED table: value 1 = PRO, value 2 = ADV.
The DecodeField and CALC_AVERAGE functions are exposed as Friend Shared for direct unit testing.
Grid Assignment
After decryption, each PERF row is routed to a grid based on the Mode field (N9):
| Grid Index | Grid Name | Mode Values | Data Field |
|---|---|---|---|
| 0 | VSCLB | 3 or 7 | VS (Vertical Speed) |
| 1 | VSDES | 4 or 8 | VS (Vertical Speed) |
| 2 | FFCLB | 3 or 7 | FF (Fuel Flow) |
| 3 | FFCRZ | 1 or 5 | FF (Fuel Flow) |
| 4 | FFDES | 4 or 8 | FF (Fuel Flow) |
Each grid type holds a List(Of PerfGrid). Each PerfGrid represents one weight page:
Weight— the gross weight this page coversIasRows— sorted list of IAS values (row headers)AltCols— sorted list of altitude values (column headers)Data(iasIndex, altIndex)— the performance value;-99999marks missing cells
Rows and columns are inserted in sorted order via InsertPoint, expanding the data matrix as needed.
Tri-Linear Interpolation (Calcit)
GetData(tableName, gw, ias, alt) dispatches to the correct grid list and calls Calcit.
The Calcit function performs 3D interpolation in three stages:
- Find weight pages — locate LOW_GRID and HIGH_GRID bracketing the target GW
- Find altitude columns — in each weight page, find ALT_MIN and ALT_MAX bracketing the target altitude
- Find IAS rows — for each (weight page, altitude column) pair, find IAS_MIN and IAS_MAX
- Collect 8 corner values — VS/FF at each combination of (low/high weight, low/high altitude, low/high IAS)
- 3-stage CALC_AVERAGE interpolation:
- Stage 1 (IAS): 4 results — interpolate along IAS axis at each (weight, altitude) corner
- Stage 2 (ALT): 2 results — interpolate along altitude axis at each weight
- Stage 3 (GW): 1 final result — interpolate along weight axis
CALC_AVERAGE is standard linear interpolation:
Boundary clamping: The engine always returns the nearest valid data instead of falling back to hardcoded approximations. Fallback is only used when the MDB file is missing or unreadable. Clamping operates at three levels:
Calcit level (GW, ALT, IAS dimensions)
- GW: If target weight is below/above all grid pages, the lowest/highest page is used (both low and high grid point to the same edge page)
- ALT: If target altitude is below/above all column headers, both low and high column indices point to the nearest edge column
- IAS: If target IAS is below/above all row headers, both low and high row indices point to the nearest edge row
- Zero corner fill: Grid cells containing 0 (no data at edge) are replaced by the nearest non-zero neighbor value from the same GW side, preventing spurious fallback at grid boundaries
FindAltCol(high): returns last column; (low): returns first columnFindIasRow: VB6 fallback scans for last valid row from top- When HIGH_GRID value is the missing sentinel (-99999), LOW_GRID value is substituted
PerfDataStore lambda level
- Before calling
engine.GetData, IAS and GW are clamped to the per-phase limits (MinIASDES..MaxIASDES, etc.) tracked from actual grid data duringLoadAndDecrypt
VSDES sign handling
- The VSDES grid returns negative values (descent rate in ft/min). These are valid, not errors. The lambda takes
Math.Abs(vs)for descent phase. The Calcit error sentinel (-1.0) is distinguished by checkingvs > -2.0 AndAlso vs < 0.
PerfDataStore Wiring
In PerfDataStore.LoadFromDatabase, after CI_IAS and CI_MACH tables are loaded:
Perf1Engineis instantiated andLoadAndDecrypt(dbPath)is called- If
IsLoadedis true, a lambda is assigned to_lookupFunction:- Phase 0 (Climb):
GetData("VSCLB")+GetData("FFCLB") - Phase 1 (Cruise): VS = 0,
GetData("FFCRZ") - Phase 2 (Descent):
GetData("VSDES")+GetData("FFDES")
- Phase 0 (Climb):
- IAS and GW are clamped to per-phase grid limits before calling
GetData, ensuring the engine always returns the nearest valid value - For descent (phase 2), negative VS values are treated as valid descent rates (
Math.Abs); only the Calcit error sentinel (-1.0, detected byvs > -2.0 AndAlso vs < 0) triggers fallback - If GetData still returns -1 after clamping, fallback functions
GetFallbackVs/GetFallbackFfprovide the old linear approximation andPerfResult.PerfSourceMdbis set toFalse PerfLimitsare updated from actual grid bounds (MaxWeightCLB, MinIASCLB, etc.)
The _lookupFunction signature includes an IAS parameter: Func(Of Long, Long, Integer, Long, PerfResult) — (altitude, grossWeight, phase, ias). TrajectoryActor passes the current managed IAS at each computation step.
Performance Cache
GetPerformanceCached uses a single-entry cache with 4-dimensional key: altitude (within threshold), weight (within 1,000 kg), phase, and IAS (within 10 kt). The IAS dimension was added to prevent stale cache hits when the approach deceleration zone produces rapidly changing IAS values at similar altitudes. Cache is reset at the start of each trajectory computation.
Performance Source Tracking
Each PerfResult carries a PerfSourceMdb As Boolean flag. The flag is True when both V/S and FF came from the Perf1Engine grids, and False when either value fell back to the hardcoded approximation (or when no _lookupFunction is wired at all). This flag propagates through ProfilePoint.PerfSourceMdb and ComputedFlightPlanLeg.PerfSourceMdb to the diagnostic popup (frmPointInfo), which displays "Source: MDB" or "Source: Fallback".
Verified Reference Data
The VSCLB grid data has been verified against the pre-computed VSCLB table in the MDB:
| Weight (kg) | IAS (kt) | 5,000 ft | 20,000 ft | 35,000 ft |
|---|---|---|---|---|
| 42,000 | 200 | 4,500 | 1,988 | 878 |
| 42,000 | 270 | 3,635 | 1,606 | 709 |
| 42,000 | 340 | 2,937 | 1,297 | 573 |
| 57,000 | 200 | 2,084 | 921 | 406 |
| 57,000 | 270 | 1,684 | 744 | 328 |
| 57,000 | 340 | 1,361 | 601 | 265 |
| 72,000 | 200 | 965 | 426 | 188 |
| 72,000 | 270 | 780 | 344 | 152 |
| 72,000 | 340 | 630 | 278 | 123 |
All values are vertical speed in ft/min. Unit tests validate exact grid point lookups and interpolated values.
Test Coverage
32 tests in Perf1EngineTests.vb (Category: Phase20):
DecodeField— 5 tests verifying exponent/mantissa decodingCALC_AVERAGE— 5 tests covering equal values, bounds, midpoint, zero-diffPerfGrid— 3 tests for grid construction and sorted insertionGetData— 11 tests covering exact grid points, interpolation, boundary clamping, out-of-rangePerfDataStorebackward compatibility — 8 tests verifying existing cache, fallback, and optional IAS parameter
Source Files
A320_FMGC/Trajectory/Perf1Engine.vb— Decryption, grid build, Calcit interpolation, GetData dispatch (~770 LOC)A320_FMGC/Trajectory/PerfDataStore.vb— _lookupFunction wiring, cache, fallback (~795 LOC)A320_FMGC.Tests/Trajectory/Perf1EngineTests.vb— 32 unit tests (~450 LOC)- VB6 reference:
/c/AST-Projects/A320_VB6/ASTServer/PREF.ctl— original COM control source