Script working for plot

This commit is contained in:
30hours 2024-03-10 08:51:58 +00:00
parent 5c0a1bb9b4
commit 6e1a4ec5d0
8 changed files with 180 additions and 7 deletions

View file

@ -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"},

View file

@ -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),

View file

@ -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

View file

@ -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
View 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

View file

@ -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>
```

View file

@ -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
View file

@ -0,0 +1,2 @@
numpy==1.26.4
matplotlib==3.8.3