Trilateration sử dụng 3 điểm vĩ độ / kinh độ và 3 khoảng cách?


34

Tôi muốn tìm ra một vị trí mục tiêu không xác định (tọa độ vĩ độ và kinh độ). Có 3 điểm đã biết (cặp phối hợp vĩ độ và kinh độ) và cho mỗi điểm một khoảng cách tính bằng km đến vị trí mục tiêu. Làm cách nào tôi có thể tính toán tọa độ của vị trí đích?

Ví dụ: giả sử tôi có các điểm dữ liệu sau

37.418436,-121.963477   0.265710701754km
37.417243,-121.961889   0.234592423446km
37.418692,-121.960194   0.0548954278262km

Điều tôi muốn là toán học cho một hàm lấy đó làm đầu vào và trả về 37.417959, -121.961954 làm đầu ra.

Tôi hiểu cách tính khoảng cách giữa hai điểm, từ http://www.movable-type.co.uk/scripts/latlong.html Tôi hiểu nguyên tắc chung là với ba vòng tròn như thế này, bạn có được chính xác một điểm trùng nhau. Điều tôi mơ hồ là toán học cần thiết để tính điểm đó với đầu vào này.


Đây là một trang hướng dẫn bạn qua toán học tìm trung tâm của ba tọa độ. Có lẽ nó có thể giúp một cách nào đó. < mathforum.org/l Library / drmath / view / 68373.html >
Jon Bringhurst

1
Điều này cần phải nằm trên hình cầu / hình cầu, hoặc một thuật toán phẳng có ổn không?
đánh dấu

1
Tôi không thể cho bạn câu trả lời, nhưng tôi nghĩ tôi có thể chỉ cho bạn đi đúng hướng. Ba tọa độ = ba điểm trung tâm. Ba khoảng cách = ba vòng tròn. Hai vòng tròn giao nhau, có thể có khả năng không có / một / hai giải pháp. Ba vòng tròn có thể không có / một / hoặc một khu vực là giải pháp của nó. Công thức thu được cho ba vòng tròn và giải nó bằng Hệ phương trình / Đại số.
CrazyEnigma

Trên thực tế, bạn thậm chí không cần hệ thống để giải quyết vấn đề này. Có một hoặc hai khả năng, nhưng vì bạn có một giá trị khoảng cách, bạn có thể tách câu trả lời đúng.
George Silva

1
+1 Đây là một câu hỏi hay. Lúc đầu, tôi nghĩ rằng một giải pháp có thể dễ dàng tìm thấy với google, nhưng dường như không. Có lẽ vấn đề có thể được nói chung hơn: cho N điểm với mỗi điểm không chỉ có khoảng cách mà còn có biên độ sai số, tìm hình elip độ tin cậy.
Kirk Kuykendall

Câu trả lời:


34

Sau khi tìm kiếm trên Wikipedia và cùng một câu hỏi / câu trả lời tại StackOverflow , tôi hình dung mình sẽ đâm vào nó và cố gắng lấp đầy những khoảng trống.

Trước hết, Không chắc chắn nơi bạn có đầu ra, nhưng dường như là sai. Tôi đã vẽ các điểm trong ArcMap, đệm chúng vào các khoảng cách được chỉ định, chạy giao nhau trên các bộ đệm và sau đó chụp đỉnh của giao lộ để có được các giải pháp. Đầu ra đề xuất của bạn là điểm màu xanh lá cây. Tôi đã tính giá trị trong hộp chú thích, khoảng 3 mét so với ArcMap đã đưa ra cho giải pháp xuất phát từ giao điểm.

văn bản thay thế

Toán học trên trang wikipedia không quá tệ, chỉ cần chuyển đổi tọa độ trắc địa của bạn sang ECEF cartesian, có thể tìm thấy ở đây . các thuật ngữ a / x + h có thể được thay thế bằng bán kính hình cầu tự động, nếu bạn không sử dụng ellipsoid.

Có lẽ dễ nhất chỉ cần cung cấp cho bạn một số mã tài liệu tốt (?), Vì vậy đây là trong python

import math
import numpy

