python-3.x - 如何检查向量何时在python中转了一圈
问题描述
我实际上正在研究表示二维空间中(大致)嘈杂圆圈的数据。我一次采集一个数据,目标是知道这些点何时形成一个圆圈。
为此,我将每个连续的点视为只有一个变位的向量。并且要知道何时转了一圈(即形成圆时),我检查 x 和 y 坐标何时都改变了符号两次(意味着矢量转了 2*0.5 圈 = 1 圈)。然后我再等半圈来补偿启动错误。事实上,根据它在最初四分之一空间的开始位置,它可能没有转一圈。
我不需要非常精确。所以这对我来说很好,但我想知道是否有另一种更有效的方法,它可以告诉真实的转数。这可以加快一点过程,因为积分到达缓慢退出(避免我再等待一个无用的半转)
重要的一点是我只能使用 Numpy。
编辑:更精确,每个点之间的距离不规则。起初,圆圈开始缓慢形成,然后加速。因此,开始时点比结束时更密集。另一件事是(0,0)点甚至可能不包含在圆中。最后,我说的大致是圆形的,因为它往往是椭圆形的,但形状不坏,只是嘈杂。
抱歉,我无法提供数据,至少目前是这样。我会告诉你这周是否可行。
解决方案
您可以监控每个点到第一个点的距离,当这个距离达到最小值时,意味着圆已经闭合。下图显示了到圆上第一个点的点距离图:
这是算法的相关代码:
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
:
推荐阅读
- android - java.lang.Error:信号 11 (SIGSEGV),代码 1 (SEGV_MAPERR) Android 应用
- python - 为什么不能在同一代码中使用函数“pack”和“grid”
- reactjs - 如何为 BrowserRouter 和 Phoenix 项目使用通配符
- c# - 我想在 Unity 中重置关卡,也不要重置变量
- assembly - x86 指令,定义值
- java - Java中字符串列表的最大值
- c++ - 如何从 C++ 中的函数返回 std::string
- libgit2 - LibGit2 初始化的内存问题
- docker - 运行 docker traefik v2.0 以使用自签名证书的问题
- amp-html - 如果 AMP 位于 AMP-LIST 和 mustache 模板内,则 AMP 不会以 base64 格式显示图像