【问题标题】:Trilateration with limits?有限制的三边测量?
【发布时间】:2011-09-03 05:43:42
【问题描述】:

我需要帮助解决一个问题,我在做一个小型机器人实验时遇到了这个问题,基本思想是每个小型机器人都有能力估计距离,从它们自己到一个物体,但是我得到的近似值太粗略了,我希望计算出更准确的值。

So:
输入:顶点列表(v_1, v_2, ... v_n),顶点v_*(机器人)
输出:未知的坐标顶点v_*(对象)

每个顶点v_1v_n 的坐标都是众所周知的(通过调用顶点上的getX()getY() 提供),并且可以通过调用得到v_* 的近似范围; getApproximateDistance(v_*),函数getApproximateDistance()返回两个变量变量,即; minDistancemaxDistance。 - 实际距离在这两者之间。

所以我一直在尝试获取v_* 的坐标,是使用三边测量,但是我似乎无法找到一个公式来进行有限制(下限和上限)的三边测量,所以这真的是我在找什么(数学还不够好,自己弄明白)。

注意:三角测量是替代方法吗?
注意:我可能很想知道一种方法,性能/准确性权衡。

数据示例:

[Vertex . `getX()` . `getY()` . `minDistance` . `maxDistance`]
[`v_1`  .  2       .  2       .  0.5          .  1  ]
[`v_2`  .  1       .  2       .  0.3          .  1  ]
[`v_3`  .  1.5     .  1       .  0.3          .  0.5]

图片展示数据:http://img52.imageshack.us/img52/6414/unavngivetcb.png

很明显v_1 的近似值可能比[0.5; 1] 更好,因为上述数据创建的图形是一个环的小切口(受v_3 限制),但是我该如何计算呢,并可能在该图中找到近似值(该图可能是凹的)?

这会更适合 MathOverflow 吗?

【问题讨论】:

  • 前往 math.stackexchange.com - 他们会全力以赴!

标签: math distance triangulation approximation trilateration


【解决方案1】:

我会选择一种简单的离散方法。环的隐式公式很简单,如果多个环的数量很大,则可以使用基于扫描线的方法有效地计算多个环的交集。

