Zum Inhalt

Migration

Diese Seite wurde aus der AirSimTech MediaWiki migriert.

Trajectory Visualization and Diagnostics

Overview

Six diagnostic forms plus a status bar provide live visibility into the FMGC's internal state, accessible from the Diagnostics menu:

Menu Group Form Description
Side View ScottPlot altitude profile (altitude vs. distance from departure) — driven by Layer 2 TrajectoryPathPoints, with nav waypoint labels from abeam projection
Map View GDI+ lateral flight path — driven by Layer 2 TrajectoryPathPoints with phase-colored scatter lines
FPLN RAW FPLN Raw primary flight plan legs plus Layer 1 (Display) view and legacy MCDU view (frmRawFpln), Test menu for SAVE / LOAD / TMPY activation
FPLN Trajectory Log Per-step trajectory computation data (frmTrajectoryLog)
SEC FPLN RAW SEC FPLN Secondary flight plan legs (auto-refresh 2 s timer)
BITE Actor exceptions and NLog Warn/Error/Fatal events

As of Phase 27 the standalone Computed FPLN diagnostic form (frmComputedFpln) has been removed. Its responsibilities were absorbed:

  • The Display tab of frmRawFpln shows Layer 1 (BuildResult.Display) — named waypoints, VNAV markers (T/C, T/D, SPDLIM, DECEL) and structural legs.
  • Side View and Map View render from Layer 2 (BuildResult.Path) — pure geometry with abeam-projected labels — so they no longer need a separate merged diagnostic feed.

SHOW DEBUG (at the bottom of the Diagnostics menu) opens the four primary views — RAW FPLN, Map View, Side View, and Trajectory Log — simultaneously in a 2x2 quadrant layout.

frmMain also shows a StatusStrip with INET connection state ("Disconnected" → "Connected") and startup progress (SEQ 1–6) via StatusSubscriberActor.

All forms participate in cross-view selection synchronization — clicking a point in any view highlights the corresponding point in all other views via DiagnosticSelectionChanged EventStream messages.

The TMPY/Active FPLN toggle lives exclusively on frmComputedFlightPlan (Layer 2 list) — it is the single master control. When a TMPY flight plan becomes active, the toggle auto-switches to TMPY on first arrival and broadcasts DiagnosticTmpyToggleChanged to the other three views, which react via OnTmpyToggleSync. When TMPY is cleared (INSERT or ERASE), the toggle hides and reverts to Active FPLN. The other views (frmRawFpln, frmMapView, frmSideView) no longer have their own toggle controls.

Each form receives live data through one or more EventStream subscriber actor bridges: a dedicated ReceiveActor subscribes to the relevant message type(s), then marshals each update to the form's UI thread via BeginInvoke with IsDisposed / IsHandleCreated guards.

EventStream Fan-Out

KernelActor is the sole publisher of build results. On every 1 s KernelTick, after TrajectoryActor returns a fresh TrajectoryResult, KernelActor calls ComputedFlightPlanBuilder.Build() and dual-publishes on the EventStream:

The BITE pathway uses a separate EventStream message type:

EventStream Messages

Message Publisher Payload Purpose
TrajectoryResult TrajectoryActor Three ProfilePoint lists (climb/cruise/descent), T/C, T/D, durations, log entries Raw 4D trajectory. Consumed by KernelActor (caches), GuidanceActor (XTE/DECEL), MCDU actors (PROG page), and diagnostic forms that still need the raw per-step data (Trajectory Log)
ComputedFlightPlanResult KernelActor ComputedFlightPlan reconstructed from BuildResult.Display Legacy message kept for backward compatibility — used by McduActor F-PLN page prediction columns
BuildResultPublished KernelActor BuildResult (Layer 1 + Layer 2) Phase 27 — carries both layers in one message. Subscribed by side/map view path actors and the raw-fpln display actor
TmpyComputedFlightPlanResult KernelActor Legacy ComputedFlightPlan for the TMPY plan Legacy TMPY equivalent of ComputedFlightPlanResult
TmpyBuildResultPublished KernelActor BuildResult for the TMPY plan Phase 27 TMPY equivalent of BuildResultPublished
TmpyComputedFlightPlanCleared KernelActor (empty) Fires when TMPY is erased / inserted — forms hide their TMPY toggle
DiagnosticSelectionChanged Any diagnostic form distance / lat / lon / altitude / source form name Cross-view selection sync
DiagnosticTmpyToggleChanged Any diagnostic form IsRight / source form name TMPY toggle state sync
BiteErrorEvent BiteNLogTarget NLog event fields BITE diagnostic bridge