#assuming elevation = 0
earthR = 6371
LatA = 37.418436
LonA = -121.963477
DistA = 0.265710701754
LatB = 37.417243
LonB = -121.961889
DistB = 0.234592423446
LatC = 37.418692
LonC = -121.960194
DistC = 0.0548954278262

#using authalic sphere
#if using an ellipsoid this step is slightly different
#Convert geodetic Lat/Long to ECEF xyz
#   1. Convert Lat/Long to radians
#   2. Convert Lat/Long(radians) to ECEF
xA = earthR *(math.cos(math.radians(LatA)) * math.cos(math.radians(LonA)))
yA = earthR *(math.cos(math.radians(LatA)) * math.sin(math.radians(LonA)))
zA = earthR *(math.sin(math.radians(LatA)))

xB = earthR *(math.cos(math.radians(LatB)) * math.cos(math.radians(LonB)))
yB = earthR *(math.cos(math.radians(LatB)) * math.sin(math.radians(LonB)))
zB = earthR *(math.sin(math.radians(LatB)))

xC = earthR *(math.cos(math.radians(LatC)) * math.cos(math.radians(LonC)))
yC = earthR *(math.cos(math.radians(LatC)) * math.sin(math.radians(LonC)))
zC = earthR *(math.sin(math.radians(LatC)))

P1 = numpy.array([xA, yA, zA])
P2 = numpy.array([xB, yB, zB])
P3 = numpy.array([xC, yC, zC])

#from wikipedia
#transform to get circle 1 at origin
#transform to get circle 2 on x axis
ex = (P2 - P1)/(numpy.linalg.norm(P2 - P1))
i = numpy.dot(ex, P3 - P1)
ey = (P3 - P1 - i*ex)/(numpy.linalg.norm(P3 - P1 - i*ex))
ez = numpy.cross(ex,ey)
d = numpy.linalg.norm(P2 - P1)
j = numpy.dot(ey, P3 - P1)

#from wikipedia
#plug and chug using above values
x = (pow(DistA,2) - pow(DistB,2) + pow(d,2))/(2*d)
y = ((pow(DistA,2) - pow(DistC,2) + pow(i,2) + pow(j,2))/(2*j)) - ((i/j)*x)

# only one case shown here
z = numpy.sqrt(pow(DistA,2) - pow(x,2) - pow(y,2))

#triPt is an array with ECEF x,y,z of trilateration point
triPt = P1 + x*ex + y*ey + z*ez

#convert back to lat/long from ECEF
#convert to degrees
lat = math.degrees(math.asin(triPt[2] / earthR))
lon = math.degrees(math.atan2(triPt[1],triPt[0]))

print lat, lon

1
Tôi sẽ đưa ra một câu trả lời tương tự, nhưng bây giờ không cần! Được upvote của tôi.
Wrass

numpy để giải cứu! Nó biên dịch khi 'triPt' được thay thế bằng 'triLatPt', nhưng nếu không thì trả về 37.4191023738 -121.960579208. Làm tốt lắm
WolfOdrade

Làm tốt lắm! Nếu tôi thay thế hệ tọa độ địa lý thành hệ tọa độ [Cartesian] cục bộ, điều này có còn hoạt động không?
zengr

đối với những người trong miền c ++..kết hợp với nhau một cách nhanh chóng thực sự pastebin.com/9Dur6RAP
raaj

2
Cảm ơn @wwnick! Tôi đã chuyển cái này sang JavaScript (dành cho Node nhưng có thể dễ dàng chuyển đổi để hoạt động trong trình duyệt). gist.github.com/dav-/bb7103008cdf9359887f
DC_

6

Tôi không chắc mình có ngây thơ không, nhưng, nếu bạn đệm từng điểm theo kích thước, và sau đó cắt cả ba vòng tròn sẽ giúp bạn có vị trí chính xác?

Bạn có thể tính toán giao lộ bằng các API không gian. Ví dụ:

  • GeoScript
  • Bộ cấu trúc liên kết Java
  • NET cấu trúc liên kết
  • GEOS

1
Chính xác, anh ấy quan tâm đến các công thức để có được điểm giao nhau đó.
Vinko Vrsalovic

Sử dụng API không gian, bạn có thể làm điều đó mà không cần sử dụng toán học thuần túy.
George Silva

1
@George bạn có thể đưa ra một ví dụ về API như vậy không?
nohat

