Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
986bfa1
Phase 2: Add TelemetrySolver integration wrapper
jonnyspicer Jun 12, 2025
5ec3b5c
Merge remote-tracking branch 'origin/main' into issue-22-telemetry-so…
jonnyspicer Jun 13, 2025
06ea357
Phase 3: Docker integration for TelemetrySolver
jonnyspicer Jun 13, 2025
af87e9b
Rename TelemetrySolver to RETINASolver throughout codebase
jonnyspicer Jun 13, 2025
e03e6f6
Add completion documentation for RETINASolver integration
jonnyspicer Jun 13, 2025
a051198
Complete RETINASolver integration testing and validation
jonnyspicer Jun 13, 2025
be85d6c
Fix failing unit tests by adding proper dependency mocking
jonnyspicer Jun 13, 2025
0af8ad8
Fix simplified test script for local and Docker environments
jonnyspicer Jun 13, 2025
54ae61d
Delete RETINASolver_Implementation_Completion.md
jonnyspicer Jun 14, 2025
431f606
Delete puppeteer_test_results.md
jonnyspicer Jun 14, 2025
6322f8d
Enable Claude to make code modifications via PR comments
jonnyspicer Jun 16, 2025
ece78f6
Claude: Add GitHub PR code review instructions to CLAUDE.md
claude[bot] Jun 16, 2025
69dcba0
Add comprehensive integration tests for RETINASolver
jonnyspicer Jun 16, 2025
3e4876e
Address code review feedback from PR #25
jonnyspicer Jun 17, 2025
dc453a2
Fix IndentationError in RETINASolverLocalisation.py
jonnyspicer Jun 17, 2025
0056208
Merge remote-tracking branch 'origin/main' into issue-22-telemetry-so…
jonnyspicer Jul 29, 2025
7333f14
Fix post-merge issues and implement ECEF-only coordinate system
jonnyspicer Jul 29, 2025
cb6b2da
Phase 1: Import Geometry functions directly from RETINAsolver
jonnyspicer Jul 29, 2025
b2a5aa2
Phase 2: Create ENU coordinate system models
jonnyspicer Jul 29, 2025
412d512
Phase 3: Update StoneSoupTracker to use ENU coordinate system
jonnyspicer Jul 29, 2025
8284468
Phase 4: Update Track output for ENU→LLA conversion
jonnyspicer Jul 29, 2025
b71c2bf
Phase 5: Update Configuration for ENU
jonnyspicer Jul 29, 2025
95aa707
Phase 6 & 7: Clean up linting and complete ENU migration
jonnyspicer Jul 29, 2025
d82d540
Add mock Geometry fallback for CI testing environments
jonnyspicer Jul 29, 2025
7689b51
Improve MockGeometry to pass all unit tests
jonnyspicer Jul 29, 2025
14e0679
feat: add configuration options and documentation for RETINASolver
jonnyspicer Jul 30, 2025
7e957bd
Delete test_puppeteer_results.md
jonnyspicer Jul 30, 2025
d318bbe
Fix RETINASolver ellipsoid visibility issues
jonnyspicer Aug 25, 2025
f442215
Fix RETINASolver test failures - update mock radar config structure
jonnyspicer Aug 26, 2025
8cf5740
Fix tile server SSL certificate errors and add satellite imagery
jonnyspicer Aug 29, 2025
66f0984
Revert "Fix tile server SSL certificate errors and add satellite imag…
jonnyspicer Aug 29, 2025
3745b52
Merge origin/main into issue-22-telemetry-solver-integration
jonnyspicer Sep 8, 2025
c0ffab9
Fix PR #25: Add missing distance methods and update .env.example
jonnyspicer Oct 8, 2025
0fd4fc2
Use relative path for RETINAsolver import fallback
jehanazad Feb 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ ELLIPSOID_N_SAMPLES=60
ELLIPSOID_THRESHOLD=500
ELLIPSOID_N_DISPLAY=50

# RETINASolver Configuration
RETINA_SOLVER_MAX_ITERATIONS=100
RETINA_SOLVER_CONVERGENCE_THRESHOLD=1e-6
RETINA_SOLVER_PATH=/app/RETINAsolver

