LISHUZUOXUN_yangjiang/UWB/across_detect.py

229 lines
8.4 KiB
Python
Raw Normal View History

2024-09-23 14:54:15 +08:00
import math
import random
import time
from math import sqrt
from typing import List, Tuple
import numpy as np
import sympy
from shapely import MultiPoint, Polygon, Point
def get_tag_pos_from_anchor(anchor_coord: List[List], tag_distance: List[float]) -> Tuple[float, float]:
node_number = len(anchor_coord)
d = [coord[0] ** 2 + coord[1] ** 2 for coord in anchor_coord]
# 根据观测距离用最小二乘法估计目标位置
H = np.zeros((node_number - 1, 2))
b = np.zeros(node_number - 1)
for i in range(1, node_number):
# A 矩阵 和 B 矩阵
H[i - 1] = [2 * (anchor_coord[i][0] - anchor_coord[1][0]), 2 * (anchor_coord[i][1] - anchor_coord[1][1])]
b[i - 1] = tag_distance[1] ** 2 - tag_distance[i] ** 2 + d[i] - d[1]
H_zhuanzhi = np.transpose(H) # H'
hhh = np.dot(np.linalg.inv(np.dot(np.transpose(H), H)), H_zhuanzhi) # inv(H'*H)*H'
estimate = np.dot(hhh, b)
tag_pos = (estimate[0], estimate[1])
return tag_pos
def distance(coord1, coord2):
return sqrt((coord1[0] - coord2[0]) ** 2 + (coord1[1] - coord2[1]) ** 2)
# 计算定位坐标
def tri_position(xa, ya, da, xb, yb, db, xc, yc, dc):
x, y = sympy.symbols('x y')
f1 = 2 * x * (xa - xc) + np.square(xc) - np.square(xa) + 2 * y * (ya - yc) + np.square(yc) - np.square(ya) - (
np.square(dc) - np.square(da))
f2 = 2 * x * (xb - xc) + np.square(xc) - np.square(xb) + 2 * y * (yb - yc) + np.square(yc) - np.square(yb) - (
np.square(dc) - np.square(db))
result = sympy.solve([f1, f2], [x, y])
locx, locy = result[x], result[y]
return [locx, locy]
def trilateration(x1, y1, d1, x2, y2, d2, x3, y3, d3):
a11 = 2 * (x1 - x3)
a12 = 2 * (y1 - y3)
b1 = pow(x1, 2) - pow(x3, 2) + pow(y1, 2) - pow(y3, 2) + pow(d3, 2) - pow(d1, 2)
a21 = 2 * (x2 - x3)
a22 = 2 * (y2 - y3)
b2 = pow(x2, 2) - pow(x3, 2) + pow(y2, 2) - pow(y3, 2) + pow(d3, 2) - pow(d2, 2)
d = [(b1 * a22 - a12 * b2) / (a11 * a22 - a12 * a21), (a11 * b2 - b1 * a21) / (a11 * a22 - a12 * a21)]
return d
def get_pos_from_2_anchor(p1, r1, p2, r2):
x0 = p1[0]
y0 = p1[1]
x1 = p2[0]
y1 = p2[1]
d = math.sqrt((abs(x1 - x0)) ** 2 + (abs(y1 - y0)) ** 2)
if d > (r1 + r2) or d < (abs(r1 - r2)):
# print("Two circles have no intersection")
center = [(x0 + x1) / 2, (y0 + y1) / 2]
return center, center
elif d == 0:
# print("Two circles have same center!")
return None, None
else:
A = (r1 ** 2 - r2 ** 2 + d ** 2) / (2 * d)
h = math.sqrt(r1 ** 2 - A ** 2)
x2 = x0 + A * (x1 - x0) / d
y2 = y0 + A * (y1 - y0) / d
x3 = x2 - h * (y1 - y0) / d
y3 = y2 + h * (x1 - x0) / d
x4 = x2 + h * (y1 - y0) / d
y4 = y2 - h * (x1 - x0) / d
c1 = [x3, y3]
c2 = [x4, y4]
return c1, c2
def is_in_poly(p, poly):
"""
:param p: [x, y]
:param poly: [[], [], [], [], ...]
:return:
"""
px, py = p
is_in = False
for i, corner in enumerate(poly):
next_i = i + 1 if i + 1 < len(poly) else 0
x1, y1 = corner
x2, y2 = poly[next_i]
if (x1 == px and y1 == py) or (x2 == px and y2 == py): # if point is on vertex
is_in = True
break
if min(y1, y2) < py <= max(y1, y2): # find horizontal edges of polygon
x = x1 + (py - y1) * (x2 - x1) / (y2 - y1)
if x == px: # if point is on edge
is_in = True
break
elif x > px: # if point is on left-side of line
is_in = not is_in
return is_in
def point_to_line_distance(point, line):
px, py = point
x1, y1, x2, y2 = line
line_magnitude = distance([x1, y1], [x2, y2])
if line_magnitude < 0.00000001:
return 9999
else:
u1 = (((px - x1) * (x2 - x1)) + ((py - y1) * (y2 - y1)))
u = u1 / (line_magnitude * line_magnitude)
if (u < 0.00001) or (u > 1):
# 点到直线的投影不在线段内, 计算点到两个端点距离的最小值即为"点到线段最小距离"
ix = distance([px, py], [x1, y1])
iy = distance([px, py], [x2, y2])
if ix > iy:
dis = iy
else:
dis = ix
else:
# 投影点在线段内部, 计算方式同点到直线距离, u 为投影点距离x1在x1x2上的比例, 以此计算出投影点的坐标
ix = x1 + u * (x2 - x1)
iy = y1 + u * (y2 - y1)
dis = distance([px, py], [ix, iy])
return dis
class AcrossDetect:
def __init__(self) -> None:
super().__init__()
self.anchor_coordinates = {}
self.anchor_side = {}
self.anchor_seq = []
self.anchor_poly = []
self.anchor_geometry: Polygon = None
self.max_anchor_distance = 0
@staticmethod
def distance(coord1, coord2):
return sqrt((coord1[0] - coord2[0]) ** 2 + (coord1[1] - coord2[1]) ** 2)
# 位置检测
def position_detect(self, record):
e = 7
# precise_distance = 3
record = {anchor: distance / 100 for anchor, distance in record.items()}
if any([distance < e for distance in record.values()]):
return True
else:
return False
# if any([distance > self.max_anchor_distance for distance in record.values()]):
# return False
# try:
# if len(record) > 3:
# anchor_coord_list = [self.anchor_coordinates[anchor] for anchor in record.keys()]
# distance_mes = list(record.values())
# p = get_tag_pos_from_anchor(anchor_coord=anchor_coord_list, tag_distance=distance_mes)
# if is_in_poly(p, self.anchor_poly):
# return True
# else:
# return False
# elif 2 < len(record) <= 3:
# anchor_coord_list = [self.anchor_coordinates[anchor] for anchor in record.keys()]
# distance_mes = list(record.values())
# p = trilateration(
# x1=anchor_coord_list[0][0], y1=anchor_coord_list[0][1], d1=distance_mes[0],
# x2=anchor_coord_list[1][0], y2=anchor_coord_list[1][1], d2=distance_mes[1],
# x3=anchor_coord_list[2][0], y3=anchor_coord_list[2][1], d3=distance_mes[2],
# )
# if is_in_poly(p, self.anchor_poly):
# return True
# else:
# return False
# elif 1 < len(record) <= 2:
# anchor_coord_list = [self.anchor_coordinates[anchor] for anchor in record.keys()]
# distance_mes = list(record.values())
# p1, p2 = get_pos_from_2_anchor(
# p1=anchor_coord_list[0], r1=distance_mes[0],
# p2=anchor_coord_list[1], r2=distance_mes[1],
# )
# p_dis = self.distance(p1, p2)
# p1_in = is_in_poly(p1, self.anchor_poly)
# p2_in = is_in_poly(p2, self.anchor_poly)
# if (p1_in or p2_in) and p_dis < precise_distance:
# return True
# else:
# return False
# else:
# dis = list(record.values())[0]
# if dis <= e:
# return True
# else:
# return False
# except:
# return False
# 设置基站坐标
def set_anchor_coordinates(self, anchor_coordinates):
return
self.anchor_coordinates = anchor_coordinates
dis_list = [
distance(anchor_0, anchor_1)
for anchor_0 in anchor_coordinates.values()
for anchor_1 in anchor_coordinates.values()
]
self.max_anchor_distance = max(dis_list)
self.anchor_seq.clear()
self.anchor_poly.clear()
mp = MultiPoint(list(anchor_coordinates.values()))
self.anchor_geometry = mp.convex_hull
self.anchor_geometry: Polygon
x, y = self.anchor_geometry.boundary.xy
x = x.tolist()[0:-1]
y = y.tolist()[0:-1]
coords_seq = [[x[i], y[i]] for i in range(len(x))]
for coords in coords_seq:
for anchor, anchor_coord in anchor_coordinates.items():
if distance(coords, anchor_coord) < 0.1:
self.anchor_seq.append(anchor)
self.anchor_poly.append(anchor_coord)