给定三个接收器的位置以及接收器接收信号的时间到达时间延迟,如何定位信号?

问题描述

我有3个接收器(A,B和C),以及一些位置未知的信号产生源(比如声音或光)。给定A,B和C的位置,以及每个接收器“听到”信号的时间,我想确定信号源的方向。

我知道可以使用TDoA多边测量/三边测量来进行此操作,但是我在实现计算时遇到了麻烦。对于那些刚接触该主题的人,这里没有很多清晰,详细的信息。对于我来说,那里含糊不清,更加理论化或太深奥了。

关于SO的一些类似帖子(但不完全是我所追求的): TDOA multilateration to locate a sound source Trilateration of a signal using Time Difference(TDOA)

这也很有趣,但是假设我们有一些界限: Multiliteration implementation with inaccurate distance data

@Dave也评论了一种出色且相当容易获得的资源https://sites.tufts.edu/eeseniordesignhandbook/files/2017/05/FireBrick_OKeefe_F1.pdf,但它的深度不足以至于人们可能可以在代码中实际实现这一点(至少对于不具备回归知识的人而言) ,找到所得双曲线的交集,等等。

[EDIT]:我要补充一点,我可以假设3个传感器位于地球表面,并且地球曲率的影响可以忽略不计(即我们可以二维地工作。

解决方法

有趣的问题。我懒得导出代数解的方程。相反,为什么不拟合结果呢?

因此,可以使用任何能够找到局部解的拟合方法(使用某些误差值的优化/最小化)简单地拟合2D(或更高)位置。当我使用我的简单approximation search来适应位置时,结果看起来还不错。

算法是:

  1. 迭代您范围内的“所有”职位

    不是所有的试探法都能大大减少问题。

  2. 在每个测试位置上计算要测量的增量时间

    从测试位置到接收站的简单旅行时间。

  3. 归一化所有增量时间,以便从零开始

    因此从所有收款时间中减去最短的到达时间。实际测量时间也是如此。这样可以确保时间不涉及相对偏移。

  4. 计算实际测量时间与计算时间之间的差值

    简单的腹肌差异就足够了。将此值用作拟合参数(优化)。

这是一个小C ++示例,使用上面链接中的我的近似类来做到这一点:

//---------------------------------------------------------------------------
// TDoA Time Difference of Arrival
//---------------------------------------------------------------------------
const int n=3;
double recv[n][3];  // (x,y) [m] receiver position,[s] time of arrival of signal
double pos0[2];     // (x,y) [m] object's real position
double pos [2];     // (x,y) [m] object's estimated position
double v=340.0;     // [m/s] speed of signal
double err=0.0;     // [m] error between real and estimated position
//---------------------------------------------------------------------------
void compute()
    {
    int i;
    double x,y,a,da,t0;
    //---------------------------------------------------------
    // init positions
    da=2.0*M_PI/(n);
    for (a=0.0,i=0;i<n;i++,a+=da)
        {
        recv[i][0]=256.0+(220.0*cos(a));
        recv[i][1]=256.0+(220.0*sin(a));
        }
    pos0[0]=300.0;
    pos0[1]=220.0;
    // simulate measurement
    t0=123.5;                   // some start time
    for (i=0;i<n;i++)
        {
        x=recv[i][0]-pos0[0];
        y=recv[i][1]-pos0[1];
        a=sqrt((x*x)+(y*y));    // distance to receiver
        recv[i][2]=t0+(a/v);    // start time + time of travel
        }
    //---------------------------------------------------------
    // normalize times into deltas from zero
    a=recv[0][2]; for (i=1;i<n;i++) if (a>recv[i][2]) a=recv[i][2];
    for (i=0;i<n;i++) recv[i][2]-=a;
    // fit position
    int N=6;
    approx ax,ay;
    double e,dt[n];
              // min,max,step,recursions,&error
    for (ax.init( 0.0,512.0,32.0,N,&e);!ax.done;ax.step())
     for (ay.init(  0.0,&e);!ay.done;ay.step())
        {
        // simulate measurement -> dt[]
        for (i=0;i<n;i++)
            {
            x=recv[i][0]-ax.a;
            y=recv[i][1]-ay.a;
            a=sqrt((x*x)+(y*y));    // distance to receiver
            dt[i]=a/v;              // time of travel
            }
        // normalize times dt[] into deltas from zero
        a=dt[0]; for (i=1;i<n;i++) if (a>dt[i]) a=dt[i];
        for (i=0;i<n;i++) dt[i]-=a;
        // error
        e=0.0; for (i=0;i<n;i++) e+=fabs(recv[i][2]-dt[i]);
        }
    pos[0]=ax.aa;
    pos[1]=ay.aa;
    //---------------------------------------------------------
    // compute error
    x=pos[0]-pos0[0];
    y=pos[1]-pos0[1];
    err=sqrt((x*x)+(y*y));  // [m]
    }
//---------------------------------------------------------------------------

这里预览:

preview

蓝点是接收器,红点是对象的真实位置,黄叉是其估计位置。该区域为512x512 m,我适合初始步骤32 m6递归,导致错误~0.005 m

我对结果感到非常满意...您可以更改接收方n的数量,而无需真正更改源或算法。我开始将接收器位置均匀分布在圆上,但这些位置可能是其他任何位置(并非全部都在粗略的单行上)

,

最简单(但不是最快)的方法是使用gradient descent求解方程。

我假设我们知道

  • 接收器A,B和C的位置不在同一行;
  • 未知源X到A,B和C的伪距。

直观地,我们模拟一个具有三个ideal springs的物理系统,其中每个弹簧的平衡长度是相应的伪距。

  A
  |
  X
 / \
B   C

当距离太小时弹簧会推动,而当距离太大时弹簧会拉。 X的大约静止位置应该是一个合理的估计值(尽管您可能需要根据应用程序进行其他验证)。

以下是一些使用复数作为2D向量的示例Python代码,应该易于音译。

import random


def distance(p,q):
    return abs(p - q)


# Force exerted by an ideal spring between variable y and fixed q of equilibrium
# length dxq.
def force(y,q,dxq):
    dyq = distance(y,q)
    return (dxq - dyq) * (y - q) / dyq


# Trilateration via gradient descent.
def trilaterate(
    a,dxa,b,dxb,c,dxc,*,max_iterations=1000000,gamma=0.001,precision=1e-12
):
    # Use the centroid of the receivers as the initial estimate.
    y = (a + b + c) / 3
    for i in range(max_iterations):
        f = force(y,dxa) + force(y,dxb) + force(y,dxc)
        y += gamma * f
        if abs(f) <= precision:
            return y
    return None


def random_point():
    return complex(random.random(),random.random())


def test_error():
    a = random_point()
    b = random_point()
    c = random_point()
    x = random_point()
    y = trilaterate(a,distance(x,a),b),c))
    return distance(x,y)


if __name__ == "__main__":
    print(test_error())

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...