# Map Configuration
MAP_LATITUDE=-34.9286
MAP_LONGITUDE=138.5999
Expand Down Expand Up @@ -46,10 +51,10 @@ TRACKER_MAX_MISSES_TO_DELETE=5
TRACKER_MIN_HITS_TO_CONFIRM=2
# Gating threshold for associating detections to tracks (meters)
TRACKER_GATING_EUCLIDEAN_THRESHOLD_M=10000.0
# Initial position uncertainty in ECEF (meters, comma-separated)
TRACKER_INITIAL_POS_UNCERTAINTY_ECEF_M=500.0,500.0,500.0
# Initial velocity uncertainty in ECEF (meters/sec, comma-separated)
TRACKER_INITIAL_VEL_UNCERTAINTY_ECEF_MPS=100.0,100.0,100.0
# Initial position uncertainty in ENU (meters, comma-separated)
TRACKER_INITIAL_POS_UNCERTAINTY_ENU_M=500.0,500.0,500.0
# Initial velocity uncertainty in ENU (meters/sec, comma-separated)
TRACKER_INITIAL_VEL_UNCERTAINTY_ENU_MPS=100.0,100.0,100.0
# Default time step for tracker (seconds)
TRACKER_DT_DEFAULT_S=1.0

Expand Down
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,37 @@ cp .env.example .env # Create and edit your .env file
sudo docker compose up -d —build
```

### Testing

#### Unit Tests
```bash
# Run tests locally
cd 3lips
./run_tests.sh

# Run tests in container
docker exec -it 3lips-event python -m pytest test/
```

#### Integration Tests
The system includes comprehensive integration tests for RETINASolver functionality:

```bash
# Start full test environment with synthetic data
docker compose -f tests/docker-compose.retina.yml up -d

# Verify all services are running
./tests/verify-retina-services.sh

