931 lines
44 KiB
Markdown
931 lines
44 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
|
||
|
||
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
|
||
|
||
Please use a settings.h 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.
|
||
|
||
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.
|
||
|
||
Before going, we must point out the target information handling which will
|
||
affect all scopes.
|
||
|
||
====================================================================================
|
||
|
||
TARGET DETAILS & TARGET PIPELINE
|
||
|
||
Targets for this project will come from two sources:
|
||
|
||
1. Raspberry pis communicating with an AIS receiver for boats and
|
||
an ADS-b receiver for aircraft
|
||
2. An on-board simulator that will simulate targets using an internal
|
||
table of target information in the postgresql database.
|
||
|
||
Please note that the components for the AIS and ADS-B target
|
||
handling are not yet available, thereby the programming for that
|
||
source will not be defined at this point.
|
||
|
||
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
|
||
time_t timestamp; // time of last fix; used to age out stale targets
|
||
float altitude; // meters, but 0 for boats
|
||
TargetType type; // type of target; vessel or aircraft
|
||
};
|
||
|
||
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):
|
||
|
||
struct target_data_to_shader_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)
|
||
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)
|
||
time_t timestamp; // Data aging tracking identifier
|
||
};
|
||
|
||
The segment handling asynchronous target ingestion is called traffic_cop.
|
||
The traffic_cop runs on a dedicated background execution thread separate from the rendering loop.
|
||
Data synchronization between threads must be managed explicitly using std::mutex blocks.
|
||
|
||
[TRAFFIC COP OPERATIONAL TIMING PROTOCOL]
|
||
1. Processing Loop: Aggregated targets are packaged into a uniform array and dispatched
|
||
as a batch operation precisely when the PPI radar sweep line crosses 0.0 radians (True North).
|
||
2. Range Filtering: Discard any targets residing outside the active radar's designated maximum operational range.
|
||
3. Altitude Restriction: Enforce a strict <= 40-meter restriction for marine nodes (Marine Chain Home
|
||
and all PPI Marine radars). Discard any aircraft violating this ceiling.
|
||
4. Precision Alignment: Latitude and longitude coordinate conversions into local meters relative to
|
||
the radar origin must be handled on the CPU thread within traffic_cop to protect against FP32 structural precision rounding errors inside the GPU.
|
||
5. Critical Section: Assert a std::mutex to gain safe writing access to the double-buffered array driving the SSBO, copy the structural contents, and clear the mutex immediately.
|
||
|
||
Note that the construction of the simulator will be discussed later in this document.
|
||
|
||
=============================================================================
|
||
|
||
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. Intensity - scope overall intensity - Keyboard 3 is lower; 4 is higher
|
||
2. Receiver Sensitivity - signal intensity - Keyboard 5 is lower; 6 is higher
|
||
3. STC Sensitivity - sensitivity for closer in targets which can overwhelm
|
||
overall sensitivity - keyboard q for lower; w for higher
|
||
4. STC Range - range to which sensitivity to closer targets is effective
|
||
keyboard e for lower; r for higher
|
||
5. Noise filter for rain noise. This is for the ppi scopes. keyboard t for decrease filtering and y
|
||
to increase filtering
|
||
6. Radiogoniometer knob for Chain Home; keyboard u for left turn; i for right turn.
|
||
7. 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
|
||
8. Range Cursor (for ppi scopes, not for a scopes) keyboard a for lower; s for higher
|
||
9. Bearing Cursor (for all ppi scopes; not for a scopes)
|
||
keyboard d for counterclockwise f for clockwise
|
||
10. 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
|
||
|
||
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.
|
||
|
||
=========================================================================
|
||
RADAR EQUATION (for all radars; note that is different for chain home)
|
||
|
||
The fundamental radar equation describes how much power returns to a radar system
|
||
after bouncing off a distant target.
|
||
|
||
Physically, it follows a "round-trip" journey of energy: the radar transmits a signal
|
||
that spreads out as a sphere (losing strength by the square of the distance, $R^2$),
|
||
hits a target that reflects a portion of that energy (the Radar Cross Section, $\sigma$),
|
||
and that reflection then spreads out again as a second sphere on its way back (losing
|
||
another factor of $R^2$).
|
||
|
||
控制方程 (Governing Equation):
|
||
$$P_r = \frac{P_t G^2 \lambda^2 \sigma}{(4\pi)^3 R^4}$$
|
||
|
||
Where:
|
||
P_r = Received Echo Power (Watts)
|
||
P_t = Peak Transmitter Power (Watts)
|
||
G = Antenna Gain (Linear)
|
||
λ = Wavelength of transmitted carrier wave (Meters)
|
||
σ = Radar Cross Section (RCS, Meters squared)
|
||
R = Target Range from station origin (Meters)
|
||
|
||
Because each of our target scopes contains fixed design loops, these values can be pushed directly
|
||
as hardware uniform parameters matching specific hardware loop gains that do not change.
|
||
|
||
========================================================
|
||
|
||
Individual scope informations
|
||
|
||
1. Introduction to project. Just text. No scopes. Only one control for entering
|
||
scope selection loop. Keyboard keys 1 for forward; 2 for backward.
|
||
This is a loop type selection If you are in the Introduction, and you touch
|
||
keyboard 2 for backward, you would go to scope 5, PPI Scope for a boat.
|
||
|
||
=================================================================
|
||
|
||
To control the extent of the selection of the scopes by the user, there sill be
|
||
a selection of what scopes are to be avaiable to the museum visitor. This
|
||
will enable the museum to select what scopes will be available and what scopes
|
||
will not be available at all. A script that will invoke the radar simulator
|
||
application will need to pass parameters to indicate what will be available.
|
||
For example, if the script were to call:
|
||
|
||
{PROJECT_DIR}/build/radar_simulator chain_home marine_ascope marine_traffic_ppi
|
||
|
||
then only the chain_home, marine_ascope and marine_traffic_ppi will be availablel
|
||
but the marine_ppi_on_a_boat will not be available.
|
||
|
||
This feature is needed for troubleshooting but also to allow the museum to control
|
||
what is available. For example, if the museum is crowded with large school groups,
|
||
then they would only have one scope available; so if they did
|
||
|
||
{PROJECT_DIR}/build/radar_simulator marine_traffic_ppi
|
||
|
||
Only the marine traffic control ppi scope will be available and the scope
|
||
selection controls will not be operatable.
|
||
|
||
To be clear, the names of the scopes currently being built are:
|
||
|
||
1. chain_home
|
||
2. marine_ascope
|
||
3. marine_traffic_ppi
|
||
4. marine_boat_ppi
|
||
|
||
Startup behavior rules based on argument count:
|
||
|
||
- No arguments: all four scopes available, Introduction shown first,
|
||
navigation keys 1 and 2 are active.
|
||
|
||
- Two or more scope names: only those scopes available in the loop,
|
||
Introduction shown first, navigation keys 1 and 2 are active.
|
||
|
||
- Exactly one scope name: Introduction is suppressed entirely. The
|
||
application launches directly into that scope and stays there.
|
||
Navigation keys 1 and 2 are disabled. The public will have no
|
||
awareness that any other scope exists. This mode is intended for
|
||
large groups and high-traffic museum days where staff want to
|
||
dedicate the exhibit to one display without contention.
|
||
|
||
====================================================================
|
||
|
||
2. A Scope - sweep on horizontal axis. A pulse will appear for a return. The distance from
|
||
the left hand side to the pulse is the range. The height of the pulse is the strength
|
||
of the return signal. The bearing is determined by manual control.
|
||
|
||
The basic controls for both A Scopes include:
|
||
Intensity
|
||
|
||
Sensitivity (the strength of the signal amplification of the
|
||
receiver). This has nothing to do with the brightness of the
|
||
pulses. This only affects the height of the pulse and the height
|
||
of any noise floor.
|
||
|
||
STC sensitivity; sensitivity for close in targets.
|
||
|
||
STC sensitivity range; how far shall the STC sensitivity have effect.
|
||
|
||
Please note that the phosphor (chemical that glows when hit by
|
||
electrons in the tube) is green, similar to an oscilloscope. The Hex
|
||
for green is #39FF14; there is a short persistance of the phosphor after being
|
||
struck by the electron beam. That persistance is about 25 milliseconds and its color
|
||
is darker green at about Hex #004400
|
||
|
||
Please also note that there are no graticules on either the Chain Home a scope nor
|
||
the marine a a scope. The only thing on the external plate is the base line (zero signal
|
||
which the operator can refer to that is going on (grass, calibration, and signals). It
|
||
is an important point of reference. That base line is illuminated on the sides with small
|
||
incandescent lamps. It is a different color than the display itself. The incandescent
|
||
color is that of the #47 pilot lamp hex #FFB347.
|
||
|
||
2-1 Chain Home A Scope
|
||
|
||
==========================================================
|
||
|
||
[INVERTED DISPLAY & ADDITIVE VIDEO SIGNAL SUMMATION]
|
||
|
||
The Chain Home A-Scope display layout is inverted. The steady, horizontal reference baseline
|
||
(the zero signal line) sits at the top of the tube display window (`y = 0.9` in viewport NDC coordinates).
|
||
All video activity—receiver noise floor grass, fixed calibration markers, and target echo pulses—deflects
|
||
vertically **downward** into the dark lower quadrants of the screen.
|
||
|
||
This top-down structure protects the upper edge of the reference line from being distorted by noise grass,
|
||
enabling the operator to align the trace against an illuminated glass graticule with a clean visual focus.
|
||
|
||
All source signals are combined in a single hardware mixing matrix before driving the electrostatic plates:
|
||
* **Receiver Chain:** The atmospheric background noise floor (grass) and the target echo pulses are combined
|
||
first, and are directly scaled by the operator's Receiver Sensitivity control.
|
||
* **Calibration Chain:** The crystal-controlled 20-nm reference pips are injected into the video chain
|
||
AFTER the primary receiver gain stage. As a result, modifications to the Sensitivity control do not scale
|
||
the vertical height of calibration pips.
|
||
|
||
[SUMMING AMPLIFIER PROTOCOL]
|
||
float receiver_signal = (noise_floor + target_echoes) * sensitivity;
|
||
float total_deflection = receiver_signal + calibration_pips;
|
||
|
||
// Map values downwards from structural baseline ceiling
|
||
float final_y = baseline_y - total_deflection;
|
||
|
||
If an operational target echo shares an identical range slot with a 20-nm calibration pip, their respective
|
||
voltages additively sum, dynamically pushing the peak tip further toward the bottom layout limit.
|
||
|
||
==========================================================================
|
||
|
||
Because the receiving antennas are very large (about 100 feet), the
|
||
operator cannot physically move them.
|
||
|
||
Therefore, the bearing is determined through a process called radio direction
|
||
finding (RDF) using a specialized instrument known as a Radiogoniometer.
|
||
|
||
The receiver towers (which were separate from the transmitter towers)
|
||
featured two sets of dipole antennas mounted at right angles to one
|
||
another—essentially one oriented North-South and the other East-West.
|
||
|
||
The signals from these two perpendicular antennas were fed into a Radiogoniometer
|
||
located in the receiver hut. Inside the device there are two fixed coils (field coils)
|
||
that were mounted at right angles matching the orientation of the outdoor antennas.
|
||
A third coil, the search coil, is mounted on a rotating shaft inside the two
|
||
field coils. The operator would physically turn a knob to rotate the search coil.
|
||
|
||
The relative strength of the signal in each antenna depended on the angle of the
|
||
incoming wave. For example, a target directly to the North would produce a maximum
|
||
signal in the North-South antenna and zero in the East-West antenna.
|
||
|
||
The operator would look for a null point (a signal or pip weaker than the noise floor).
|
||
At that point, the operator would read the bearing from a calibrated scale attached
|
||
to the radiogoniometer knob.
|
||
|
||
We can simulate the radiogoniometer knob that would affect the null point depending
|
||
on the bearing of a target. The museum visitor could experience seeing different
|
||
null points for each target. Since we do not have a physical calibrated knob, we
|
||
can put the bearing as a text indicator below the A Scope.
|
||
|
||
The range is 200 nm. That is the only range option for this scope.
|
||
|
||
|
||
RADAR EQUATION STUFF FOR CHAIN HOME
|
||
|
||
For Chain Home:
|
||
Transmitter Power : 500 KW
|
||
Wavelength 12 Meters
|
||
Antenna Gain 5 dB
|
||
Pulse Width 20 microseconds
|
||
Beam Width 150 degrees (floodlight)
|
||
PRF 25 HZ
|
||
|
||
[METRIC RESONANCE MODEL]
|
||
Because the 12-meter carrier wavelength closely matches the physical physical dimensions (wingspan)
|
||
of historical combat aircraft (e.g., 10-12 meters), the target functions as a resonant half-wave dipole.
|
||
When a target's physical length falls within the Rayleigh/Mie resonant band (40% to 60% of the carrier wavelength),
|
||
the backscattering intensity receives an explicit 1.5x structural cross-section multiplier.
|
||
|
||
// Pseudocode for Shader/Logic
|
||
// Derive range and bearing from SSBO Cartesian fields
|
||
float ch_range = sqrt(target.target_x * target.target_x + target.target_y * target.target_y);
|
||
float ch_bearing_rad = atan(target.target_x, target.target_y); // GLSL atan(y,x) measured from north
|
||
float ch_aspect_angle = ch_bearing_rad - target.course; // course is radians in SSBO
|
||
float ch_proj_width = abs(sin(ch_aspect_angle)) * target.length + abs(cos(ch_aspect_angle)) * target.beam;
|
||
float base_sigma = ch_proj_width * 2.5;
|
||
|
||
float resonance = (target.length >= wavelength * 0.4 && target.length <= wavelength * 0.6) ? 1.5 : 1.0;
|
||
float final_sigma = base_sigma * resonance;
|
||
|
||
The 20-nm Markers: Chain Home used crystal-controlled oscillators to create
|
||
fixed reference "pips" every 20 nm. These should be rendered as thin,
|
||
vertical spikes that never move, regardless of target sensitivity.
|
||
|
||
The "Floodlight" Effect: Because the beam is 150° wide, the A-Scope will
|
||
show every aircraft in that massive sector simultaneously. The only way to
|
||
tell them apart was the range (distance from left) and the Radiogoniometer nulling.
|
||
|
||
The Waveform Shape: For CH, the pips should be slightly "noisier" than
|
||
marine radar. Use a random jitter function in your vertex shader to
|
||
simulate the atmospheric noise floor common at 25 MHz.
|
||
|
||
2-2 Marine A Scope
|
||
|
||
Utilization of A scope marine was limited to military use prior to PPI scope
|
||
invention. An example is British Type 271 radar, introduced in 1941.
|
||
|
||
Marine radar frequencies allowed the use of much smaller antennas;
|
||
dishes or horns. Those antennas would be mounted on the shaft of a servo motor. The
|
||
servo motor would be driven by another servo that is attached to the bearing control
|
||
knob on the radar console. The bearing is on a calibrated dial on the bearing control
|
||
knob.
|
||
|
||
We can simulate the bearing knob that would affect the simulated pointing of the
|
||
dish antenna. The museum visitor could experience seeing different
|
||
pips appear as they rotate the antenna toward them. Likewise the pips would disappear
|
||
as the antenna is rotated away.
|
||
|
||
The range is indicated at how far the pip is from the left hand side of the scope which
|
||
is the location of the radar transmitter. If the target goes further away,
|
||
the pip will move to the right. If the target comes close to you, the pip will
|
||
move left.
|
||
|
||
This pip has a finite rise time as the transmitter starts.
|
||
The width is set by the modulator stage in the transmitter.
|
||
Following the width, the pip has a finite fall time as the transmitter stops. This
|
||
creates a curved waveform; not just a line.
|
||
|
||
A photograph for this display show no graticule at all. Only range pips formed by an oscillator.
|
||
Those oscillator pips are fixed. Range settings do not affect them. There is a baseline at the
|
||
bottom, etched in glass, that is side illuminated by incandescent lamps.
|
||
|
||
Like Chain Home, the Marine A-scope sums noise, calibration pips, and target echoes into a
|
||
single signal before the deflection plates — this is a hardware reality of any CRT A-scope.
|
||
The calibration pips are injected after the receiver gain stage, so they remain at constant
|
||
height regardless of the Sensitivity control. The shader summing follows the same structure:
|
||
|
||
/* Simulated Summing Amplifier Logic — same pattern as Chain Home.
|
||
Cal pips outside sensitivity multiply because they bypass the receiver gain stage. */
|
||
float receiver_signal = (noise_floor + target_echoes) * sensitivity;
|
||
float total_deflection = receiver_signal + calibration_pips;
|
||
|
||
// Apply to upward-deflecting baseline (Marine scope is right-side up)
|
||
float final_y = baseline_y + total_deflection;
|
||
|
||
The maximum ranges for this scope are:
|
||
1. 1.5 nm; marker pips every 0.25 nm
|
||
2. 3.0 nm; marker pips every 0.5 nm
|
||
3. 6.0 nm; marker pips every 1.0 nm
|
||
4. 12.0 nm; marker pips every 2.0 nm
|
||
|
||
RADAR EQUATION FOR MARINE A SCOPE
|
||
|
||
Here are the fixed values (those values that can be declared as
|
||
uniforms) for the marine a scope radar. I suggest these for the uniform names
|
||
|
||
peak_power = 500 KW
|
||
wavelength = 10 centimeters
|
||
antenna_gain = 30 db
|
||
pulse_rep_frequency = 500 hz
|
||
horizontal_beamwidth = 2.5 degrees
|
||
|
||
Now we have some stuff for the settings file:
|
||
|
||
SYSTEM_TEMPERATURE ($T_s$): Usually 290K; used to calculate the noise floor
|
||
NOISE_FIGURE ($F$): A value in dB that determines how much "grass" your
|
||
specific receiver adds to the signal (20 dB typical for early centimetric systems).
|
||
BOLTZMANN_CONSTANT ($k$): $1.38 \times 10^{-23}$, essential for the thermal
|
||
noise part of your simulation.
|
||
|
||
Now, here is a snippet of pseudo code:
|
||
|
||
/* Uniform Variables provided by CPU */
|
||
uniform float u_AntennaBearing; // Current rotation of knob/motor, degrees
|
||
uniform float horizontal_beamwidth; // Fixed for the scope (e.g., 2.5 degrees)
|
||
|
||
/* Logic for each Target — all derived from SSBO fields target_x, target_y, length, beam, course */
|
||
|
||
// Derive range (meters) and bearing (degrees, north-clockwise) from Cartesian SSBO fields
|
||
float target_range = sqrt(target.target_x * target.target_x + target.target_y * target.target_y);
|
||
float target_bearing_rad = atan(target.target_x, target.target_y); // GLSL atan(y,x) from north
|
||
float target_bearing_deg = degrees(target_bearing_rad);
|
||
if (target_bearing_deg < 0.0) target_bearing_deg += 360.0;
|
||
|
||
// Compute RCS from length and beam using aspect angle (course is radians in SSBO)
|
||
float aspect_angle = target_bearing_rad - target.course;
|
||
float projected_width = abs(sin(aspect_angle)) * target.length + abs(cos(aspect_angle)) * target.beam;
|
||
float target_rcs = projected_width * 2.5;
|
||
|
||
float angle_diff = abs(target_bearing_deg - u_AntennaBearing);
|
||
|
||
// Handle the 359 to 0 degree wrap-around
|
||
if (angle_diff > 180.0) angle_diff = 360.0 - angle_diff;
|
||
|
||
// BeamFactor: 1.0 at center, drops to 0.5 at horizontal_beamwidth/2
|
||
// This creates the "fade in / fade out" effect as you turn the knob
|
||
float beam_factor = exp(-2.77 * pow(angle_diff / (horizontal_beamwidth / 2.0), 2.0));
|
||
|
||
// Final received power Pr — uses only derived values, no missing SSBO fields
|
||
float Pr = (peak_power * pow(antenna_gain, 2.0) * pow(wavelength, 2.0) * target_rcs * beam_factor) /
|
||
(pow(4.0 * PI, 3.0) * pow(target_range, 4.0));
|
||
|
||
3. PPI Scope
|
||
|
||
PPI stands for Plan Position Indicator
|
||
|
||
The Core VisualizationThe PPI scope represents the radar antenna as a
|
||
central point (the origin).The "Sweep": A radial line rotates 360
|
||
degrees around the center, synchronized with the physical rotation of the
|
||
radar antenna.Distance (Range):
|
||
|
||
The distance from the center of the screen to a "blip"
|
||
represents how far away the object is.
|
||
|
||
Bearing (Azimuth): The angle of the blip
|
||
relative to the top of the screen (usually North or the front of a ship/aircraft)
|
||
represents its direction.
|
||
|
||
Key Technical ComponentsIf you are prompting an AI to simulate or analyze a PPI,
|
||
use these technical markers:Persistence: Older CRT scopes used "long-persistence
|
||
phosphors" so that a target would remain visible as a glowing trail
|
||
even after the sweep line passed over it.
|
||
|
||
Range Rings: Concentric circles overlaid on the display to help the operator estimate
|
||
distance at a glance.
|
||
|
||
Strobe/Cursor: A line or marker used to pinpoint the exact coordinates of a specific target.
|
||
|
||
Mathematical LogicFor an AI to process PPI data, it needs to understand the conversion
|
||
from Polar to Cartesian coordinates. If a radar detects a target at distance $r$ and
|
||
angle $\theta$, the position on the 2D screen $(x, y)$ is calculated as:$$x = r \cdot
|
||
\sin(\theta)$$$$y = r \cdot \cos(\theta)$$.
|
||
|
||
Why it differs from other ScopesTo clarify for the AI, distinguish it from the A-Scope: A
|
||
simple 1D graph showing "Energy vs. Distance" (looks like an EKG).
|
||
|
||
Please note that the P7 phosphor for vintage PPI radar has several colors; the
|
||
following table describes this:
|
||
|
||
Suggested Simulation Table for the P7 PPI phosphor
|
||
|
||
1. Excitation 0 (flash) Bright Blue hex #A0CFFF - note this is active electron beam
|
||
2. Immediate blue - 1 ms duration after Excitation; Blue hex #1010FF - note that
|
||
from here on is afterglow after beam stops
|
||
3. Short term Yellow Green - 1 second duration after Immediate blue; yellow green hex #E2FF80
|
||
4. Long Term Amber - 10 seconds duration after Short Term; Amber hex #FFA040
|
||
5. Expiration - 12 seconds duration after Long Term Amber; very dark hex #050700
|
||
|
||
=========================================================================
|
||
|
||
[PPI BEAM-WIDTH & TARGET SPATIAL ARC DISPERSION]
|
||
|
||
Because the radar antenna emits a beam with a finite horizontal beamwidth rather than an
|
||
infinitely narrow beam, targets intersect the energy wave continuously as the antenna rotates
|
||
across their angular boundaries. This spatial geometric interaction distorts a standalone point target
|
||
into a concentric circumferential **arc** drawn perpendicular to the radar's origin vector.
|
||
|
||
The returned signal intensity distribution across this structural arc is defined by three rules:
|
||
1. **Geometric Profile Aspect:** The cross-section $\sigma$ is computed dynamically using the target's explicit
|
||
course vector and bearing. The projected surface area facing the wavefront handles the ship's
|
||
length and beam parameters:
|
||
$$\text{Projected Width} = (|\sin(\text{aspect\_angle})| \times \text{length}) + (|\cos(\text{aspect\_angle})| \times \text{beam})$$
|
||
$$\sigma = \text{Projected Width} \times 2.5$$
|
||
2. **Gaussian Power Distribution:** The returned echo energy along the arc changes smoothly according to a
|
||
Gaussian curve. The absolute edges are dimmest (where the beam's outer threshold grazes the
|
||
target perimeter) and expand exponentially to max intensity at the center axis of alignment.
|
||
3. **Sweep Intersect Envelope:** Energy returns climb from the noise floor, achieve peak voltage
|
||
at perfect cross-coincidence, and fade back down into the receiver noise as the sweep line passes the target.
|
||
|
||
Very important note on PPI radars: Definition of the 'top of the scope' and the graticule:
|
||
|
||
For a marine traffic control center radar, the top of the scope or 0 degrees is true north.
|
||
It does not move sice the control center radar does not move.
|
||
|
||
for a boat, the top of the scope is the bow of the boat (where are you heading). The zero
|
||
degrees on the graticule is still true north. The graticule is rotated by a small motor that
|
||
is tied to the boat's gyro compass. This allows the instinctive behavior of the skipper to
|
||
look forward by looking at the top of the scope.
|
||
|
||
Another importand note. The circular sweep on the scopr is clockwise. The degree ticks on the
|
||
graticule count clockwise from true north.
|
||
|
||
Note on blooming. If the signal on the grid of the crt is too great, the
|
||
brightness will no longer increase, but there will be a slight blooming of
|
||
the target.
|
||
|
||
This is suggested example psudeo code for the target shader
|
||
for both the radar equation as well as the blooming
|
||
|
||
Note that values will change depending on the scope being used (traffic control or boat)
|
||
|
||
-------------------------------------------------------------------
|
||
|
||
The selected_range is from the operator control to select the maximum range of the radar
|
||
Options for traffic control are:
|
||
1.5 nm range
|
||
6 nm range
|
||
12 nm range
|
||
|
||
Options for boat radar are:
|
||
1.0 nm range
|
||
3 nm range
|
||
6 nm range
|
||
|
||
|
||
------------------------------------------------------------------------------------
|
||
|
||
=====================================================================================
|
||
|
||
PPI Radar Equiation
|
||
|
||
===================================================================================
|
||
For vessel traffic control radar:
|
||
|
||
Transmitter Peak Power - float transmitter_peak; 25.0 KW
|
||
Frequency - float frequency; 9.375 GHZ
|
||
Wavelength - float wavelength; 0.032 meters
|
||
Receiver Noise Figure - float nf; 11 dB
|
||
System Losses - float sl; 8 dB
|
||
Antenna Beam Width - float beamwidth; 0.7 degrees
|
||
Pulse width - float pulsewidth; 0.1 microsecond
|
||
Pulse Rep Rate lookup table based on selected maximum range - float prf;
|
||
1.5 nm range PRF 3500. HZ
|
||
6 nm range PRF 2000. HZ
|
||
12 nm range 1000. HZ
|
||
Radar Antenna Rotation Rate float antenna_rpm; 15 RPM
|
||
Radar Antenna Gain - float radar_antenna_gain_db; 34 dB
|
||
|
||
Receiver gain notes:
|
||
Raw gain is about 100 dB
|
||
However the gain is logarithmic. It compressed the massive dynamic range
|
||
of real-world echoes so that a giant ship and a small wooden fishing
|
||
boat could both be visible on the CRT at the same time without the operator
|
||
constantly riding the gain knob.
|
||
|
||
The operator would turn the Gain knob up until the background
|
||
of the CRT just started to fill with a faint, shimmering, dancing
|
||
texture of fine static sparks (often called "grass" or "receiver noise").
|
||
|
||
If the gain was too low, weak echoes from distant targets or small
|
||
fiberglass boats in Bellingham Bay wouldn't have enough voltage
|
||
to overcome the CRT's grid cutoff, leaving them completely invisible.
|
||
If the gain was too high, the screen would "blossom" with solid white noise,
|
||
blinding the operator entirely.
|
||
|
||
======================================================================
|
||
|
||
For Polce or coast guard boat radar:
|
||
|
||
Transmitter Peak Power - float transmitter_peak; 15.0 KW
|
||
Frequency - float frequency; 9.375 GHZ
|
||
Wavelength - float wavelength; 0.032 meters
|
||
Receiver Noise Figure - float nf; 11 dB
|
||
System Losses - flost sl; 8 dB
|
||
Antenna Beam Width - float beamwidth; 1.2 degrees
|
||
Pulse Rep Rate lookup table based on selected maximum range - float prf;
|
||
1.0 nm range PRF 4000. HZ
|
||
3 nm range PRF 3000. HZ
|
||
6 nm range 1000. HZ
|
||
Pulse width - float pulsewidth; 0.1 microsecond
|
||
Radar Antenna Rotation Rate float antenna_rpm; 25 RPM
|
||
Radar Antenna Gain - float radar_antenna_gain_db; 31 dB
|
||
|
||
Receiver gain notes:
|
||
Raw gain is about 100 dB
|
||
However the gain is logarithmic. It compressed the massive dynamic range
|
||
of real-world echoes so that a giant ship and a small wooden fishing
|
||
boat could both be visible on the CRT at the same time without the operator
|
||
constantly riding the gain knob.
|
||
|
||
The operator would turn the Gain knob up until the background
|
||
of the CRT just started to fill with a faint, shimmering, dancing
|
||
texture of fine static sparks (often called "grass" or "receiver noise").
|
||
|
||
If the gain was too low, weak echoes from distant targets or small
|
||
fiberglass boats in Bellingham Bay wouldn't have enough voltage
|
||
to overcome the CRT's grid cutoff, leaving them completely invisible.
|
||
If the gain was too high, the screen would "blossom" with solid white noise,
|
||
blinding the operator entirely.
|
||
|
||
=====================================================================
|
||
|
||
Locations of the radars -
|
||
|
||
Chain Home : RAF Ventnor (Isle Of Wight)
|
||
Decimal Degrees (Latitude / Longitude): 50.600° N, 1.183° W
|
||
|
||
A Scope Marine - Anchored Boat at Community Boating Center (stays here, not moving around)
|
||
latitude \(48.70529^{\circ}\text{ N}\) and longitude \(-122.50547^{\circ}\text{ W}\)
|
||
|
||
PPI Marine Traffic Control - center of bellingham bay
|
||
latitude \(48^\circ 43' 25" \text{ N}\) and longitude \(122^\circ 34' 35" \text{ W}\)
|
||
|
||
PPI Police Boat ( starts as docked at the taylor street dock; but will be moving around
|
||
48.7253874° N latitude and -122.5077482° W longitude.
|
||
|
||
=====================================================================
|
||
|
||
Graticules - These are plastic overlays over the face of the scope. They are
|
||
for the purposes of showing the bearing. They are calibrated in degrees; short line (1/8 inch)
|
||
each degree; medium line (1/4 inch) for every 5 degrees; and a longer line (1/2 inch) for every
|
||
10 degrees. Line for true north; 2/3 inch.
|
||
|
||
Notes that these graticule lines are lit by a #47 incandescent bulb #FFB347.
|
||
|
||
There are text numeric values for every 15 degreen
|
||
|
||
There are two rings
|
||
The bearing ticks are on the inside of the outer ring.
|
||
The numeric degree values are between the outer and inner rings.
|
||
The innter ring is the boundry for active targets and the sweep.
|
||
|
||
=======================================================================
|
||
|
||
Range Rings:
|
||
|
||
There shall be range rings (Direct emission from the phosphor, same
|
||
as target. They will vary by the maximum range setting.
|
||
|
||
Range rings shall be only for the PPI radar. Not for the a scope radar.
|
||
For the Marine Traffic Radar:
|
||
|
||
Options for traffic control are:
|
||
1.5 nm range rings
|
||
.5 nm
|
||
1.0 nm
|
||
6 nm range
|
||
2.0 nm
|
||
4.0 nm
|
||
12 nm range
|
||
4.0 nm
|
||
8.0 nm
|
||
|
||
Options for boat radar are:
|
||
1.0 nm range
|
||
.5 nm
|
||
3 nm range
|
||
1 nm
|
||
2 nm
|
||
6 nm range
|
||
2 nm
|
||
4 nm
|
||
|
||
PLease note that there is no range ring for the full range as that is
|
||
the inner ring of the graticule
|
||
|
||
Please also note that the range rings will behave the same as targets as
|
||
far as the P7 phosphor is concerned. This means that they will glow brigh
|
||
as the sweep passes over them. But they will decay the same as the targets.
|
||
|
||
The range rings will not be subject to effects by the gain control nor
|
||
the noise suppression control
|
||
|
||
=======================================================================
|
||
|
||
GROUND TERRAIN AND LIDAR DATA PROCESSING
|
||
|
||
Note: Do not do this for the Chain Home Radar. Theu user will heve enough
|
||
of a challenging dealing with the targets and noise alone.
|
||
|
||
Note that the following files already exist in the project directory
|
||
in the following:
|
||
|
||
map
|
||
map/lidar_raw
|
||
map/lidar_raw/wa2016_west_dem_J1364939.zip
|
||
map/lidar_raw/wa2022_nooksack_dem_J1364940.zip
|
||
map/charts_enc
|
||
map/charts_enc/US5WA45M.000
|
||
map/charts_enc/n48_w123_1arc_v3.tif
|
||
|
||
This needs to be processed into a fragment shader via ray casting.
|
||
|
||
Details on files:
|
||
|
||
US5WA45M.000 (ENC Chart): This is an Electronic Navigational Chart
|
||
(S-57 format) specifically covering the Bellingham Bay and Harbor
|
||
area. It contains vector data for the shoreline, docks, piers,
|
||
and water depths (bathymetry), as well as navigational aids.
|
||
|
||
Note that the US5WA45M.000 (ENC Chart) may not be needed at all. The
|
||
n48_w123_1arc_v3.tif (DEM) and the LiDAR DEMs already define land vs. water
|
||
by elevation — any cell above 0 meters is land and will return a radar echo.
|
||
The ENC vector shoreline data would be redundant for this purpose.
|
||
|
||
|
||
n48_w123_1arc_v3.tif (DEM): This is a USGS 1-arc-second Digital
|
||
Elevation Model in GeoTIFF format. It provides a continuous grid of
|
||
land elevation data for the area (roughly 30-meter resolution).
|
||
This is your primary source for the broad terrain shape.
|
||
|
||
wa2022_nooksack...zip & wa2016_west...zip (LiDAR DEMs): These are
|
||
high-resolution Digital Elevation Model zips from the Washington
|
||
State LiDAR portal. They contain the incredibly detailed data for
|
||
localized buildings, docks, and fine shoreline features that the
|
||
30-meter USGS data misses.
|
||
|
||
Suggestion for creating height map:
|
||
|
||
Use GDAL (Geospatial Data Abstraction Library): Use command-line
|
||
tools like gdal_translate or gdalwarp to extract the elevation data
|
||
from the .tif and the unzipped LiDAR files.
|
||
|
||
Reproject to a Common Grid: Crop and reproject all of these datasets
|
||
into a matching coordinate system (like UTM Zone 10N) and resample
|
||
them onto a single, standardized 2D grid. Layer them so that the
|
||
high-resolution LiDAR overrides the coarser USGS data where they overlap.
|
||
|
||
Generate a Height Map Texture: Convert this final 2D grid of
|
||
elevation values into a single-channel floating-point data structure.
|
||
In OpenGL, you will load this directly into VRAM as a GL_R32F
|
||
(32-bit floating-point red channel) 2D texture, where the texture
|
||
coordinates $(u, v)$ represent latitude/longitude or local grid
|
||
coordinates, and the pixel value represents the height above sea level.
|
||
|
||
Note that it may be better to do the conversion once and save the grid of 2d
|
||
elevation data into a file. So, during the first invocation of the radar program,
|
||
run the conversion once and put the final data into map/converted_data. If the file
|
||
is already there, then do not perform the conversion.
|
||
|
||
The texture will need to be moved around for the police boat ppi radar, but it
|
||
will be stationary for the vessel traffic control ppi radar.
|
||
|
||
Please note that we should have values defined in the settings.h file for the
|
||
strengths of the DEM map information and the LiDAR information as well as the
|
||
total strength of all of the shoreline information.
|
||
|
||
SETTINGS.H VALUES FOR LAND AND TERRAIN DATA
|
||
|
||
The following entries belong in settings.h so that terrain rendering behavior
|
||
can be tuned or disabled without touching shader or pipeline code.
|
||
|
||
/* ------------------------------------------------------------------
|
||
TERRAIN / LAND DATA — settings.h entries
|
||
------------------------------------------------------------------ */
|
||
|
||
/* Master on/off switch for all terrain rendering.
|
||
Set to 0 to suppress land echoes entirely; useful when you want to
|
||
observe only live targets without any terrain clutter. */
|
||
#define ENABLE_TERRAIN_RENDERING 1
|
||
|
||
/* Individual layer enable flags.
|
||
Lets you isolate which elevation source is contributing echoes. */
|
||
#define ENABLE_DEM_LAYER 1 // USGS 1-arc-second (~30 m) GeoTIFF
|
||
#define ENABLE_LIDAR_LAYER 1 // High-res WA State LiDAR DEMs
|
||
|
||
/* Elevation threshold (meters) above which a cell is treated as land
|
||
and returns a radar echo. 0.0 = sea level. Raise slightly (e.g.
|
||
0.5) to suppress low-lying marshes that are technically above datum
|
||
but unlikely to produce a real ship-hazard echo. */
|
||
#define LAND_ELEVATION_THRESHOLD_M 0.0f
|
||
|
||
/* Echo amplitude scalars for each elevation source.
|
||
These feed the fragment shader as uniforms so the DEM and LiDAR
|
||
layers can be weighted independently.
|
||
1.0 = nominal; raise to exaggerate; lower to soften. */
|
||
#define DEM_ECHO_STRENGTH 1.0f
|
||
#define LIDAR_ECHO_STRENGTH 1.2f // slightly stronger — LiDAR is more accurate
|
||
|
||
/* Overall terrain echo scale applied after the per-layer scalars.
|
||
Acts as a master volume knob for all shoreline / land returns.
|
||
Adjust this first before touching the per-layer values. */
|
||
#define TERRAIN_ECHO_TOTAL_SCALE 1.0f
|
||
|
||
/* Raycasting step size (meters) used when marching each radar beam
|
||
sample through the height-map texture. Smaller = more accurate
|
||
shoreline but more GPU cost. 8.0 is a reasonable starting point
|
||
for the ~30 m DEM; drop to 4.0 if LiDAR detail is being missed. */
|
||
#define TERRAIN_RAY_STEP_M 8.0f
|
||
|
||
/* Maximum elevation (meters) used to normalize the GL_R32F texture
|
||
values before they reach the shader. Should be >= the tallest
|
||
terrain feature in the scene (Bellingham area peaks ~600 m). */
|
||
#define TERRAIN_MAX_ELEVATION_M 700.0f
|
||
|
||
/* Height (meters) at which LiDAR data takes priority over the coarser
|
||
USGS DEM when the two grids are composited during map/converted_data
|
||
generation. Cells with LiDAR values >= this threshold replace the
|
||
DEM value; cells below fall back to DEM. */
|
||
#define LIDAR_PRIORITY_HEIGHT_M 0.5f
|
||
|
||
/* Debug: show only terrain echoes, suppress all moving targets.
|
||
Set to 1 to isolate land-clutter rendering during development. */
|
||
#define DEBUG_TERRAIN_ONLY 0
|
||
|
||
/* Debug: colour-code which elevation source is active for each pixel
|
||
(blue = DEM only, green = LiDAR override). Set to 1 to visualise
|
||
coverage boundaries when compositing the height-map. */
|
||
#define DEBUG_SHOW_LIDAR_COVERAGE 0
|
||
|
||
|
||
==================================
|
||
|
||
End of discussion
|
||
|
||
==================================
|
||
|
||
settings.h file suggestions:
|
||
|
||
The settings.h file needs to improve variables that the developer may need
|
||
to change for facilitate troubleshooting. Need ability to change amplifier gain,
|
||
radar beam width, antenna, gain, and so on.
|