Numpy将角度范围从(-Pi,Pi)转换为(0,2*Pi)。

22

这似乎很简单,但我似乎无法想出如何将在 -Pi 和 Pi 之间的角度映射到 0 到 2Pi 的范围内。 我尝试使用 np.select,但出于某种原因它会冻结我的程序。由于神经网络不能输出负数,所以我需要在此范围内使用角度作为训练数据。

audio = wav.read('/home/chase/Desktop/ge.wav')[1].astype(np.float32)
audio = np.mean(audio, 1)
audio /= np.max(np.abs(audio))
audio = np.array([np.fft.rfft(audio[i:i + FRAME_SIZE]) for i in range(0, len(audio) - len(audio) % FRAME_SIZE, FRAME_SIZE)])
audio /= FRAME_SIZE
audio_mag = np.abs(audio)
audio_phase = np.angle(audio)

#this line freezes the program
audio_phase = np.select(audio_phase < 0 , 2 * np.pi + audio_phase, audio_phase)

我需要音频


你尝试过使用np.where吗? - BrenBarn
谢谢,那个可行。 - chasep255
5个回答

17

这里有几种不同的方法,并附上时间:

In [1]: import numpy as np; from numpy import linspace, pi

In [2]: N=10000

In [3]: %timeit x=linspace(-pi, pi, N); np.where(x<0 , 2*pi+x, x)
10000 loops, best of 3: 79.1 µs per loop

In [4]: %timeit x=linspace(-pi, pi, N); np.select(x<0 , 2*pi+x, x)
1 loops, best of 3: 354 ms per loop

In [5]: %timeit x=linspace(-pi, pi, N); x[x<0] += 2*pi
10000 loops, best of 3: 82.5 µs per loop

In [6]: %timeit x=linspace(-pi, pi, N); (x + 2*pi)*(x<0) + x*(x>=0)
10000 loops, best of 3: 149 µs per loop

In [7]: %timeit x=linspace(-pi, pi, N); (x + 2*pi)%(2*pi)
10000 loops, best of 3: 192 µs per loop

我认为x[x<0] += 2*pi是最易读的,但where(x<0, x+2*pi, x)略微更快。而select形式则明显最慢。

为了比较,在同一台机器上运行的普通linspace函数如下:

In [8]: %timeit x=linspace(-pi, pi, N)
10000 loops, best of 3: 35.9 µs per loop

考虑到程序在选择操作而不是昂贵得多的fft函数上失败,您可能会遇到低内存情况,使数组分页到磁盘(x<02*pi+x都生成数组,加上由select创建的原始x和返回值)。 如果是这种情况,那么逐帧纠正相位可能更好。


3
比较和时间方面都加一分!我的选择是 x[x<0] += 2 * np.pi,不仅因为易读性好,而且因为它对数组进行了原地修改,如果 x 非常大,这个方法非常有用。 - Imanol Luengo

13

假设你有这些角度:

>>> angles = np.linspace(-np.pi, np.pi, 10)
>>> angles
array([-3.14159265, -2.44346095, -1.74532925, -1.04719755, -0.34906585,
    0.34906585,  1.04719755,  1.74532925,  2.44346095,  3.14159265])

有两种可能的方法来完成这个任务...

  1. 使用numpy表达式来查找负值。

小于零的数应该被转换为正确的值。类似这样:

>>> (2*np.pi + angles) * (angles < 0) + angles*(angles > 0)
array([ 3.14159265,  3.83972435,  4.53785606,  5.23598776,  5.93411946,
    0.34906585,  1.04719755,  1.74532925,  2.44346095,  3.14159265])

请记住,在numpy中,您可以进行逻辑测试...angles < 0是一个布尔数组。但是,1*(angles < 0)是一个数值数组,其中True值映射为1,而False值则映射为0。您可以结合这两个概念来得出答案。

2. 您可以简单地认识到,这是一个您正在尝试解决的数学表达式:

因此,只需将2*np.pi添加到所有内容并取模即可。这就像找到“单位位数”或将数字转换为八进制数等一样...

>>> (angles + 2 * np.pi) % (2 * np.pi)
array([ 3.14159265,  3.83972435,  4.53785606,  5.23598776,  5.93411946,
    0.34906585,  1.04719755,  1.74532925,  2.44346095,  3.14159265])

我希望这个能有所帮助。


1
在第一个解决方案中:如果 angles == 0 怎么办?也许可以替换为 (2*np.pi + angles) * (angles < 0) + angles*(angles >= 0) - Ethunxxx

8

介于 -π 和 +π 之间的角度:

>>> import numpy as np
>>> angles = np.linspace(-np.pi, np.pi, 10)

转换为从0到2*Pi的范围:

>>> angles_2pi = np.mod(angles, 2*np.pi)
>>> angles_2pi
array([3.14159265, 3.83972435, 4.53785606, 5.23598776, 5.93411946,
   0.34906585, 1.04719755, 1.74532925, 2.44346095, 3.14159265])

0

我也发现使用Neapolitan上面的部分答案可以将角度限制在[0-2pi]之间,同时实现包装。

import numpy as np
def wrap(angle):
    tmp = np.arctan2(np.sin(angle), np.cos(angle))
    return float(np.where(tmp<0 , 2*np.pi+tmp, tmp))

当角度超过2 pi的两倍时,其他一些方法存在问题。


-1
你可以尝试使用带有lambda的map函数。
>>>angles = np.linspace(-np.pi, np.pi, 10)
array([-3.14159265, -2.44346095, -1.74532925, -1.04719755, -0.34906585,
        0.34906585,  1.04719755,  1.74532925,  2.44346095,  3.14159265])

>>>map(lambda x: x if x > 0 else x + 2*np.pi, angles)

[3.1415926535897931, 3.839724354387525, 4.5378560551852569, 5.2359877559829879, 5.9341194567807207, 0.34906585039886595, 1.0471975511965974, 1.7453292519943293, 2.4434609527920612, 3.1415926535897931]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接