Chỉnh sửa bài để phản ánh yêu cầu của nohat.
George Silva

+1, suy nghĩ bên tốt, ngay cả khi có lẽ không hiệu quả nhất về mặt tính toán!
đánh dấu

2

Các ghi chú sau sử dụng hình học phẳng (tức là bạn sẽ phải chiếu tọa độ của mình vào một hệ tọa độ cục bộ thích hợp).

Lý luận của tôi, với một ví dụ hoạt động trong Python, như sau:

Lấy 2 trong số các điểm dữ liệu (gọi chúng ab). Gọi điểm mục tiêu của chúng tôi x. Chúng tôi đã biết khoảng cách axbx. Chúng ta có thể tính khoảng cách abbằng định lý Pythagoras.

>>> import math
>>> a = (1, 4)
>>> b = (3, 6)
>>> dist_ax = 3
>>> dist_bx = 5.385
# Pythagoras's theorem
>>> dist_ab = math.sqrt(abs(a[0]-b[0])**2 + abs(a[1]-b[1])**2)
>>> dist_ab
2.8284271247461903

Bây giờ, bạn có thể tìm ra các góc của các đường này:

>>> angle_abx = math.acos((dist_bx * dist_bx + dist_ab * dist_ab - dist_ax * dist_ax)/(2 * dist_bx * dist_ab))
>>> math.degrees(angle_abx)
23.202973815040256
>>> angle_bax = math.acos((dist_ax * dist_ax + dist_ab * dist_ab - dist_bx * dist_bx)/(2 * dist_ax * dist_ab))
>>> math.degrees(angle_bax)
134.9915256259537
>>> angle_axb = math.acos((dist_ax * dist_ax + dist_bx * dist_bx - dist_ab * dist_ab)/(2 * dist_ax * dist_bx))
>>> math.degrees(angle_axb)
21.805500559006095

Thật không may, tôi không có nhiều thời gian để hoàn thành câu trả lời cho bạn, tuy nhiên, bây giờ bạn đã biết các góc, bạn có thể tính toán hai vị trí có thể cho x. Sau đó, bằng cách sử dụng điểm thứ ba c, bạn có thể tính toán vị trí nào là chính xác.


2

Điều này có thể làm việc. Nhanh chóng một lần nữa trong python, bạn có thể đặt cái này vào phần thân của hàm xN, yN = tọa độ của các điểm, r1 & r2 = giá trị bán kính

dX = x2 - x1
dY = y2 - y1

centroidDistance = math.sqrt(math.pow(e,2) + math.pow(dY,2)) #distance from centroids
distancePL = (math.pow(centroidDistance,2) + (math.pow(r1,2) - math.pow(r2,2))) / (2 * centroidDistance) #distance from point to a line splitting the two centroids

rx1 = x1 + (dX *k)/centroidDistance + (dY/centroidDistance) * math.sqrt(math.pow(r1,2) - math.pow(distancePL,2))
ry1 = y1 + (dY*k)/centroidDistance - (dX /centroidDistance) * math.sqrt(math.pow(r1,2) - math.pow(distancePL,2))

rx2 = x1 + (dX *k)/centroidDistance - (dY/centroidDistance) * math.sqrt(math.pow(r1,2) - math.pow(distancePL,2))
ry2 = y1 + (dY*k)/centroidDistance + (dX /centroidDistance) * math.sqrt(math.pow(r1,2) - math.pow(distancePL,2))

Giá trị rx & ry là các giá trị trả về (nên nằm trong một mảng) của hai điểm giao nhau trên một vòng tròn, nếu điều đó giúp làm rõ mọi thứ.

Làm điều này cho 2 vòng tròn đầu tiên, sau đó một lần nữa cho vòng đầu tiên và cuối cùng. Nếu một trong hai kết quả từ lần lặp đầu tiên so sánh với kết quả từ lần thứ hai (trong một số dung sai, có thể), thì bạn có điểm giao nhau. Đó không phải là một giải pháp tuyệt vời, đặc biệt là khi bạn bắt đầu thêm nhiều hơn điểm vào quy trình, nhưng là cách đơn giản nhất tôi có thể thấy mà không cần giải hệ phương trình.


