Files
updated-radar/DESIGN.md
2026-05-10 09:14:59 -07:00

4.8 KiB

Radar Exhibit — Design Document

Hardware target

  • Geekom A8 Max: AMD Ryzen 9 8945HS, Radeon 780M (Mesa/RADV), 32 GB RAM
  • Ubuntu 25.10, g++ 15.2.0, C++20, OpenGL 4.3 Core

Screen layout

Three fixed regions rendered with glViewport + glScissor:

Region Content
Left panel Text description, control list (white text; red labels; pink keystrokes)
Right panel — upper Radar scope
Right panel — lower Status bar: range, bearing, scope ID (yellow text)

Scope sequence (cycled with keys 1 / 2)

  1. Exhibit introduction (text only)
  2. Chain Home A-Scope (1940s)
  3. Marine A-Scope (1940s)
  4. PPI — stationary marine traffic control
  5. PPI — on-board boat

Each scope's control state is independent and resets on re-entry.


Radar equation

P_r = \frac{P_t G^2 \lambda^2 \sigma}{(4\pi)^3 R^4}

Signal strength falls off with 1/R^4. Each radar type has fixed hardware loop gain baked into its shader set as a constant.


Controls (keyboard until physical panel is built)

Key Action
1 / 2 Next / previous scope
3 / 4 Intensity down / up
5 / 6 Receiver sensitivity down / up
q / w STC sensitivity down / up
e / r STC range down / up
t / y Radiogoniometer left / right (Chain Home only)
u / i Max range down / up (all except Chain Home)
o / p Range cursor down / up (PPI only)
a / s Bearing cursor CCW / CW (PPI only)
d / f Antenna bearing CCW / CW (Marine A-Scope only)

Notes:

  • Radiogoniometer, marine antenna bearing, and PPI bearing cursor share one physical knob on the eventual panel; kept separate in software.
  • Range cursor ≠ max range: max range is the radar's selected range setting; range cursor is the measurement cursor on the PPI display.

Scope specifications

Chain Home A-Scope

  • Fixed range: 200 miles
  • No graticule; crystal-oscillator range pips every 20 miles (operator cannot change)
  • Bearing via radiogoniometer simulation: operator finds null point; bearing shown as text below scope
  • Two perpendicular antenna sets (N-S, E-W); radiogoniometer angle determines which target pip goes to null

Marine A-Scope

  • Ranges: 1.5 / 3.0 / 6.0 / 12.0 miles
  • Range pips: every 0.25 / 0.5 / 1.0 / 2.0 miles respectively (fixed oscillator; not affected by range setting)
  • No graticule
  • Bearing by rotating simulated dish/horn antenna (d/f keys)
  • Pip shape: finite rise, fixed-width pulse, finite fall — curved waveform, not a vertical line

PPI scopes (both)

  • 360° sweep with phosphor persistence via FBO (semi-transparent black quad each frame; no full clear)
  • Range cursor and bearing cursor overlay

Stationary (marine traffic control)

  • Fixed observer position; targets move relative to scope center

On-boat

  • Observer is scope center; heading-up display — world rotates as boat heading changes
  • Boat position/heading supplied from GDAL/PostgreSQL data

Architecture

Class hierarchy (State pattern)

BaseScope          — intensity, sensitivity, STC vars, virtual render/update
├── AScope         — horizontal sweep, curved pip waveform
│   ├── ChainHomeScope   — radiogoniometer, fixed 200 mi range, 20 mi pips
│   └── MarineAScope     — antenna bearing knob, 4 range settings
└── PPIScope       — 360° sweep, FBO persistence, range/bearing cursors
    ├── StationaryPPI
    └── OnBoatPPI        — heading offset passed into shader

Threading model

Thread Responsibility
Render (main) OpenGL loop, GLFW input, all glDraw* calls — never blocks
Simulation Polls target_data (PostgreSQL) and GDAL; updates shared std::vector<Target> under std::mutex

FBO phosphor decay

  • Render sweep into FBO each frame
  • Blit FBO to screen
  • Do not clear color buffer between frames; draw full-screen quad at very low alpha (~0.05) to decay old sweeps

Shader notes

  • GL_DEBUG_OUTPUT + glDebugMessageCallback enabled at startup (GPU robustness protocol)
  • No NVIDIA-specific extensions; Mesa/RADV only
  • 1/R^4 attenuation computed in fragment shader; hardware loop gain is a per-scope uniform constant

File structure

new-radar/
├── CMakeLists.txt
├── src/          — .cpp source files
├── include/      — .h/.hpp headers
│   ├── glad/
│   └── KHR/
├── glad/src/     — glad.c (bundled)
├── shaders/      — .vert / .frag files
├── data/         — patrol_route.json, etc.
└── map/
    ├── charts_enc/   — ENC .000 and GeoTIFF files
    └── lidar_raw/    — LIDAR zips

Database

  • PostgreSQL, database radar, user radar, password radar
  • Table target_data: polled by simulation thread for live target positions