GPS坐标的多点定位

时间:2011-11-29 21:39:55

标签: algorithm language-agnostic gps coordinates

我有N GPS坐标,N距离给我想要确定的未知位置。

我的第一种方法是仅使用三点和三边测量,完全如描述here。这种方法已经非常准确(最佳误差~5km),但我想改进这一点并增加鲁棒性。 因为给定距离开始时不是很准确,所以我考虑使用多个测量和多点定位。 然而,事实证明这种方法准确性不太准确(最佳误差~100km)虽然我提供超过3点/距离(最多6次测试),现在我问,如果有人知道我可以拥有什么做错了。

简而言之,我的多角化方法如下:

  1. 将所有坐标转换为ECEF
  2. 按照方程7中wikipedia
  3. 所述构建矩阵
  4. 使用SVD查找最小化程序
  5. 由于解决方案仅达到规模,我使用根寻找方法来确定归一化,以便转换回LLA的坐标导致高度为0(我的初始假设是所有坐标都在零高度)
  6. 转换回LLA
  7. LLA / ECEF转换经过双重检查并且正确无误。第2步和第3步我用欧氏坐标(和精确距离)检查并显示正确。我自己想出了第4步,我不知道这是否是一个很好的方法,所以欢迎提出建议。

    +++ UPDATE

    我在python中汇总了示例代码来说明问题 有一些基本的事实。三边测量接近400米,而 多点定位范围为10-130km。 由于篇幅,我把它放在ideone

4 个答案:

答案 0 :(得分:6)

最终,我自己弄清楚了 - 或者至少显着提高了准确性。

维基百科(Eq.7)中描述的方法显然不太适合这个应用程序,但在这种情况下它已经容易得多了。

考虑方程式6来自维基百科,我们可以简化它:R_0可以猜测为地球半径,因为ECEF坐标的原点位于地球的中心。因此,没有必要转移所有内容以使一个Point成为原点,我们可以使用所有N方程式。

在python中,P是一个ECEF坐标数组,dists到这些点的距离,一切都归结为

R = 6378137 # Earth radius in meters
A = []
for m in range(0,len(P)):
    x = P[m][0]
    y = P[m][1]
    z = P[m][2]
    Am = -2*x
    Bm = -2*y
    Cm = -2*z
    Dm = R*R + (pow(x,2)+pow(y,2)+pow(z,2)) - pow(dists[m],2)
    A += [[Am,Bm,Cm,Dm]]
# Solve using SVD
A = numpy.array(A)
(_,_,v) = numpy.linalg.svd(A)
# Get the minimizer
w = v[3,:]
w /= w[3] # Resulting position in ECEF

使用这种方法,我不再需要我所描述的 Step 4 。事实上,它甚至会使解决方案变得更糟。

现在,准确度范围在2km到275m之间 - 在大多数情况下比“最佳”三边测量更好,误差为464m。

答案 1 :(得分:2)

一些意见:

1)您已经针对确切答案检查了一些步骤。我建议您创建玩具问题,并在观察中添加已知量的随机噪声。由于您在这种情况下知道正确答案,因此您可以看到错误传播会发生什么。如果你的方法在这里工作得很好但对真实数据很糟糕,你可能想要考虑现实生活中的可怕行为,例如一个或几个距离严重错误。

2)我不知道为什么你的解决方案只是按比例扩展,因为基础数据被正确缩放 - 如果我去那里用绳索剪切长度并将它们绑定到固定点,那么就没有歧义。当您使用SVD求解方程式(7)时,您是否正在执行类似www.cse.unr.edu/~bebis/MathMethods/SVD/lecture.pdf的操作以获得最小二乘解?这应该给你x,y和z没有歧义。

3)我完全不确定观察错误是如何起作用的(7)。一方面,我不喜欢所有的分歧。对于未知位置给定x,y,z的测量距离和计算距离之间的差异的平方和,可能值得写下方程式,然后将其最小化为x,y,z。维基百科的文章由于其成本而放弃了这种方法,但它可能会给你一个更准确的答案,即使你不能在实践中使用这种方法,计算和比较这个答案也可能会告诉你一些事情。

答案 2 :(得分:0)

我按照上面显示的@ zerm代码运行得相当好(黄色是从3个塔点计算的)。结果显示在Folium片段中。 Multilateration using linalg.SVD

然而,当我使用@mcdowella建议(#2)使用MxN系统解决方案的最小二乘法进行的相同算法时,结果要好得多。 Multilateration using Least Squares MxN

以下是修订后的代码:

A = []
b = []
for m in range(0,len(P)):
    x = P[m][0]
    y = P[m][1]
    z = P[m][2]
    Am = 2*x
    Bm = 2*y
    Cm = 2*z
    Dm = R*R + (pow(x,2)+pow(y,2)+pow(z,2)) - pow(dists[m],2)
    A += [[Am,Bm,Cm]]
    b += [[Dm]]
# Solve using Least Squares of an MxN System
# A*x = b --> x = (ATA)_inv.AT.b = A+.b
A = np.array(A)
b = np.array(b)
AT = A.T
ATA = np.matmul(AT,A)
ATA_inv = np.linalg.inv(ATA)
Aplus = np.matmul(ATA_inv,AT)
x = np.matmul(Aplus,b)
# convert back to lat/long from ECEF
# convert to degrees
lat = math.degrees(math.asin(x[2] / R))
lon = math.degrees(math.atan2(x[1],x[0]))

我还在探索其他多重定位方法,但是这篇文章真的让我理解了N点MLAT的基础知识。谢谢!

答案 3 :(得分:0)

为了改善the accepted answer,改善SVD解决方案的一种方法是根据纬度考虑地球半径的变化;这特别影响海拔估计,但它对纬度和经度也有一些连锁反应。 “简单”的解决方案是使用R的平均值,根据维基百科的平均值为6371008.8米,而不是6378137米。

更准确的估算是调整纬度的R

def EarthRadiusAtLatitude(lat):
    rlat = np.deg2rad(lat)

    a = np.float64(6378137.0)
    b = np.float64(6356752.3)

    rad = np.sqrt(((a*a*np.cos(rlat))**2 + (b*b*np.sin(rlat))**2) /
                  ((a*np.cos(rlat))**2 + (b*np.sin(rlat))**2))
    return rad

然后根据其中一个初始点的纬度设置R。或者,如果您的纬度变化很大,您可以根据估算值R来计算SVD,并使用初步解决方案的纬度来使用更近的R估算来解决。

在进行此调整之后,在我使用构建的示例和基于LTE eNodeB时序提前值的“真实世界”数据的实验中,SVD解决方案通常在纬度和经度的一秒之内,除了在一些退化情况下,这是相当的与基于迭代优化的解决方案相当(即最小化距离残差)。