mirror of
https://github.com/30hours/3lips.git
synced 2024-11-18 12:33:58 +00:00
Start plotting target local
This commit is contained in:
parent
2c7c4358b7
commit
561baf5a35
8 changed files with 116 additions and 80 deletions
|
@ -17,7 +17,8 @@ app = Flask(__name__)
|
||||||
# store state data
|
# store state data
|
||||||
servers = [
|
servers = [
|
||||||
{"name": "radar4", "url": "radar4.30hours.dev"},
|
{"name": "radar4", "url": "radar4.30hours.dev"},
|
||||||
{"name": "radar5", "url": "radar5.30hours.dev"}
|
{"name": "radar5", "url": "radar5.30hours.dev"},
|
||||||
|
{"name": "radar6", "url": "radar6.30hours.dev"}
|
||||||
]
|
]
|
||||||
associators = [
|
associators = [
|
||||||
{"name": "ADSB Associator", "id": "adsb-associator"}
|
{"name": "ADSB Associator", "id": "adsb-associator"}
|
||||||
|
|
|
@ -16,14 +16,17 @@ function event_radar() {
|
||||||
const target = data["detections_localised"][key];
|
const target = data["detections_localised"][key];
|
||||||
const points = target["points"];
|
const points = target["points"];
|
||||||
|
|
||||||
removeEntitiesByType("test");
|
console.log(target);
|
||||||
|
console.log(points);
|
||||||
|
|
||||||
|
removeEntitiesOlderThanAndFade("detection", 60, 0.5);
|
||||||
|
|
||||||
for (const point in points) {
|
for (const point in points) {
|
||||||
addPoint(
|
addPoint(
|
||||||
points[point][0],
|
points[point][0],
|
||||||
points[point][1],
|
points[point][1],
|
||||||
points[point][2],
|
points[point][2],
|
||||||
"test",
|
"detection",
|
||||||
style_point.color,
|
style_point.color,
|
||||||
style_point.pointSize,
|
style_point.pointSize,
|
||||||
style_point.type,
|
style_point.type,
|
||||||
|
@ -46,7 +49,7 @@ function event_radar() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var style_point = {};
|
var style_point = {};
|
||||||
style_point.color = 'rgba(128, 0, 0, 1.0)';
|
style_point.color = 'rgba(0, 255, 0, 1.0)';
|
||||||
style_point.pointSize = 10;
|
style_point.pointSize = 16;
|
||||||
style_point.type = "test";
|
style_point.type = "detection";
|
||||||
style_point.timestamp = Date.now();
|
style_point.timestamp = Date.now();
|
|
@ -281,8 +281,9 @@ function removeEntitiesOlderThanAndFade(entityType, maxAgeSeconds, baseAlpha) {
|
||||||
const type = entity.properties["type"].getValue();
|
const type = entity.properties["type"].getValue();
|
||||||
const timestamp = entity.properties["timestamp"].getValue();
|
const timestamp = entity.properties["timestamp"].getValue();
|
||||||
if (entity.properties && entity.properties["type"] &&
|
if (entity.properties && entity.properties["type"] &&
|
||||||
entity.properties["type"].getValue() === entityType &&
|
entity.properties["type"].getValue() === entityType) {
|
||||||
Date.now()-timestamp > maxAgeSeconds*1000) {
|
|
||||||
|
if (Date.now()-timestamp > maxAgeSeconds*1000) {
|
||||||
viewer.entities.remove(entity);
|
viewer.entities.remove(entity);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -290,7 +291,7 @@ function removeEntitiesOlderThanAndFade(entityType, maxAgeSeconds, baseAlpha) {
|
||||||
entity.point.color.getValue(), baseAlpha*(1-(Date.now()-timestamp)/(maxAgeSeconds*1000)));
|
entity.point.color.getValue(), baseAlpha*(1-(Date.now()-timestamp)/(maxAgeSeconds*1000)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeEntitiesByType(entityType) {
|
function removeEntitiesByType(entityType) {
|
||||||
|
|
|
@ -58,7 +58,7 @@ class Message:
|
||||||
with conn:
|
with conn:
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
data = conn.recv(8096)
|
data = conn.recv(30000)
|
||||||
if not data:
|
if not data:
|
||||||
break
|
break
|
||||||
decoded_data = data.decode()
|
decoded_data = data.decode()
|
||||||
|
@ -82,7 +82,7 @@ class Message:
|
||||||
try:
|
try:
|
||||||
client_socket.connect((self.host, self.port))
|
client_socket.connect((self.host, self.port))
|
||||||
client_socket.sendall(message.encode())
|
client_socket.sendall(message.encode())
|
||||||
reply = client_socket.recv(8096).decode()
|
reply = client_socket.recv(30000).decode()
|
||||||
return reply
|
return reply
|
||||||
except ConnectionRefusedError:
|
except ConnectionRefusedError:
|
||||||
print(f"Connection to {self.host}:{self.port} refused.")
|
print(f"Connection to {self.host}:{self.port} refused.")
|
||||||
|
|
|
@ -44,6 +44,8 @@ class EllipsoidParametric:
|
||||||
for target in assoc_detections:
|
for target in assoc_detections:
|
||||||
|
|
||||||
print(target, flush=True)
|
print(target, flush=True)
|
||||||
|
target_samples = {}
|
||||||
|
target_samples[target] = {}
|
||||||
|
|
||||||
for radar in assoc_detections[target]:
|
for radar in assoc_detections[target]:
|
||||||
|
|
||||||
|
@ -73,20 +75,48 @@ class EllipsoidParametric:
|
||||||
radar["radar"]
|
radar["radar"]
|
||||||
)
|
)
|
||||||
|
|
||||||
print(ellipsoid.yaw, flush=True)
|
samples = self.sample(ellipsoid, radar["delay"], 20)
|
||||||
print(ellipsoid.pitch, flush=True)
|
target_samples[target][radar["radar"]] = samples
|
||||||
|
|
||||||
self.sample(ellipsoid, radar["delay"], 10000)
|
# find close points
|
||||||
|
radar_keys = list(target_samples[target].keys())
|
||||||
|
samples_intersect = {key: [] for key in radar_keys}
|
||||||
|
threshold = 200
|
||||||
|
for i in range(0, len(target_samples[target])-1):
|
||||||
|
|
||||||
print("", flush=True)
|
for j in range(i+1, len(target_samples[target])):
|
||||||
|
|
||||||
|
for point1 in target_samples[target][radar_keys[i]]:
|
||||||
|
|
||||||
|
for point2 in target_samples[target][radar_keys[j]]:
|
||||||
|
|
||||||
|
if Geometry.distance_ecef(point1, point2) < threshold:
|
||||||
|
samples_intersect[radar_keys[i]].append(point1)
|
||||||
|
samples_intersect[radar_keys[j]].append(point2)
|
||||||
|
|
||||||
|
# remove duplicates and convert to LLA
|
||||||
|
output[target] = {}
|
||||||
|
output[target]["points"] = []
|
||||||
|
for key in radar_keys:
|
||||||
|
samples_intersect[key] = [list(t) for t in {tuple(point) for point in samples_intersect[key]}]
|
||||||
|
for i in range(len(samples_intersect[key])):
|
||||||
|
samples_intersect[key][i] = Geometry.ecef2lla(
|
||||||
|
samples_intersect[key][i][0],
|
||||||
|
samples_intersect[key][i][1],
|
||||||
|
samples_intersect[key][i][2])
|
||||||
|
output[target]["points"].append([
|
||||||
|
round(samples_intersect[key][i][0], 3),
|
||||||
|
round(samples_intersect[key][i][1], 3),
|
||||||
|
round(samples_intersect[key][i][2])])
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def sample(self, ellipsoid, bistatic_range, n):
|
def sample(self, ellipsoid, bistatic_range, n):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@brief Generate a set of points for the ellipsoid.
|
@brief Generate a set of ECEF points for the ellipsoid.
|
||||||
@details No arc length parametrisation.
|
@details No arc length parametrisation.
|
||||||
|
@details Use ECEF because distance measure is simple over LLA.
|
||||||
@param ellipsoid (Ellipsoid): The ellipsoid object to use.
|
@param ellipsoid (Ellipsoid): The ellipsoid object to use.
|
||||||
@param bistatic_range (float): Bistatic range for ellipsoid.
|
@param bistatic_range (float): Bistatic range for ellipsoid.
|
||||||
@param n (int): Number of points to generate.
|
@param n (int): Number of points to generate.
|
||||||
|
@ -101,51 +131,39 @@ class EllipsoidParametric:
|
||||||
|
|
||||||
phi = ellipsoid.pitch
|
phi = ellipsoid.pitch
|
||||||
theta = ellipsoid.yaw
|
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)]
|
|
||||||
# ])
|
|
||||||
R = np.array([
|
R = np.array([
|
||||||
[np.cos(theta), -np.sin(theta)*np.cos(phi), np.sin(theta)*np.sin(phi)],
|
[np.cos(theta), -np.sin(theta)*np.cos(phi), np.sin(theta)*np.sin(phi)],
|
||||||
[np.sin(theta), np.cos(theta)*np.cos(phi), -np.cos(theta)*np.sin(phi)],
|
[np.sin(theta), np.cos(theta)*np.cos(phi), -np.cos(theta)*np.sin(phi)],
|
||||||
[0, np.sin(phi), np.cos(phi)]
|
[0, np.sin(phi), np.cos(phi)]
|
||||||
])
|
])
|
||||||
|
|
||||||
# rotation matrix normal
|
|
||||||
# theta = ellipsoid.pitch_plane
|
|
||||||
# phi = ellipsoid.yaw_plane
|
|
||||||
# R2 = 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
|
# compute samples vectorised
|
||||||
a = (bistatic_range+ellipsoid.distance)/2
|
a = (bistatic_range+ellipsoid.distance)/2
|
||||||
b = np.sqrt(a**2 - (ellipsoid.distance/2)**2)
|
b = np.sqrt(a**2 - (ellipsoid.distance/2)**2)
|
||||||
u_values = np.linspace(0, 2 * np.pi, n)
|
u_values = np.linspace(0, 2 * np.pi, n)
|
||||||
v_values = np.linspace(-np.pi, np.pi, n)
|
v_values = np.linspace(-np.pi/2, np.pi/2, int(n/2))
|
||||||
u, v = np.meshgrid(u_values, v_values, indexing='ij')
|
u, v = np.meshgrid(u_values, v_values, indexing='ij')
|
||||||
# x = a * np.cos(u)
|
x = a * np.cos(u)
|
||||||
# y = b * np.sin(u) * np.cos(v)
|
y = b * np.sin(u) * np.cos(v)
|
||||||
# z = b * np.sin(u) * np.sin(v)
|
z = b * np.sin(u) * np.sin(v)
|
||||||
x = a * np.cos(u) * np.cos(v)
|
|
||||||
y = b * np.sin(u)
|
|
||||||
z = a * np.cos(u) * np.sin(v)
|
|
||||||
r = np.stack([x, y, z], axis=-1).reshape(-1, 3)
|
r = np.stack([x, y, z], axis=-1).reshape(-1, 3)
|
||||||
|
|
||||||
#r_1 = np.dot(r, np.dot(R, R2)) + ellipsoid.midpoint
|
|
||||||
#r_1 = np.dot(r, R) + ellipsoid.midpoint
|
|
||||||
r_1 = np.dot(r, R)
|
r_1 = np.dot(r, R)
|
||||||
#r_1 = r
|
output = []
|
||||||
|
|
||||||
a, b, c = Geometry.ecef2lla(
|
|
||||||
ellipsoid.midpoint[0], ellipsoid.midpoint[1], ellipsoid.midpoint[2])
|
|
||||||
|
|
||||||
for i in range(len(r_1)):
|
for i in range(len(r_1)):
|
||||||
x, y, z = Geometry.enu2ecef(r_1[i][0], r_1[i][1], r_1[i][2],
|
# points to ECEF
|
||||||
a, b, c)
|
x, y, z = Geometry.enu2ecef(
|
||||||
r_1[i] = [x, y, z]
|
r_1[i][0], r_1[i][1], r_1[i][2],
|
||||||
|
ellipsoid.midpoint_lla[0],
|
||||||
|
ellipsoid.midpoint_lla[1],
|
||||||
|
ellipsoid.midpoint_lla[2])
|
||||||
|
# points to LLA
|
||||||
|
[x, y, z] = Geometry.ecef2lla(x, y, z)
|
||||||
|
# only store points above ground
|
||||||
|
if z > 0:
|
||||||
|
# convert back to ECEF for simple distance measurements
|
||||||
|
[x, y, z] = Geometry.lla2ecef(x, y, z)
|
||||||
|
output.append([round(x, 3), round(y, 3), round(z)])
|
||||||
|
|
||||||
return r_1.tolist()
|
return output
|
|
@ -183,3 +183,10 @@ class Geometry:
|
||||||
n = -sin_lat * t + cos_lat * w
|
n = -sin_lat * t + cos_lat * w
|
||||||
|
|
||||||
return e, n, u
|
return e, n, u
|
||||||
|
|
||||||
|
def distance_ecef(point1, point2):
|
||||||
|
|
||||||
|
return math.sqrt(
|
||||||
|
(point2[0]-point1[0])**2 +
|
||||||
|
(point2[1]-point1[1])**2 +
|
||||||
|
(point2[2]-point1[2])**2)
|
|
@ -30,11 +30,11 @@ class Ellipsoid:
|
||||||
# dependent members
|
# dependent members
|
||||||
self.midpoint = [(f1[0]+f2[0])/2,
|
self.midpoint = [(f1[0]+f2[0])/2,
|
||||||
(f1[1]+f2[1])/2, (f1[2]+f2[2])/2]
|
(f1[1]+f2[1])/2, (f1[2]+f2[2])/2]
|
||||||
midpoint_lla = Geometry.ecef2lla(
|
self.midpoint_lla = Geometry.ecef2lla(
|
||||||
self.midpoint[0], self.midpoint[1], self.midpoint[2])
|
self.midpoint[0], self.midpoint[1], self.midpoint[2])
|
||||||
vector_enu = Geometry.ecef2enu(f1[0], f1[1], f1[2],
|
vector_enu = Geometry.ecef2enu(f1[0], f1[1], f1[2],
|
||||||
midpoint_lla[0], midpoint_lla[1], midpoint_lla[2])
|
self.midpoint_lla[0], self.midpoint_lla[1], self.midpoint_lla[2])
|
||||||
self.yaw = -math.atan2(vector_enu[1], vector_enu[0])-math.pi/2
|
self.yaw = -math.atan2(vector_enu[1], vector_enu[0])
|
||||||
self.pitch = math.atan2(vector_enu[2],
|
self.pitch = math.atan2(vector_enu[2],
|
||||||
math.sqrt(vector_enu[0]**2 + vector_enu[1]**2))
|
math.sqrt(vector_enu[0]**2 + vector_enu[1]**2))
|
||||||
self.distance = math.sqrt(
|
self.distance = math.sqrt(
|
||||||
|
|
|
@ -105,30 +105,36 @@ async def event():
|
||||||
associated_dets = associator.process(item["server"], radar_dict_item)
|
associated_dets = associator.process(item["server"], radar_dict_item)
|
||||||
localised_dets = coordreg.process(associated_dets, radar_dict_item)
|
localised_dets = coordreg.process(associated_dets, radar_dict_item)
|
||||||
|
|
||||||
|
if associated_dets:
|
||||||
|
print(associated_dets, flush=True)
|
||||||
|
|
||||||
|
#if localised_dets:
|
||||||
|
print(localised_dets, flush=True)
|
||||||
|
|
||||||
# tmp test
|
# tmp test
|
||||||
localised_dets = {}
|
# localised_dets = {}
|
||||||
localised_dets["test"] = {}
|
# localised_dets["test"] = {}
|
||||||
x_tx, y_tx, z_tx = Geometry.lla2ecef(
|
# 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']['latitude'],
|
||||||
radar_dict_item['radar4.30hours.dev']["config"]['location']['tx']['longitude'],
|
# radar_dict_item['radar4.30hours.dev']["config"]['location']['tx']['longitude'],
|
||||||
radar_dict_item['radar4.30hours.dev']["config"]['location']['tx']['altitude']
|
# radar_dict_item['radar4.30hours.dev']["config"]['location']['tx']['altitude']
|
||||||
)
|
# )
|
||||||
x_rx, y_rx, z_rx = Geometry.lla2ecef(
|
# 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']['latitude'],
|
||||||
radar_dict_item['radar4.30hours.dev']["config"]['location']['rx']['longitude'],
|
# radar_dict_item['radar4.30hours.dev']["config"]['location']['rx']['longitude'],
|
||||||
radar_dict_item['radar4.30hours.dev']["config"]['location']['rx']['altitude']
|
# radar_dict_item['radar4.30hours.dev']["config"]['location']['rx']['altitude']
|
||||||
)
|
# )
|
||||||
ellipsoid = Ellipsoid(
|
# ellipsoid = Ellipsoid(
|
||||||
[x_tx, y_tx, z_tx],
|
# [x_tx, y_tx, z_tx],
|
||||||
[x_rx, y_rx, z_rx],
|
# [x_rx, y_rx, z_rx],
|
||||||
'radar4.30hours.dev'
|
# 'radar4.30hours.dev'
|
||||||
)
|
# )
|
||||||
pointsEcef = ellipsoidParametric.sample(ellipsoid, 6000, 15)
|
# points = ellipsoidParametric.sample(ellipsoid, 2000, 25)
|
||||||
pointsLla = []
|
# pointsLla = []
|
||||||
for point in pointsEcef:
|
# for point in points:
|
||||||
lat, lon, alt = Geometry.ecef2lla(point[0], point[1], point[2])
|
# lat, lon, alt = Geometry.ecef2lla(point[0], point[1], point[2])
|
||||||
pointsLla.append([round(lat, 4), round(lon, 4), round(alt)])
|
# pointsLla.append([round(lat, 3), round(lon, 3), round(alt)])
|
||||||
localised_dets["test"]["points"] = pointsLla
|
# localised_dets["test"]["points"] = pointsLla
|
||||||
|
|
||||||
# output data to API
|
# output data to API
|
||||||
item["detections_associated"] = associated_dets
|
item["detections_associated"] = associated_dets
|
||||||
|
|
Loading…
Reference in a new issue