'E' và 'k' trong mã của bạn là gì?
RebierDG

Tôi không nhớ :-) câu trả lời của wwnick sẽ giống với những điều bạn muốn thực hiện nếu bạn chỉ có ba vòng tròn.
WolfOdrade

1

Bạn có thể sử dụng API không gian từ postgis (các hàm St_Intersection, St_buffer). Như fmark nhận thấy, bạn cũng phải nhớ rằng Postgis sử dụng thuật toán phẳng, nhưng đối với các khu vực nhỏ, sử dụng phép chiếu xa không gây ra nhiều lỗi.


PostGIS có thể thực hiện các phép tính hình cầu bằng cách sử dụng GEOGRAPHYloại chứ không phải GEOMETRYloại.
đánh dấu

1

Làm điều đó bằng ngôn ngữ PHP:

// giả sử độ cao = 0
$ earthR = 6371; // trong km (= 3959 trong dặm)

$ LatA = 37.418436;
$ LonA = -121.963477;
$ DistA = 0,265710701754;

$ LatB = 37.417243;
$ LonB = -121,961889;
$ DistB = 0,234592423446;

$ LatC = 37.418692;
$ LonC = -121,960194;
$ DistC = 0,0548954278262;

/ *
#use hình cầu tự động
#if sử dụng ellipsoid, bước này hơi khác
# Chuyển đổi trắc địa Lat / Dài sang ECEF xyz
# 1. Chuyển đổi Lat / Long sang radian
# 2. Chuyển đổi Lat / Long (radian) sang ECEF
* /
$ xA = $ earthR * (cos (deg2rad ($ LatA)) * cos (deg2rad ($ LonA)));
$ yA = $ earthR * (cos (deg2rad ($ LatA)) * sin (deg2rad ($ LonA)));
$ zA = $ earthR * (sin (deg2rad ($ LatA)));

$ xB = $ earthR * (cos (deg2rad ($ LatB)) * cos (deg2rad ($ LonB)));
$ yB = $ earthR * (cos (deg2rad ($ LatB)) * sin (deg2rad ($ LonB)));
$ zB = $ earthR * (sin (deg2rad ($ LatB)));

$ xC = $ earthR * (cos (deg2rad ($ LatC)) * cos (deg2rad ($ LonC)));
$ yC = $ earthR * (cos (deg2rad ($ LatC)) * sin (deg2rad ($ LonC)));
$ zC = $ earthR * (sin (deg2rad ($ LatC)));

/ *
CÀI ĐẶT, DỰNG LÊN:
sudo lê cài đặt Math_Vector-0.7.0
lê cài đặt Math_Matrix-0.8.7
* /
// Bao gồm PEAR :: Math_Matrix
// /usr/share/php/Math/Matrix.php
// include_path = ".: / usr / local / php / pear /"
request_once 'Math / Matrix.php';
allow_once 'Math / Vector.php';
allow_once 'Math / Vector3.php';


$ P1vector = new Math_Vector3 (mảng ($ xA, $ yA, $ zA));
$ P2vector = new Math_Vector3 (mảng ($ xB, $ yB, $ zB));
$ P3vector = new Math_Vector3 (mảng ($ xC, $ yC, $ zC));

#from wikipedia: http://en.wikipedia.org/wiki/Trilateration
#transform để có được vòng tròn 1 tại điểm gốc
#transform để có được vòng tròn 2 trên trục x

// CALC EX
$ P2minusP1 = Math_VectorOp :: sub trích ($ P2vector, $ P1vector);
$ l = Math_Vector mới ($ P2minusP1);
$ P2minusP1_length = $ l-> length ();
$ Norm = new Math_Vector3 (mảng ($ P2minusP1_length, $ P2minusP1_length, $ P2minusP1_length));
$ d = $ định mức; // lưu calc D
$ ex = Math_VectorOp :: split ($ P2minusP1, $ Norm);
// echo "ex:". $ ex-> toString (). "\ n";
$ ex_x = floatval ($ ex -> _ tuple-> getData () [0]);
$ ex_y = floatval ($ ex -> _ tuple-> getData () [1]);
$ ex_z = floatval ($ ex -> _ tuple-> getData () [2]);
$ ex = new Math_Vector3 (mảng ($ ex_x, $ ex_y, $ ex_z));

