diff --git a/CLAUDE.md b/CLAUDE.md index 0789cc0..e54d4d9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -78,7 +78,11 @@ struct target_data_structure { TargetType type; }; -To optimize memory bandwidth on the Radeon 780M GPU, the traffic_cop packs raw telemetry down into a lightweight structure passed directly into a standard OpenGL Shader Storage Buffer Object (SSBO) with a layout(std430) alignment.C++struct target_data_to_shader_structure { +To optimize memory bandwidth on the Radeon 780M GPU, the traffic_cop packs raw telemetry +down into a lightweight structure passed directly into a standard OpenGL Shader +Storage Buffer Object (SSBO) with a layout(std430) alignment. + +C++struct target_data_to_shader_structure { float target_x; // Local Cartesian offset East (meters from radar origin) float target_y; // Local Cartesian offset North (meters from radar origin) float length; // Vessel length bounding box size (meters) @@ -87,7 +91,76 @@ To optimize memory bandwidth on the Radeon 780M GPU, the traffic_cop packs raw t float altitude; // Target altitude profile (meters) long long timestamp;// Data alignment padding field }; -Ingestion ProtocolThread Isolation: The traffic_cop handles parsing, scaling, and double-buffering completely isolated on its own thread to prevent blocking the frame rendering pipeline.Precision Correction: Coordinate projections (converting Lat/Long maps to local relative meters) are performed on the CPU using double-precision calculations before passing parameters down as 32-bit floating-point numbers to protect against rounding distortions.Boundary & Ceiling Filters: Targets residing beyond the selected scope's maximum range are immediately culled. Marine installations enforce an absolute <= 40-meter altitude cap; any aircraft target exceeding this height is dropped.Synchronized Dispatch: The traffic_cop writes updates into the graphics pipeline using a std::mutex critical section precisely when the PPI radar line swings past 0.0 radians (True North).4. Operational Exhibit ScopesUsers step through the available scope list in a continuous loop using the forward (1) and backward (2) keys. Scopes reset to their baseline parameters upon entry.Exhibit Introduction: Displays static informational text on the left panel. The right view panel remains blank until navigation keys are pressed.Chain Home A-Scope (1940s): Simulated 1D electrostatic vector trace. Features an inverted top-down baseline. All video signals deflect downward. Includes crystal-controlled 20-mile reference pips and a wide $150^\circ$ floodlight footprint. Target azimuth coordinates are evaluated manually via a radiogoniometer search coil nulling control.Marine A-Scope (1940s): Represents early surface-search systems like the British Type 271. Features a bottom-up baseline trace showing signal power versus range. The antenna is rotated manually using a servo motor console knob to sweep for target peak voltages.Marine Traffic Control PPI Scope (1960s): Stationary shore installation tracking Bellingham Bay. Features a high-power $25\text{ kW}$ transmitter, a highly directional 12-foot linear waveguide array ($0.7^\circ$ horizontal beamwidth), and a slow 15 RPM rotation rate. The screen top is locked to True North.Shipborne Marine PPI Scope (1960s): Simulates a moving patrol boat or Coast Guard cutter. Features a $15\text{ kW}$ tactical transmitter, a 4-to-6-foot antenna ($1.2^\circ$ horizontal beamwidth), and a fast 25 RPM sweep. The screen top is locked to the vessel's bow, and the graticule ring dynamically adjusts using gyrocompass inputs.5. Shader Modularization StrategyThe rendering engine decomposes processing tasks across distinct, optimized shader sets to isolate raw signal generation from persistent phosphor simulations. [Target SSBO Data] & [GDAL Elevation Maps] + +Ingestion ProtocolThread Isolation: + +The traffic_cop handles parsing, scaling, and double-buffering completely +isolated on its own thread to prevent blocking the frame rendering pipeline. + +Precision Correction: Coordinate projections (converting Lat/Long maps to +local relative meters) are performed on the CPU using double-precision +calculations before passing parameters down as 32-bit floating-point +numbers to protect against rounding distortions. + +Boundary & Ceiling Filters: + +Targets residing beyond the selected scope's maximum range are immediately culled. +Marine installations enforce an absolute <= 40-meter altitude cap; any +aircraft target exceeding this height is dropped. + +Synchronized Dispatch: + +The traffic_cop writes updates into the graphics pipeline using a +std::mutex critical section precisely when the PPI radar +line swings past 0.0 radians (True North). + +4. Operational Exhibit Scopes + +Users step through the available scope list in a continuous loop using the +forward (1) and backward (2) keys. + +Scopes reset to their baseline parameters upon entry. + +Exhibit Introduction: Displays static informational text on the left panel. + +The right view panel remains blank until navigation keys are pressed. + +Chain Home A-Scope (1940s): + +Simulated 1D electrostatic vector trace. Features an inverted top-down baseline. All video signals +deflect downward. Includes crystal-controlled 20-mile reference pips and a +wide $150^\circ$ floodlight footprint. + +Target azimuth coordinates are evaluated manually +via a radiogoniometer search coil nulling control. + +Marine A-Scope (1940s): + +Represents early surface-search systems like the British Type 271. Features a + +bottom-up baseline trace showing signal power versus range. The antenna is +rotated manually using a servo motor console knob to sweep for target peak voltages. + +Marine Traffic Control PPI Scope (1960s): + +Stationary shore installation tracking Bellingham Bay. Features a high-power $25\text{ kW}$ +transmitter, a highly directional 12-foot linear waveguide array ($0.7^\circ$ horizontal beamwidth), +and a slow 15 RPM rotation rate. The screen top is locked to True North. + +Shipborne Marine PPI Scope (1960s): + +Simulates a moving patrol boat or Coast Guard cutter. Features a $15\text{ kW}$ tactical +transmitter, a 4-to-6-foot antenna ($1.2^\circ$ horizontal beamwidth), and a +fast 25 RPM sweep. The screen top is locked to the vessel's bow, +and the graticule ring dynamically adjusts using gyrocompass inputs. + +5. Shader Modularization Strategy + +The rendering engine decomposes processing tasks across distinct, optimized +shader sets to isolate raw signal generation from persistent phosphor +simulations. + +[Target SSBO Data] & [GDAL Elevation Maps] │ ▼ ┌──────────────────────────────────────────────────┐ @@ -106,58 +179,28 @@ Ingestion ProtocolThread Isolation: The traffic_cop handles parsing, scaling, an │ PASS C: Orthographic 2D UI & Graticule Overlay │ │ (Applies Backlit Vector Rings and Text Overlays) │ └──────────────────────────────────────────────────┘ -Pass A (Signal Generation & Terrain Pipeline): Evaluates the radar equation, target cross-sections, and landscape masks on a per-pixel basis. It writes output results directly into a high-precision floating-point Framebuffer Object (FBO) texture, preventing signal clipping and rounding artifacts.Pass B (P7 Phosphor Integration & Persistence Pass): Emulates vintage cathode-ray tube long-persistence phosphors. It blends the newly generated excitation texture from Pass A into a historical ping-pong frame buffer tracking multi-stage exponential decay.Pass C (Orthographic 2D UI & Graticule Overlay): Draws edge-lit vector rings, angular graduation marks, baseline coordinates, and text glyph textures directly onto screen coordinates.6. Complete Compilation Blueprint Natively for UbuntuCMakeLists.txtCMakecmake_minimum_required(VERSION 3.22) -project(RadarSimulator SYSTEM CXX) -# Target configuration details: Mark Allyn, 2026 -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) +Pass A (Signal Generation & Terrain Pipeline): -# Enforce architectural optimizations for the Geekom A8 Max (Ryzen 9 8945HS) -if(CMAKE_COMPILER_IS_GNUCXX) - add_compile_options(-Wall -Wextra -O3 -march=native -pthread) -endif() +Evaluates the radar equation, target cross-sections, and landscape masks on a +per-pixel basis. It writes output results directly into a high-precision +floating-point Framebuffer Object (FBO) texture, preventing signal clipping and +rounding artifacts. -# Find systemic hardware dependencies inside Ubuntu -find_package(PkgConfig REQUIRED) -pkg_check_modules(FREETYPE REQUIRED freetype2) -pkg_check_modules(GLFW3 REQUIRED glfw3) +Pass B (P7 Phosphor Integration & Persistence Pass): -find_package(PostgreSQL REQUIRED) +Emulates vintage cathode-ray tube long-persistence phosphors. It blends the +newly generated excitation texture from Pass A into a historical ping-pong +frame buffer tracking multi-stage exponential decay. -find_path(GDAL_INCLUDE_DIR gdal.h PATH_SUFFIXES gdal) -find_library(GDAL_LIBRARY NAMES gdal) +Pass C (Orthographic 2D UI & Graticule Overlay): -if(NOT GDAL_LIBRARY OR NOT GDAL_INCLUDE_DIR) - message(FATAL_ERROR "GDAL structural development assets not found in ecosystem.") -endif() +Draws edge-lit vector rings, angular graduation marks, baseline coordinates, +and text glyph textures directly onto screen coordinates.6. -# Define the primary radar simulator executable target -add_executable(radar_simulator - main.cpp - settings.h -) +Settings file used for troubleshooting and tuning parameters without +having to re-compile. -# Explicit target layout inclusion bounds -target_include_directories(radar_simulator PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} - ${FREETYPE_INCLUDE_DIRS} - ${GLFW3_INCLUDE_DIRS} - ${PostgreSQL_INCLUDE_DIRS} - ${GDAL_INCLUDE_DIR} -) - -# Core library synchronization -target_link_libraries(radar_simulator PRIVATE - ${GLFW3_LIBRARIES} - ${FREETYPE_LIBRARIES} - ${PostgreSQL_LIBRARIES} - ${GDAL_LIBRARY} - GL - dl - pthread -) settings.hC++/* * MIT License * Copyright (c) 2026 Mark Allyn @@ -260,6 +303,7 @@ namespace MarineBoatPPI { const float ANTENNA_RPM = 25.0f; /* 25 RPM high-frequency sweep */ const float ANTENNA_GAIN = 1258.93f; /* 31 dB linear converter multiplier */ } + main.cppC++/* * MIT License * Copyright (c) 2026 Mark Allyn diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 562a384..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,59 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -project(new-radar LANGUAGES C CXX) - -set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) - -# Output binaries to build/bin -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) - -# ── Find system packages ────────────────────────────────────────────────────── -find_package(OpenGL REQUIRED) -find_package(glfw3 REQUIRED) -find_package(Freetype REQUIRED) -find_package(GDAL REQUIRED) - -# PostgreSQL (libpq) -find_package(PostgreSQL REQUIRED) - -# ── GLAD (bundled) ──────────────────────────────────────────────────────────── -add_library(glad STATIC glad/src/glad.c) -target_include_directories(glad PUBLIC ${CMAKE_SOURCE_DIR}/include) - -# ── Collect sources ─────────────────────────────────────────────────────────── -file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS src/*.cpp) - -# ── Main executable ─────────────────────────────────────────────────────────── -add_executable(radar ${SOURCES}) - -target_include_directories(radar PRIVATE - ${CMAKE_SOURCE_DIR}/include - ${FREETYPE_INCLUDE_DIRS} - ${GDAL_INCLUDE_DIRS} - ${PostgreSQL_INCLUDE_DIRS} -) - -target_link_libraries(radar PRIVATE - glad - OpenGL::GL - glfw - Freetype::Freetype - ${GDAL_LIBRARIES} - ${PostgreSQL_LIBRARIES} - pthread -) - -# ── Compiler flags ──────────────────────────────────────────────────────────── -target_compile_options(radar PRIVATE - -Wall - -Wextra - -Wpedantic - $<$:-g -O0> - $<$:-O2> -) - -# AMD Radeon 780M uses Mesa; no vendor-specific extensions -target_compile_definitions(radar PRIVATE - GL_GLEXT_PROTOTYPES -) diff --git a/DESIGN.md b/DESIGN.md deleted file mode 100644 index a1736c3..0000000 --- a/DESIGN.md +++ /dev/null @@ -1,145 +0,0 @@ -# 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` 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 diff --git a/build_progress.md b/build_progress.md deleted file mode 100644 index e69de29..0000000 diff --git a/claude.save b/claude.save deleted file mode 100644 index 6ded8ae..0000000 --- a/claude.save +++ /dev/null @@ -1,1733 +0,0 @@ -Introduction: - -This is a project for a museum to demonstrate a simulation of a 1950's to 1960's -vintage marine radar and air traffic control radar - -The project will be implemented on a Geekom A8 Max -with AMD AI chip R9-8945HS with 32 GB ram - -# Project: C++ OpenGL Radar Simulation -**Environment:** Ubuntu Linux (Remote SSH from Windows) -**Tech Stack:** C++20, OpenGL 3.3 Core, GLFW, GLAD, FreeType, GDAL (libgdal-dev) - - -The operating system is Linux (Ubuntu) -Details: - -Distributor ID: Ubuntu -Description: Ubuntu 25.10 -Release: 25.10 -Codename: questing - -The compiler is cpp (Ubuntu 15.2.0-4ubuntu4) 15.2.0 - -We plan to use the cmake for building. - -Please add MIT license header to each file -Please add Author: Mark Allyn to each file - -Here is the directory structure with files already installed: -All directories are in the new-radar top level directory. The -entire directory list is /home/maallyn/new-radar on the Geekom. - -./shaders -./shaders/CLAUDE.md -./glad -./glad/src -./glad/src/glad.c -./include -./include/glad -./include/glad/glad.h -./include/CLAUDE.md -./include/KHR -./include/KHR/khrplatform.h -./new-claude -./README.md -./CMakeLists.txt -./build -./build/CLAUDE.md -./CLAUDE.md -./.new-claude.swp -./LICENSE -./src -./src/CLAUDE.md -./map -./map/lidar_processed -./map/charts_enc -./map/charts_enc/US5WA45M.000 -./map/charts_enc/n48_w123_1arc_v3.tif -./map/lidar_raw -./map/lidar_raw/wa2022_nooksack_dem_J1364940.zip -./map/lidar_raw/wa2016_west_dem_J1364939.zip - - -================================================================== - -GENERAL STUFF - -================================================================== - -COLORS - -1. P7 Strike Color (when things are written to p7 = Blue white Hex #F0F8FF -2. P7 Persistence (during persistence after strike = Yellow Hex #F2BF1C -3. All Graticules and PPI Cursors are incandescent #47 lamp Hex #FFF4CC - This is for bearing rings on ppi scope as well as bearing ticks and - bearing degree texts -4. Left Panel Text for description is white hex #FFFFFF except for controls - as described below -5. Control operation via keyboard key strokes are light red Hex #FFCCCB -6. Control operation description are light green #64E3A1 -7. Status text panel under scope are cyan hex #00FFFF -8. Note that all targets are to be p7; this includes land features and - active targets. Range rings on ppi are also p7 - Please note that range rings shall be fixed brightness; not affected - by sensitivity. -9. Range markings and range calibration pips shall be p7 on the chain - home scope. -10. Center line on precision approach radar horizontal and guide path - on precision approach radar vertical shall be p7 -11. Rain noise as well as water wave noise shall also be p7 and be - affected by gain as well as noise filtering controls -12. Please note for each color in this table, there shall be a variable - in the settings.h file that can be used to change the color. Values should be in hex. -13. The marine a scope display is p1 phosphor (green) -14. The chain home scope display is p2 phosphor (blue green with some persistence) - -================================================================== - -Please note that all on-screen text shall be white and fully -illuminated and is not subject to phosphor persistence or decay. - -Please note that direction as stated here are True directions. 000 is True North - -Maximum Range is 6 miles for marine type radar -Maximum Range is 20 miles for air traffic control radar. -Maximum Range is 100 miles for chain home -Maximum Range 10 miles for precision approach radar; graticule is - incandescent showing the azimuth path and elevation path as described - below in PAR description. Those graticules are etched glass for minimal - parallax - -The proposed location of the marine radar antenna is in the middle of Bellingham -Bay on a 100 foot platform. (This should be mentioned as fictitious in the description) -Location is 48.74361448950435 latitude, -122.56466911663048 longitude - -The proposed location of the air traffic control radar is the Bellingham -airport (BLI) control tower. Latitude: 48° 47' 33.7" N ; Longitude: 122° 32' 15.1" W - -The proposed location for the chain home would be at the original location on -the UK coast facing the European Continent - -The following types of scope will be used; (note that these are not all -going to show at once. They will be selectable using a push button (a letter on -the keyboard until I get physical buttons that are connected to a gpio pin. -The selection key should be s (short for scope) - -Please note that all keyboard based controls need to be described in each -scope's left hand text panel. These are different for each scope. Note that -the s for selecting a scope should be in each scope's description and what -would the next scope be. - -Also note that when the radar exhibit starts, the very first option will -be on the screen. Then the screen will advance through the scopes by two means; -the pressing of the s key by the user, or automatically at every 120 seconds. You will -need to emphasize in the first description that you can advance without waiting -for the automatic advancing by pressing the s key. You can reverse by hitting the S key -(upper case s) This should be articulated for the -description window for each scope. When the main exhibit descriptor screen comes up, it's -important to highlight the feature that the user can press the s key or the S key any time to 'hurry up' -the scope advancement. - -Please note that controls are used for the current scope that is selected. When you move to another scope or to scope -1 after leaving the Exhibit introduction screen; the controls must be reset for the scope you are entering - -Also ensure that the timeout clock will reset when the user changes to a new scope, or presses -any key or operates any control on the panel. This -should be articulated in the descriptive text - - - 1. Exhibit introduction - a text block describing the exhibit and the - basics on how to use it and what you are seeing. This should be text only. Top would - be in all caps, "WELCOME TO MUSEUM VINTAGE RADAR EXHIBIT" - - 2. Marine A-Scope - (horizontal axis is range; vertical axis is amplitude of - return pulse; bearing will be set via a bearing control; current implementation - would be two keys on the keyboard; one key to go clockwise on bearing and another - key would be to go counterclockwise. - The c key for clockwise on a scope and v for counterclockwise. - The step rate for this control, before the knob is implemented would be one or two - degrees per key press, but if the key is held down, it would increase slowly due to - how long the key is depressed - - The max range setting shall be included in the status text window below the scope - - The A scope graticule is manually swapped out at each maximum range value - by the operator during the period. Here we will have to fake it out. And that - graticule needs to have an incandescent color. That graticule will have three horizontal - graticule lines for estimating return pulse strength. The range lines (vertical lines) - must match the interim and final ranges as selected by the max range selection - To change maximum range, use key u for up and d for down. Possible settings are 2,4,6 - miles; this must be noted clearly on the description text. - - Max is 2; one interim range at 1 - Max is 4; one interim range at 2 - Max is 6; one interim range at 4 - - In addition to the blips for targets, there would be a floor of noise (signal received by - rain and waves. This needs to be shown. - - Graticule swap simulation: In the period, changing maximum range required the operator - to physically slide the glass graticule panel upward and out from in front of the CRT, - then slide the replacement graticule (calibrated for the new range) downward into position. - This must be simulated when the operator presses u or d to change range. - - The graticule swap animation uses four states: - NORMAL - graticule in place, scope operating normally - SLIDING_OUT - old graticule translates upward off screen (~0.5 seconds) - BARE_CRT - no graticule visible; CRT trace and noise floor still running - SLIDING_IN - new graticule (correct lines for new range) slides down into position (~0.5 seconds) - After SLIDING_IN completes, state returns to NORMAL with the new range active. - The u and d keys are ignored during the swap animation (operator's hands are busy). - The graticule remains incandescent color throughout — it is edge-lit glass. - - The sliding out, bare crt, and sliding in should all be settable in settings.h - - 3. Chain Home A Scope There is a second use of the a-scope. - That is for the early world war 2 chain home - radar. This operated very differently. You have a large array of high power transmitters - 'floodlighting' the target area (in World War 2, that would be the English Channel. - Since we don't care about land reflections with the original chain home setup was - facing the English Channel, we can tell visitors that this radar is set at the - English Channel (do this explanation on the explanation side panel for this - radar mode. And for simulating operator using this radar, there would be two controls, - one for the 'nulling the signal at the correct direction; simulating the behavior - of the goniometer and the other for using the goniometer for elevation. For museum - accuracy, we need to simulate the sharp 'null' when the goniometer is at the direction - of the signal. This concept needs to be covered in the description text thoroughly - as this is a bit advanced. I need your advice on how to do this for children and those - who never heard of chain home. - - The goniometer vertical and horizontal switch could be key [ for toggling. The goniometer tuning - would be 9 and 0 to avoid using the shift key. The tuning keys should have one unit - for single press, but a slow build of of speed if key is held down. This has to stay - slow due to the sudden appearance of the null. - - The status for goniometer switch shall be shown in the status text windo below - the scope as well as the goniometer setting in degrees as selected by the switch - - Targets for Chain Home would all have to be simulated as there will be no ais - nor ads-b. Simulations would show several aircraft approaching the radar in many - different directions and ranges. The museum visitor for exercise could try to sort - out the targets by range and bearing and elevation by the nulling procedure noted - above as well as the distance of the pulse from the origin. - - The graticule is etched glass (side lit with incandescent lights) with 10 mile - markers for range (horizontal axis). There are no vertical markers; the signal - strength value is not important. The only vertical value that is important is the - nulling of the signal based on bearing and elevation from the manipulation of the - goniometer. - - The refresh rates for chain home were slow in order to avoid aliasing with targets - far away, the pulse repetition frequency (PRF) is about 25 times per second. This - rate is 1/2 of the standard 50 Hz for British power. - - The operator did have a switch to switch from the 25 pulses per second PRF to 12.5 - pulses per second PRF so that they could help eliminate the range ambiguity - problem, where a target far away could appear to be right on site since that echo - would return at the precise time for the next pulse to go out at 25 PRF. This needs - to be explained in the explainer window for the chain home. Mention that mountains or planes - in the continent could have that kind of range. Furthermore, the operator can reduce - the PRF in order to reduce confusion caused by other radio transmissions such as press-to-talk - communications transmissions. - - Let's assign key . for toggling between 25 and 12.5 PRF. There is no range selection. - Note on description; this is to reduce use of the shift key. - - The setting for the range should be on the status text panel below the scope. - - Another unique feature would be a response to the drifting problem in early electronics. - The scope electronics would use a crystal calibrator that puts tiny pips or spikes at - known intervals (10 miles). The operator would use a knob, or control, to stretch or - shrink the electronic trace so that the 10 mile pips align perfectly with the 10 mile - marks on the edge lit glass graticule. - - Let's assign key n for shrink and m for stretch. (may be ambiguous, but I am running - out of keys. Note in the descriptor. - - 4. All PPI Scopes (common features) - All three ppi scopes (marine stationary; marine police boat; and Air Traffic Control - Have the following common features: - - When the operator changes max range (u/d keys), the new ring geometry - takes effect only for the sector the sweep is currently painting. The - rest of the scope still holds the old ring positions in the phosphor, - glowing and fading normally. As the sweep continues rotating, each - sector it reaches is repainted with the new ring geometry, replacing the - old. One full sweep rotation after the change, the transition is complete - and only the new rings remain. This is physically correct — the phosphor - holds whatever the beam last wrote. No special transition animation is - needed; the behavior emerges naturally from the phosphor model. - - Note on range. If cursor range is beyond max, clamp it to the max. - - Bear in mind that the max range setting is independent for both radars. - - The bearing graticule (lit incandescent) There should - be an inner circle with tickmarks for each degree, starting at 0 (north) and going - clockwise to the last tick, which is 359. Outside the inner ring shall be text - labels for every 15 degrees. Outside the text labels, there will be - an outer ring. Both inner and outer rings, along with ticks, and the bearing - labels are to be incandescent color. - - The sweep direction is clockwise, which means that the antenna - dish rotates clockwise. - - The scope has a cursor for range and bearing. The cursor consists of a - section of a ring ( 10 degrees) and a cross line for bearing. - The cursor should be yellow (it - a plastic overlay in the period time. Two controls control the cursor; range and - bearing. Both were physical crank controls. For now, both we need to use key pairs - on the keyboard. A white text indication of range and bearing should be put under - the scope. In the real day, it was a machanical readout. The key sequence would be - r for bearing to the right and l for bearing for the left; and t for higher range - and y for smaller range. These controls should have slow movement for single stroke; but - gradual for holding key down. - - 5. Marine PPI Scope specific items: - - This scope is for a fixed location marine radar. It is for marine traffic control. - The maximum range settings are 6 miles for the marine radar scope - Rings should be 2,4, and 6 miles for marine. - The max range settings for marine ppi will be u for up and d for - down. If you are in the marine ppi, you change only the max range for the marine - ppi. The possible max range values for - the marine radar are 2,4,6 - miles. - - Marine: - Max is 2; one interim range at 1, final ring at 2 - Max is 4; one interim range at 2, final ring at 4 - Max is 6; one interim range at 4, final ring at 6 - - - - 6. Police Patrol Boat PPI - - This scope shows the radar display aboard a simulated Bellingham Police - Department patrol vessel making its routine waterfront patrol. Unlike all - other scopes in this exhibit the radar origin is not fixed — it moves with - the boat, making this a genuinely different operational experience. - - THE PATROL VESSEL AND ITS RADAR - The vessel carries a professional-grade open-array radar: 6 kW peak power, - 24-inch open array, ~1.9° horizontal beamwidth, mounted 3–4 m above the - waterline on a flybridge or radar arch. This is a working law-enforcement - vessel, not a recreational boat; the equipment reflects that. The narrower - beamwidth (vs a recreational radome's 4–6°) gives better azimuth resolution - and less sea clutter per range cell — important when searching for small - targets such as kayakers and stand-up paddleboards near the ferry lane. - - MAX RANGE: 2 miles. Range steps: 0.5 / 1 / 2 miles. - The patrol mission is close-in situational awareness. The tight range steps - let the officer zoom into the marina entrance, Whatcom Waterway, or the - ferry lane without switching to a different scope. - - RADAR HORIZON: ~4.3 nm at 3.5 m antenna height. Range is mission-limited - (2 miles) rather than horizon-limited. - - PATROL ROUTE (v1 — open water only) - The simulated vessel follows a continuous back-and-forth patrol of the - working waterfront at variable speed. Entry into Squalicum Marina and - Whatcom Waterway is deferred to a future version; v1 stays in open water - where the radar geometry is straightforward. - - Speed by zone: - Open waterfront / ferry lane: 10 knots - Near docks and breakwater: 4 knots - Route (loaded from data/patrol_route.json at startup): - Whatcom Waterway entrance → ferry terminal → Boulevard Park → - Taylor Dock → Community Boating Center → reverse and repeat - - SMALL TARGET SCENARIO — FERRY LANE - The Bellingham terminal serves Alaska Marine Highway ferries up to 400 ft. - The simulator places a scripted stand-up paddleboarder on a slow drift - across the ferry departure lane, plus random kayakers near the harbor mouth. - These are marginal radar targets: low RCS, no metal, minimal freeboard. - At 10 kt approach in light chop the paddleboarder may show as a faint - intermittent blip or vanish into sea clutter entirely. Visitors can try the - wave clutter filter (keys 5/6) and observe how suppressing clutter can also - suppress the very target they are looking for. This is the central teaching - moment of this scope: radar does not see everything. - - DISPLAY ORIENTATION - Default is North-up (000° at top). The k/j keys rotate the display offset. - Matching the offset to the boat's heading puts the bow at the top — Head-up - mode. The left panel labels the current mode and shows the heading marker, - a white dashed line from scope center toward the bow, drawn after all - phosphor content so it never decays. - - The heading and the range max settings shall be indicated on the status text - panel below the scope - - TERRAIN AND BREAKWATER CLUTTER - The concrete Squalicum Harbor outer breakwater is a strong radar return and - a significant shadow-caster. Everything behind the breakwater from the - patrol boat's point of view is shadowed — no return. The marina interior is - not visible from open water. This is realistic and visible on the scope. - Coastline, piers, and the ferry terminal structure also appear as clutter. - Shadow masks are pre-computed for patrol route waypoints by - terrain_preprocess and selected at runtime by nearest-waypoint lookup. - - Left panel status (below description text): - Zone: [plain text, e.g. "Ferry lane — open waterfront"] - Boat pos: XX.XXXX°N XXX.XXXX°W - Boat heading: XXX°T - Boat speed: X.X kt - Display mode: North-up (or Head-up) - Cursor range: X.X nm - Cursor brg: XXX°T - Max range: X.X mi - - 7. Air Traffic PPI Scope - - - Rings should be 5,10,15,20 for the air traffic control radar. - The max range settings for air ppi will be u for up and d for - down. Use of these controls affect only the scope you are in. No other scopes are - affected. - The ranges for air traffic control radar are 5,10,15,20 - miles. - - Air Traffic Control: - Max is 5; one interim range; two total; rings at 2.5; final ring at 5 - Max is 10; four interim ranges, five total; 2,4,6,8; final ring at 10 - Max is 15; three interim ranges four total; 4,8,12; final ring at 15 - Max is 20, three interim ranges four total; 5,10,15; final ring at 20 - - Note on range. If cursor range is beyond max, clamp it to the max. - - Bear in mind that the max range setting is independent for both radars. - - The bearing graticule (lit incandescent) for the scopes are the same. There should - be an inner circle with tickmarks for each degree, starting at 0 (north) and going - clockwise to the last tick, which is 359. Outside the inner ring shall be text - labels for every 15 degrees. Outside the text labels, there will be - an outer ring. Both inner and outer rings, along with ticks, and the bearing - labels are to be incandescent color. - - The sweep time shall be 5 seconds for the - air traffic scope. - - The sweep direction on the scope is clockwise, which means that the antenna - dish rotates clockwise. - - The scope has cursor for range and bearing. The cursor consists of a - section of a ring ( 10 degrees) and a cross line for bearing. - Two controls control the cursor; range and - bearing. Both were physical crank controls. For now, both we need to use key pairs - on the keyboard. A white text indication of range and bearing should be put under - the scope. In the real day, it was a machanical readout. The key sequence would be - r for bearing to the right and l for bearing for the left; and t for higher range - and y for smaller range. - These controls should have slow movement for single stroke; but - gradual increase movement for holding key down. - - 8. Precision approach (PAR for short) - PAR was developed in WWII and matured in the 1950s. With a fixed 10 mile range, it was - controller who talked the pilot down verbally over radio, which means that the pilot - does not have to rely on any equipment on the plane itself to help with landing. - The display shows the full 10-mile approach path, but the controller's active guidance window - is roughly the last 5 miles, intensifying from about 2 miles out to touchdown. - This needs to be carefully explained on the explainer screen. - Let's locate this at the south end of Runway 16/34 landing at BLI and let's have the - active runway 34 (northbound landing) - - Locate at the end of Runway 16/34 - at Bellingham Airport (BLI). Two vertically stacked scopes share the - right panel. Top scope: azimuth (lateral deviation vs. range from - touchdown). Bottom scope: elevation (vertical deviation vs. range). - Both the azimuth scope and the elevation scope should be the same size - Both use P7 phosphor; graticules are incandescent etched glass. - Range: 10 miles maximum, fixed (no range change control). - Non-linear scale: inner 5 miles occupies 70% of horizontal width. - All targets are simulated. No cursor or bearing controls; PAR - has no bearing selection — it always points toward the runway. - Sweep rate: approximately 30 Hz alternating between azimuth and - elevation planes so that each will scan 1/15 th of a second. - -THREADS - -These are the threads of processes: - -1. Display initiation and operation (anything that 'touches' the display and the shaders) Thread 1 -2. Software that receives data for targets. Thread 2 (this is the traffic cop that polls the - raspberry pis. and the Simulator. This needs mutex access to shared data with thread 1. It will - also need mutex access to shared data with thread 4 (the simulator) -3. Knob panel - thread 3 - uses a mutex to write shared state variables that thread 1 reads - to send to the shaders. -4. Simulator, thread 4. It is polled by the traffic cop - -Threads 2,3, need mutex access to shared data that is read by thread 1. -Thread 2 needs mutex access for shared data with thread 4, the simulator - -SUMMARY OF Controls: -● ┌─────┬─────────────────────────────────────┬───────┬──────────┬──────────────┬────────────┬──────────┬─────────┬─────┐ - │ Key │ Function │ Intro │ Marine A │ Chain Home A │ Marine PPI │ Boat PPI │ ATC PPI │ PAR │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ s │ Advance to next scope │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ S │ back to previous scope │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ c │ Bearing clockwise │ │ ✓ │ │ │ │ │ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ v │ Bearing counterclockwise │ │ ✓ │ │ │ │ │ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ u │ Max range up │ │ ✓ │ │ ✓ │ ✓ │ ✓ │ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ d │ Max range down │ │ ✓ │ │ ✓ │ ✓ │ ✓ │ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ r │ Cursor bearing right │ │ │ │ ✓ │ ✓ │ ✓ │ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ l │ Cursor bearing left │ │ │ │ ✓ │ ✓ │ ✓ │ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ t │ Cursor range increase │ │ │ │ ✓ │ ✓ │ ✓ │ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ y │ Cursor range decrease │ │ │ │ ✓ │ ✓ │ ✓ │ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ k │ Display offset right (boat heading) │ │ │ │ ✓ │ ✓ │ │ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ j │ Display offset left (boat heading) │ │ │ │ ✓ │ ✓ │ │ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ [ │ Goniometer H/V switch │ │ │ ✓ │ │ │ │ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ 9 │ Goniometer tune left │ │ │ ✓ │ │ │ │ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ 0 │ Goniometer tune right │ │ │ ✓ │ │ │ │ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ . │ Toggle PRF (25/12.5 Hz) │ │ │ ✓ │ │ │ │ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ n │ Calibrator shrink │ │ │ ✓ │ │ │ │ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ m │ Calibrator stretch │ │ │ ✓ │ │ │ │ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ 1 │ Gain increase │ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ 2 │ Gain decrease │ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ 3 │ Rain clutter filter increase │ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ 4 │ Rain clutter filter decrease │ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ ✓ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ 5 │ Wave clutter filter increase │ │ ✓ │ ✓ │ ✓ │ ✓ │ │ │ - ├─────┼─────────────────────────────────────┼───────┼──────────┼──────────────┼────────────┼──────────┼─────────┼─────┤ - │ 6 │ Wave clutter filter decrease │ │ ✓ │ ✓ │ ✓ │ ✓ │ │ │ - └─────┴─────────────────────────────────────┴───────┴──────────┴──────────────┴────────────┴──────────┴─────────┴─────┘ - -Note: k/j (display bearing offset) are for marine PPI scopes only. The fixed ATC tower -at BLI has no heading offset need. On the fixed Marine PPI, k/j demonstrate North-up vs. -Head-up orientation as a teaching aid. On the Boat PPI, k/j are operationally meaningful: -zero offset = North-up (chart-style); offset matching boat heading = Head-up (bow at top). - -Table for general controls not yet implemented on the keyboard in the table above: - -1. Intensity -2. Focus -3. Astigmatism -4. Graticule light intensity - -Note: Gain (keys 1/2), rain clutter (keys 3/4), and wave clutter (keys 5/6) are now -in the keyboard control table above. They remain physical encoder controls on the -operator panel when that hardware is installed; the keyboard keys are the temporary -stand-in. All three have defaults in settings.h. - -SUMMARY of target handling: - -The traffic cop handles anything that is coming from the simulator as well as the raspberry pi's -It will use polling to find if anything is available from the raspberry pis and the simulator. It will -poll each source once per beam update - -The raspberry pi receiver pulls the data from each raspberry pi. If nothing, it does nothing else -for this sweep. If there is data, it will provide data to the traffic cop upon poll. - -Each raspberry pi, after boot-up, will respond to polls from the raspberry pi receiver (thread 2) - -The Simulator will run all fake targets. It will provide data to the traffic cop upon traffic cop poll. -It can run as a separate thread. It will not write data to anywhere except when polled by the traffic cop. - - -CONTROLS - -Every control listed above — both keyboard controls and the 7 general operator controls — -shall have a corresponding default constant in settings.h. This allows any startup value -to be changed at compile time without touching scope or rendering code. - -The 7 general controls (Intensity, Focus, Astigmatism, Gain, Rain Clutter, Wave Clutter, -Graticule Intensity) are physical encoder controls not yet purchased. Their placeholder -default constants are defined in settings.h. KnobPanel (Thread 3) will compile and run -from the start but will idle without ever acquiring Mutex A until real hardware is wired -in. SharedRenderState holds the default values unchanged; Thread 1 reads and applies them -every frame. No feature flags or conditional compilation are needed — the code path is -complete end-to-end, always at the compile-time default. - -Three of the 7 general controls — Gain, Rain Clutter, and Wave Clutter — have temporary -keyboard implementations (keys 1/2, 3/4, and 5/6 respectively) that write to the same -SharedRenderState fields the hardware encoders will eventually write to. When physical -encoders are installed, the keyboard keys can be removed or left as redundant overrides. - -Things to note about the keyboard type controls. -The letter on the keyboard are temporary. When I get around to making -the operators panel, this all will go away. - -Implementation of controls: - -1. For keyboard controls. Those are run as thread one where The keyboard callback - belongs to GLFW (glfwSetKeyCallback) - They will manipulate the shaders only. - -2. The control desk controls will have to mutex to access the state variables that - thread 1 sends to the shaders. - -3. If the control does not yet exist, we still want stubs for receiving control - data for that control. It's just that nothing will call it. - -Scope and left window arrangement. - -For each scope, put the scope itself on the right hand of the window. -On the left hand of the window will be a text description of that scope. - -The text status panel under each scope shall show, in addition to notes above, -the bearing and range for the cursor in the status text panel below the scope. -Please note that some keys may be the same from scope to scope. This is okay. Each -scope's controls are for that scope that you are connected do.They will not effect -settings on another scope. - -Please note that the maximum range setting on a scope specific to that scope -and will be in that scope's definition. and the bearing selection -is scope specific. The manually operated radar dish for the a scope is not the same -as the PPI radar dishes. They are from different eras. In addition, all range and -bearing data for marine is separate than for air traffic control. They are completely -different radars. Range and bearing for the precision approach radar will be different -than any other radar as that radar is located at the end of the runway and scan both -horizontal and vertical. - -================================================================== - -CLASS DESIGN AND FILE LAYOUT - -================================================================== - -Class Hierarchy: - - Scope (abstract base) - ├── ExhibitIntro - ├── AScope (abstract) - │ ├── MarineAScope - │ └── ChainHomeAScope - ├── PPIScope (abstract) - │ ├── MarinePPIScope - │ ├── BoatPPIScope - │ └── ATCPPIScope - └── PARScope - -Scope (abstract base) — everything all scopes share: - - Left panel text rendering - - s / S key handling (scope advance / reverse) - - Auto-advance timer reset on any key or control input - - Pure virtual: render(), handleKey(), getDescription() - -ExhibitIntro : public Scope - - Text-only rendering, no radar display - - Header: "WELCOME TO MUSEUM VINTAGE RADAR EXHIBIT" (all caps) - -AScope : public Scope (abstract) — shared A-scope behavior: - - Horizontal range axis, vertical amplitude axis - - Noise floor rendering (rain/wave clutter) - - Incandescent graticule (three horizontal amplitude lines + vertical range lines) - - Bearing control with key-hold acceleration - -MarineAScope : public AScope - - P1 phosphor (green) - - Range settings: 2, 4, 6 miles - - Graticule swap animation state machine (NORMAL/SLIDING_OUT/BARE_CRT/SLIDING_IN) - when operator changes max range — see Marine A-Scope section above for full detail - - Keys: c (bearing CW), v (bearing CCW), u (range up), d (range down) - u and d ignored during graticule swap animation - -ChainHomeAScope : public AScope - - P2 phosphor (blue green) - - Goniometer state: H/V mode toggle, azimuth angle, elevation angle - - PRF toggle: 25 Hz / 12.5 Hz - - Calibrator stretch/shrink scale factor - - Fixed 100-mile range - - Keys: [ (goniometer H/V toggle), 9/0 (tune), . (PRF), n/m (calibrator) - -PPIScope : public Scope (abstract) — shared PPI behavior: - - Clockwise sweep with P7 phosphor persistence (blue strike, green/yellow decay) - - Incandescent bearing graticule (1-degree ticks, 15-degree labels, inner/outer rings) - - Incandescent cursor: 10-degree arc + bearing crossline - - Cursor range/bearing readout under scope (white text) - - Bearing offset for boat mode (k/j) - - Cursor range clamped to max range - - There shall be a gain independent channel for the p7 phosphor - that shall not be impacted by the operator gain control. - - Range rings are beam-painted per sweep sector with P7 persistence and decay; - operator gain does not dim the rings - - No range ring labels. That era had no text in the p7. - - IMPLEMENTER CHECKLIST — required in every new PPIScope subclass: - 1. computeRingRadii(): multiply each normalised ring radius by - GRAT_INNER_RING_FRAC (same as MarinePPIScope). Omitting this - places the outer ring at the scope boundary where it is clipped - and hidden behind the graticule. Target positions are scaled - automatically by PhosphorRenderer::update(); ring radii are not. - 2. No labeling of range rings.That era did not have them - -RANGE POSITION NORMALISATION - -All ring radii and target range values are normalised so that -max-range maps to GRAT_INNER_RING_FRAC (0.915), NOT 1.0. - -Normalised 1.0 is the outer edge of the phosphor circle (scope boundary). -The bearing graticule overlay occupies 0.915 to 0.985 of scope radius. -If max-range mapped to 1.0, the outer ring would sit at the scope -boundary — half-clipped by the sweep shader's rng > 1.0 early-exit and -visually hidden behind the graticule outer ring. - -================================================================== - - -MarinePPIScope : public PPIScope - - Sweep time: 4 seconds - - Max range: 2, 4, 6 miles with correct ring sets - - Keys: u (range up), d (range down) — this scope only - -BoatPPIScope : public PPIScope - - Direct subclass of PPIScope (not of MarinePPIScope) - - Range steps: 0.5 / 1 / 2 miles; sweep time 4 s; phosphor P7 - - Radar parameters: 6 kW, 1.9° open array (distinct from 30 kW / 0.5° coastal) - - Radar origin = boat lat/lon from SharedRenderState, updated every sweep - - Variable patrol speed per route segment (loaded from data/patrol_route.json) - - Heading marker: white dashed line from scope center toward boat heading; - drawn after all phosphor content so it always appears fully bright - - Nearest pre-computed shadow mask selected each sweep via - TerrainMap::selectNearestBoatMask() — no runtime ray-marching - - Display mode indicator: "North-up" / "Head-up" based on offset vs heading - - Left panel status: zone text, lat/lon, boat heading, speed, display mode - - Keys: u/d (range 0.5/1/2), r/l (cursor bearing), t/y (cursor range), - k/j (display offset), 1/2 (gain), 3/4 (rain filter), 5/6 (wave filter) - -ATCPPIScope : public PPIScope - - Sweep time: 5 seconds - - Max range: 5, 10, 15, 20 miles with correct ring sets - - Keys: u (range up), d (range down) — this scope only - -PARScope : public Scope - - Two stacked sub-scopes: azimuth on top and elevation below - - 30 Hz alternating scan between planes (~15 Hz each) - - Fixed 10-mile range, non-linear scale (inner 5 miles = 70% width) - - P7 phosphor; incandescent etched glass graticules - - All targets simulated; no cursor or bearing controls - -Supporting classes: - ScopeManager Thread 1 — owns scope list, s/S switching, 120s auto-advance timer - PhosphorRenderer Thread 1 — P1, P2 and P7 decay/persistence; shared dependency - Graticule Thread 1 — incandescent graticule lines/text; parameterized per scope - LeftPanel Thread 1 — scope description text panel (left side of window) - SharedRenderState Threads 1,2,3 — Mutex A; state vars Thread 1 reads each frame for shader uniforms - TargetBuffer Threads 2,4 — Mutex B; target data handoff between TrafficCop and Simulator - TrafficCop Thread 2 — polls Simulator and RPi receivers; writes to SharedRenderState - Simulator Thread 4 — runs fake targets; returns data to TrafficCop when polled - KnobPanel Thread 3 — future hardware stub; writes to SharedRenderState under Mutex A - RPiReceiver Thread 2 — stub; one per Raspberry Pi; called by TrafficCop - -File layout: - -src/scope.cpp / scope.h = scope abstract -src/ascope.cpp /ascope.h = a scope abstract and shared a scope logic -src/marine_ascope.cpp / marine_ascope.h - MarineAScope -src/chain_ascope.cpp / chain_ascope.h - ChainHomeAScope -src/ppi_scope.cpp / ppi_scope.h - ppi scope abstract -src/ppi_scope_marine.cpp / ppi_scope_marine.h - marine ppi scope abstract -src/ppi_scope_marine_tower_scope.cpp / ppi_scope_marine_tower_scope.h - MarineTowerScope -src/ppi_scope_police_boat.cpp /ppi_scope_police_boat.h - MarinePoliceScope -src/ppi_scope_atc.cpp / ppi_scope_atc.h - AirTrafficScope -src/par_scope.cpp / src/par_scope.h - PARScope - note; this is for precision approach radar -src/status_text.cpp / status_text.h - StatusText - note; this is for status text below scope -src/land_feature.cpp / land_feature.h - LandFeature - note; this is for land feature terrain, shore, lidar -src/descriptive_text.cpp / descriptive_text.h - DescriptiveText note; this is for left panel text - including keyboard control descriptions -src/traffic_cop.cpp / src/traffic_cop.h - InputTrafficCop note; receiving data from rpis and simulator -src/simulator.cpp / simulator.h - TargetSimulator -src/rpi_receiver.cpp / src/rpi_receiver.h - RPIReceiver -src/keyboard_control.cpp / keyboard_control.h - KeyBoardControls -src/physical_control.cpp / physical_control.h - PhysicalControls -src/shared_render_state.cpp / shared_render.h - SharedRenderState -src/scope_manager.cpp / scope_manager.h - ScopeManager - -Shader pairs (include .vert and .frag - -P7_persistent_stage - having to do with the persistent (yellow green) of the p7 phosphor -marine_ascope_targets - handling marine ascope targets -marine_ascope_land - handling land for ascope -marine_ascope_bearing - handling marine a scope bearing -marine_ascope_graticule - handling changing marine ascope graticules -chainhome_ascope_graticules - handling chain home a scope graticules -chainhome_ascope_targets - handling chain home targets including the - goniometer operation -ppi_scope_graticules - handling all ppi scope graticules -ppi_scope_target - handling target for all ppi scopes -terrain_clutter - for terrain -par_scope_graticule - handling graticules for Precision Approach Radar Scopes -par_scope_targets - handling targets for Precision Approach Radar Scopes -bloom - two pass gaussian blur on pixels above luminance threshold, three tuning constants in settings.h -rain_noise - noise caused by rain amount to be set by a random CPU function -sea_wave_noise - noise caused by wind on waves; stronger when close to radar ; amount to be set by CPU function - -================================================================== - -PHOSPHOR FBO ARCHITECTURE - -================================================================== - -The P7 phosphor simulation uses a single floating-point offscreen -texture (the phosphor FBO) to store the current glow state of every -pixel in the scope. The texture format is RGBA16F. - -CHANNEL ASSIGNMENTS - R channel — gain-affected content: targets, land clutter, noise. - Multiplied by u_gain during the display pass. - G channel — gain-independent content: range rings only. - Displayed at full brightness regardless of u_gain. - B, A — reserved for future use. - -THREE PASSES PER FRAME - - 1. DECAY PASS (P7_persistent_stage.vert / .frag) - Reads the phosphor FBO and writes back to it with both R and G - channels multiplied by P7_DECAY_FACTOR (default ~0.985 at 60 Hz, - settable in settings.h). Both channels decay at the same rate. - When P7_PERSISTENCE_ENABLED is false in settings.h this pass is - skipped — the FBO is cleared each frame — allowing debugging of - raw strike data only. - - 2. STRIKE PASS (per-scope target shaders and terrain_clutter) - Runs during the sweep. Each fragment that the beam illuminates - writes a brightness value into the appropriate channel: - - Targets, clutter, noise → write to R, leave G unchanged - - Range rings → write to G, leave R unchanged - The brightness value is computed from the radar equation result - uploaded per-target via SSBO or uniform array. - - 3. DISPLAY PASS (composited in each scope's render method) - Reads both channels and maps to P7 colors: - target_glow = phosphorFBO.R × u_gain - ring_glow = phosphorFBO.G (no gain factor) - output = P7_color(target_glow) + P7_color(ring_glow) - P7_color() maps the glow value to the P7 palette: high values - produce P7_STRIKE_COLOR (#F0F8FF), lower values produce - P7_PERSISTENCE_COLOR (#F2BF1C). - -DEBUGGING SUPPORT - P7_PERSISTENCE_ENABLED (settings.h) — set false to skip decay pass; - each frame shows only raw strike data. - P7_STRIKE_DEBUG_ALPHA (settings.h) — scales the strike brightness - to evaluate persistence timing by eye. - -================================================================== - -LEFT PANEL TEXT — ONE ENTRY PER SCOPE - -================================================================== - -Note: Each left panel renders its description text followed immediately by its -control table. Every panel also states the next scope name so the visitor knows -what pressing s will show. The s / S advance note appears in every panel. - ------------------------------------------------------------------- -PANEL 1 — EXHIBIT INTRODUCTION ------------------------------------------------------------------- - -Header (all caps, large): - WELCOME TO THE MUSEUM VINTAGE RADAR EXHIBIT - -Body: - Welcome! This exhibit lets you experience how radar worked from the 1940s - through the 1960s — technology that changed the course of World War 2 and - shaped modern aviation and maritime safety. - - Radar works by sending out short bursts of radio energy and listening for - the echo that bounces back from ships, aircraft, and terrain. By measuring - the time it takes for the echo to return, the radar calculates how far away - the object is. Rotating the antenna builds a map of everything around it. - - This exhibit features seven radar displays. Explore each one at your own pace. - - Press s at any time to jump to the next display — do not wait for the - automatic 120-second advance. Press S (shift+s) to go back. - Pressing any key or control resets the 120-second timer. - - Next: Marine A-Scope → - - ┌─────┬───────────────────────┐ - │ KEY │ FUNCTION │ - ├─────┼───────────────────────┤ - │ s │ Next display │ - │ S │ Previous display │ - └─────┴───────────────────────┘ - ------------------------------------------------------------------- -PANEL 2 — MARINE A-SCOPE ------------------------------------------------------------------- - - The A-Scope was one of the earliest radar displays, used aboard ships and - in coastal stations in the 1950s. Unlike the circular display you may have - seen in movies, the A-Scope sweeps left to right: distance (range) runs - along the bottom axis, and the height of each spike shows how strong the - echo is from that direction. - - To look in a different direction, the operator physically rotates the - antenna by hand. Use c and v to rotate the antenna on this display. - - The green glow is the P1 phosphor coating on the inside of the cathode ray - tube. In a real radar room this was often the only light in the space. - - The glass panel in front of the screen is the graticule — an etched, - back-lit calibration scale for measuring range. When you change the maximum - range setting, watch the operator swap the graticule panel by hand — just - as it was done in the period. - - Location: Bellingham Bay, WA — a fictional 100-foot mid-bay platform. - - Press s to advance. Press S to go back. Auto-advance in 120 seconds. - Any key press resets the timer. Next: Chain Home A-Scope → - - ┌──────┬──────────────────────────────┐ - │ KEY │ FUNCTION │ - ├──────┼──────────────────────────────┤ - │ s/S │ Next / previous scope │ - │ c/v │ Bearing clockwise / CCW │ - │ u/d │ Max range up / down (2,4,6) │ - │ 1/2 │ Gain increase / decrease │ - │ 3/4 │ Rain filter increase / dec │ - │ 5/6 │ Wave filter increase / dec │ - └──────┴──────────────────────────────┘ - ------------------------------------------------------------------- -PANEL 3 — CHAIN HOME A-SCOPE ------------------------------------------------------------------- - - Chain Home was Britain's early warning radar network, built in the late - 1930s and critical during the Battle of Britain (1940). Instead of a - rotating dish, it used a fixed array of tall transmit towers that flooded - the sky over the English Channel with radio energy — a technique called - floodlighting. Aircraft crossing the Channel reflected this energy back - to separate receive antennas, sometimes at ranges up to 100 miles. - - FINDING DIRECTION — THE GONIOMETER - Because there was no rotating dish, finding the bearing and altitude of a - target required a technique called nulling. A device called a goniometer - electronically combined signals from several receive antennas. The operator - slowly turned the goniometer dial while watching the screen. In most - positions the signal was strong. But at one precise setting the signal - suddenly disappeared — this was the null. When nulled, the goniometer was - pointing directly at the aircraft. Think of it like tuning a radio: you - search for the silent spot between two stations. Press [ to switch the - goniometer between bearing (horizontal) and elevation (vertical) modes. - Use keys 9 and 0 to tune — turn slowly, the null appears suddenly. - - CALIBRATOR PIPS - Early electronics drifted, stretching or compressing the range scale. - The crystal calibrator injects tiny spikes at exact 10-mile intervals. - Use n to shrink and m to stretch the trace until the pips line up with - the 10-mile marks on the glass graticule. - - This display is set at the Chain Home station at Poling, East Sussex, - facing the English Channel. All targets are simulated German aircraft. - - Press s to advance. Press S to go back. Auto-advance in 120 seconds. - Any key press resets the timer. Next: Marine PPI → - - ┌──────┬─────────────────────────────────┐ - │ KEY │ FUNCTION │ - ├──────┼─────────────────────────────────┤ - │ s/S │ Next / previous scope │ - │ [ │ Goniometer mode: bearing / elev │ - │ 9/0 │ Goniometer tune left / right │ - │ . │ Toggle PRF: 25 Hz / 12.5 Hz │ - │ n/m │ Calibrator shrink / stretch │ - │ 1/2 │ Gain increase / decrease │ - │ 3/4 │ Rain filter increase / dec │ - │ 5/6 │ Wave filter increase / dec │ - └──────┴─────────────────────────────────┘ - ------------------------------------------------------------------- -PANEL 4 — MARINE PPI SCOPE ------------------------------------------------------------------- - - The PPI (Plan Position Indicator) became the standard radar display for - ships from the late 1950s onward. The antenna rotates clockwise and the - sweep line rotates with it, painting a map of everything within range. - Targets glow bright blue the instant the sweep passes over them, then - fade through green to yellow before the sweep returns — this is the P7 - phosphor persistence that keeps the picture visible between sweeps. - - The dotted range rings give distance reference. The incandescent bearing - scale shows True direction (0 = North, clockwise to 359). - - The yellow overlay is a mechanical cursor — a plastic ring and crosshair - mounted in front of the screen. Use the cursor keys to position it over a - target; range and bearing read out below the scope. - - Location: Bellingham Bay, WA — a fictional 100-foot mid-bay platform. - Targets: AIS-equipped vessels and simulated traffic. - - Press s to advance. Press S to go back. Auto-advance in 120 seconds. - Any key press resets the timer. Next: Marine PPI — Boat Scenario → - - ┌──────┬────────────────────────────────────────────────┐ - │ KEY │ FUNCTION │ - ├──────┼────────────────────────────────────────────────┤ - │ s/S │ Next / previous scope │ - │ u/d │ Max range up / down (2, 4, 6 mi) │ - │ r/l │ Cursor bearing right / left │ - │ t/y │ Cursor range increase / decrease │ - │ k/j │ Display offset right / left │ - │ │ (zero = North-up; rotate to match heading │ - │ │ = Head-up — a teaching aid on fixed radar) │ - │ 1/2 │ Gain increase / decrease │ - │ 3/4 │ Rain filter increase / decrease │ - │ 5/6 │ Wave filter increase / decrease │ - └──────┴────────────────────────────────────────────────┘ - ------------------------------------------------------------------- -PANEL 5 — POLICE PATROL BOAT PPI ------------------------------------------------------------------- - - This display is from the radar aboard a Bellingham Police Department - patrol vessel making its routine waterfront patrol. The scope center - is the boat — it moves with the patrol route, not fixed in the bay. - - THE RADAR IS DIFFERENT HERE - The patrol boat carries a professional 6-kilowatt open-array radar - with a 1.9-degree beam — narrower than a cheap boat radar, but wider - than the big 30-kilowatt coastal radar you saw two displays back. The - blips look noticeably fatter than on the coastal radar. The maximum - range here is 2 miles: the patrol mission is close-in harbor work, - not long-range scanning. - - THE FERRY LANE PROBLEM - The Bellingham terminal serves Alaska state ferries up to 400 feet - long. When a ferry departs, anyone in the departure lane — a kayaker, - a paddleboarder — must get clear. Watch the scope carefully: there - is a stand-up paddleboarder drifting slowly near the ferry lane. - Can you spot it? - - Stand-up paddleboards are very hard to see on radar. No metal, almost - no freeboard, small size — the radar echo is barely above the noise. - Try adjusting the wave clutter filter (keys 5 and 6). Turning it up - reduces the sea clutter that is hiding the target — but it may also - suppress the target itself. This trade-off is real. Radar does not - see everything. - - NORTH-UP AND HEAD-UP - By default the scope shows North-up: True North at the top, like a - chart. Press k or j to rotate the display. When the heading marker - (white dashed line) points straight up, you are in Head-up mode — - the bow is at the top. This is how most early marine radars worked. - - Location: Bellingham waterfront patrol, Bellingham Bay, WA. - Targets: AIS vessels, paddleboarder, random kayakers. - - Press s to advance. Press S to go back. Auto-advance in 120 seconds. - Any key press resets the timer. Next: ATC PPI → - - ┌──────┬────────────────────────────────────────────────┐ - │ KEY │ FUNCTION │ - ├──────┼────────────────────────────────────────────────┤ - │ s/S │ Next / previous scope │ - │ u/d │ Max range up / down (0.5, 1, 2 mi) │ - │ r/l │ Cursor bearing right / left │ - │ t/y │ Cursor range increase / decrease │ - │ k/j │ Display offset right / left │ - │ │ (0° = North-up; match heading = Head-up) │ - │ 1/2 │ Gain increase / decrease │ - │ 3/4 │ Rain filter increase / decrease │ - │ 5/6 │ Wave filter increase / decrease │ - └──────┴────────────────────────────────────────────────┘ - ------------------------------------------------------------------- -PANEL 6 — AIR TRAFFIC CONTROL PPI SCOPE ------------------------------------------------------------------- - - This is the Airport Surveillance Radar (ASR) display used by air traffic - controllers at regional airports in the 1960s. It works on the same - principle as the marine PPI but covers a larger area (up to 20 miles) and - is optimised for tracking aircraft rather than ships. The S-Band frequency - (3 GHz) gives a good balance of range, resolution, and resistance to - weather clutter for airspace surveillance. - - Controllers used this display to sequence arriving and departing aircraft, - identify potential conflicts, and provide navigation guidance to pilots - flying in low visibility conditions. - - Location: Bellingham International Airport (BLI), dedicated radar tower. - Targets: ADS-B equipped aircraft and simulated traffic. - - Press s to advance. Press S to go back. Auto-advance in 120 seconds. - Any key press resets the timer. Next: Precision Approach Radar → - - ┌──────┬──────────────────────────────────────────┐ - │ KEY │ FUNCTION │ - ├──────┼──────────────────────────────────────────┤ - │ s/S │ Next / previous scope │ - │ u/d │ Max range up / down (5, 10, 15, 20 mi) │ - │ r/l │ Cursor bearing right / left │ - │ t/y │ Cursor range increase / decrease │ - │ 1/2 │ Gain increase / decrease │ - │ 3/4 │ Rain filter increase / decrease │ - └──────┴──────────────────────────────────────────┘ - ------------------------------------------------------------------- -PANEL 7 — PRECISION APPROACH RADAR (PAR) ------------------------------------------------------------------- - - The Precision Approach Radar was developed during World War 2 and refined - through the 1950s. It gives a controller a precise picture of exactly where - an aircraft is on its final approach to the runway — both its left-right - position and its altitude. - - Unlike instrument landing systems that require special equipment on the - aircraft, PAR needed nothing from the pilot's plane. The controller watched - the display and talked the pilot down over the radio: "You are slightly - right of centerline, begin correcting left. You are above the glide path, - begin a slightly steeper descent." This made PAR invaluable when a plane's - own instruments failed or when visibility dropped to near zero in heavy fog. - - TOP DISPLAY — AZIMUTH (left-right) - Shows whether the aircraft is left or right of the runway centerline. - The centerline runs horizontally through the middle of the display. - - BOTTOM DISPLAY — ELEVATION (up-down) - Shows whether the aircraft is above or below the correct glide slope. - The ideal descent path runs through the center of the display. - - Both displays expand the inner 5 miles to 70% of the screen width — - giving maximum precision during the critical final approach phase. - - Location: South end of Runway 16/34, Bellingham Airport (BLI). - Active runway: 34 (aircraft landing northbound). All traffic is simulated. - - Press s to advance. Press S to go back. Auto-advance in 120 seconds. - Any key press resets the timer. Next: Exhibit Introduction → - - ┌──────┬──────────────────────────────┐ - │ KEY │ FUNCTION │ - ├──────┼──────────────────────────────┤ - │ s/S │ Next / previous scope │ - │ 1/2 │ Gain increase / decrease │ - │ 3/4 │ Rain filter increase / dec │ - └──────┴──────────────────────────────┘ - -================================================================== - -UNITS - -================================================================== - -All dimensions are stored and computed in METERS throughout the -entire system — in shared state, in the database, in shaders, and -in all target data structures. - -Any incoming value that arrives in feet (e.g. ADS-B altitude, -antenna heights from configuration) MUST be converted to meters -at the data boundary — in RPiReceiver::parseFrame() or -Simulator::poll() — before the value enters any shared data -structure. No feet values may appear anywhere inside the system -after the conversion point. - -Conversion constant in settings.h: - FEET_TO_METERS = 0.3048 (exact) - -================================================================== - -DEFAULT TARGET DIMENSIONS - -================================================================== - -When a target is first seen with no database record, the system -inserts a row using the defaults below. All values in meters. -need_update is set TRUE so the operator knows to fill in real data. - - ┌──────────────────┬───────────┬──────────────────┬────────────┐ - │ Category │ Length (m)│ Width/Beam (m) │ Material │ - ├──────────────────┼───────────┼──────────────────┼────────────┤ - │ GA aircraft │ 4.0 │ 1.0 (fuselage) │ aluminum │ - │ Commercial a/c │ 30.0 │ 5.0 (fuselage) │ aluminum │ - │ AIS vessel │ 20.0 │ 5.0 (beam) │ steel │ - │ Simulator boat │ 6.0 │ 2.0 (beam) │ fiberglass │ - └──────────────────┴───────────┴──────────────────┴────────────┘ - -Notes: -- AIS vessels are legally required commercial traffic, so steel is - the correct default material. -- Simulator boats are small pleasure craft, so fiberglass is correct. -- The system defaults all new aircraft to GA. The operator must - update commercial entries via the --database panel. -- Height above water/ground defaults to 0 for vessels and 0 for - aircraft (updated by live data). - -================================================================== - -POSTGRESQL DATABASE - -================================================================== - -PostgreSQL is installed. Database: radar. User: radar. Password: radar. -User has full privileges on database radar. Table is target_data. - -Schema (all dimensions in METERS): - - 1. target_type ENUM('AIS', 'ADSB', 'LOCAL') - 2. target_id BIGINT — MMSI for marine; ICAO 24-bit address for - aircraft; simulator may reuse same space - 3. length_m REAL — length in meters - 4. width_m REAL — beam (vessels) or fuselage width (aircraft) - in meters - 5. height_m REAL — height above water/ground in meters - 6. material ENUM('fiberglass', 'wood', 'aluminum', 'steel') - 7. need_update BOOLEAN DEFAULT TRUE - 8. last_seen TIMESTAMPTZ — ISO 8601, updated each time target - is received from any source - 9. last_updated TIMESTAMPTZ — ISO 8601, updated when operator saves - changes via DB panel - 10. track history — deferred to a future version; not in v1 schema - -The fields length_m, width_m, height_m, and material are used by the -CPU to compute RCS before passing to the shader. They are static -per-target data uploaded to GPU via SSBO or uniform array each frame. - -Per-frame dynamic fields (location, heading, altitude) are NOT stored -in the database. They live in TargetBuffer (Threads 2/4) and are -updated from live Raspberry Pi or simulator data each sweep. - -================================================================== - -DATABASE MANAGEMENT PANEL - -================================================================== - -Activated by command-line flag: --database -In this mode NO radar display is shown. main.cpp skips all scope -and shader initialization and starts the Dear ImGui loop instead. - -Toolkit: Dear ImGui, integrated with GLFW/OpenGL 3.3. -Source lives in src/imgui/ and is compiled directly into the project -(no separate install step required). - -The panel provides: - - Scrollable table of all targets with need_update highlighted - - Inline edit fields for length, width, height, material - - Dropdown for target_type - - Save button that writes to PostgreSQL via libpq - - Quit button to exit the DB panel (then start main exhibit separately) - -================================================================== - -RADAR EQUATION AND BLOOM - -================================================================== - -The radar equation is evaluated CPU-side to compute received power -(P_r) for each target. The result drives target brightness and bloom. -Computation happens in TrafficCop after each poll, outside any mutex -lock (read-only access to target physical data at that point). - -The computed brightness value is uploaded per-target to the GPU via -SSBO or uniform array. The phosphor shader reads it to set amplitude. - -BLOOM POST-PROCESSING (bloom.vert / bloom.frag): - Separate shader pair. Pipeline: - 1. Render targets to offscreen FBO at full computed brightness - 2. Apply two-pass Gaussian blur to pixels above luminance threshold - 3. Additively blend blurred result back onto main framebuffer - Constants in settings.h: BLOOM_LUMINANCE_THRESHOLD, - BLOOM_BLUR_RADIUS_PX, BLOOM_BLEND_STRENGTH - -RADAR PARAMETERS — MARINE (X Band): - Frequency: 9225 MHz - Peak power: 30 kW - Horizontal beamwidth: 0.5 degrees - Vertical beamwidth: 20 degrees - Antenna length: 15 feet (4.572 m) - Antenna height: 50 feet (15.24 m) above surface - -RADAR PARAMETERS — ATC (S Band): - Frequency: 3000 MHz (3 GHz) - Peak power: 25 kW (exhibit value; real ASR is higher) - Horizontal beamwidth: 1.4 degrees - Vertical beamwidth: 5 degrees - Antenna width: 20 feet (6.096 m) - Antenna height: 50 feet (15.24 m) above runway - -RADAR PARAMETERS — CHAIN HOME (AMES Type 1): - Frequency: 30 MHz - Peak power: 500 kW - Pulse width: 20 microseconds - PRF: 25 Hz or 12.5 Hz (operator selectable) - Transmit gain (Gt): ~7.5 linear (~8.7 dBi) — floodlight, not a beam - formula: G = 30000 / (az_bw_deg × el_bw_deg) - with az ~100 deg, el ~40 deg - Receive gain (Gr): 4 to 10 linear (6–10 dBi) - System loss: ~8 dB (transmission line) - Bistatic: yes — separate transmit and receive antennas - RCS resonance: at 30 MHz (lambda ~10 m) aircraft are in the - Mie/resonant scattering region; RCS is multiplied - by CHAIN_HOME_RCS_RESONANCE_FACTOR (default 3.0) - before radar equation computation. Applied to - Chain Home targets only. - -RADAR PARAMETERS — PAR (X Band): - Peak power: 100 kW - Frequency: ~10 GHz (lambda ~3 cm) - Antenna size: ~5 meters - Beamwidth: ~0.34 degrees (lambda/D) - Horizontal scan: 20 degrees total - Vertical scan: 10 degrees total - Pulse width: short (high range resolution) - PRF: high (~30 Hz alternating az/el) - -RADAR PARAMETERS — PATROL BOAT (X Band): - Frequency: 9300–9500 MHz (X-band; treat same as marine for exhibit) - Peak power: 6 kW - Antenna type: Open array, 24-inch (610 mm) - Horizontal beamwidth: 1.9 degrees - Vertical beamwidth: 20 degrees - Antenna height: 3.5 m above waterline (flybridge or radar arch) - Radar horizon: ~4.3 nm to sea-level target - Operational max range: 2 miles (mission-limited, not horizon-limited) - - NOTE — beamwidth comparison: - Fixed coastal marine: 0.5° — sharp blips, high azimuth resolution - Police patrol boat: 1.9° — noticeably fatter blips; good exhibit contrast - Consumer radome: 4–6° — poorest resolution (not used in this exhibit) - - NOTE — small target detection in sea clutter: - The narrower 1.9° beam illuminates ~1/3 the sea surface area per range - cell compared to a 5° radome, improving signal-to-clutter ratio by ~5 dB. - Even so, a stand-up paddleboard (RCS ~0.1–0.5 m²) is marginal in any chop. - Detection is realistic only in near-calm conditions at ≤1 mile. - -All radar parameters shall have corresponding constexpr constants -in settings.h so they can be tuned without touching equation code. - -================================================================== - -TERRAIN AND LAND CLUTTER - -================================================================== - -DATA SOURCES - map/charts_enc/US5WA45M.000 - S-57 Electronic Navigational Chart; coastline polygon, - pier/breakwater geometry, named landmarks. Parsed with GDAL/OGR. - - map/charts_enc/n48_w123_1arc_v3.tif - USGS 1 arc-second (~30 m) DEM GeoTIFF. Terrain elevation for the - Bellingham area — Cascades, Chuckanut Mountain, coastal lowlands. - - map/lidar_raw/wa2016_west_dem_J1364939.zip - 2016 western WA LiDAR DEM. Resolves waterfront structures, - breakwaters, piers, Boulevard Park boardwalk, and other man-made - features at ~1 m resolution. - - map/lidar_raw/wa2022_nooksack_dem_J1364940.zip - 2022 Nooksack basin LiDAR DEM. Covers the delta and lowlands - northeast of Bellingham Bay; used for terrain shadowing from the - northeast quadrant. - - All four sources are processed offline by terrain_preprocess into - binary grids in map/lidar_processed/. The raw files are never opened - at exhibit runtime. See TERRAIN PREPROCESSING section below. - - GDAL (libgdal-dev) is a required build dependency for - terrain_preprocess. It is NOT linked into the main radar binary. - -TERRAIN MATERIALS AND RCS - - Each terrain cell is classified as one of four materials. Normalized - backscatter coefficient σ° (linear, m²/m²) is defined in settings.h: - - TERRAIN_SIGMA0_SOIL ~0.010 (−20 dB) — moist vegetated soil - TERRAIN_SIGMA0_ROCK ~0.032 (−15 dB) — exposed rock, rough face - TERRAIN_SIGMA0_CONCRETE ~0.100 (−10 dB) — smooth hard surface; - structures produce - corner-reflector effect - TERRAIN_SIGMA0_WATER_CALM ~0.0003 (−35 dB) — open water, calm; - mostly specular, low - backscatter - TERRAIN_SIGMA0_WATER_ROUGH ~0.010 (−20 dB) — choppy sea, sea clutter - - Classification rules applied by terrain_preprocess at build time: - - Below sea level or inside S-57 coastline polygon → water - - Inside S-57 pier/breakwater/wharf feature → concrete - - Elevation > TERRAIN_ROCK_THRESHOLD_M AND slope - > TERRAIN_ROCK_SLOPE_THRESHOLD_DEG → rock - - All remaining land cells → soil - -RADAR EQUATION FOR TERRAIN (area-extensive / clutter form) - - P_r = (P_t × G² × λ² × σ° × A_cell) / ((4π)³ × R⁴) - - A_cell is the terrain cell area projected along the beam. - Evaluated CPU-side in LandClutter for each illuminated cell. - Result drives per-cell brightness in the clutter texture. - Same radar parameters (P_t, G, λ) used for point targets. - -SHADOW / LINE-OF-SIGHT MASKING - - Computed by terrain_preprocess for each fixed radar location and - stored in the processed data as uint8 shadow masks. Algorithm: march - outward from the radar along each azimuth radial, tracking the maximum - elevation angle seen. Any cell whose surface angle falls below that - maximum is shadowed — clutter amplitude = 0 and target returns through - that cell are attenuated proportionally. - - Shadow masks stored per radar location: - map/lidar_processed/shadow_marine.u8 — marine bay platform - map/lidar_processed/shadow_atc.u8 — BLI ATC tower - - Bearing offset (k/j keys on PPI scopes): - The k/j keys change display heading only — which direction appears - at the top of the scope. They do NOT move the radar geographically. - The shadow mask is unchanged. The terrain clutter shader receives - the offset as a rotation uniform and samples the polar texture at - the offset angle. Zero CPU overhead; no shadow recomputation. - - Boat PPI scope scenario: - When BoatPPIScope is active, SharedRenderState.boatModeActive is set - TRUE. LandClutter uses boatLatDeg / boatLonDeg as the polar grid origin - instead of the fixed marine platform position. - - Shadow mask selection: terrain_preprocess pre-computes BOAT_CLUTTER_MASK_COUNT - shadow masks for waypoints evenly spaced around the simulated route. - These are written as: - map/lidar_processed/shadow_boat_NNN.u8 — one file per boat mask waypoint - NNN = zero-padded index - At runtime, TerrainMap::selectNearestBoatMask() scans the BOAT_CLUTTER_MASK_COUNT - waypoints and returns the index whose position is nearest to the current boat - lat/lon (straight-line distance). The selected mask changes at most once per - 4-second sweep when the boat has moved more than BOAT_MASK_SWITCH_THRESHOLD_M - (default 500 m) from the last selected waypoint position. - - Since Bellingham Bay is open water, the major terrain shadowing features - (Chuckanut Mountain, Eliza Island, Lummi Island) are visible from most bay - positions. The nearest-mask approximation introduces negligible error within - the 500 m switching threshold. - - The terrain clutter shader receives the boat position offset as a translation - uniform (u_radarOffsetM, a vec2) in addition to the bearing offset rotation. - The shader adds this offset when sampling the polar texture so coastline - features appear at their correct positions relative to the moving radar. - -PER-SCOPE TERRAIN BEHAVIOR - - Marine A-Scope: - Land returns appear as stable blips at fixed ranges on the current - antenna bearing. Concrete structures give strong returns; soil/hills - give moderate returns; shadowed areas return nothing. Period - operators were trained to discard stable blips when searching for - moving targets. - - Marine PPI (fixed platform and boat heading offset): - Land clutter is fully visible. Coastline, hills, piers, and - breakwaters paint exactly as on a real period marine radar. The - clutter texture updates once per 4-second sweep rotation. - - ATC PPI: - Moving Target Indicator (MTI) cancellation suppresses land clutter. - Controlled by ATC_TERRAIN_CLUTTER_SUPPRESSED (default true) in - settings.h. Terrain shadowing of aircraft IS applied — controlled - by ATC_TERRAIN_SHADOW_ENABLED (default true). Aircraft approaching - behind a ridge appear at reduced amplitude or disappear until they - clear the ridge, as on period ASR equipment. - - Chain Home A-Scope: - No terrain data applied. The exhibit scenario faces the English - Channel; the transmitter floodlights the sea. Land returns are - not simulated for this scope. - - PAR: - No terrain clutter. PAR points at a single fixed approach path; - the narrow beam and short range make land returns negligible. - -TERRAIN CLUTTER SHADER - - terrain_clutter.vert / terrain_clutter.frag - Renders the polar clutter texture as a quad overlay on the PPI - scope. Converts screen coordinates to polar, samples the clutter - texture, and outputs P7-compatible phosphor color and alpha so - terrain returns decay on the same timescale as target echoes. - Uniforms: - u_bearingOffsetDeg — display heading correction (default 0.0) - u_radarOffsetM — vec2 (dx_m, dy_m) from fixed marine platform origin - to current radar position; (0,0) for fixed scopes, - non-zero for Boat PPI as boat moves around the bay - u_clutterSuppressed — bool; 1 = suppress (ATC mode) - u_maxRangeM — current scope max range in meters - u_clutterBrightness — TERRAIN_MARINE_CLUTTER_BRIGHTNESS scale - Used by MarinePPIScope, BoatPPIScope, and ATCPPIScope. - -================================================================== - -TERRAIN PREPROCESSING - -================================================================== - -All four raw terrain sources are processed in a single pass by the -offline tool terrain_preprocess, which writes ready-to-use binary grids -to map/lidar_processed/. Must be run before first launch and re-run -whenever TERRAIN_BBOX_* or TERRAIN_PROCESSED_CELL_DEG constants in -settings.h change. - -Sources processed: - map/charts_enc/n48_w123_1arc_v3.tif — USGS 1 arc-second DEM - (~30 m); already WGS84; - covers full ATC radar range - including distant ridges - map/lidar_raw/wa2016_west_dem_J1364939.zip — 2016 LiDAR DEM (~1 m); - projected; requires warp - map/lidar_raw/wa2022_nooksack_dem_J1364940.zip — 2022 LiDAR DEM (~1 m); - projected; requires warp - map/charts_enc/US5WA45M.000 — S-57 ENC; material - classification only; no - elevation data - -TOOL - Build target: terrain_preprocess (separate CMake executable) - Source: src/terrain_preprocess.cpp - Links: GDAL only; NOT linked into the main radar binary - Run: ./terrain_preprocess (from build directory) - -PIPELINE (runs in order) - 1. Open USGS DEM (n48_w123_1arc_v3.tif) directly via GDAL — already - in WGS84, no warp needed. Crop to TERRAIN_BBOX_LAT/LON bounds. - 2. Unzip both LiDAR archives to a temp directory. - 3. Inventory LiDAR tiles — enumerate .tif / .img files, check CRS - and native resolution of each survey. - 4. Merge tiles within each LiDAR survey into a GDAL VRT mosaic. - 5. Warp both LiDAR surveys to WGS84 (EPSG:4326) at - TERRAIN_PROCESSED_CELL_DEG resolution. Crop to bounding box. - 6. Three-way elevation merge — priority order, highest to lowest: - LiDAR 2022 (Nooksack survey) — highest resolution, newest vintage - LiDAR 2016 (western survey) — fills gaps in 2022 coverage - USGS DEM (1 arc-second) — floor; covers full extent of all - radar scopes including distant - terrain beyond LiDAR coverage - (Cascades, far ridges for ATC shadow) - Any cell with no data from any source → elevation 0.0 m (water). - 7. Material classification: - Load S-57 ENC (US5WA45M.000) via GDAL/OGR. - Apply classification rules described in TERRAIN section above. - 8. Compute shadow masks using radial elevation-angle march along each - azimuth bearing for each of the following radar positions: - - Fixed marine platform (lat 48.7436, lon -122.5647) - - ATC tower at BLI - - BOAT_CLUTTER_MASK_COUNT boat waypoints from BOAT_SIM_WAYPOINTS[] - All shadow masks use the same algorithm; only the origin differs. - 9. Write to map/lidar_processed/: - elevation.f32 float32 row-major grid, meters, WGS84 - material.u8 uint8 per cell (0=water 1=soil 2=rock 3=concrete) - shadow_marine.u8 uint8 visibility mask for marine radar - shadow_atc.u8 uint8 visibility mask for ATC radar - shadow_boat_000.u8 … - shadow_boat_NNN.u8 uint8 visibility masks for boat waypoints; - NNN = zero-padded waypoint index - terrain_meta.json grid dimensions, lat/lon origin, cell size, - checksums for all four source files, - processing date, - boat mask waypoint lat/lon list - -RUNTIME VALIDATION - TerrainMap reads terrain_meta.json at startup and compares the stored - bounding box and cell-size values against current settings.h constants. - If they differ it prints a warning and continues with stale data: - WARNING: terrain data was built with different bounding box or - cell size — re-run terrain_preprocess before exhibit launch. - The exhibit does not crash; it runs with the old grid. - -OUTPUT FILES (map/lidar_processed/) - elevation.f32 — float32 elevation grid - material.u8 — uint8 material classification grid - shadow_marine.u8 — uint8 line-of-sight mask, marine radar - shadow_atc.u8 — uint8 line-of-sight mask, ATC radar - shadow_boat_000.u8 … — uint8 line-of-sight masks for boat waypoints - shadow_boat_NNN.u8 (BOAT_CLUTTER_MASK_COUNT files total) - terrain_meta.json — metadata, provenance record, and boat mask - waypoint lat/lon list used for nearest-mask lookup - - These files are the only terrain inputs at runtime. - The raw source files in map/lidar_raw/ and map/charts_enc/ are - never opened by the exhibit binary. - -================================================================== - -BOAT SCENARIO - -================================================================== - -The boat scenario (scope 6 — Police Patrol Boat PPI) simulates a Bellingham -Police Department patrol vessel making its waterfront patrol. The radar is a -6 kW professional open-array unit (1.9° beamwidth), not the same hardware as -the fixed coastal marine radar. The radar origin moves with the boat every sweep. - -PATROL ROUTE FILE — data/patrol_route.json - - Loaded by the Simulator at startup. Not compiled in — the route can be - refined without a rebuild. Format (approximate): - - { - "waypoints": [ - { "lat": 48.7530, "lon": -122.5150, "speed_kt": 10.0, - "zone": "Ferry lane — open waterfront" }, - { "lat": 48.7480, "lon": -122.5050, "speed_kt": 4.0, - "zone": "Near Squalicum breakwater" }, - { "lat": 48.7460, "lon": -122.5120, "speed_kt": 10.0, - "zone": "Open waterfront west" }, - { "lat": 48.7380, "lon": -122.5200, "speed_kt": 10.0, - "zone": "Boulevard Park approach" }, - { "lat": 48.7340, "lon": -122.5150, "speed_kt": 4.0, - "zone": "Taylor Dock area" }, - { "lat": 48.7320, "lon": -122.5050, "speed_kt": 4.0, - "zone": "Community Boating Center" } - ], - "loop": "reverse" - } - - "loop": "reverse" means the boat reaches the last waypoint then reverses - direction back through the list — a back-and-forth patrol, not a closed loop. - All coordinates are open water; marina and Whatcom Waterway entry deferred. - Adjust lat/lon values to keep the vessel in navigable water once the ENC - coastline is loaded. Values above are starting approximations. - -BOAT NAVIGATION SIMULATION (Simulator, Thread 4) - - The Simulator maintains a BoatNavigator sub-object that loads the JSON route - at startup and advances the vessel each time TrafficCop polls. Data returned - to TrafficCop alongside the regular target list: - boat_lat_deg — current latitude (degrees WGS84) - boat_lon_deg — current longitude (degrees WGS84) - boat_heading_deg — current true heading (degrees, 0 = north) - boat_speed_kts — current speed from active waypoint segment - boat_zone_str — zone label string for left panel display - - TrafficCop writes these to SharedRenderState under Mutex A. - Thread 1 reads them every frame when BoatPPIScope is active. - - Navigation algorithm (runs in Simulator::poll(), Thread 4): - 1. Compute great-circle bearing from current position to next waypoint. - 2. Rotate boatHeadingDeg toward that bearing at up to - BOAT_HEADING_TURN_RATE_DEG_S per elapsed second (clamped). - 3. Advance position along current heading at the current segment speed_kt. - 4. If distance to next waypoint < BOAT_WAYPOINT_ARRIVAL_M, advance index. - On reverse-loop: flip traversal direction at each end. - 5. Store updated state in BoatNavigator; return to TrafficCop on poll. - -TARGET PROJECTION FOR MOVING RADAR ORIGIN - - For fixed scopes, target positions are projected from a known constant origin. - For the Boat PPI, TrafficCop recalculates each target's polar coordinates - relative to the boat's current position after every poll. - - Flat-earth projection (adequate for 2 nm max range): - dx_m = (target_lon − boat_lon) × cos(boat_lat × π/180) × METERS_PER_DEGREE - dy_m = (target_lat − boat_lat) × METERS_PER_DEGREE - range_m = sqrt(dx_m² + dy_m²) - bearing_deg = atan2(dx_m, dy_m) × 180/π (adjusted to 0–360, CW from north) - - METERS_PER_DEGREE = 111320.0 (constexpr in settings.h). - Result (range_m, bearing_deg, brightness) stored in TargetBuffer under Mutex B. - -HEADING MARKER RENDERING - - BoatPPIScope::renderHeadingMarker() runs inside render() after all phosphor - content, using the graticule shader so the line never decays. - - Geometry: dashed line from scope center to - center + BOAT_HEADING_MARKER_FRACTION × scope_radius - in the direction (boatHeadingDeg + bearingOffsetDeg). - Color: BOAT_HEADING_MARKER_COLOR (default white). - Dash/gap: BOAT_HEADING_MARKER_DASH_PX / BOAT_HEADING_MARKER_GAP_PX. - -DISPLAY MODE LOGIC - - Every frame, BoatPPIScope computes: - float diff = fabs(fmod(bearingOffsetDeg − boatHeadingDeg + 540.0f, 360.0f) − 180.0f) - mode = (diff <= BOAT_HEADUP_TOLERANCE_DEG) ? "Head-up" : "North-up" - Rendered as white text in the left-panel status area. - -TERRAIN CLUTTER AND BREAKWATER SHADOWS - - See SHADOW / LINE-OF-SIGHT MASKING → Boat PPI scope scenario for the - mask-selection algorithm and shadow_boat_NNN.u8 file set. - - The Squalicum Harbor outer breakwater is a significant shadow-caster. - From any open-water patrol position the interior of the marina basin is - shadowed — nothing behind the breakwater is visible. This is realistic - and is visible on the scope as a sharp shadow arc on the far side of the - breakwater return. - - At the start of each 4-second sweep, BoatPPIScope::updateLandClutter() calls: - 1. TerrainMap::selectNearestBoatMask(boatLatDeg, boatLonDeg) - 2. LandClutter::generateForBoat(boatLatDeg, boatLonDeg, maskIndex) - 3. Upload new polar clutter texture to GPU. - If the mask index is unchanged from the previous sweep, steps 2–3 are skipped. - - Terrain clutter shader receives: - u_radarOffsetM = vec2( - (boatLon − MARINE_PLATFORM_LON) × cos(boatLat × π/180) × METERS_PER_DEGREE, - (boatLat − MARINE_PLATFORM_LAT) × METERS_PER_DEGREE) - -V1 GEOMETRY SCOPE (open water only — marina deferred) - - - Outer shoreline of Bellingham Bay - - Squalicum Harbor outer breakwater (solid, strong return, shadow-caster) - - Ferry terminal structure (Bellingham Cruise Terminal area) - - Taylor Dock pier outline (weak return — wood, but pilings visible) - - Boulevard Park shoreline - Internal marina dock fingers, Whatcom Waterway channel walls, and Georgia - Pacific / Waterfront District structures are deferred until the patrol - route is extended into those areas in a future version. - - -IMPORTANT NOTES ON IMPLEMENTATION - -To facilitate debugging: - -1. All p7 persistent stuff should be in one shader; with uniforms that are set by - the settings.h file for time of decay and anything else to facilitate debugging - The p7 persistent shader itself shall be able to be turned off by way of the settings - file. This would allow debugging of the strike (blue) data for each scope. -2. The blue strike activity (prior to persistence) should have a debugging variable - in settings.h so I could do a persistence evaluation by my eyes without the persistence - shader -3. each scope shall have its own shaders for the target activity (what is struck in - the blue color on the screen). This will allow debugging. Note that these shall - have on/off toggles. -4. The three land features (shoreline, terrain, and lidar) should each have their own shaders - to facilitate debugging. Each of these shaders should be turned off and on via settings in - the settings.h file so that I can try each one one at a time. - -C++ files for the CPU should be divided as follows: - -1. Programs that feed the shaders for each scope -2. Receiving program (the traffic cop) for handling targets for each raspberry pi as well as - the simulator. -3. The simulator -4. Initialization of the display -5. Loading the shaders -6. handling controls from keyboard for each scope -7. Each scope's general operation including targets, graticules, max range, -8. The code (now stubs) that handles input from a real control panel with knobs. - - -DO NOT CODE ANYTHING diff --git a/possible-claude.md-changes b/possible-claude.md-changes deleted file mode 100644 index 5345f48..0000000 --- a/possible-claude.md-changes +++ /dev/null @@ -1,80 +0,0 @@ -Implementation: Use a Frame Buffer Object (FBO). Instead of clearing the screen each frame, draw a full-screen quad with a very low alpha (e.g., 0.95) to slowly "dim" previous sweeps. - -Threading for PostgreSQL and LIDAR - -Reading from PostgreSQL (targets) and GDAL (LIDAR terrain) can cause "micro-stuttering" if done on the main render thread. - - The Simulation Thread: Create a background thread that polls the target_data table and updates a thread-safe std::vector. - - The Render Thread: The OpenGL loop should simply read the latest target positions and render them at 60 FPS (or higher) to keep the "sweep" of the PPI radar smooth. - -Class Hierarchy and PPI SpecificsSince you have four distinct scopes (Chain Home A-Scope, Marine A-Scope, Stationary PPI, and On-boat PPI), a State Pattern is ideal.BaseScope Class: Handles the universal Intensity and Sensitivity variables.AScope Subclass: Implements the horizontal sweep and the "curved waveform" logic for the marine version.PPIScope Subclass: Implements the $360^\circ$ rotation logic. For the "On-boat" version, you will need to pass the boat's own GPS/Heading coordinates (from GDAL/LIDAR) into the shader to offset the target positions. - -Deepseek: - -Mathematical Logic vs. Contextual UnderstandingDeepSeek's Strength: DeepSeek is often more "aggressive" with mathematical optimization. It will likely give you very efficient GLSL code for the $1/R^4$ calculations.The "DeepSeek.md" file: You should rename your instructions to DEEPSEEK.md. DeepSeek models are trained to look for specific instructions in the root directory, similar to how Claude looks for CLAUDE.md. - -Explicit Hardware Prompting - -While Claude is currently aware of the AMD Radeon 780M and Ubuntu 25.10 nuances through our conversation, DeepSeek may require more explicit "reminders" about: - - Mesa Drivers: Remind it to avoid vendor-specific (NVIDIA) extensions. - - C++20 Strictness: DeepSeek sometimes defaults to older C++ standards; ensure your CMakeLists.txt is the first thing it reviews to lock it into your C++20 requirement. - -Coding Style Enforcement - -DeepSeek is generally good at following style guides, but it can be "talkative." You may need to add a directive: - - "Provide code only. Do not explain standard C++ features unless they relate directly to the OpenGL 4.3 Core specification or the Geekom A8 Max hardware." - -Suggested Additions to your .md file - -To help either AI (Claude or DeepSeek) write better code for the PPI scopes, I recommend adding these details to your file: - - PPI Rotation Speed: Specify the "RPM" for the marine traffic control (e.g., 12-24 RPM). - - The "North-Up" vs "Head-Up" display: For the on-boat radar, will the display rotate as the boat turns (Head-Up), or will "North" always be at the top? - - LIDAR Resolution: Define how many LIDAR data points should be converted into "clutter" on the radar screen. - -This setup on your Geekom A8 Max should provide plenty of power to handle both the PostgreSQL queries and the complex OpenGL fragments required for a realistic "vintage" look. - -Proposed Addition: > [THREADING MODEL] - - Main/Render Thread: Handles the OpenGL loop, GLFW input, and glDraw calls. It must remain non-blocking to ensure a smooth 60 FPS sweep. - - Simulation/Data Thread: A background thread that polls the target_data table and updates a thread-safe shared state (using std::mutex or atomics) for the Render thread to consume. - -The PPI Scope Particulars - -Since you are ready to define the two PPI modes (Stationary and On-Boat), adding these "Rules of Behavior" will prevent the AI from guessing. - - Proposed Addition: - - [PPI SCOPE SPECIFICS] - - Persistence (Phosphor Decay): Implement using a Frame Buffer Object (FBO). Do not clear the color buffer every frame; instead, draw a semi-transparent black quad to simulate 1940s-60s CRT decay. - - Marine Traffic Control (Stationary): Fixed location. Targets move relative to the center of the scope. - - Police Boat (On-Boat): The center of the scope is the boat. Integrate boat heading (heading-up display) so the "world" rotates around the observer as the boat turns. - -File Structure & CMake Prep - -To make the two-step CMakeLists.txt generation easier, add a section for organization. - - Proposed Addition: - - [PROJECT STRUCTURE] - - /src: All .cpp source files. - - /include: All .hpp header files. - - /shaders: External .glsl files for vertex and fragment shaders. - - /data: Location for GDAL LIDAR and ENC chart files. - - -pdated Logic for DeepSeek/Claude SelectionOnce you add these, the transition will be seamless:Claude will be better at setting up the Class Hierarchy (the BaseScope and its derivatives) because it follows the "System Engineer" logic of your persona very well.DeepSeek will be excellent if you need to optimize the GLSL Shaders for the $1/R^4$ logic or the GDAL coordinate transformations, as it tends to be very mathematically rigorous.How to proceed:Go ahead and update your CLAUDE.md with these details. Once you're ready, paste the updated content here (or just tell me it's done), and we can generate that Foundation CMakeLists.txt to get your Geekom A8 Max environment ready for the first "Hello Radar" sweep. diff --git a/sec-stuff b/sec-stuff deleted file mode 100644 index 850640b..0000000 --- a/sec-stuff +++ /dev/null @@ -1,52 +0,0 @@ -LOcked key method on backup linode - -from="PROD_IP_HERE",command="/usr/local/bin/run-backup.sh",no-agent-forwarding,no-port-forwarding,no-X11-forwarding,no-pty ssh-rsa AAAAB3... (rest of your key) - -Create a simple script at /usr/local/bin/run-backup.sh on the backup machine: - -#!/bin/bash -# 1. Sync the Gitea Database (assuming it was dumped to a file) -# 2. Re-run the Git Clone/Pull for your radar & website projects -cd /path/to/backup/folder -git pull origin main || git clone http://your-gitea-url/repo.git . - -# Optional: Log the backup time -echo "Backup successful: $(date)" >> /var/log/backup_history.log - - -from="PROD_IP",command="/usr/share/doc/rsync/scripts/rrsync -ro /mnt/backups/ilovearthur/",restrict ssh-rsa AAAAB3... - -#!/bin/bash -# Sync critical system and user data -rsync -az --delete /etc /var /home root@backup.ilovearthur.org:/ - - - - - -Wrapper script on backup server - -#!/bin/bash -case "$SSH_ORIGINAL_COMMAND" in - rsync*) - # Allows rsync to only touch the designated backup folder - $SSH_ORIGINAL_COMMAND - ;; - "git-sync") - # Custom command to refresh your Gitea mirrors - cd /home/backups/radar-repo - git pull || git clone http://your-gitea-url/repo.git . - ;; - *) - echo "Access Denied: Command not permitted." - exit 1 - ;; -esac - -Authorized keys file: - -from="PROD_IP",command="/usr/local/bin/backup-handler.sh",no-agent-forwarding,no-port-forwarding,no-pty ssh-rsa AAAAB3... - - -from="192.0.2.1,2001:db8::1",command="/usr/local/bin/backup-handler.sh",no-pty ... [your-ssh-key] -