Files
radar-simulation/CLAUDE.md
2026-04-01 10:21:26 -07:00

229 lines
10 KiB
Markdown

Hello, this is a project to create a simulation of a vintage marine radar before the
days of digital electronics and we had to use a cathode ray tube with p7 phosphor
I plan to use c++ and opengl and shaders for access to a GPU. I am in ubuntu 25.10.
I wish the c++ be arranged as follows:
All code in the src subdirectory
The main program and the binary would be called radar-simulation.
The shaders are in the shaders subdirectory
We need to use classes. For now, I can see one class for all things
having to do with putting stuff on the screen. Includes initializing
OpenGL and put up two windows on the screen. One is for the PPI display,
locate on the right hand side of the screen with margins for the sides of
the monitor. The A Scope is a smaller window on the center of the left
side of the display.
All inputs to either display will be performed in that class. Data fields
for the methods of that class should be put into a header file in the
headers directory.
Another class would be used to communicate with the raspberry pies that
will obtain data from the ais and ads-b software defined radios. This
is for purposes of adding targets. Marine radar can pick up low flying
targets plus I may (in the future) add an option for a vintage air traffic
control radar with precision approach radar, but not now.
Another class would be used for simulating targets, like for example
a sailboat regatta race.
Classes:
1. Anything to do with sending anything to the display. Needs to be on the
same thread as the main function
2. Communications with outside sources; ais and ads-b for targets
3. Operator controls
4. Internal target simulation
5. All of these have to use mutex for anything going into the display class
There may be more classes TBD
The platform is a Geekom GEEKOM A8 Max, AMD Ryzen 9 8945HS 5.2GHz 32GB RAM
Now here is the overall project and proposed architecture
This project is to simulate a period 1950 to 1960 marine radar with a crt p7
phosphor for the ppi scope and a p1 phosphor (this is oscilloscope phosphor)
for the a scope. The ppi scope
will be on the right side of the screen and the a scope will be on the left
hand side of the screen.
Use one window with viewports covering the entire screen. For development,
F11 toggles fullscreen, Escape exits the program entirely.
The radar is fixed at the Community Boating Center dock in Bellingham,
Washington. That location is 0,0 in local Cartesian coordinates. North on
the radar display is true north.
GPS coordinates from targets are converted to local Cartesian coordinates
referenced to this origin using a flat-earth equirectangular projection,
which is accurate enough for harbor radar ranges (0-24 nautical miles):
x = (lon - origin_lon) * cos(origin_lat) * R
y = (lat - origin_lat) * R
Where R is Earth's radius (6,371,000 m). Result is in meters from the origin.
No need to be concerned with spherical or vector geometry at these ranges.
Coordinate conversion belongs in the main application, not in the Raspberry Pi
communication class. The RPi class delivers raw lat/lon; the main app converts
to local Cartesian. This keeps the RPi code simple and means a change to the
radar origin only requires changing one place.
Notes for controls the user can play with
Here are the controls that I am proposing
1. Intensity
2. Focus
3. Astignatism
4. Range selection (for both a scope and ppi scope)
5. Sensitivity
6. Clutter elimination (I believe only ppi scope; please research)
7. There is some sort of control having to do with the mangatron
but I don't know what its called and what it does.
8. Bearing (only for a scope) which in the old days uses a servo motor to
rotate the antenna. I don't know what form of feedback (text on the
screen or mechanical numbers on a dial)
9. Magnetron tune
10. Anti clutter rain (ftc)
11. Will not need heading (this will be a fixed radar location for
the harbor master or lifeguard
12. Off-centering
13. Graticule brilliance
14. Reset (in case kids really mess things up)
15. Pulse length selection (short pulse for better range resolution,
long pulse for better sensitivity at distance; operator selectable)
(Please suggest other controls I may have missed.)
Now, for controls, the tentative approach is to use encoders (that do not
have end stops so they cannot be broken by visitors at the museum) I will
need help on how to impliment them. I am guessing a few raspberry pies to
handle the encoders. I am thinking of encoders have one common terminal and
a clockwise pulse terminal and a counter clockwise pulse terminal.
Let do this like this. The control handling will be a different class and run
as a separate thread from the display. Each control function will have a parameter
for how many pulses received and in what direction. That would be permanent.
Temporary code necessary for changing control selection and value via the
keyboard until I get the necessary hardware for the controls.
Also please note that this will need to be flexible as encoders can
be expensive, especially robust ones that kids cannot break.
Shaders:
Each of the following is a separate shader set. Keeping them separate is
intentional for easier debugging — each layer can be disabled, modified,
or tested independently without affecting the others. At least the following shader sets
1. PPI targets, current, in white blue
2. clutter for rain, in white blue
3. clutter for waves, in white blue
4. graticule for PPI for bearing ticks, numbers, and range rings that
will change with range selection
5. Have operator switch graticules on the vintage a scope
6. Shoreline; tricky as shoreline has hills.
7. This may be overkill, but something for notable buildings and docks. The
curved south bay trail and taylor dock comes to mind, also the squalicum
marina and the breakwaters.
Details for A scope (predecessor to the PPI scope)
The a scope will have pulse amplitude on the vertical axis and the range on the horizontal
axis. There will be a graticule for the a scope. This will show range markings. In the
day, the operator would physically change the graticule overlay. What we can do is to
electronically change the overlay and put a brief message saying operator changes
the graticule.
The graticule was illuminated with #47 incandescent dial lights, we need to have that
graticule lit with an equivalent color. Horizontal is range, vertical is strength
of the return blip. The phosphor of the A scope is green, similar to P1, which was
used on oscillosopes.
On vintage a scope, the operator changes the graticule when range is changed. Suggest
briefly display the message "operator inserts new graticule manually". If possible for
realism, have the old graticule move up and off the screen and then the new graticule move
onto and down the screen until it is in place, simulating the operator changing the
graticule.
There are as of now, no shaders nor any c++ files created yet
Details for PPI display:
Located on right hand of the screen. Put 1/2 inch margins on the right and top and bottom.
The PPI display will need shaders for the following:
1. Active radar target echos (blue white phosphor)
2. Graticule (warm incandescent color, it was a plastic overlay lit with lamps. Does
not get included with persistant phosphor. Can change if the operator changes the
range. Have ticks for bearing; each degree. Every 10 degrees have a small text label, put these
outside the ring. No range rings for now. Have to figure out how that is done with vintage
radars. Perhaps you can suggest. Does operator have to change the plastic graticule when they
change the range?
3. facility to change clutter, rain and waves. Immediate is blue white same as targets
4. facility to include shore lines. This will change with range settings. If possible, can
we include docks and tall buildings? Immediate is blue white same as targets.
5. Persistence (green yellow) for targets, clutter, and shore lines. Persistence uses
ping-pong framebuffers with a decay multiplier each frame. Target persistence is
approximately 3 seconds, matching the P7 phosphor decay to 10% brightness.
6. The pulse repetition frequency (PRF) is a simulation parameter. At 24 RPM antenna
rotation, one full sweep takes 2.5 seconds and produces ~150 frames at 60 fps —
smooth with no aliasing concern.
Communication:
All I know now is that I plan to use a combination of raspberry pi 4 and a Airspy
SDR for each of ais, ads-b, and uat. UAT (978 MHz) and ADS-B (1090 MHz) are different
frequencies and require separate SDRs, but a single Raspberry Pi 4 is powerful enough
to run both dump1090 (ADS-B) and dump978 (UAT) simultaneously with two SDRs on its USB
ports. AIS requires a separate Raspberry Pi with its own SDR tuned to VHF 161/162 MHz.
Each Raspberry Pi will act as a server fielding requests from this program.
Each Raspberry Pi is a separate instantiation of a class called RemoteTargetSource.
Those classes will use a common target data structure:
1. double longitude
2. double latitude
3. std::string vessel_name
4. std::string registration
5. float length_meters
6. float beam_meters
7. int vessel_type (AIS type code; aircraft type for ADS-B/UAT)
8. uint32_t mmsi (AIS unique identifier; ICAO hex address for aircraft)
9. float course (course over ground, degrees)
10. float speed (speed over ground, knots)
11. time_t timestamp (time of last fix; used to age out stale targets)
12. float altitude (meters; 0 for surface vessels)
13. TargetType type (enum: vessel, aircraft, etc.)
The RPi communication thread blocks on a socket read until data arrives, then
writes to a shared target queue protected by a mutex and signals a condition
variable. The main application consumes from that queue.
The Raspberry Pi code will live in a separate git repository with its own CLAUDE.md
and its own CMakeLists.txt, since it targets a different architecture (ARM) and has
a different toolchain and dependencies. Do not mix it into this repository hierarchy.
Right now, I just want to make sure that the structure is okay and that the
CMakeLists.txt looks okay. I am not ready to ask you to create any code