// CALC tôi
$ P3minusP1 = Math_VectorOp :: sub trích ($ P3vector, $ P1vector);
$ P3minusP1_x = floatval ($ P3minusP1 -> _ tuple-> getData () [0]);
$ P3minusP1_y = floatval ($ P3minusP1 -> _ tuple-> getData () [1]);
$ P3minusP1_z = floatval ($ P3minusP1 -> _ tuple-> getData () [2]);
$ P3minusP1 = new Math_Vector3 (mảng ($ P3minusP1_x, $ P3minusP1_y, $ P3minusP1_z));
$ i = Math_VectorOp :: dotSản phẩm ($ ex, $ P3minusP1);
// tiếng vang "i = $ i \ n";

// CALC EY
$ iex = Math_VectorOp :: scale ($ i, $ ex);
// tiếng vang "iex =". $ iex-> toString (). "\ n";
$ P3P1iex = Math_VectorOp :: sub khu vực ($ P3minusP1, $ iex);
// tiếng vang "P3P1iex =". $ P3P1iex-> toString (). "\ n";
$ l = new Math_Vector ($ P3P1iex);
$ P3P1iex_length = $ l-> length ();
$ Norm = new Math_Vector3 (mảng ($ P3P1iex_length, $ P3P1iex_length, $ P3P1iex_length));
// echo "Norm:". $ Norm-> toString (). "\ n";
$ ey = Math_VectorOp :: split ($ P3P1iex, $ Norm);
// echo "ey =". $ ey-> toString (). "\ n";
$ ey_x = floatval ($ ey -> _ tuple-> getData () [0]);
$ ey_y = floatval ($ ey -> _ tuple-> getData () [1]);
$ ey_z = floatval ($ ey -> _ tuple-> getData () [2]);
$ ey = new Math_Vector3 (mảng ($ ey_x, $ ey_y, $ ey_z));

// KÍNH
$ ez = Math_VectorOp :: crossSản phẩm ($ ex, $ ey);
// tiếng vang "ez =". $ ez-> toString (). "\ n";

// CALC D
// làm điều đó trước
$ d = floatval ($ d -> _ tuple-> getData () [0]);
// tiếng vang "d = $ d \ n";

// CALC J
$ j = Math_VectorOp :: dotSản phẩm ($ ey, $ P3minusP1);
// tiếng vang "j = $ j \ n";

# từ wikipedia
#plug và chug sử dụng các giá trị trên
$ x = (pow ($ DistA, 2) - pow ($ DistB, 2) + pow ($ d, 2)) / (2 * $ d);
$ y = ((pow ($ DistA, 2) - pow ($ DistC, 2) + pow ($ i, 2) + pow ($ j, 2)) / (2 * $ j)) - (($ i / $ j) * $ x);

# chỉ một trường hợp hiển thị ở đây
$ z = sqrt (pow ($ DistA, 2) - pow ($ x, 2) - pow ($ y, 2));

// tiếng vang "x = $ x - y = $ y - z = $ z \ n";

#triPt là một mảng với ECEF x, y, z của điểm trilateration
$ xex = Math_VectorOp :: scale ($ x, $ ex);
$ yey = Math_VectorOp :: scale ($ y, $ eye);
$ zez = Math_VectorOp :: scale ($ z, $ ez);

// CALC $ triPt = $ P1vector + $ xex + $ yey + $ zez;
$ triPt = Math_VectorOp :: add ($ P1vector, $ xex);
$ triPt = Math_VectorOp :: add ($ triPt, $ yey);
$ triPt = Math_VectorOp :: add ($ triPt, $ zez);
// echo "triPt =". $ triPt-> toString (). "\ n";
$ triPt_x = floatval ($ triPt -> _ tuple-> getData () [0]);
$ triPt_y = floatval ($ triPt -> _ tuple-> getData () [1]);
$ triPt_z = floatval ($ triPt -> _ tuple-> getData () [2]);


#convert trở lại lat / long từ ECEF
# chuyển sang độ
$ lat = rad2deg (asin ($ triPt_z / $ earthR));
$ lon = rad2deg (atan2 ($ triPt_y, $ triPt_x));

tiếng vang $ lat. ','. $ lon;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.