技术文档

AFDS and cold-and-dark audit against Zibo (build 28)

此页为项目的英文技术文档原文。 docs/AFDS_AUDIT.md

Status (build 29)#

# Status
A1 fixed: bank angle selector at 25 deg (position 3)
A2 fixed: zibomod's disconnect annunciators (red A/P, amber A/T, amber FMC) and the A/P disconnect test switches; the wailer (FMOD sound) is not rewritten
A3 fixed: the gauge observes the joystick's axis events as zibomod's yoke; CMD -> CWS P / R on yoke input, disconnect below 400 ft
A4 fixed: CWS gives the controls to the pilot out of the detent and holds the attitude at the release (wings level below 6 deg)
A5 fixed: the yoke is the pilot's axis, not MSFS's YOKE Y. Correction to A5 below: zibomod refuses CMD with the yoke off centre (disconnect warning), it does not engage CWS
A6 build 36: the gauge masks MSFS's throttle events (SimConnect, highest maskable priority) and the systems module decides where the levers go, L:LU737_THR_HW_MODE 0 last mover (default: relative manual override of the A/T, A/T back 2 s after the hardware stops; pickup without the A/T), 1 follow the A/T, 2 follow the hardware (wasm/src/core/thr/thr_arbiter.h; L:LU737_THR_HW_STATE_1/2 -1 not masked, 0 waiting for pickup, 1 A/T, 2 override, 3 hardware). Needs the owner's test in the sim
A7 open: needs the FMS (M5c)
A8 build 36: APP never armed and VOR LOC / APP never captured: mmr_act_mode / nav_horz_dsp (Zibo's FMS Lua mmr_active_mode) were not computed. Ported (section D)
B open (systems not rewritten), except the A/P disconnect test switch, the yoke animation (build 31) and the pressurization gauges / outflow valve (build 31)
E1-E6, E8 fixed: the electrics compute instrument_brightness_ratio[n] as zibomod (Systems, Chrono), the DU states and the MCP button glow; cold-and-dark comparison with Zibo: no difference with the battery off
E7 IRS display blank (as Zibo with the IRS off) until the IRS display unit (keypad, PPOS / HDG display) is rewritten

Owner: "I found a few more problems; find them, compare with Zibo, do not fix yet." Method:

  • End-to-end comparison with the original plugin (tools/re/afds_e2e/): the oracle (real zibomod in xphost) and the systems module get the same airborne state (FL100, 250 kt) and the same 60 cockpit actions (FD, A/T, every MCP mode, CMD A / B, CWS, C/O, TO/GA, disconnects); all 176 AFDS outputs, the MCP values and the thrust levers are compared at 33 checkpoints.
  • Cockpit coverage: every one of the 2123 events the cockpit model sends is fired at Systems; every one of the 940 L:vars the cockpit model reads is checked for a writer.
  • Code audit of what zibomod gets from X-Plane or from code outside the translated AFDS (commands, servo, yoke, annunciators), each checked in the zibomod listing / Lua.
  • Closed-loop rig (wasm/test/test_afds_capture.cpp style) for TO/GA take-off.

A. Differences from Zibo (port gaps) — autopilot#

# What you see Zibo Ours Cause
A1 HDG SEL / LNAV turns are slow, bank only 10° bank angle selector starts at 25° (position 3) starts at 10° (position 0) Zibo's Lua sets bank_angle_pos = 3 at flight start (B738.glaresheild.lua:6544); mcp::Outputs::bankAngle = 0 (wasm/src/core/mcp/mcp.h:21). Oracle: 3 vs 0 at every checkpoint.
A2 Red A/P and amber A/T disconnect lights never light (also A/T FMC light); no disconnect wailer lights flash on disconnect dark The translated AFDS produces B738DR_ap_disconnect / B738DR_at_disconnect, but zibomod's annunciator code that makes ap_disconnect1/2, at_disconnect1/2, at_fms_disconnect1/2 (and the light test) is not translated; L:LU737_ANNUNCIATOR_AP_DISCONNECT1/2, AT_DISCONNECT1/2, AT_FMS_DISCONNECT1/2 have no writer. Sound: FMOD not rewritten.
A3 Pushing the yoke while CMD is engaged does not override the autopilot; with a joystick the controls fight the autopilot yoke moved > 0.11 from its engage position: CMD → CWS P / R (below 400 ft or with the yoke-disconnect option: A/P disconnect) nothing happens; the servo keeps writing the elevator / ailerons every frame check_yoke compares curr_pitch_ratio2 / curr_roll_ratio2 (zibomod's servo / Read_axis) with the engage position; never set in the port (afds_external audit). Our servo (afds/servo.cpp) sends AXIS_ELEVATOR_SET / AXIS_AILERONS_SET each frame while engaged.
A4 CWS A / B: the autopilot holds attitude but the yoke cannot steer it control wheel steering: yoke force commands pitch / roll rate, released = hold holds the flight director attitude, yoke ignored Zibo's servo reads B738DR_joy_axis_pitch / _roll (Read_axis, stubbed) in CWS; our servo follows fdir_pitch / roll_main only.
A5 CMD A / B sometimes engages as CWS (risk, check in the sim) CMD is refused (CWS instead) when the yoke is > 10 % off centre at engage MSFS's YOKE Y POSITION stays where our servo last put the elevator after a disconnect (no joystick moving it) Zibo reads the pilot's joystick (yoke_pitch_ratio); in MSFS the servo's axis output is the same variable. Same root as A3.
A6 A/T with a hardware throttle: unwanted A/T override / disconnects or lever fights (risk, check) X-Plane keeps the joystick axis separate from the throttle the A/T moves any MSFS throttle change we did not command is taken as the pilot (afdsThrUser_, systems_afds.cpp); an unmotorised throttle's axis noise counts One MSFS throttle variable for pilot and A/T.
A7 Take-off N1 about 93.5 % (climb thrust) the FMS's take-off N1 (about 95–97 % with N1 LIMIT data) 93.5 % No FMS yet: the active N1 limit is the temporary climb value (systems_afds.cpp, "N1 limits ... temporary"). Zibo without performance data gives the same 93.5 % (oracle). Expected until M5c.

B. Cockpit controls that do nothing yet (systems not rewritten; Zibo has them all)#

All cockpit controls go through H:LU737_* events to the systems module (the cockpit XML sends no K: events), and 1723 of the 2123 events have no handler; 718 of the 940 cockpit L:vars have no writer. So these work from the keyboard / hardware but not from the cockpit, and their levers / lights do not follow:

  • Flight controls: flap lever, hydraulic pumps, FLT CONTROL / SPOILER / ALTN FLAPS (build 32); gear lever and lights (33); speedbrake lever, parking brake, autobrake, stab trim switches / cutouts / wheel, yaw damper (34, zibomod Systems); reverse levers (35). Still open: aileron / rudder trim as zibomod (MSFS's own trim for now).
  • Glareshield / pedestal: ALT INTV, A/T light-test buttons, A/P disconnect test switch, N1 SET and SPD REF knobs, MASTER CAUTION light and most of the six-pack, COMM radios and audio panels, HGS (HUD) controls.
  • Gauges: standby altimeter (analog option). (Cabin altitude / differential / outflow valve: build 31.)

The counts above are from build 28; builds 29–36 wired many more controls (see the list) and need a recount.

C. Checked and the same as Zibo#

  • Modes, lights, MCP: at all 33 checkpoints (FD, A/T arm, HDG SEL, ALT HLD, SPEED, CMD A, V/S + wheel, LVL CHG, N1, C/O to Mach and back, VNAV / LNAV / VOR LOC / APP presses, CWS A, CMD B, CMD A+B, TO/GA in the air, A/P disconnect buttons, disengage bar, A/T disengage, FD off) every FMA mode, MCP light, CMD / CWS / A/T status and MCP value equals Zibo's. Remaining output differences are A1 and effects of the oracle's frozen flight state (flight director pitch and the A/T lever in MCP SPD integrate without feedback there), the standby horizon still erecting (30 s after AC standby power), and the pressurization gauges (B).
  • TO/GA take-off (closed-loop rig): N1 mode, levers to the N1 limit, FD 10° nose down until 60 kt then the rotation command — as Zibo (and the real aircraft).
  • MCP speed 100 kt after LVL CHG / V/S on the ground: Zibo's own behaviour (build 28).
  • X-Plane commands: zibomod's handlers for servos_fdir_off and take_off_go_around return 0, so X-Plane's own handlers never run; knots_mach_toggle is emulated since build 28.
  • Every AFDS value the PFD reads (FD bars included) is published.

D. Not verifiable here#

  • LOC / GS capture (APP, VOR LOC): the integration maps MSFS NAV CDI / NAV GSI to X-Plane's deviation dots with the same sign assumed; a sign error would turn the aircraft away from the localizer or the wrong way on the glideslope. Needs an ILS approach in the sim (watch the localizer pointer and the bank direction on capture). Owner (build 35): LOC right; GS not seen. Build 36: the PFD / ND glideslope flag came from MSFS's NAV GS FLAG (sense unverified, suspected of hiding the pointer) and now from NAV HAS GLIDE SLOPE; the AFDS took MSFS's NAV GSI (0 = centred) also without a glideslope (false G/S capture risk) and now full scale then; an ILS tuned before the glideslope is received stayed LOC-only. And the AFDS's MMR mode / deviations-shown inputs (Zibo's FMS Lua mmr_active_mode) were never set: APP did not arm, VOR LOC / APP did not capture. Ported in build 36 (closed- loop test). The GS sign still needs the sim.

E. Cold and dark: lit without power (owner: "the MCP and the clocks light before the battery is on")#

Why it was missed. The panel windows (MCP, clocks, radios, ...) are Zibo's own panel program; in X-Plane each window's lit level is sim/cockpit2/switches/instrument_brightness_ratio[n], which zibomod sets to 0 without power (and to the knob / daylight level with power). Our DuSource (avionics/src/du/DuSource.ts, PANEL_BRIGHTNESS) returns constants copied from the panel oracle, and all three oracle states (avionics/test/data/panel_oracle.json: ground, cruise, approach) are warm, fully powered, so the test said "same as Zibo". No unpowered state was ever compared. DisplayUnit.ts assumes "the panel windows gate each window themselves", which is only true in X-Plane because zibomod writes those ratios. The build-28 AFDS audit started airborne with power on and only checked that each L:var has a writer, not its value cold. The electrics already compute L:LU737_MCP_PWR, RADIO1/2_PWR, EFIS_CPT/FO_PWR, ELEC_METER_PWR (elec_sci.cpp); nothing reads them.

Method. Cold start on the ground, then battery off / battery only / APU generators (xphost/test/sci/cold_dark_panel.json), compared with Systems in the same states: every panel window (the panel program's SHOW conditions and brightness, evaluated with Zibo's values and with ours through DuSource), and all 1140 light / visibility codes of the 3D cockpit (LU738_INTERIOR.xml), with Zibo's datarefs mapped to the L:vars.

Zibo, instrument_brightness_ratio[n] (battery only and APU depend on the dimmer / daylight; ours is a constant):

n panel windows battery off battery only APU gens ours
9 MCP displays (CRS, IAS/MACH, HDG, ALT, V/S); LE DEVICES lights 0 0.8 0.4 0.4
15 MCP backlight 0 0.8 0.32 0.4
8 / 18 clock digits captain / F/O 0 1 / 0 1 / 1 1 / 1
21 / 22 clock backlight captain / F/O 0 0.47 / 0 0.47 / 0.47 0.47 / 0.47
27 / 28 radio panels (COM, NAV, ADF) and MMR, dim variant 0 0 0.34 0.34
17 cabin pressure digital panel needle 0 1 1 1
# What you see (battery off unless noted) Zibo Ours Cause
E1 MCP windows and MCP backlight lit dark lit (0.4) PANEL_BRIGHTNESS[9], [15] constants; the MCP windows have no power condition of their own (AP displays_W: light test and colour only). MCP_PWR unused.
E2 Clock backlights lit (both clocks) dark lit (0.47) [21], [22] constants. The digits are gated by CLOCK_PWR (dark with the battery off).
E3 Battery only: F/O clock digits and backlight lit F/O clock dark until AC ([18], [22] = 0) lit Both clocks use the captain's L:LU737_CLOCK_PWR (PanelSources.ts, B738DR_clock_fo_power) and constant [18], [22].
E4 COM 1/2/3, NAV, ADF and both MMR displays lit (dim variant) dark lit (0.34) [27], [28] constants; nav1_status / nav2_status pending = 1. RADIO1/2_PWR unused.
E5 LE DEVICES panel (slat transit / extended lights) lit dark lit (0.4) brightness [9] (E1).
E6 Cabin pressure digital panel (FLT / LAND ALT digits, needle) lit dark lit [17] constant, digital_press_panel pending.
E7 IRS display unit (LAT / LON digits) always shown, also with power and the IRS off shown only when the IRS / display selector shows something (lat_deg_show etc. 0 here in all three states) shown lat_deg_show, lon_deg_show, ns_show, ew_show, decimals_show, ... pending = 1 (PanelSources.ts); IRS display logic not ported.
E8 DU screen backlight / glass groups in the "on" variant (risk: check whether the dark screens look grey or lit) display_units/odu_cpt, idu_cpt, odu_fo, idu_fo, ldu = −1 (unit off) without power; F/O side and lower DU −1 on battery only L:vars have no writer, stay 0 (= on) COCKPIT_BACKLIGHT_grp*, BCOCKPIT_grp_821–834 visibility. Their emission (instrument_brightness_ratio_manual) is 0 in ours, so the effect is probably small.

Checked and the same as Zibo (cold and dark): the DU contents (PFD, ND, EICAS, lower DU, ISFD, CDU) are dark with the battery off and the F/O side stays dark on battery only (DU power gates with warm-up); MCP button lights; overhead annunciators dark with the battery off and DRIVE, SOURCE OFF, TRANSFER BUS OFF, ELEC lit on battery as Zibo (elec_spec_battery.json; GEN OFF BUS follows X-Plane's generator_off, which the host does not simulate); every 3D-cockpit light emission is 0 with the battery off. Not power related, noted only: the panel / flood light knobs are not wired (B), so the panel backlighting (COCKPIT_*_LIT) stays dark also with power.

Suggested fix (not done). Make instrument_brightness_ratio[n] follow Zibo's computation (power × knob / daylight) instead of constants: at least gate [9], [15] by MCP_PWR, [8], [21] by the captain clock, [18], [22] by the F/O clock (its own power), [27], [28] by RADIO1/2_PWR, [17] by the pressurisation panel; write display_units/* from the DU power and the IRS display datarefs from the IRS module; add a cold-and-dark state to panel_oracle.json (from cold_dark_panel.json) so the panel test fails on this.

Suggested order of fixes#

E1–E6 (panel brightness from power, one source file), A1 (one line), A2 (port zibomod's disconnect annunciators), A3–A5 (yoke override and CWS: feed curr_*_ratio2 / joy_axis_* from the pilot's input and stop the servo writing the axis the pilot moves), A6 (needs an MSFS input design: e.g. read the pilot's throttle axis events separately), then the B controls by subsystem.

A9 — LOC tracking: S-turns on the localizer (owner, build 44)#

  • Owner: ILS approach with the A/P at a 4 km runway, the localizer tracked poorly (S-turns, see the flight track).
  • Closed loop (wasm/test/test_afds_capture.cpp afds_loc_intercept_and_track: a 30° intercept at 180 kt, MSFS's quantised CDI, crosswind, course error, roll lag; LU737_LOC_SWEEP=1 prints the sweep). Two causes:
    1. Deviation scaling. MSFS's NAV CDI is normalised to each localizer's own width; long runways have narrow beams (about ±1.4° for 4 km: 700 ft at the threshold). Our CDI / 127 × 2.5 gave Zibo's LOC law up to 1.8× the deviation it is tuned for (X-Plane's, about 1 dot per degree: Zibo's GLS emulation sets full scale to distance × tan 2.5° + 0.28 nm). With a ±1.5° beam the loop weaved by 2–5°. Now the deviation is in degrees (1 dot per degree): the beam's half-width is measured from MSFS's NAV RADIAL ERROR against the CDI (off centre, not pinned, per tuned frequency), 2.5° until measured (Systems::locDots). ±1.5 / 2.5 / 4° beams now track alike.
    2. Bank loop too slow. Our servo's bank gain (0.5 /s: about a 2 s time constant plus MSFS's lag) sat where the LOC law weaves: through the servo and a roll-mode plant, 7–8 centreline crossings, ±3.4° with weak aileron authority. Gain 1.0 /s: within 0.08°, 1–3 crossings for aileron power 0.5–2× and roll-mode lag 0.5–1 s. L:LU737_AP_ROLL_GAIN multiplies it for tuning in the sim.