首页 > 解决方案 > 如何检查向量何时在python中转了一圈

问题描述

我实际上正在研究表示二维空间中(大致)嘈杂圆圈的数据。我一次采集一个数据,目标是知道这些点何时形成一个圆圈。

为此,我将每个连续的点视为只有一个变位的向量。并且要知道何时转了一圈(即形成圆时),我检查 x 和 y 坐标何时都改变了符号两次(意味着矢量转了 2*0.5 圈 = 1 圈)。然后我再等半圈来补偿启动错误。事实上,根据它在最初四分之一空间的开始位置,它可能没有转一圈。

我不需要非常精确。所以这对我来说很好,但我想知道是否有另一种更有效的方法,它可以告诉真实的转数。这可以加快一点过程,因为积分到达缓慢退出(避免我再等待一个无用的半转)

重要的一点是我只能使用 Numpy。

编辑:更精确,每个点之间的距离不规则。起初,圆圈开始缓慢形成,然后加速。因此,开始时点比结束时更密集。另一件事是(0,0)点甚至可能不包含在圆中。最后,我说的大致是圆形的,因为它往往是椭圆形的,但形状不坏,只是嘈杂。

抱歉,我无法提供数据,至少目前是这样。我会告诉你这周是否可行。

标签: python-3.xcomputational-geometry

解决方案


您可以监控每个点到第一个点的距离,当这个距离达到最小值时,意味着圆已经闭合。下图显示了到圆上第一个点的点距离图:

距离

这是算法的相关代码:

distances = []
points = [next_point()]
while True:  # break below
    points.append(next_point())
    distances.append(np.linalg.norm(points[-1] - points[0]))
    if len(distances) >= 3:
        left = distances[-2] - distances[-3]
        right = distances[-1] - distances[-2]
        if left < 0 and right > 0:  # minimum detected
            break
del points[-1], distances[-1]  # optionally delete the last point in order to leave the circle open

在改变角度差和半径的数据集上进行测试,得到以下结果:

例子

这是完整的示例代码:

from math import pi
import random

import matplotlib.pyplot as plt
import numpy as np


def generate():
    angle = pi/4
    angle_upper_lim = 0.002
    while True:
        angle += 2*pi * random.uniform(0.001, angle_upper_lim)
        # radius = random.uniform(0.95, 1.05)
        radius = 1
        yield np.array([3 + radius*np.cos(angle), 5 + radius*np.sin(angle)])
        angle_upper_lim *= 1.03  # make the circle fill faster


generator = generate()


def next_point(n=1):
    """n: number of points per group"""
    return sum(next(generator) for __ in range(n)) / n


distances = []
points = [next_point()]
while True:  # break below
    points.append(next_point())
    distances.append(np.linalg.norm(points[-1] - points[0]))
    if len(distances) >= 3:
        left = distances[-2] - distances[-3]
        right = distances[-1] - distances[-2]
        if left < 0 and right > 0:  # minimum detected
            break
del points[-1], distances[-1]  # optionally delete the last point in order to leave the circle open

fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10.8, 4.8))
plt.subplots_adjust(wspace=0.11)
ax1.set_title('Data points')
ax1.scatter(*np.stack(points, axis=1), s=5, c=np.arange(len(points)))
ax1.plot(*points[ 0], 's', ms=8, label='First point', color='#2ca02c')
ax1.plot(*points[-1], '*', ms=12, label='Last point', color='#ff7f0e')
ax1.legend(loc='center')

ax2.set(title='Distance of circle points to first point', xlabel='Point #', ylabel='Distance')
ax2.yaxis.tick_right()
ax2.yaxis.set_label_position('right')
ax2.plot(distances, '-o', ms=4)
ax2.plot(len(distances)-1, distances[-1], '*', ms=10, label='circle closed')
ax2.legend()

plt.show()

可变半径

如果数据点的半径也发生变化,重要的是选择一个足够大的窗口,它将对连续数据点进行分组和平均,以提高稳定性。该功能next_point可以通过使用n=5例如进行调整。通过取消注释上述代码中的半径变化并使用窗口大小获得以下结果n=5

变化半径示例


推荐阅读