# Run integration tests using Claude Code with Puppeteer MCP
# Load and run: tests/retina-solver-test-suite.js
```

Test coverage includes:
- **UI Integration**: RETINASolver dropdown selection and form submission
- **Pipeline Integration**: Data flow from synthetic ADS-B through RETINASolver
- **End-to-End**: Complete aircraft tracking and visualization

~~The API front-end is available at [http://localhost:49156](http://localhost:49156).~~

### Environment Variables
Expand All @@ -43,6 +74,9 @@ The following environment variables can be configured:
#### Localisation Configuration
- `ELLIPSE_N_SAMPLES`, `ELLIPSE_THRESHOLD`, `ELLIPSE_N_DISPLAY` - Ellipse sampling parameters
- `ELLIPSOID_N_SAMPLES`, `ELLIPSOID_THRESHOLD`, `ELLIPSOID_N_DISPLAY` - Ellipsoid sampling parameters
- `RETINA_SOLVER_MAX_ITERATIONS` - Maximum iterations for RETINASolver optimization (default: 100)
- `RETINA_SOLVER_CONVERGENCE_THRESHOLD` - Convergence threshold for optimization (default: 1e-6)
- `RETINA_SOLVER_PATH` - Path to RETINASolver module (default: /app/RETINAsolver)

#### ADSB Configuration
- `ADSB_T_DELETE` - Time to delete ADSB data
Expand All @@ -65,6 +99,12 @@ The target localisation uses 1 of the following algorithms:

- **Spherical intersection** a closed form solution which applies when a common receiver or transmitter are used. As described in [Two Methods for Target Localization in Multistatic Passive Radar](https://ieeexplore.ieee.org/document/6129656).

- **RETINA Solver** uses Levenberg-Marquardt optimization for TDOA/FDOA localization. This advanced algorithm:
- Generates intelligent initial position guesses based on detection geometry
- Applies least squares optimization to solve target positions from bistatic range and Doppler measurements
- Handles 3 or more radar detections for improved accuracy
- Provides robust error handling for non-converging cases

The system architecture is as follows:

- The API server and HTML pages are served through a [Flask](http://github.com/pallets/flask) in Python.
Expand Down
2 changes: 2 additions & 0 deletions api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
{"name": "Ellipsoid Parametric (Mean)", "id": "ellipsoid-parametric-mean"},
{"name": "Ellipsoid Parametric (Min)", "id": "ellipsoid-parametric-min"},
{"name": "Spherical Intersection", "id": "spherical-intersection"},
{"name": "RETINA Solver", "id": "retina-solver"},
]

adsbs = [
Expand Down Expand Up @@ -171,6 +172,7 @@ def api():
return reply
except Exception as e:
import traceback

error_trace = traceback.format_exc()
print(f"Exception occurred: {e}", flush=True)
print(f"Traceback: {error_trace}", flush=True)
Expand Down
67 changes: 67 additions & 0 deletions docker-compose-e2e-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@

version: '3.8'

networks:
3lips:
driver: bridge
retina-network:
external: true
name: retina-network

services:
# Synthetic ADS-B data source
synthetic-adsb:
build:
context: ../synthetic-adsb
dockerfile: Dockerfile
image: synthetic-adsb
ports:
- "5001:5001"
networks:
- retina-network
- 3lips
container_name: synthetic-adsb-test
environment:
- PYTHONUNBUFFERED=1
- TRANSMITTER_LAT=-34.9286
- TRANSMITTER_LON=138.5999
- RADAR1_LAT=-34.9000
- RADAR1_LON=138.6000
- RADAR2_LAT=-34.9500
- RADAR2_LON=138.6000
volumes:
- ../synthetic-adsb:/app
command: ["python", "server.py"]

# 3lips API with RETINASolver
api:
extends:
file: docker-compose.yml
service: api
environment:
- FLASK_ENV=development
- FLASK_DEBUG=1
- LOCALISATION_ALGORITHM=${LOCALISATION_ALGORITHM:-retina-solver}
- ADSB_URL=http://synthetic-adsb-test:5001
depends_on:
- event
- synthetic-adsb

# Event processor with RETINASolver integration
event:
extends:
file: docker-compose.yml
service: event
environment:
- TRACKER_VERBOSE=true
- LOCALISATION_ALGORITHM=${LOCALISATION_ALGORITHM:-retina-solver}
- ADSB_URL=http://synthetic-adsb-test:5001
- SYNTHETIC_RADAR_URLS=http://synthetic-adsb-test:5001/radar1,http://synthetic-adsb-test:5001/radar2,http://synthetic-adsb-test:5001/radar3
depends_on:
- synthetic-adsb

# Cesium visualization
cesium-apache:
extends:
file: docker-compose.yml
service: cesium-apache
1 change: 1 addition & 0 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ services:
# Enhanced hot-reloading for development
- ./event:/app/event:ro
- ./event/algorithm:/app/event/algorithm:ro
- ../RETINAsolver:/app/RETINAsolver
environment:
- TRACKER_VERBOSE=true
- PYTHONUNBUFFERED=1
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ services:
- ./common:/app/common
- ./test:/app/test
- ./save:/app/save
- ../RETINAsolver:/app/RETINAsolver
container_name: 3lips-event
env_file:
- .env
Expand Down
13 changes: 12 additions & 1 deletion event/algorithm/associator/AdsbAssociator.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def process(self, radar_list, radar_data, timestamp):
if valid_config and valid_detection:
# get URL for adsb2truth
url = self.generate_api_url(radar, radar_data[radar])
print(f"🔗 Generated URL: {url}")

# get ADSB detections
try:
Expand Down Expand Up @@ -82,7 +83,7 @@ def process_1_radar(self, radar, radar_detections, adsb_detections, timestamp, f
@return dict: Associated detections.
"""
assoc_detections = {}
distance_window = 10
distance_window = 100

for aircraft in adsb_detections:
if "delay" in radar_detections:
Expand Down Expand Up @@ -116,12 +117,15 @@ def process_1_radar(self, radar, radar_detections, adsb_detections, timestamp, f
radar_dopplers,
)
if distance < distance_window:
print(f"✅ ASSOCIATION SUCCESS: {aircraft} on {radar}, distance={distance:.3f}")
assoc_detections[aircraft] = {
"radar": radar,
"delay": closest_point[0],
"doppler": closest_point[1],
"timestamp": adsb_detections[aircraft]["timestamp"],
}
else:
print(f"❌ ASSOCIATION FAIL: {aircraft} on {radar}, distance={distance:.3f} > {distance_window}")

return assoc_detections

Expand All @@ -141,6 +145,13 @@ def generate_api_url(self, radar, radar_data):
fc = radar_data["config"]["capture"]["fc"]

adsb = radar_data["config"]["truth"]["adsb"]["tar1090"]

# Translate localhost URLs to container names for adsb2dd
original_adsb = str(adsb)
adsb = str(adsb).replace("localhost:5001", "synthetic-adsb-test:5001")
adsb = str(adsb).replace("//localhost:5001", "//synthetic-adsb-test:5001")
if original_adsb != adsb:
print(f"📡 Translated ADS-B URL: {original_adsb} → {adsb}")

api_url = os.environ.get("ADSB2DD_API_URL", "http://adsb2dd.30hours.dev/api/dd")
if not api_url.startswith("http://") and not api_url.startswith("https://"):
Expand Down
Loading