more rangelocator experimenting
This commit is contained in:
parent
d3c4d71331
commit
ad98eecf41
2 changed files with 81 additions and 16 deletions
|
@ -638,12 +638,12 @@ class MeshUIConsumer(AsyncJsonWebsocketConsumer):
|
||||||
return
|
return
|
||||||
if data["msg"]["msg_type"] == MeshMessageType.LOCATE_RANGE_RESULTS.name:
|
if data["msg"]["msg_type"] == MeshMessageType.LOCATE_RANGE_RESULTS.name:
|
||||||
data = data.copy()
|
data = data.copy()
|
||||||
location = await self.locator(data["msg"])
|
location = await self.locator(data["msg"], data["msg"]["src"])
|
||||||
data["position"] = None if not location else (int(location.x*100), int(location.y*100), int(location.z*100))
|
data["position"] = None if not location else (int(location.x*100), int(location.y*100), int(location.z*100))
|
||||||
await self.send_json(data)
|
await self.send_json(data)
|
||||||
|
|
||||||
@database_sync_to_async
|
@database_sync_to_async
|
||||||
def locator(self, msg):
|
def locator(self, msg, orig_addr=None):
|
||||||
locator = RangeLocator.load()
|
locator = RangeLocator.load()
|
||||||
return locator.locate(
|
return locator.locate(
|
||||||
{
|
{
|
||||||
|
@ -651,7 +651,8 @@ class MeshUIConsumer(AsyncJsonWebsocketConsumer):
|
||||||
for r in msg["ranges"]
|
for r in msg["ranges"]
|
||||||
if r["distance"] != 0xFFFF
|
if r["distance"] != 0xFFFF
|
||||||
},
|
},
|
||||||
None
|
permissions=None,
|
||||||
|
orig_addr=orig_addr,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def disconnect(self, code):
|
async def disconnect(self, code):
|
||||||
|
|
|
@ -77,7 +77,8 @@ class RangeLocator:
|
||||||
cls.cached = cls.load_nocache(update)
|
cls.cached = cls.load_nocache(update)
|
||||||
return cls.cached
|
return cls.cached
|
||||||
|
|
||||||
def locate(self, ranges: dict[str, int], permissions=None):
|
def locate(self, ranges: dict[str, int], permissions=None, orig_addr=None):
|
||||||
|
pprint(ranges)
|
||||||
# get the i and peer for every peer that we actually know
|
# get the i and peer for every peer that we actually know
|
||||||
relevant_ranges = tuple(
|
relevant_ranges = tuple(
|
||||||
(i, distance) for i, distance in (
|
(i, distance) for i, distance in (
|
||||||
|
@ -85,19 +86,25 @@ class RangeLocator:
|
||||||
) if i is not None
|
) if i is not None
|
||||||
)
|
)
|
||||||
|
|
||||||
|
relevant_positions = self.beacon_positions[tuple(i for i, _ in relevant_ranges), :]
|
||||||
|
mean = np.mean(relevant_positions, axis=0)
|
||||||
|
relevant_positions = relevant_positions
|
||||||
|
|
||||||
# create 2d array with x, y, z, distance as rows
|
# create 2d array with x, y, z, distance as rows
|
||||||
np_ranges = np.hstack((
|
np_ranges = np.hstack((
|
||||||
self.beacon_positions[tuple(i for i, distance in relevant_ranges), :],
|
relevant_positions,
|
||||||
np.array(tuple(distance for i, distance in relevant_ranges)).reshape((-1, 1)),
|
np.array(tuple(distance for i, distance in relevant_ranges)).reshape((-1, 1)),
|
||||||
))
|
))
|
||||||
|
|
||||||
|
print(np_ranges)
|
||||||
|
|
||||||
if np_ranges.shape[0] < 3:
|
if np_ranges.shape[0] < 3:
|
||||||
# can't get a good result from just two beacons
|
# can't get a good result from just two beacons
|
||||||
# todo: maybe we can at least give… something?
|
# todo: maybe we can at least give… something?
|
||||||
print('less than 3 ranges, can\'t do ranging')
|
print('less than 3 ranges, can\'t do ranging')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if np_ranges.shape[0] == 3:
|
if np_ranges.shape[0] == 3 and 0:
|
||||||
print('2D trilateration')
|
print('2D trilateration')
|
||||||
dimensions = 2
|
dimensions = 2
|
||||||
else:
|
else:
|
||||||
|
@ -105,38 +112,95 @@ class RangeLocator:
|
||||||
dimensions = 3
|
dimensions = 3
|
||||||
|
|
||||||
measured_ranges = np_ranges[:, 3]
|
measured_ranges = np_ranges[:, 3]
|
||||||
|
print('a', measured_ranges)
|
||||||
|
#measured_ranges[measured_ranges<1] = 1
|
||||||
|
print('b', measured_ranges)
|
||||||
|
|
||||||
# rating the guess by calculating the distances
|
# rating the guess by calculating the distances
|
||||||
|
def diff_func(guess):
|
||||||
|
result = scipy.linalg.norm(np_ranges[:, :dimensions] - guess[:dimensions], axis=1) - measured_ranges
|
||||||
|
#print(result)
|
||||||
|
return result
|
||||||
|
# factors = scipy.linalg.norm(np_ranges[:, :dimensions] - guess[:dimensions], axis=1) / measured_ranges
|
||||||
|
# return factors - np.mean(factors)
|
||||||
|
|
||||||
def cost_func(guess):
|
def cost_func(guess):
|
||||||
factors = scipy.linalg.norm(np_ranges[:, :dimensions] - guess[:dimensions], axis=1) / measured_ranges
|
result = np.abs(diff_func(guess))
|
||||||
return factors - np.mean(factors)
|
result[result<300] = result[result<300]/3+200
|
||||||
|
return result
|
||||||
|
|
||||||
# initial guess i the average of all beacons, with scale 1
|
# initial guess i the average of all beacons, with scale 1
|
||||||
initial_guess = np.average(np_ranges[:, :dimensions], axis=0)
|
initial_guess = np.average(np_ranges[:, :dimensions], axis=0)
|
||||||
|
|
||||||
# here the magic happens
|
# here the magic happens
|
||||||
results = least_squares(cost_func, initial_guess)
|
results = least_squares(
|
||||||
|
fun=cost_func,
|
||||||
|
#jac="3-point",
|
||||||
|
loss="linear",
|
||||||
|
bounds=(
|
||||||
|
np.min(self.beacon_positions[:, :dimensions], axis=0) - np.array([200, 200, 100])[:dimensions],
|
||||||
|
np.max(self.beacon_positions[:, :dimensions], axis=0) + np.array([200, 200, 100])[:dimensions],
|
||||||
|
),
|
||||||
|
x0=initial_guess,
|
||||||
|
)
|
||||||
|
|
||||||
# create result
|
# create result
|
||||||
# todo: figure out level
|
# todo: figure out level
|
||||||
|
result_pos = results.x
|
||||||
from c3nav.mapdata.models import Level
|
from c3nav.mapdata.models import Level
|
||||||
location = CustomLocation(
|
location = CustomLocation(
|
||||||
level=Level.objects.first(),
|
level=Level.objects.first(),
|
||||||
x=results.x[0]/100,
|
x=result_pos[0]/100,
|
||||||
y=results.x[1]/100,
|
y=result_pos[1]/100,
|
||||||
permissions=(),
|
permissions=(),
|
||||||
icon='my_location'
|
icon='my_location'
|
||||||
)#
|
)
|
||||||
location.z = results.x[2]
|
location.z = result_pos[2]/100
|
||||||
|
|
||||||
pprint(relevant_ranges)
|
pprint(relevant_ranges)
|
||||||
|
|
||||||
|
orig_xyz = None
|
||||||
|
print('orig_addr', orig_addr)
|
||||||
|
if orig_addr:
|
||||||
|
orig_xyz = self.get_xyz(orig_addr)
|
||||||
|
if orig_xyz:
|
||||||
|
orig_xyz = np.array(orig_xyz)
|
||||||
|
|
||||||
|
print()
|
||||||
|
print("result:", ", ".join(("%.2f" % i) for i in tuple(result_pos)))
|
||||||
|
if orig_xyz is not None:
|
||||||
|
print("correct:", ", ".join(("%.2f" % i) for i in tuple(orig_xyz)))
|
||||||
|
print("diff:", ", ".join(("%.2f" % i) for i in tuple(orig_xyz-result_pos)))
|
||||||
|
print()
|
||||||
print("measured ranges:", ", ".join(("%.2f" % i) for i in tuple(np_ranges[:, 3])))
|
print("measured ranges:", ", ".join(("%.2f" % i) for i in tuple(np_ranges[:, 3])))
|
||||||
print("result ranges:", ", ".join(
|
print("result ranges:", ", ".join(
|
||||||
("%.2f" % i) for i in tuple(scipy.linalg.norm(np_ranges[:, :dimensions] - results.x[:dimensions], axis=1))
|
("%.2f" % i) for i in tuple(scipy.linalg.norm(np_ranges[:, :dimensions] - result_pos[:dimensions], axis=1))
|
||||||
))
|
))
|
||||||
print("cost:", cost_func(results.x))
|
if orig_xyz is not None:
|
||||||
|
print("correct ranges:", ", ".join(
|
||||||
|
("%.2f" % i) for i in tuple(scipy.linalg.norm(np_ranges[:, :dimensions] - orig_xyz[:dimensions], axis=1))
|
||||||
|
))
|
||||||
|
print()
|
||||||
|
print("diff result-measured:", ", ".join(
|
||||||
|
("%.2f" % i) for i in
|
||||||
|
tuple(diff_func(result_pos))
|
||||||
|
))
|
||||||
|
if orig_xyz is not None:
|
||||||
|
print("diff correct-measured:", ", ".join(
|
||||||
|
("%.2f" % i) for i in
|
||||||
|
tuple(diff_func(orig_xyz))
|
||||||
|
))
|
||||||
|
|
||||||
|
def print_cost(title, pos):
|
||||||
|
cost = cost_func(pos)
|
||||||
|
print(title, ", ".join(
|
||||||
|
("%.2f" % i) for i in cost
|
||||||
|
), '=', np.sum(cost**2))
|
||||||
|
print_cost("cost:", result_pos)
|
||||||
|
if orig_xyz is not None:
|
||||||
|
print_cost("cost of correct position:", orig_xyz)
|
||||||
if dimensions > 2:
|
if dimensions > 2:
|
||||||
print("height:", results.x[2])
|
print("height:", result_pos[2])
|
||||||
# print("scale:", (factor or results.x[3]))
|
# print("scale:", (factor or results.x[3]))
|
||||||
|
|
||||||
return location
|
return location
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue