mirror of
https://github.com/30hours/3lips.git
synced 2024-11-18 12:33:58 +00:00
Script working for plot
This commit is contained in:
parent
5c0a1bb9b4
commit
6e1a4ec5d0
8 changed files with 180 additions and 7 deletions
|
@ -26,7 +26,8 @@ associators = [
|
||||||
# todo: ellipse conic int (analytic), SX, arc length
|
# todo: ellipse conic int (analytic), SX, arc length
|
||||||
localisations = [
|
localisations = [
|
||||||
{"name": "Ellipse Parametric", "id": "ellipse-parametric"},
|
{"name": "Ellipse Parametric", "id": "ellipse-parametric"},
|
||||||
{"name": "Ellipsoid Parametric", "id": "ellipsoid-parametric"}
|
{"name": "Ellipsoid Parametric", "id": "ellipsoid-parametric"},
|
||||||
|
{"name": "Spherical Intersection", "id": "spherical-intersection"}
|
||||||
]
|
]
|
||||||
adsbs = [
|
adsbs = [
|
||||||
{"name": "adsb.30hours.dev", "url": "adsb.30hours.dev"},
|
{"name": "adsb.30hours.dev", "url": "adsb.30hours.dev"},
|
||||||
|
|
|
@ -104,7 +104,7 @@ class EllipseParametric:
|
||||||
samples_intersect[i] = Geometry.ecef2lla(
|
samples_intersect[i] = Geometry.ecef2lla(
|
||||||
samples_intersect[i][0],
|
samples_intersect[i][0],
|
||||||
samples_intersect[i][1],
|
samples_intersect[i][1],
|
||||||
0)
|
samples_intersect[i][2])
|
||||||
output[target]["points"].append([
|
output[target]["points"].append([
|
||||||
round(samples_intersect[i][0], 3),
|
round(samples_intersect[i][0], 3),
|
||||||
round(samples_intersect[i][1], 3),
|
round(samples_intersect[i][1], 3),
|
||||||
|
|
|
@ -34,4 +34,14 @@ class SphericalIntersection:
|
||||||
|
|
||||||
output = {}
|
output = {}
|
||||||
|
|
||||||
|
# return if no detections
|
||||||
|
if not assoc_detections:
|
||||||
|
return output
|
||||||
|
|
||||||
|
for target in assoc_detections:
|
||||||
|
|
||||||
|
print(assoc_detections)
|
||||||
|
#nDetections = assoc_detections
|
||||||
|
#S = np.zeros()
|
||||||
|
|
||||||
return output
|
return output
|
|
@ -12,6 +12,7 @@ import time
|
||||||
import copy
|
import copy
|
||||||
import json
|
import json
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import os
|
||||||
|
|
||||||
from algorithm.associator.AdsbAssociator import AdsbAssociator
|
from algorithm.associator.AdsbAssociator import AdsbAssociator
|
||||||
from algorithm.localisation.EllipseParametric import EllipseParametric
|
from algorithm.localisation.EllipseParametric import EllipseParametric
|
||||||
|
@ -19,7 +20,6 @@ from algorithm.localisation.EllipsoidParametric import EllipsoidParametric
|
||||||
from algorithm.localisation.SphericalIntersection import SphericalIntersection
|
from algorithm.localisation.SphericalIntersection import SphericalIntersection
|
||||||
from algorithm.truth.AdsbTruth import AdsbTruth
|
from algorithm.truth.AdsbTruth import AdsbTruth
|
||||||
from common.Message import Message
|
from common.Message import Message
|
||||||
|
|
||||||
from data.Ellipsoid import Ellipsoid
|
from data.Ellipsoid import Ellipsoid
|
||||||
from algorithm.geometry.Geometry import Geometry
|
from algorithm.geometry.Geometry import Geometry
|
||||||
|
|
||||||
|
@ -195,6 +195,11 @@ async def main():
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
def append_api_to_file(api_object, filename=saveFile):
|
def append_api_to_file(api_object, filename=saveFile):
|
||||||
|
|
||||||
|
if not os.path.exists(filename):
|
||||||
|
with open(filename, 'w') as new_file:
|
||||||
|
pass
|
||||||
|
|
||||||
with open(filename, 'a') as json_file:
|
with open(filename, 'a') as json_file:
|
||||||
json.dump(api_object, json_file)
|
json.dump(api_object, json_file)
|
||||||
json_file.write('\n')
|
json_file.write('\n')
|
||||||
|
|
10
script/Dockerfile
Normal file
10
script/Dockerfile
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# use an official Python runtime as a parent image
|
||||||
|
FROM python:3.9-slim
|
||||||
|
|
||||||
|
# set the working directory to /app
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# install any needed packages specified in requirements.txt
|
||||||
|
COPY requirements.txt /app
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
|
@ -2,4 +2,14 @@ This folder is for post-processing scripts on API data.
|
||||||
|
|
||||||
## Scripts
|
## Scripts
|
||||||
|
|
||||||
- TODO
|
- **plot_accuracy.py** plots a comparison between ADS-B truth and target localisation data in ENU coordinates.
|
||||||
|
|
||||||
|
## Docker Environment
|
||||||
|
|
||||||
|
To avoid having to install extra libraries on the host machine (e.g. numpy, matplotlib), a Dockerfile is provided to create this environment.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo docker build -t 3lips-script .
|
||||||
|
sudo docker run -it -v /opt/3lips/save:/app/save -v /opt/3lips/script:/app/script -v /opt/3lips/event/algorithm/geometry:/app/geometry 3lips-script bash
|
||||||
|
PYTHONPATH=/app python <script> <args>
|
||||||
|
```
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
|
import sys
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import numpy as np
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
|
from geometry.Geometry import Geometry
|
||||||
|
|
||||||
def parse_posix_time(value):
|
def parse_posix_time(value):
|
||||||
try:
|
try:
|
||||||
|
@ -11,23 +16,153 @@ def parse_posix_time(value):
|
||||||
def parse_command_line_arguments():
|
def parse_command_line_arguments():
|
||||||
parser = argparse.ArgumentParser(description="Process command line arguments.")
|
parser = argparse.ArgumentParser(description="Process command line arguments.")
|
||||||
|
|
||||||
parser.add_argument("json_string", type=str, help="Input JSON string")
|
parser.add_argument("json_file", type=str, help="Input JSON file path")
|
||||||
parser.add_argument("target_name", type=str, help="Target name")
|
parser.add_argument("target_name", type=str, help="Target name")
|
||||||
parser.add_argument("--start_time", type=parse_posix_time, help="Optional start time in POSIX seconds")
|
parser.add_argument("--start_time", type=parse_posix_time, help="Optional start time in POSIX seconds")
|
||||||
parser.add_argument("--stop_time", type=parse_posix_time, help="Optional stop time in POSIX seconds")
|
parser.add_argument("--stop_time", type=parse_posix_time, help="Optional stop time in POSIX seconds")
|
||||||
|
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
|
||||||
|
def interpolate_positions(timestamp_vector, truth_timestamp, truth_position):
|
||||||
|
# Convert lists to NumPy arrays for easier manipulation
|
||||||
|
truth_timestamp = np.array(truth_timestamp)
|
||||||
|
truth_position = np.array(truth_position)
|
||||||
|
|
||||||
|
# Interpolate positions for the new timestamp vector
|
||||||
|
interpolated_positions = np.zeros((len(timestamp_vector), truth_position.shape[1]))
|
||||||
|
|
||||||
|
for i in range(truth_position.shape[1]):
|
||||||
|
interpolated_positions[:, i] = np.interp(timestamp_vector, truth_timestamp, truth_position[:, i])
|
||||||
|
|
||||||
|
return interpolated_positions
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
|
# input handling
|
||||||
args = parse_command_line_arguments()
|
args = parse_command_line_arguments()
|
||||||
json_data = json.loads(args.json_string)
|
json_data = []
|
||||||
|
with open(args.json_file, 'r') as json_file:
|
||||||
|
for line in json_file:
|
||||||
|
try:
|
||||||
|
json_object = json.loads(line)
|
||||||
|
json_data.append(json_object)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
print(f"Error decoding JSON from line: {line}")
|
||||||
|
json_data = [item for item in json_data if item]
|
||||||
start_time = args.start_time if args.start_time else None
|
start_time = args.start_time if args.start_time else None
|
||||||
stop_time = args.stop_time if args.stop_time else None
|
stop_time = args.stop_time if args.stop_time else None
|
||||||
print("JSON String:", json_data)
|
print("JSON String (Last Non-Empty Data):", json_data[-1])
|
||||||
print("Target Name:", args.target_name)
|
print("Target Name:", args.target_name)
|
||||||
print("Start Time:", start_time)
|
print("Start Time:", start_time)
|
||||||
print("Stop Time:", stop_time)
|
print("Stop Time:", stop_time)
|
||||||
|
|
||||||
|
# get LLA coords from first radar
|
||||||
|
radar4_lla = [-34.91041, 138.68924, 210]
|
||||||
|
|
||||||
|
# extract data of interest
|
||||||
|
server = json_data[0][0]["server"]
|
||||||
|
timestamp = []
|
||||||
|
position = {}
|
||||||
|
truth_timestamp = []
|
||||||
|
truth_position = []
|
||||||
|
for item in json_data:
|
||||||
|
|
||||||
|
for method in item:
|
||||||
|
|
||||||
|
if method["server"] != server:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if start_time and method["timestamp_event"]/1000 < start_time:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if stop_time and method["timestamp_event"]/1000 > stop_time:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# store target data
|
||||||
|
method_localisation = method["localisation"]
|
||||||
|
if method_localisation not in position:
|
||||||
|
position[method_localisation] = {}
|
||||||
|
position[method_localisation]["timestamp"] = []
|
||||||
|
position[method_localisation]["detections"] = []
|
||||||
|
else:
|
||||||
|
if args.target_name in method["detections_localised"] and \
|
||||||
|
len(method["detections_localised"][args.target_name]["points"]) > 0:
|
||||||
|
position[method_localisation]["timestamp"].append(
|
||||||
|
method["timestamp_event"]/1000)
|
||||||
|
position[method_localisation]["detections"].append(
|
||||||
|
method["detections_localised"][args.target_name]["points"][0])
|
||||||
|
# covert to ENU
|
||||||
|
x, y, z = Geometry.lla2ecef(
|
||||||
|
position[method_localisation]["detections"][-1][0],
|
||||||
|
position[method_localisation]["detections"][-1][1],
|
||||||
|
position[method_localisation]["detections"][-1][2])
|
||||||
|
x, y, z = Geometry.ecef2enu(x, y, z, radar4_lla[0],
|
||||||
|
radar4_lla[1], radar4_lla[2])
|
||||||
|
if not "detections_enu" in position[method_localisation]:
|
||||||
|
position[method_localisation]["detections_enu"] = []
|
||||||
|
position[method_localisation]["detections_enu"].append([x, y, z])
|
||||||
|
|
||||||
|
# store truth data
|
||||||
|
if args.target_name in method["truth"]:
|
||||||
|
truth_timestamp.append(
|
||||||
|
method["truth"][args.target_name]["timestamp"])
|
||||||
|
truth_position.append([
|
||||||
|
method["truth"][args.target_name]["lat"],
|
||||||
|
method["truth"][args.target_name]["lon"],
|
||||||
|
method["truth"][args.target_name]["alt"]])
|
||||||
|
|
||||||
|
timestamp.append(method["timestamp_event"])
|
||||||
|
|
||||||
|
# remove duplicates in truth data
|
||||||
|
timestamp = list(dict.fromkeys(timestamp))
|
||||||
|
timestamp = [element/1000 for element in timestamp]
|
||||||
|
truth_timestamp_unique = []
|
||||||
|
truth_position_unique = []
|
||||||
|
for t, p in zip(truth_timestamp, truth_position):
|
||||||
|
if t not in truth_timestamp_unique:
|
||||||
|
truth_timestamp_unique.append(t)
|
||||||
|
truth_position_unique.append(p)
|
||||||
|
truth_timestamp = truth_timestamp_unique
|
||||||
|
truth_position = truth_position_unique
|
||||||
|
|
||||||
|
# resample truth to event time (position already sampled correct)
|
||||||
|
for i in reversed(range(len(timestamp))):
|
||||||
|
if timestamp[i] < min(truth_timestamp) or timestamp[i] > max(truth_timestamp):
|
||||||
|
del timestamp[i]
|
||||||
|
truth_position_resampled = interpolate_positions(
|
||||||
|
timestamp, truth_timestamp, truth_position)
|
||||||
|
|
||||||
|
# convert truth to ENU
|
||||||
|
truth_position_resampled_enu = []
|
||||||
|
for pos in truth_position_resampled:
|
||||||
|
x, y, z = Geometry.lla2ecef(pos[0], pos[1], pos[2])
|
||||||
|
truth_position_resampled_enu.append(
|
||||||
|
Geometry.ecef2enu(x, y, z,
|
||||||
|
radar4_lla[0], radar4_lla[1], radar4_lla[2]))
|
||||||
|
|
||||||
|
# plot x, y, z
|
||||||
|
plt.figure(figsize=(5,7))
|
||||||
|
for i in range(3):
|
||||||
|
yaxis_truth = [pos[i] for pos in truth_position_resampled_enu]
|
||||||
|
plt.subplot(3, 1, i+1)
|
||||||
|
plt.plot(timestamp, yaxis_truth, label="ADS-B Truth")
|
||||||
|
for method in position:
|
||||||
|
for i in range(3):
|
||||||
|
yaxis_target = [pos[i] for pos in position[method]["detections_enu"]]
|
||||||
|
plt.subplot(3, 1, i+1)
|
||||||
|
plt.plot(position[method]["timestamp"], yaxis_target, 'x', label=method)
|
||||||
|
plt.xlabel('Timestamp')
|
||||||
|
if i == 0:
|
||||||
|
plt.ylabel('ENU X (m)')
|
||||||
|
if i == 1:
|
||||||
|
plt.ylabel('ENU Y (m)')
|
||||||
|
if i == 2:
|
||||||
|
plt.ylabel('ENU Z (m)')
|
||||||
|
|
||||||
|
plt.subplot(3, 1, 1)
|
||||||
|
plt.legend()
|
||||||
|
plt.tight_layout()
|
||||||
|
plt.savefig('save/plot_accuracy.png', bbox_inches='tight', pad_inches=0.01)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
2
script/requirements.txt
Normal file
2
script/requirements.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
numpy==1.26.4
|
||||||
|
matplotlib==3.8.3
|
Loading…
Reference in a new issue