Subscriber Actor Catalogue

The subscriber actors live in A320_FMGC/Forms/TrajectorySubscriberActor.vb. They are the bridge between the Akka EventStream and the WinForms UI thread.

Actor Subscribes To Forwards To Throttling
SideViewSubscriberActor TrajectoryResult frmSideView.OnTrajectoryResult 3 s minimum interval (dropped silently if within window)
SideViewCfpSubscriberActor ComputedFlightPlanResult, TmpyComputedFlightPlanResult, TmpyComputedFlightPlanCleared, DiagnosticTmpyToggleChanged frmSideView.OnComputedFlightPlan / OnTmpyComputedFlightPlan / OnTmpyCleared / OnTmpyToggleSync Deduplicates by ComputedAt timestamp
SideViewPathSubscriberActor BuildResultPublished, TmpyBuildResultPublished frmSideView.OnPathUpdated (ACT) / OnTmpyPathUpdated (TMPY) Deduplicates by ComputedAt
MapViewSubscriberActor TrajectoryResult frmMapView.OnTrajectoryResult 3 s minimum interval
MapViewCfpSubscriberActor same as Side View CFP actor frmMapView equivalents Deduplicated
MapViewPathSubscriberActor BuildResultPublished, TmpyBuildResultPublished frmMapView.OnPathUpdated (ACT) / OnTmpyPathUpdated (TMPY) Deduplicated
RawFplnBuildResultSubscriberActor BuildResultPublished, TmpyBuildResultPublished, ComputedFlightPlanResult, TmpyComputedFlightPlanResult frmRawFpln.OnDisplayFlightPlanUpdated(msg.Result.Display) and the legacy CFP handler Deduplicated
TrajectoryLogSubscriberActor TrajectoryResult frmTrajectoryLog.OnTrajectoryResult 3 s minimum interval
DiagnosticSelectionSubscriberActor DiagnosticSelectionChanged Generic callback delegate — each form supplies its own No throttling (low rate)
BiteSubscriberActor BiteErrorEvent frmBITE No throttling
StatusSubscriberActor StartupProgress, INET state frmMain status strip No throttling

WireToActorSystem Pattern

All diagnostic forms follow an identical wiring protocol that ensures the form's window handle exists before any subscriber actor begins receiving messages.

Critical Ordering

' CORRECT: Show() first, then WireToActorSystem()
_sideViewForm = New A320_FMGC.Forms.frmSideView()
_sideViewForm.Show()                                  ' Creates window handle
_sideViewForm.WireToActorSystem(_actorSystem)         ' Creates subscribers
  1. Show() is called first — this creates the Win32 window handle (IsHandleCreated = True).
  2. WireToActorSystem(system) is called immediately after — each ActorOf(...) call creates a subscriber actor whose PreStart() subscribes to the EventStream.
  3. Every subscriber actor checks IsDisposed = False AndAlso IsHandleCreated = True on the target form before every BeginInvoke call.

If the order is reversed, the actor could receive messages and call BeginInvoke on a form with no window handle, causing an InvalidOperationException.

frmSideView Wiring

frmSideView.WireToActorSystem (frmSideView.vb:39) creates four actors:

_subscriberActor    = system.ActorOf(Props.Create(Of SideViewSubscriberActor)(Me), ...)
_cfpSubscriberActor = system.ActorOf(Props.Create(Of SideViewCfpSubscriberActor)(Me), ...)
_pathSubscriberActor = system.ActorOf(Props.Create(Of SideViewPathSubscriberActor)(Me), ...)
_selectionSubscriber = system.ActorOf(Props.Create(Of DiagnosticSelectionSubscriberActor)(Me, ...), ...)

frmMapView mirrors this pattern with its own three actors plus the selection subscriber. frmRawFpln creates the RawFplnBuildResultSubscriberActor plus TMPY / kernel-state / startup-progress subscribers.

Side View (frmSideView)

frmSideView renders the 4D trajectory altitude profile as a line chart using the ScottPlot.WinForms FormsPlot control.

Data Sources

