更快的 numpy 笛卡尔到球坐标转换?
我有来自 3 轴加速度计 (XYZ) 的 300 万个数据点数组,我想向包含等效球面坐标 (r、theta、phi) 的数组添加 3 列。下面的代码可以工作,但看起来太慢了。我怎样才能做得更好?
import numpy as np
import math as m
def cart2sph(x,y,z):
XsqPlusYsq = x**2 + y**2
r = m.sqrt(XsqPlusYsq + z**2) # r
elev = m.atan2(z,m.sqrt(XsqPlusYsq)) # theta
az = m.atan2(y,x) # phi
return r, elev, az
def cart2sphA(pts):
return np.array([cart2sph(x,y,z) for x,y,z in pts])
def appendSpherical(xyz):
np.hstack((xyz, cart2sphA(xyz)))
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
这类似于 Justin Peel 的答案,但仅使用 numpy 并利用其内置矢量化:
请注意,正如评论中所建议的,我已经从原始函数中更改了仰角的定义 。在我的机器上,使用 pts = np.random.rand(3000000, 3) 进行测试,时间从 76 秒缩短到 3.3 秒。我没有 Cython,所以我无法将时间与该解决方案进行比较。
This is similar to Justin Peel's answer, but using just
numpy
and taking advantage of its built-in vectorization:Note that, as suggested in the comments, I've changed the definition of elevation angle from your original function. On my machine, testing with
pts = np.random.rand(3000000, 3)
, the time went from 76 seconds to 3.3 seconds. I don't have Cython so I wasn't able to compare the timing with that solution.以下是我为此编写的快速 Cython 代码:
我使用 3,000,000 个点将时间从 62.4 秒缩短到 1.22 秒。那还不算太寒酸。我确信还可以进行一些其他改进。
Here's a quick Cython code that I wrote up for this:
It took the time down from 62.4 seconds to 1.22 seconds using 3,000,000 points for me. That's not too shabby. I'm sure there are some other improvements that can be made.
!上面的所有代码中仍然存在错误..这是 Google 的顶级结果..
总而言之:
我已经用 VPython 对此进行了测试,使用 atan2 表示 theta (elev) 是错误的,请使用
阿科斯!对于 phi (azim) 来说这是正确的。
我推荐 sympy1.0 acos 函数(它甚至不会抱怨 acos(z/r) 和 r = 0 )。
http://mathworld.wolfram.com/SphericalCooperatives.html
如果我们将其转换为物理系统(r, theta, phi) = (r, elev, azimuth) 我们有:
右手物理系统的未优化但正确代码:
您可以使用以下函数自行测试:
一些其他测试一些象限的数据:
我还使用 VPython 来轻松可视化向量:
! There is an error still in all the code above.. and this is a top Google result..
TLDR:
I have tested this with VPython, using atan2 for theta (elev) is wrong, use
acos! It is correct for phi (azim).
I recommend the sympy1.0 acos function (it does not even complain about acos(z/r) with r = 0 ) .
http://mathworld.wolfram.com/SphericalCoordinates.html
If we convert that to the physics system (r, theta, phi) = (r, elev, azimuth) we have:
Non optimized but correct code for right-handed physics system:
you can test it yourself with a function like:
some other test data for some quadrants:
I used VPython additionally to easily visualize vectors:
为了完成前面的答案,这里有一个 Numexpr 实现(可能会回退到 Numpy),
对于大型数组大小,与纯 Numpy 实现相比,这允许速度提高 2 倍,并且与 C 或 Cython 速度相当。当前的 numpy 解决方案(与 ceval=eval 参数一起使用时)也比 appendSpherical_np 函数快 25%。 com/a/4116899/1791279">@mtrw 回答大数组大小,
尽管对于较小的数组,
appendSpherical_np
实际上更快,To complete the previous answers, here is a Numexpr implementation (with a possible fallback to Numpy),
For large array sizes, this allows a factor of 2 speed up compared to pure a Numpy implementation, and would be comparable to C or Cython speeds. The present numpy solution (when used with the
ceval=eval
argument) is also 25% faster than theappendSpherical_np
function in the @mtrw answer for large array sizes,although for smaller sizes,
appendSpherical_np
is actually faster,Octave 有一些内置的坐标转换功能,可以使用 oct2py 包访问这些功能,以将笛卡尔坐标中的 numpy 数组转换为球面或极坐标(以及反之):
Octave has some built-in functionality for coordinate transformations that can be accessed with the package oct2py to convert numpy arrays in Cartesian coordinates to spherical or polar coordinates (and back):
我的代码基于 mrtw 的答案 - 我添加了轴支持、反向函数并将其基于三元组形状:
I base my code on mrtw's answer - I added axis support, the reverse function and base it off a 3-tuple shape:
您可以使用
hyperspherical
包。它适用于任何维度。时间:
You can use
hyperspherical
package. It works for any dimension.The time: