Files
modular-radar/CLAUDE.md

474 lines
23 KiB
Markdown

This is a project for a museum to demonstrate a simulation of a 1940's to 1960's
vintage radar, including the Chain Home radar from early World War 2, marine radar
at a marine traffic control station, and marine radar on a boat.
The project will be implemented on a Geekom A8 Max
32 GB RAM
AMD Ryzen 9 8945HS w/ Radeon 780M Graphics
We need to render to the Radeon 780M Graphics GPU
Tech Stack: We are using C++20, OpenGL 4.3 Core, GLFW, GLAD, FreeType, GDAL (libgdal-dev)
Compiler: is g++ (Ubuntu 15.2.0-4ubuntu4) 15.2.0
Coding will be done using the c++ language for the CPU
GPU coding will be GLSL (as required by OpenGL)
FreeType is the text type we use
GDAL is used for reading the LIDAR/ENC chart files
GLFW (graphics library framework) open-source, multi-platform library used to manage windows
GLAD (Multi-Language GL/GLES/WGL/GLX Loader-Generator) Loads the pointers to
OpenGL functions (like glDrawArrays or glCompileShader)
PostgreSQL is installed. Database: radar. User: radar. Password: radar.
User has full privileges on database radar. Table is target_data.
Operating system details:
Distributor ID: Ubuntu
Description: Ubuntu 25.10
Release: 25.10
Codename: questing
Use cmake for building.
[DIRECTIVE: GPU ROBUSTNESS PROTOCOL]
Debug Callback: Enable GL_DEBUG_OUTPUT and glDebugMessageCallback
to capture driver-level warnings and errors in real-time.
I will be using SSH from Windows to write code and check with claude.
You may compile the code during an SSH session.
Please do not try to run the code during SSH session.
I will run the code while physically using the Geekom.
Please add MIT license header to each file
Please add Author: Mark Allyn to each file
Use snake_case for variables and PascalCase for classes
use #pragma once
Use // for single line comments
use /* */ for multiple block comments spanning multiple lines
avoid using auto
==================================================================
SYSTEMWIDE INCLUDE FILE AND GLOBAL DATA FILE
This file is located at /include/data_structure_and_constants.h
There will be a system wide include header file for constants and
data structures
For each entry in this file (which may be added piecemeal, a comment
needs to be in place with the name of the components that uses that
constant or data structure. Note that these comments will be updated
as I add new components to be built.
SYSTEMWIDE GLOBAL DATA FILE
There will be a file containing global data items.
The file is at global_data.cpp
For each entry in this file (which may be added piecemeal, a comment
needs to be in place with the name of the components that uses that
constant or data structure. Note that these comments will be updated
as I add new components to be built.
SYSREMWIDE TESTING AND SETTINGS INCLUDE FILE
The system wide testing and configuation file, located at include/settings.h
The values for each component shall be preceded by the session name
as a comment. It shall be included in all components.
Please use this file for defines and variables that I can
change and do a simple re-compile instead of having the ai re write the
code. This is for debugging. For example, I may want to disable the p7 persistance
to troubleshoot the actual target processnig before it goes to persistance,
disable the land and terrain so that I can see the targets alone. Things like
that.
==================================================================
PIECEMEAL BUILDING
This project will be built piecemeal. Each components will be build by itself an integrated
with components that have been already built.
Each component will have its own .md file for instructions and specifications.
As a component is built and tested, I wil add a statement at the end of it's
.md file, looking like "COMPONENT DONE"
Please note that each component shall have it's own c++ file; its own .h file;
and it's own sets for shaders. Full independance.
The name of each component shall have a number, then an undeline, then the name
of the component, for example 01_classes, 02_management, 03_chain_Home, and so on.
==================================================================
TEMPORARY TESTING FILES
As each component if built, I may ask for temporary files to be created
for testing of the component. For example, I may ask for targets on a radar
before any target handling code is made.
I will indicated what is needed to be built. And when I am done testing, I will
instruct that that file be deleted. These instructions will be done during the
dialog with claude code.
===================================================================
HANDLING COMPILE AND BUILD OF SHADEARS DURIANG PIECEMEAL BUILDING
As you know, all shaders are to be built and loaded at the beginning
of the application.
I propose that each components will have it's own code for making the linking
its shaders as a function that will be called by the system's initialization code.
====================================================================
Summary of project:
This is a museum exhibit displaying and providing some interaction
of vintage 1940's, 1950's, and 1960's radars. A key objective is to
provide interaction with and viewing of radars from that era.
The name of the application (the name of it's executable file) shall be
radar_simulator. Therefore, if you are in the directory in which the executable
is compiled, which in this case would be the build subdirectory of the project
directory, you would type ./radar_simulator, or use a full path name
of {PROJECT_DIR}/build/radar_simulator.
In the CMakeLists.txt, plese use the name radar_simulator for the add_executable call.
There will be three main areas of the screen. On the right hand side will be the radar
scope.
On the left hand side of the screen will be a text description of the scope as well
as the controls of the scope and keyboard keys for each control. This text will be
white while the control labels will be red and the keystrokes will be in pink.
At some point, pending a decision with the museum, we may purchase components to mount the controls on a panel. Until that is done, the controls will be on the keyboard.
On the right hand side of the screen, below the scope, would be a text status window, showing current
maximum range, range, and bearing as appropriate to which scope we are using as well as the identification
of the scope that we are using.
Suggest that we use glViewport to define the left-hand text area, the main scope,
and the yellow status bar. This allows you to render the scope with its own coordinate
system while keeping the text fixed. Along with glViewport, use glScissor and glEnable(GL_SCISSOR_TEST)
Below the scope will be a text status window. This text will be yellow
Scopes in the right panel
1. Introduction of Exhibit (Explanation of the project on the left hand text panel.
2. A-scope for Chain Home Radar in the 1940's (first radar and could be tricky)
3. A-scope for marine radar in the 1940's (Before PPI radar); was a bit tedious to operate
4. PPI scope for marine traffic control (uses beam sweeping in all 360 degrees of
rotation); Easier to use than a scope
5. PPI scope on board a boat. Shows how movement of a boat affects the radar display
Please note that these scopes will not appear all at once. The selection of which scope
the visitor sees is done by pressing a forward control and a reverse control to go around
the loop of scopes. The first display when the system is turned on or booted up is the
Introduction of the exhibit.
=====================================================================
CONTROL DEFINITIONS
Please note that the first iteration of the project will have only minimal controls.
This is a suggestion I got after meeting with the museum staff. Perhaps later we may
add more controls.
Also, please note that the state of the controls of each scope is independent of any
other scope. Furthermore, the controls will reset when a scope is exited and then re-entered.
Controls to affect the behavior of the scopes; (these first implemented using keyboard
strokes; later when and if physical controls are completed, the keyboard controls will be removed)
These controls will affect the state variables and the uniform variables of the shaders.
Please note that identical controls will be the same keyboard strikes or physical controls for all scopes.
=======================================================
Overall control information
These are knobs on the panel once that is built. Keyboard keys until then
1. Radar Selection - which radar to run. Selection is done with up or down; the radars are to be
in the selection order as follows 1, chain_home; 2, marine_ascope; 3, marine_traffic; 4, police boat.
When the application is started, chain_home is current selection. You go up, then marine_ascope is
selected. And so on. Then you hit enter to activate the selected radar. The Keyboard is 1 for going
forward; 2 for going backward. Note that when a radar is operating, you can go back to the selection
bt using the 1 key to go back to the selection.
2. Intensity - scope overall intensity - Keyboard 3 is lower; 4 is higher - uniform is float intensity;
3. Receiver Sensitivity - signal intensity - Keyboard 5 is lower; 6 is higher - uniform is float sensitivity;
4. STC Sensitivity - sensitivity for closer in targets which can overwhelm
overall sensitivity - keyboard q for lower; w for higher - uniform is float stc_sensitivity;
5. STC Range - range to which sensitivity to closer targets is effective
keyboard e for lower; r for higher - uniform is float stc_range;
6. Noise filter for rain noise. This is for the ppi scopes. keyboard t for decrease filtering and y
to increase filtering - uniform is float noise_filter;
7. Radiogoniometer knob for Chain Home; keyboard u for left turn;
i for right turn. - uniform is float radiogoniometer;
8. Maximum Range for all scopes except for chain home, which is fixed. This control
will not operate for Chain Home. These maximum
range selections will be defined for each scope; If you try to go beyond the stated
maximum ranges, the control will have no effect; note that the default maximum range would
be the highest for that scope; keyboard o for lower; p for higher uniform is float max_range;
9. Range Cursor (for ppi scopes, not for a scopes)
keyboard a for lower; s for higher - uniform is float range_cursor;
10. Bearing Cursor (for all ppi scopes; not for a scopes)
keyboard d for counterclockwise f for clockwise uniform is float bearing_cursor;
11. Bearing for Marine A Scope. This is not for a cursor, but this operates the motor
that revolves the antenna unit keyboard g for counterclockwise and h for clockwise
uniform is float marine_a_bearing;
Notes; I am maintaining control separation between radiogon, marine a scope bearing, and ppi bearing.
However, when I make the control panel, those will be combined as one physical knob with three
labels, chain home radiogon, marine a scope antenna rotation, and ppi scope bearing to save on
hardware; the same physical control can be used for multiple scopes.
Note that the range cursor is different from the maximum range. Maximum range is the maximum
radar range setting and range cursor is the range portion of the ppi cursor.
Note that these are to be implimented as I work on each component. You cannot impliment all of these
at the beginning as there will be no shaders for the uniforms
Note that a copy of each uniform shall be maintained in the global_data.cpp file.
===================================================================
Some data structures from my previoius work that should be relavent:
All targets from the network pipeline and simulator map to this C master structure:
struct target_data_structure {
double target_longitude;
double target_latitude;
std::string vessel_name; // will be null for no available name
std::string registration; // will be null for no registration
float length; // in meters
float beam; // in meters
int vessel_type; // AIS type code or aircraft type
uint32_t mmsi; // AIS unique identifier; ICAO hex address for aircraft
float course; // course over ground, degrees, based on true north
float speed; // speed over ground, knots
float altitude; // meters, but 0 for boats
int type; // type of target; vessel or aircraft; 0 = vessel
int police_boat // 1 is police boat; 0 is not
time_t timestamp;
};
Of this heavy structure, only the following lean mathematical footprint is submitted
to the graphics shaders via an OpenGL Shader Storage Buffer Object (SSBO) layout(std430):
ssbo_target_information { // This is what is sent to the shaders as SSBO
float target_x; // Pre-converted local Cartesian offset X (meters relative to radar)
float target_y; // Pre-converted local Cartesian offset Y (meters relative to radar)
float length; // Vessel length bounds (meters)
float beam; // Vessel beam bounds (meters)
float course; // Course over ground vector (radians relative to True North)
float altitude; // Target altitude profile (meters = 0 for boats)
time_t timestamp; // Data aging tracking identifier
float current_reflectivity; // derivied from vessel_type (see table below)
float height_estimate; // derived from vessel_type (see table below)
float noiseglint; // derived from vessel_type (see table below)
int32_t police_boat; // this indicates that the target is for the roaming police boat. 1 = police boat
uint32_t mmsi; // AIS unique identifier; ICAO hex address for aircraft
int type; // target type (0 for boat 1 for aircraft)
};
This is the structure sent to the software to send to the shaders. It does include the
text (string) values, but those are stripped off prior to being sent to the shaders.
struct target_data_to_thread_1_structure {
float target_x; // Pre-converted local Cartesian offset X (meters relative to radar)
float target_y; // Pre-converted local Cartesian offset Y (meters relative to radar)
std::string vessel_name; // will be null for no available name
std::string registration; // will be null for no registration
float length; // Vessel length bounds (meters)
float beam; // Vessel beam bounds (meters)
float course; // Course over ground vector (radians relative to True North)
float altitude; // Target altitude profile (meters = 0 for boats)
time_t timestamp; // Data aging tracking identifier
float current_reflectivity; // derived from calculation based on material - is dynamic
float height_estimate; // derived from vessel_type (see table below)
float noiseglint; // derived from vessel_type (see table below)
int32_t police_boat; // this indicates that the target is for the roaming police boat. 1 = police boat
int type; // target type (0 for boat 1 for aircraft)
uint32_t mmsi; // AIS unique identifier; ICAO hex address for aircraft
};
Please note that height and material are not included in the data received from the simulator
nor the raspberry pis. This has to be derived. That will be discussed when I talk about the
traffic cop component.
Please note that the ssbo_target_information
data structure does not include the vessel_name nor the registration.
Those do not go to the shaders.
Here is the data items for the table in the Postgres database:
1. float length
2. float beam
3. int32_t may_need_update (this if a randome value is applied to any part of the target
and that the user may want to update the database. This
will not force the user to do the update, a later
database editing program will use this.
4. int vessel_type (AIS type code or aircraft type)
5. int type (1 for airplane, 0 for boat)
6. uint32_t mmsi (unique identification for boat or ICAL for aircraft
7. float reflectivity (derived from target type)
8. float height_estimate (derived from target type)
9. float noiseglint (derived from target type_
10. std::string vessel_name;
11. std::string registration;
12. int32_t police_boat (this indicates that this is for the police boat - 1 is true)
Please note that this database is only for the physical characteristics. Dynamic
information which is created by the simulator (or raspberry pis) as that data changes.
=====================================================================
THE THREAD INFORMATION
I don't know how the mutex data is handled in an include file or global data;
This is the outline of the threads that I know so far. We add those as needed when we
get to the components that need them.
Now, lets discuss the threads. There will be five threads:
Thread 1 = Operation of setting up the system; ie; initializeing Opengl,
compiling, building, and loading all of the shaders. It also handles
the keyboard operation of the radar controls as those are callbacks from
the OpenGL. Accepting target traffic from the Traffic Cop will be performed,
however, the Traffic Cop will need to assert mutex-target-data in order to write any
target data to this Thread 1.
Please note that this thread also includes the hit_test as noted below.
Thread 2 = Traffic Cop. The Traffic Cop will accept Target Data from the Simulator (which
will be discussed here) ; and the AIS and ADS(b) data from the raspberry pis. At
this time, we need to provide only a stub withing the traffic cop to access the Raspberry pis.
The traffic cop will need to set a mutex-target-data before
handing radar traffic to the Thread 1 software
which will send the radar data on to the shaders. Note that the traffic cop needs to do
the following processing with target data:
1. Convert the GPS longitude information to the local coordinates for each radar.
2. Check and discard targets that are outside the range of the radar that is
currently being used.
3. Discard targets whose timestamp is older than 1 hour
Thread 3 = Simulator. The simulator creates and manages the simulated targets. It needs to
assert mutex-simulator-to-traffic-cop to transfer target information to the Traffic cop
Thread 4 = Physical controls, knobs and switches. This has not been developed and will not
be developed with the current version of the project. It will be developed later. It
does need to set a mutex-control-data-to-shaders in order to send control
information to Thread 1 so that thread
can set the state variables and the uniforms for the controls in the shaders.
Thread 5 = Raspberry pi data recever = this receives the data from the raspberry pis. It will
not be developed for the current version of the project. The Raspberry PI receiver will
need to set mutex-raspberry-pi in order to transfer target data to the traffic cop.
Thread 6 = Physical control panel (to be defined later)
This will handle control operations from the physical control panel. It will need
to make appropriate changes to the CPU globals and the uniforms in the shades,
similar to the Keyboard controls. However, since this thread 6, it will need
to assert the mutex-to-pass-controls-to-thread-1 mutex before sending
values to thread 1.
================================================================================
RADAR STATUS INFORMATION AND CONTROL
The curent exhibit proposal has four discrete radars:
Chain Home : Radar developed by United Kingdom for defending
the south west coast (Vetnor) from attacks from the continent.
It is called chain_home. All variables and function names and
shader names shall be prefixed with "chain_home". For this exhibit,
it's location is at RAF Vetnor (Isle Of Wight) at:
Decimal Degrees (Latitude / Longitude): 50.600° N, 1.183° W
Marine A-Scope : Manually Pointable Radar used by United Kingdom to
discover germain submarines when they come up to charge their batteries.
It's key feature is a microwave dish antenna that is manually pointed
by the operator using a servo control to electrically rotate the
microwave dish antenna. This radar preceded the development of
the modern Plan Poing Indicator radars of todky. All variables and
function names and shader names shall be prefixed with "marine_ascope"
For this exhibit the location is on a boat moored at the dock of the
Community Boating Center (not movable) at:
latitude \(48.70529^{\circ}\text{ N}\) and longitude \(-122.50547^{\circ}\text{ W}\)
Marine Traffic Control PPI Radar : This is a PPI radar using the plan position indictor.
This is a more powerful stationary radar that is used for marine traffic control. The Coast
Guard uses them.
All variables, function names, and shader names shall be prefixed with "marine_traffic".
For this project, the marine traffic control radar is located
in the center of Bellingham Bay at:
latitude \(48^\circ 43' 25" \text{ N}\) and longitude \(122^\circ 34' 35" \text{ W}\)
Marine Radar On Police Boat : This is a PPI radar that is located on a police boat. The purpose
of this radar (which behaves the same as the Marine Traffic Control Radar) is to demonstrate
to the museum guest how a radar scope changes as a bost moves and changes direction. It is lower
power than the Marine Traffic Control PPI Radar.
All variables, function names, and sharder names shall be prefixed with "police_boat".
This radar and boat shall be moveable like any other target.
For this exhibit, the starting location, when
the exhibit is started, is at the dock at the end of Tayor Street and the Boulevard Park
boardwalk at:
48.7253874° N latitude and -122.5077482° W longitude.
Selection and availability of the radars:
The museum operator, upon startup of the exhibit shall be able to select which radars are to
be avaailable for use by the museum visitors. This selection shall be via passing parameters
when starting the exhibit.
The operational status for each radar shall be noted by a variable indicating whether the
radar is working within a global data structure.
The currently selelction of which radar is currently operating shall also be noted by a global
data structure.
Here is a suggested global data for managing the radars:
struct radar_management_structure {
int radar_type // 1 is chain_home; 2 is marine_ascope; 3 = marine_traffic 4 = police_boat
int operatable; // 1 is yes, 0 is no
int available; // 1 is yes, 0 is no - this is the one controled by the exhibit owner
int selected; // 1 is currently operating, 0 is not operating
int testing; // What is being developed and tested; 1 = overall management
including startup and radar selectionr,
2 = chain_home, 3 = marine_ascope, 4 = marine_traffic, 5 = police_boat, 6 = traffic_cop,
7 = simulator, and 8 = raspberry pi receiver
};
Note that if a radar is in testing, no other radars can be available. Also testing code can be used
to work on the radar being tested and developed
In the global data, we need these items:
struct radar_management_structure radar_management;
int current_radar; // 0 is none; 1 is chain_home; 2 is marine_ascope; 3 is marine_traffic; 4 is police_boat
===========================================================================