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
frmRawFplnshows 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
Show()is called first — this creates the Win32 window handle (IsHandleCreated = True).WireToActorSystem(system)is called immediately after — eachActorOf(...)call creates a subscriber actor whosePreStart()subscribes to the EventStream.- Every subscriber actor checks
IsDisposed = False AndAlso IsHandleCreated = Trueon the target form before everyBeginInvokecall.
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):
- Walk
_latestPathPointsin strict list order — no sorting, noOrderBy. The list fromComputedFlightPlanBuilderis already chronologically ordered, deduplicated, and phase-tagged. - Split into three phase-contiguous runs: Climb (xs+ys), Cruise, Descent. Track
maxAlt. - 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
- Climb — green (
- Add vertical dashed T/C and T/D marker lines (
#CC0000) atresult.TopOfClimbDistanceNm/TopOfDescentDistanceNm. - Axis: X 0→
maxDist * 1.02, Y 0→maxAlt + 1000, until the user zooms (_userHasZoomed). - Optional grey dotted speed profile from
_allProfilePointsIasKts, ifchkSpeedProfileis 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
DiagnosticSelectionChangedmessage for cross-view sync. - A
frmPointInfopopup 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 |