0

J'ai une matrice (en réalité une image chargée) dans laquelle chaque élément est à une distance L2 d'un point central inconnu.Trouver la matrice de distance donnée du point central

Voici un exemple trivial

A = [1.4142 1.0000 1.4142 2.2361] 
    [1.0000 0.0000 1.0000 2.0000] 
    [1.4142 1.0000 1.4142 2.2361] 

Dans ce cas, le centre de coordonnées est évidemment à (1,1) (indice A [1,1] dans une matrice indexée 0 ou un tableau 2D).

Cependant, dans le cas où mes centres ne sont pas contraints d'être des indices entiers, ce n'est plus aussi évident. Par exemple, étant donné cette matrice B, où est ma coordonnée de centre?

B = [3.0292 1.9612 2.8932 5.8252] 
    [1.2292 0.1612 1.0932 4.0252] 
    [1.4292 0.3612 1.2932 4.2252] 

Comment vous trouvez que la réponse est dans ce cas à la ligne et de la colonne 1,034 1.4?

Je connais la solution trilateration (ayant provided MATLAB code to visualize that in 3D previously), mais existe-t-il un moyen plus efficace (par exemple un système sans inversion de matrice)?

Cette question est un peu agnostique, car je cherche plus d'aide algorithmique. Si vous pouviez vous en tenir à MATLAB, Python ou C++ dans une solution, ce serait génial ;-).

+1

Les valeurs de A ou B sont-elles des valeurs exactes ou sont-elles bruitées? –

+0

ils peuvent être traités comme assez exact – marcman

+1

Je demande parce que - comme sascha également mentionné - B semble être «faux». Bien que A est évidemment correct, B pour votre point central donné devrait être quelque chose comme [[1,74044707 1,10867308 1,19547313 1,90503438] [1,4004128 0,4014424 0,60096256 1,60036121] [1,70092798 1,04554101 1,13717017 1,86899866]] –

Répondre

1

Tout en n'ayant aucune expérience avec des tâches similaires, j'ai lu quelques trucs et aussi essayé quelque chose.

Lorsque vous ne connaissez pas ce sujet, il est difficile à saisir et toutes les ressources que j'ai trouvées sont un peu chaotiques.

encore peu claire en ce qui concerne la théorie pour moi:

  • est le problème comme indiqué ci-dessus un problème d'optimisation convexe; (-minimum local =-minimum global signifierait l'accès aux solveurs puissants!)
    • il y a beaucoup plus de ressources sur les problèmes plus génériques (réseau de capteurs Localisation), qui sont non-convexe et où des méthodes extrêmement complexes ont été développés
  • est votre approche de trilatération capable d'exploiter> 3 points (trilatération vs multilatération; au moins ce code ne semble pas comme il peut ce qui signifie: mauvaise performance avec le bruit)

Voici quelques exemples de code avec deux approches:

  • A: Convex-optimisation: SOCP -relaxation
  • B: optimisation Nonlinear programmation
    • Mis en œuvre en utilisant scipy.optimize
    • Quasiment parfait dans mes expériences synthétiques; même de bons résultats dans un cas bruyant; malgré le fait que nous utilisons la différenciation numérique (disque automatique diff à utiliser ici)

une remarque supplémentaire:

  • Votre exemple B a sûrement quelques-uns (très mauvais) bruit ou un autre problème à mon avis, car mes approches sont complètement éteintes; tout particulièrement l'approche B brille pour mes-données synthétiques (au moins c'est mon impression)

code:

import numpy as np 
import cvxpy as cvx 
from scipy.spatial.distance import cdist 
from scipy.optimize import minimize 
np.random.seed(1) 

""" Create noise-free (not anymore!) fake-problem """ 
real_x = np.random.random(size=2) * 3 

M, N = 5, 10 
NOISE_DISTS = 0.1 
pos = np.array([(i,j) for i in range(M) for j in range(N)]) # ugly -> tile/repeat/stack 
real_x_stacked = np.vstack([real_x for i in range(pos.shape[0])]) 
Y = cdist(pos, real_x[np.newaxis]) 
Y += np.random.normal(size=Y.shape)*NOISE_DISTS # Let's add some noise! 
print('-----') 
print('PROBLEM') 
print('-------') 
print('real x: ', real_x) 
print('dist mat: ', np.round(Y,3).T) 

""" Helper """ 
def cost(x, Y, pos): 
    res = np.linalg.norm(pos - x, ord=2, axis=1) - Y.ravel() 
    return np.linalg.norm(res, 2) 

print('cost with real_x (check vs. noisy): ', cost(real_x, Y, pos)) 

""" SOLVER SOCP """ 
def solve_socp_relax(pos, Y): 
    x = cvx.Variable(2) 
    y = cvx.Variable(pos.shape[0]) 
    fake_stack = [x for i in range(pos.shape[0])]      # hacky 

    objective = cvx.sum_entries(cvx.norm(y - Y)) 
    x_stacked = cvx.reshape(cvx.vstack(*fake_stack), pos.shape[0], 2) # hacky 
    constraints = [cvx.norm(pos - x_stacked, 2, axis=1) <= y] 

    problem = cvx.Problem(cvx.Minimize(objective), constraints) 
    problem.solve(solver=cvx.ECOS, verbose=False) 
    return x.value.T 

