diff --git a/api/map/event/radar.js b/api/map/event/radar.js index f9e7d82..453f95c 100644 --- a/api/map/event/radar.js +++ b/api/map/event/radar.js @@ -1,4 +1,26 @@ function event_radar() { - setTimeout(event_radar, 1000); + radar_url = window.location.origin + '/api' + window.location.search; + console.log(radar_url); + + fetch(radar_url) + .then(response => { + if (!response.ok) { + throw new Error('Network response was not ok'); + } + return response.json(); + }) + .then(data => { + // Update aircraft points based on new data + console.log("test"); + }) + .catch(error => { + // Handle errors during fetch + console.error('Error during fetch:', error); + }) + .finally(() => { + // Schedule the next fetch after a delay (e.g., 5 seconds) + setTimeout(event_radar, 1000); + }); + } \ No newline at end of file diff --git a/api/templates/map.html b/api/templates/map.html deleted file mode 100644 index 98f95e1..0000000 --- a/api/templates/map.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - Map Page - - -

Map Page

- - - diff --git a/common/Message.py b/common/Message.py index 1f36d87..5e9f748 100644 --- a/common/Message.py +++ b/common/Message.py @@ -58,7 +58,7 @@ class Message: with conn: while True: - data = conn.recv(1024) + data = conn.recv(65000) if not data: break decoded_data = data.decode() @@ -82,7 +82,7 @@ class Message: try: client_socket.connect((self.host, self.port)) client_socket.sendall(message.encode()) - reply = client_socket.recv(1024).decode() + reply = client_socket.recv(65000).decode() return reply except ConnectionRefusedError: print(f"Connection to {self.host}:{self.port} refused.") diff --git a/event/algorithm/associator/AdsbAssociator.py b/event/algorithm/associator/AdsbAssociator.py index 65ac0cc..6ef7904 100644 --- a/event/algorithm/associator/AdsbAssociator.py +++ b/event/algorithm/associator/AdsbAssociator.py @@ -39,7 +39,10 @@ class AdsbAssociator: for radar in radar_list: - if radar_data[radar]["config"] is not None: + valid_config = radar_data[radar]["config"] is not None + valid_detection = radar_data[radar]["detection"] is not None + + if valid_config and valid_detection: # get URL for adsb2truth url = self.generate_api_url(radar, radar_data[radar]) @@ -127,10 +130,7 @@ class AdsbAssociator: tx_alt = radar_data['config']['location']['tx']['altitude'] fc = radar_data['config']['capture']['fc'] - if (radar == "radar5.30hours.dev"): - adsb = radar_data['config']['truth']['adsb']['ip'] - else: - adsb = radar_data['config']['truth']['adsb']['tar1090'] + adsb = radar_data['config']['truth']['adsb']['tar1090'] api_url = "http://adsb2dd.30hours.dev/api/dd" diff --git a/event/algorithm/coordreg/EllipsoidParametric.py b/event/algorithm/coordreg/EllipsoidParametric.py index ada052c..464afbc 100644 --- a/event/algorithm/coordreg/EllipsoidParametric.py +++ b/event/algorithm/coordreg/EllipsoidParametric.py @@ -4,6 +4,8 @@ """ from data.Ellipsoid import Ellipsoid +from algorithm.geometry.Geometry import Geometry +import numpy as np class EllipsoidParametric: @@ -20,18 +22,96 @@ class EllipsoidParametric: @brief Constructor for the EllipsoidParametric class. """ + self.ellipsoids = [] + def process(self, assoc_detections, radar_data): """ @brief Perform coord registration using the ellipsoid parametric method. @details Generate a (non arc-length) parametric ellipsoid for each node. - Find - @param radar_detections (str): JSON of blah2 radar detections. - @param adsb_detections (str): JSON of adsb2dd truth detections. + @param assoc_detections (dict): JSON of blah2 radar detections. + @param radar_data (dict): JSON of adsb2dd truth detections. @return str: JSON of associated detections. """ output = {} + # return if no detections + if not assoc_detections: + return output + + for target in assoc_detections: + + print(target, flush=True) + + for radar in assoc_detections[target]: + + print(radar["radar"], flush=True) + print(radar["delay"], flush=True) + + # create ellipsoid for radar + ellipsoid = next(( + item for item in self.ellipsoids + if item.name == radar["radar"]), None) + + if ellipsoid is None: + config = radar_data[radar["radar"]]["config"] + x_tx, y_tx, z_tx = Geometry.lla2ecef( + config['location']['tx']['latitude'], + config['location']['tx']['longitude'], + config['location']['tx']['altitude'] + ) + x_rx, y_rx, z_rx = Geometry.lla2ecef( + config['location']['rx']['latitude'], + config['location']['rx']['longitude'], + config['location']['rx']['altitude'] + ) + ellipsoid = Ellipsoid( + [x_tx, y_tx, z_tx], + [x_rx, y_rx, z_rx], + radar["radar"] + ) + + print(ellipsoid.yaw, flush=True) + print(ellipsoid.pitch, flush=True) + + self.sample(ellipsoid, radar["delay"], 10000) + + print("", flush=True) + return output - \ No newline at end of file + + def sample(self, ellipsoid, bistatic_range, n): + + """ + @brief Generate a set of points for the ellipsoid. + @details No arc length parametrisation. + @param ellipsoid (Ellipsoid): The ellipsoid object to use. + @param bistatic_range (float): Bistatic range for ellipsoid. + @param n (int): Number of points to generate. + @return list: Samples with size [n, 3]. + """ + + # rotation matrix + phi = ellipsoid.pitch + theta = ellipsoid.yaw + R = np.array([ + [np.cos(phi)*np.cos(theta), -np.sin(phi)*np.cos(theta), np.sin(theta)], + [np.sin(phi), np.cos(phi), 0], + [-np.cos(phi)*np.sin(theta), np.sin(phi)*np.sin(theta), np.cos(theta)] + ]) + + # compute samples vectorised + a = (bistatic_range-ellipsoid.distance)/2 + b = np.sqrt(a**2 - (ellipsoid.distance/2)) + u_values = np.linspace(0, 2 * np.pi, n) + v_values = np.linspace(-np.pi/2, np.pi/2, n) + u, v = np.meshgrid(u_values, v_values, indexing='ij') + x = a * np.cos(u) + y = b * np.sin(u) * np.cos(v) + z = b * np.sin(u) * np.sin(v) + r = np.stack([x, y, z], axis=-1).reshape(-1, 3) + + r_1 = np.dot(r, R) + ellipsoid.midpoint + + return r_1.tolist() \ No newline at end of file diff --git a/event/algorithm/geometry/Geometry.py b/event/algorithm/geometry/Geometry.py new file mode 100644 index 0000000..5855f32 --- /dev/null +++ b/event/algorithm/geometry/Geometry.py @@ -0,0 +1,42 @@ +""" +@file Geometry.py +@author 30hours +""" + +import math +import numpy as np + +class Geometry: + + """ + @class Geometry + @brief A class to store geometric functions. + """ + + def __init__(self, f1, f2, name): + + """ + @brief Constructor for the Ellipsoid class. + """ + + def lla2ecef(latitude, longitude, altitude): + + # WGS84 constants + a = 6378137.0 # semi-major axis in meters + f = 1 / 298.257223563 # flattening + + # Convert latitude and longitude to radians + lat_rad = math.radians(latitude) + lon_rad = math.radians(longitude) + + # Calculate the auxiliary values + cos_lat = math.cos(lat_rad) + sin_lat = math.sin(lat_rad) + N = a / math.sqrt(1 - f * (2 - f) * sin_lat**2) + + # Calculate ECEF coordinates + ecef_x = (N + altitude) * cos_lat * math.cos(lon_rad) + ecef_y = (N + altitude) * cos_lat * math.sin(lon_rad) + ecef_z = (N * (1 - f) + altitude) * sin_lat + + return ecef_x, ecef_y, ecef_z diff --git a/event/data/Ellipsoid.py b/event/data/Ellipsoid.py index c9939f3..d7ebb7e 100644 --- a/event/data/Ellipsoid.py +++ b/event/data/Ellipsoid.py @@ -11,19 +11,22 @@ class Ellipsoid: @class Ellipsoid @brief A class to store ellipsoid parameters for bistatic radar. @details Stores foci, midpoint, pitch, yaw and distance. - Able to generate samples through public functions. """ def __init__(self, f1, f2, name): """ @brief Constructor for the Ellipsoid class. + @param f1 (list): [x, y, z] of foci 1 in ECEF. + @param f2 (list): [x, y, z] of foci 2 in ECEF. + @param name (str): Name to associate with shape. """ self.f1 = f1 self.f2 = f2 self.name = name + # dependent members self.midpoint = [(f1[0]+f2[0])/2, (f1[1]+f2[1])/2, (f1[2]+f2[2])/2] vector = (f2[0]-f1[0], f2[1]-f1[1], f2[2]-f1[2]) @@ -34,19 +37,3 @@ class Ellipsoid: (f2[0] - f1[0])**2 + (f2[1] - f1[1])**2 + (f2[2] - f1[2])**2) - - def process(self, bistatic_range): - - """ - @brief Perform coord registration using the ellipsoid parametric method. - @details Generate a (non arc-length) parametric ellipsoid for each node. - Find - @param radar_detections (str): JSON of blah2 radar detections. - @param adsb_detections (str): JSON of adsb2dd truth detections. - @return str: JSON of associated detections. - """ - - output = {} - - return output - \ No newline at end of file diff --git a/event/event.py b/event/event.py index 3f77a09..a72fa63 100644 --- a/event/event.py +++ b/event/event.py @@ -17,6 +17,9 @@ from algorithm.associator.AdsbAssociator import AdsbAssociator from algorithm.coordreg.EllipsoidParametric import EllipsoidParametric from common.Message import Message +from data.Ellipsoid import Ellipsoid +from algorithm.geometry.Geometry import Geometry + # init event loop api = [] @@ -101,7 +104,27 @@ async def event(): # processing associated_dets = associator.process(item["server"], radar_dict_item) localised_dets = coordreg.process(associated_dets, radar_dict_item) - + + # tmp test + localised_dets = {} + localised_dets["test"] = {} + x_tx, y_tx, z_tx = Geometry.lla2ecef( + radar_dict_item['radar4.30hours.dev']["config"]['location']['tx']['latitude'], + radar_dict_item['radar4.30hours.dev']["config"]['location']['tx']['longitude'], + radar_dict_item['radar4.30hours.dev']["config"]['location']['tx']['altitude'] + ) + x_rx, y_rx, z_rx = Geometry.lla2ecef( + radar_dict_item['radar4.30hours.dev']["config"]['location']['rx']['latitude'], + radar_dict_item['radar4.30hours.dev']["config"]['location']['rx']['longitude'], + radar_dict_item['radar4.30hours.dev']["config"]['location']['rx']['altitude'] + ) + ellipsoid = Ellipsoid( + [x_tx, y_tx, z_tx], + [x_rx, y_rx, z_rx], + 'radar4.30hours.dev' + ) + localised_dets["test"]["points"] = ellipsoidParametric.sample(ellipsoid, 10000, 5) + # output data to API item["detections_associated"] = associated_dets item["detections_localised"] = localised_dets @@ -154,6 +177,8 @@ async def callback_message_received(msg): else: api[-1][key] = value api[-1]["timestamp"] = timestamp + if not isinstance(api[-1]["server"], list): + api[-1]["server"] = [api[-1]["server"]] # json dump output = json.dumps(api)