为了通过快速计算获得高精度,一种选择可能是使用多分辨率方法(即首先以低分辨率开始,然后仅在接近有效点的高分辨率样本中重新计算。

我编写的一个小型 python 玩具可以在大约 0.5 秒内生成一个 400x400 像素的交叉区域图像(如果使用 C 完成这种计算,可以得到 100 倍的加速)。

# x, y, r0, r1
data = [(2.0, 2.0, 0.5, 1.0),
        (1.0, 2.0, 0.3, 1.0),
        (1.5, 1.0, 0.3, 0.5)]

x0 = max(x - r1 for x, y, r0, r1 in data)
y0 = max(y - r1 for x, y, r0, r1 in data)
x1 = min(x + r1 for x, y, r0, r1 in data)
y1 = min(y + r1 for x, y, r0, r1 in data)

def hit(x, y):
    for cx, cy, r0, r1 in data:
        if not (r0**2 <= ((x - cx)**2 + (y - cy)**2) <= r1**2):
            return False
    return True

res = 400
step = 16
white = chr(255)
grey = chr(192)
black = chr(0)
img = [black] * (res * res)

# Low-res pass
cells = {}
for i in xrange(0, res, step):
    y = y0 + i * (y1 - y0) / res
    for j in xrange(0, res, step):
        x = x0 + j * (x1 - x0) / res
        if hit(x, y):
            for h in xrange(-step*2, step*3, step):
                for v in xrange(-step*2, step*3, step):
                    cells[(i+v, j+h)] = True

# High-res pass
for i in xrange(0, res, step):
    for j in xrange(0, res, step):
        if cells.get((i, j), False):
            img[i * res + j] = grey
            img[(i + step - 1) * res + j] = grey
            img[(i + step - 1) * res + (j + step - 1)] = grey
            img[i * res + (j + step - 1)] = grey
            for v in xrange(step):
                y = y0 + (i + v) * (y1 - y0) / res
                for h in xrange(step):
                    x = x0 + (j + h) * (x1 - x0) / res
                    if hit(x, y):
                        img[(i + v)*res + (j + h)] = white

open("result.pgm", "wb").write(("P5\n%i %i 255\n" % (res, res)) +
                               "".join(img))

如果可用,另一个有趣的选项可能是使用 GPU。从一张白色图片开始,用黑色绘制,每个环的外部将在末端留下白色的交叉区域。

例如,使用 Python/Qt 进行此计算的代码很简单:

img = QImage(res, res, QImage.Format_RGB32)
dc = QPainter(img)
dc.fillRect(0, 0, res, res, QBrush(QColor(255, 255, 255)))
dc.setPen(Qt.NoPen)
dc.setBrush(QBrush(QColor(0, 0, 0)))
for x, y, r0, r1 in data:
    xa1 = (x - r1 - x0) * res / (x1 - x0)
    xb1 = (x + r1 - x0) * res / (x1 - x0)
    ya1 = (y - r1 - y0) * res / (y1 - y0)
    yb1 = (y + r1 - y0) * res / (y1 - y0)
    xa0 = (x - r0 - x0) * res / (x1 - x0)
    xb0 = (x + r0 - x0) * res / (x1 - x0)
    ya0 = (y - r0 - y0) * res / (y1 - y0)
    yb0 = (y + r0 - y0) * res / (y1 - y0)
    p = QPainterPath()
    p.addEllipse(QRectF(xa0, ya0, xb0-xa0, yb0-ya0))
    p.addEllipse(QRectF(xa1, ya1, xb1-xa1, yb1-ya1))
    p.addRect(QRectF(0, 0, res, res))
    dc.drawPath(p)

800x800 分辨率图像的计算部分大约需要 8 毫秒(我不确定它是硬件加速的)。

如果只计算交点的重心,则根本不需要内存分配。例如,“蛮力”方法只是几行 C

typedef struct TReading {
    double x, y, r0, r1;
} Reading;

int hit(double xx, double yy,
        Reading *readings, int num_readings)
{
    while (num_readings--)
    {
        double dx = xx - readings->x;
        double dy = yy - readings->y;
        double d2 = dx*dx + dy*dy;
        if (d2 < readings->r0 * readings->r0) return 0;
        if (d2 > readings->r1 * readings->r1) return 0;
        readings++;
    }
    return 1;
}

int computeLocation(Reading *readings, int num_readings,
                    int resolution,
                    double *result_x, double *result_y)
{
    // Compute bounding box of interesting zone
    double x0 = -1E20, y0 = -1E20, x1 = 1E20, y1 = 1E20;
    for (int i=0; i<num_readings; i++)
    {
        if (readings[i].x - readings[i].r1 > x0)
          x0 = readings[i].x - readings[i].r1;
        if (readings[i].y - readings[i].r1 > y0)
          y0 = readings[i].y - readings[i].r1;
        if (readings[i].x + readings[i].r1 < x1)
          x1 = readings[i].x + readings[i].r1;
        if (readings[i].y + readings[i].r1 < y1)
          y1 = readings[i].y + readings[i].r1;
    }

    // Scan processing
    double ax = 0, ay = 0;
    int total = 0;
    for (int i=0; i<=resolution; i++)
    {
        double yy = y0 + i * (y1 - y0) / resolution;
        for (int j=0; j<=resolution; j++)
        {
            double xx = x0 + j * (x1 - x0) / resolution;
            if (hit(xx, yy, readings, num_readings))
            {
                ax += xx; ay += yy; total += 1;
            }
        }
    }
    if (total)
    {
        *result_x = ax / total;
        *result_y = ay / total;
    }
    return total;
}

在我的 PC 上,可以用 resolution = 100 在 0.08 毫秒内(x=1.50000,y=1.383250)或 resolution = 400 在 1.3 毫秒内(x=1.500000,y=1.383308)计算重心。当然,即使是仅重心版本也可以实现双步加速。

【讨论】:

  • 即使将图片作为输出很可爱,我该如何修改它以输出坐标? - 如 io 分析中所述
  • 我的机器人也没有运行 gpu 硬件,很遗憾 ;)
  • 可能平均值(重心)是一个合理的选择(虽然理论上重心可能落在可接受的区域之外,但考虑到具体应用,我想说这不会发生。否则,一个好点可能是“最内部的点”(即距离排除区域最远的内部点);但是,该点计算起来有点烦人(IMO 最好的方法是使用欧几里得变换并选择绝对最大值 - 在结果的边界框区域内仍然是线性的,但算法并不简单)。
  • 我不太确定这就是我要找的东西,可能只是因为我似乎无法理解如何应用你的说法,或者我只是有点害怕不得不分配一个 huge 字符数组。
  • 我在 C 中添加了一个重心计算实现,它根本不需要内存分配(简单的蛮力)。为了计算“最内部的点”,我认为一个可行的解决方案需要分配一个矩阵,以便能够快速计算欧几里得距离变换。
【解决方案2】:

我会从“最大/最小”切换到尝试最小化错误函数。这会让您解决Finding a point that best fits the intersection of n spheres 中讨论的问题,这比与一系列复杂形状相交更容易处理。 (如果一个机器人的传感器出现故障并给出一个不可能的值怎么办?这种变化通常仍然会给出合理的答案。)

【讨论】:

  • 检查机器人传感器读数,三边测量中不会包含任何不可用的值。
【解决方案3】:

不确定您的情况,但在典型的机器人应用程序中,您将定期读取传感器并处理数据。如果是这种情况,您会尝试根据嘈杂的数据来估计位置,这是一个常见问题。作为一种简单(不太严格)的方法,您可以获取现有位置并将其调整为朝向或远离每个已知点。将测量到的目标距离减去当前到目标的距离,将该增量(误差)乘以 0 到 1 之间的某个值,然后将您的估计位置向目标移动那么远。对每个目标重复。然后在每次获得一组新测量值时重复。乘数将产生类似低通滤波器的效果,较小的值将为您提供更稳定的位置估计,但对运动的响应较慢。对于距离,使用最小值和最大值的平均值。如果您可以对一个目标的范围设置更严格的界限,则可以将乘数增加到接近 1 的目标。

这当然是一个粗略的位置估计。数学家伙可能更严格,但也更复杂。解决方案绝对与相交区域和几何形状无关。

【讨论】:

    猜你喜欢
    • 2012-04-28
    • 2012-04-02
    • 2013-10-25
    • 1970-01-01
    • 1970-01-01
    • 2016-03-07
    • 2022-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多