""" SOLVER NLP """ 
def solve_nlp(pos, Y): 
    sol = minimize(cost, np.zeros(pos.shape[1]), args=(Y, pos), method='BFGS') 
    # print(sol) 
    return sol.x 

""" TEST """ 
print('-----') 
print('SOLVE') 
print('-----') 

socp_relax_sol = solve_socp_relax(pos, Y) 
print('SOCP RELAX SOL: ', socp_relax_sol) 

nlp_sol = solve_nlp(pos, Y) 
print('NLP SOL: ', nlp_sol) 

Sortie:

----- 
PROBLEM 
------- 
real x: [ 1.25106601 2.16097348] 
dist mat: [[ 2.444 1.599 1.348 1.276 2.399 3.026 4.07 4.973 6.118 6.746 
    2.143 1.149 0.412 0.766 1.839 2.762 3.851 4.904 5.734 6.958 
    2.377 1.432 0.856 1.056 1.973 2.843 3.885 4.95 5.818 6.84 
    2.711 2.015 1.689 1.939 2.426 3.358 4.385 5.22 6.076 6.97 
    3.422 3.153 2.759 2.81 3.326 4.162 4.734 5.627 6.484 7.336]] 
cost with real_x (check vs. noisy): 0.665125233772 
----- 
SOLVE 
----- 
SOCP RELAX SOL: [[ 1.95749275 2.00607253]] 
NLP SOL: [ 1.23560791 2.16756168] 

Edit: plus l'accélération peut être atteinte (surtout à grande échelle) en utilisant les moindres carrés non linéaires au lieu du mo re approche générale NLP! Mes résultats sont toujours les mêmes (comme prévu si le problème serait convexe). Les délais entre NLP/NLS peuvent ressembler à 9 vs 0.5 secondes!

Ceci est ma méthode recommandée!

def solve_nls(pos, Y): 
    def res(x, Y, pos): 
     return np.linalg.norm(pos - x, ord=2, axis=1) - Y.ravel() 
    sol = least_squares(res, np.zeros(pos.shape[1]), args=(Y, pos), method='lm') 
    # print(sol) 
    return sol.x 

Surtout exécutera également des instances beaucoup plus la deuxième approche (PNL) (les frais généraux de cvxpy fait mal, ce n'est pas un inconvénient du SOCP résolveur qui devrait évoluer beaucoup mieux!).

Voici quelques sortie pour M, N = 500, 1000 avec un peu plus de bruit:

----- 
PROBLEM 
------- 
real x: [ 12.51066014 21.6097348 ] 
dist mat: [[ 24.706 23.573 23.693 ..., 1090.29 1091.216 
1090.817]] 
cost with real_x (check vs. noisy): 353.354267797 
----- 
SOLVE 
----- 
NLP SOL: [ 12.51082419 21.60911561] 
used: 5.9552763315495625 # SECONDS 

Donc, dans mes expériences, il fonctionne, mais je ne donne aucune garantie globale de convergence ou reconstruction garanties (manque encore une théorie). Dans un premier temps, j'ai pensé à utiliser l'optimum global du problème relaxé-SOCP comme point initial dans le solveur NLP, mais je n'ai trouvé aucun exemple où cela soit nécessaire!

Quelques visuels juste pour-fun en utilisant:

M, N = 20, 30 
NOISE_DISTS = 0.2 
... 

import matplotlib.pyplot as plt 
plt.imshow(Y.reshape(M, N), cmap='viridis', interpolation='none') 
plt.colorbar() 
plt.scatter(nlp_sol[1], nlp_sol[0], color='red', s=20) 
plt.xlim((0, N)) 
plt.ylim((0, M)) 
plt.show() 

enter image description here

Et certains cas, super bruyant (belle performance!):

M, N = 50, 100 
NOISE_DISTS = 5 

----- 
PROBLEM 
------- 
real x: [ 12.51066014 21.6097348 ] 
dist mat: [[ 22.329 18.745 27.588 ..., 94.967 80.034 91.206]] 
cost with real_x (check vs. noisy): 354.527196716 
----- 
SOLVE 
----- 
NLP SOL: [ 12.44158986 21.50164637] 
used: 0.01050068340320306 

enter image description here

0

Si je comprends bien, vous avez une matrice A, où A [i, j] tient la distance de (i, j) à un point inconnu (y, x) . Vous pouvez trouver (y, x) comme ceci:

Place chaque élément de A, pour faire une matrice B disons. Nous voulons donc trouver (y, x) si

(y-i)*(y-i) + (x-j)*(x-j) = B[i,j] 

Soustraire chaque équation de l'équation et 0,0 réorganisant:

2*i*y + 2*j*x = B[0,0] + i*i + j*j - B[i,j] 

Ceci peut être résolu par moindres carrés linéaires. Notez que puisqu'il y a 2 inconnues, l'inversion de matix (mieux, la factorisation) impliquée sera sur une matrice 2x2 et donc pas de temps. Vous pourriez en effet, compte tenu uniquement des dimensions de A, élaborer la matrice requise et son inverse analytiquement.