Data Source Used For
Profile points (speed overlay, selection snap) TrajectoryResult via SideViewSubscriberActor Speed profile scatter line, cross-view selection hit-testing, _allProfilePoints cache
Named waypoint labels and VNAV markers ComputedFlightPlanResult via SideViewCfpSubscriberActor Phase-colored waypoint labels, TMPY overlay when the toggle is on
Trajectory path line and abeam labels BuildResultPublished.Result.Path via SideViewPathSubscriberActor Phase-split climb/cruise/descent scatter lines and abeam-projected waypoint labels

Chart Rendering

OnTrajectoryResult(result) caches the result as _latestResult, clears the plot, and rebuilds the chart from the active Layer 2 path points (ACT or TMPY depending on _tmpyViewActive):

  1. Walk _latestPathPoints in strict list order — no sorting, no OrderBy. The list from ComputedFlightPlanBuilder is already chronologically ordered, deduplicated, and phase-tagged.
  2. Split into three phase-contiguous runs: Climb (xs+ys), Cruise, Descent. Track maxAlt.
  3. Emit three scatter lines:
    • Climb — green (#009900), 2 px
    • Cruise — blue (#0066CC), 2 px, prepended with the last climb point so the segment connects at T/C
    • Descent — amber (#CC6600), 2 px, prepended with the last cruise/climb point so the segment connects at T/D
  4. Add vertical dashed T/C and T/D marker lines (#CC0000) at result.TopOfClimbDistanceNm / TopOfDescentDistanceNm.
  5. Axis: X 0→maxDist * 1.02, Y 0→maxAlt + 1000, until the user zooms (_userHasZoomed).
  6. Optional grey dotted speed profile from _allProfilePoints IasKts, if chkSpeedProfile is checked.

Layer 2 Waypoint Labels (Abeam Projection)

After the phase lines are drawn, the form walks the active path points a second time and emits a ScottPlot marker + text label for every path point with a non-null WaypointName — except points whose name starts with ** (raw curve-geometry tags). Abeam-tagged CurvePoints (carrying a plain ident from abeam projection) are rendered with labels and are clickable:

For Each pt In activePathPoints
    If pt.WaypointName Is Nothing Then Continue For
    If pt.AltitudeFt <= 0 Then Continue For
    If pt.WaypointName.StartsWith("**") Then Continue For
    ' ... marker + text label ...
Next

OnPathUpdated triggers a full chart rebuild via OnTrajectoryResult(_latestResult) when a cached result exists, so the side view populates instantly when Layer 2 path points arrive — without waiting for the next throttled (3 s) TrajectoryResult.

Mouse Interaction

  • Left-click selects the nearest active path point (ACT or TMPY) by distance-from-departure delta and shows a red open-circle marker. CurvePoints are clickable when they carry a non-** waypoint name (abeam-tagged).
  • The click publishes a DiagnosticSelectionChanged message for cross-view sync.
  • A frmPointInfo popup opens on mouse-down (not requiring a second click on an already-selected point) and closes on mouse-up.
  • Mouse wheel disables auto-scaling by setting _userHasZoomed = True.

Map View (frmMapView)

frmMapView renders the lateral flight path on a geographic grid using GDI+ custom painting.

Rendering Architecture

The map panel (pnlMap) uses double-buffering enabled via reflection on OnLoad. The Panel.Paint handler projects lat/lon to panel pixels using a simple equirectangular projection with scale, pan offset, and zoom factor maintained as form-level state.

Data Sources

Map View subscribes to the same three actor types as Side View:

Data Source Used For
Raw profile points TrajectoryResult via MapViewSubscriberActor Bounding box, selection snap, fallback rendering
Named waypoints + VNAV markers ComputedFlightPlanResult via MapViewCfpSubscriberActor Waypoint dots and labels
Layer 2 path BuildResultPublished.Result.Path via MapViewPathSubscriberActor Phase-colored track line, abeam-projected labels

Track Line Rendering

Paint walks the active path points (_latestPathPoints or _tmpyPathPoints when TMPY is active) in order, classifies each point by phase, and draws connected segments in the three phase colours. Internal points contribute vertices to the track line but are not individually marked. CurvePoints are rendered inline as part of the arc segment — no separate dot styling.

Waypoint Dot Rendering

Source Rendering
Layer 1 Normal / Adep / Ades / procedure legs 8 px black dot with dark-blue ident label
VnavMarker (T/C, T/D, SPDLIM, DECEL) Magenta dot with ident label in parentheses
Layer 2 path point with WaypointName (abeam projected) Grey 6 px dot with grey ident (subdued)
Internal / unlabeled path points Not drawn individually

Mouse Interaction

Left-click hit-tests the nearest active path point (ACT or TMPY) by pixel distance (30 px hit radius) on mouse-down, publishes DiagnosticSelectionChanged, and shows a frmPointInfo popup immediately. The TMPY toggle (controlled by frmComputedFlightPlan) switches both the path line/dot rendering and click hit-testing between active and TMPY data.

Raw FPLN (frmRawFpln)

frmRawFpln replaces the three separate FPLN-family diagnostic forms from before Phase 27. It presents three tabs:

Tab Content Source
RAW Every leg from FlightPlanActor.GetAllLegs(): 14 columns including leg type, ident, course, distances, constraints, ARINC command, procedure identifier, altitude/speed limits RawFplnTmpySubscriberActor (TMPY events) and direct FlightPlan Ask
DISPLAY Layer 1 BuildResult.Display: named waypoints, VNAV markers (T/C, T/D, SPDLIM, DECEL), structural legs. 18 columns including phase-colored rows and predicted IAS/Alt/GS/ETA/FF/VS RawFplnBuildResultSubscriberActor via OnDisplayFlightPlanUpdated(msg.Result.Display)
MCDU Legacy ComputedFlightPlanResult list, identical format to Display but sourced from the legacy message for consumers that still depend on it Same subscriber, legacy branch

Test Menu

The Test menu is enabled at SEQ 6 (NavDb fully loaded, observed via RawFplnStartupProgressSubscriberActor):

Item Action
SAVE FPLN Serialise the current computed FPLN to JSON (uses cached CI / CRZ FL from KernelStateSnapshot)
LOAD FPLN Deserialise JSON, call RequestTrajectoryRecompute with a plan override
TMPY ACTIVATE / TOGGLE Activates a TMPY plan for testing; the TMPY/ACT toggle on frmComputedFlightPlan controls all views

Status Bar

The status bar shows: {planSource}Layer 1 FPLN — {legCount} legs where planSource is "TMPY " when the TMPY toggle is active, blank otherwise. It updates on every OnDisplayFlightPlanUpdated call.

BITE Diagnostics (frmBITE)

frmBITE is the Built-In Test Equipment diagnostic form. It captures NLog Warn/Error/Fatal events from the running actor system and displays them without crashing the application.

BiteNLogTarget

BiteNLogTarget is a custom NLog target registered in frmMain at application startup. It receives all Warn/Error/Fatal log events from the NLog pipeline, enqueues them in a ConcurrentQueue, and publishes a BiteErrorEvent to the Akka EventStream.

BiteSubscriberActor

BiteSubscriberActor subscribes to BiteErrorEvent on the EventStream and forwards each event to frmBITE via BeginInvoke.

ListView Display

Four columns — Timestamp (HH:mm:ss.fff), Level (Warn / Error / Fatal), Logger (fully qualified NLog logger name), Message. Row background colours: yellow / orange-red / red. Selecting a row shows the full entry including exception callstack in a detail text box. The form updates on a 500 ms timer (tmrBiteDrain) that drains BiteNLogTarget.DrainEntries().

Diagnostics Menu

BuildDiagnosticsMenu() in frmMain builds the Diagnostics menu with grouped sub-menus:

Diagnostics
├── Side View
├── Map View
├── ─────────
├── FPLN          ►  RAW FPLN
│                    Trajectory Log
├── SEC FPLN      ►  RAW SEC FPLN
├── ─────────
├── BITE
├── ─────────
└── SHOW DEBUG       (opens RAW FPLN, Trajectory Log, Map View, Side View in 2×2 quadrant layout)

Cross-View Selection Sync

DiagnosticSelectionChanged message fields:

Field Type Purpose
LegIndex Integer? Flight plan leg index; Nothing for pseudo-waypoints
DistanceFromDepartureNm Double Primary match key for trajectory points
AltitudeFt Double For Side View marker placement
Latitude / Longitude Double For Map View marker and lat/lon-based matching
SourceFormName String Echo prevention — receivers skip their own events

DiagnosticSelectionSubscriberActor is a generic subscriber. Each form creates its own instance with a callback delegate.

TMPY Toggle Sync

DiagnosticTmpyToggleChanged synchronizes the TMPY/Active FPLN state from the master toggle on frmComputedFlightPlan to all other diagnostic forms:

Field Type Purpose
IsRight Boolean Toggle position: True = TMPY, False = Active FPLN
SourceFormName String Echo prevention

Only frmComputedFlightPlan publishes this message (from its SlideToggle handler and auto-switch logic). The other three forms (frmRawFpln, frmMapView, frmSideView) receive it via OnTmpyToggleSync and update their internal _tmpyViewActive state — they have no toggle control of their own.

Point Info Popup

frmPointInfo is a borderless auto-sized popup form that displays all fields of a ComputedFlightPlanLeg (or a ProfilePoint) in a monospace Consolas 9 pt layout on a light beige background. In both Map View (30 px hit radius) and Side View, left-click immediately selects the nearest point and shows the popup on mouse-down; releasing the mouse button dismisses it. Fields displayed include: ident, type, phase, lat/lon, ARINC command, course, constraints, all prediction values (including ETA as HH:MM:SS), fuel flow (kg/h), vertical speed (fpm), performance data source (MDB or Fallback), and distance metrics.

Performance Optimisations

Long routes (e.g. EDDF–LPMA, 1500 NM) produce ~300 intermediate trajectory points. Three optimisations prevent UI overload:

A — Throttled Subscriber Actors : Raw TrajectoryResult subscribers (SideViewSubscriberActor, MapViewSubscriberActor, TrajectoryLogSubscriberActor) enforce a 3 s minimum interval between UI forwards. Messages within the throttle window are silently dropped at the actor level. KernelActor / McduActor are not throttled. : BuildResultPublished / ComputedFlightPlanResult subscribers compare the ComputedAt timestamp and skip messages with the same timestamp as the last forwarded message. These actors also subscribe to the TMPY equivalents and to DiagnosticTmpyToggleChanged.

B — ScottPlot Phase-Split Scatter Lines : In frmSideView, each phase is drawn as a single plt.Add.ScatterLine(xs, ys) call (three plottables total for climb/cruise/descent) instead of one plottable per point. Named-waypoint labels are added as individual markers but only for points with a non-null WaypointName.

C — Double-Buffered GDI+ Panels : frmMapView.pnlMap is double-buffered via reflection to prevent flicker during redraws.

Source Files

File Purpose
A320_FMGC/Forms/frmSideView.vb ScottPlot altitude profile; Layer 2 phase-colored scatter lines; abeam-projected labels (CurvePoints skipped); click-and-hold popup
A320_FMGC/Forms/frmMapView.vb GDI+ lateral map; Layer 2 path rendering; waypoint labels from Layer 1 + abeam projection; click-and-hold popup
A320_FMGC/Forms/frmRawFpln.vb Raw + Display + MCDU tabs; Test menu (SAVE / LOAD / TMPY); status bar with layer 1 leg count
A320_FMGC/Forms/frmTrajectoryLog.vb Per-step trajectory computation data; TrajectoryResult subscriber; selection sync
A320_FMGC/Forms/frmBITE.vb BITE diagnostic form; ListView drain; error detail display
A320_FMGC/Forms/frmPointInfo.vb Borderless auto-sized popup; displays all ComputedFlightPlanLeg fields
A320_FMGC/Forms/DiagnosticSelectionModels.vb DiagnosticSelectionChanged, DiagnosticTmpyToggleChanged message classes
A320_FMGC/Forms/TrajectorySubscriberActor.vb All subscriber actors: SideView / MapView / RawFpln / TrajectoryLog / DiagnosticSelection + path and CFP variants
A320_FMGC/Forms/StatusSubscriberActor.vb Subscribes to StartupProgress for frmMain status bar
A320_FMGC/Forms/BiteSubscriberActor.vb EventStream bridge for BITE error events
A320_FMGC/Forms/BiteNLogTarget.vb Custom NLog target; enqueues events and publishes to EventStream
A320_FMGC/frmMain.vb BuildDiagnosticsMenu(); ShowDebugQuadrants(); StatusStrip; form creation and wiring
A320_FMGC/Kernel/KernelMessages.vb BiteErrorEvent message class
A320_FMGC/FlightPlan/ComputedFlightPlanMessages.vb ComputedFlightPlanResult, BuildResultPublished, TmpyComputedFlightPlanResult, TmpyBuildResultPublished, TmpyComputedFlightPlanCleared