【问题标题】:Compute sum of sine waves in numpy; avoid large matrices while maintaining numpy performance在 numpy 中计算正弦波的总和;在保持 numpy 性能的同时避免使用大型矩阵
【发布时间】:2021-02-24 08:27:37
【问题描述】:

我目前正在尝试计算多个生成的正弦波的总和,生成如下:

np.sin(2 * np.pi * freq * np.arange(N) / SAMPLE_RATE)

其中N 是我要生成的样本数,SAMPLE_RATE 是以 Hz 为单位的采样率。我意识到的一件巧妙的事情是,如果我为freq 传递一个列向量,它会由于广播而生成一个样本矩阵,其中每一行对应于单个频率的单个正弦波,每列对应于每个频率的单个采样点。举个例子:

freq = np.array([[1,2,3,4]]).T
SAMPLE_RATE = 1
N = 5
print(np.sin(2 * np.pi * freq * np.arange(N) / 20))

输出

[[ 0.          0.30901699  0.58778525  0.80901699  0.95105652]
 [ 0.          0.58778525  0.95105652  0.95105652  0.58778525]
 [ 0.          0.80901699  0.95105652  0.30901699 -0.58778525]
 [ 0.          0.95105652  0.58778525 -0.58778525 -0.95105652]]

如果沿 0 轴求和,则产生所有正弦波的总和。但是,这会占用O(N * len(freq)) 空间,当 N 和 freq 很大时,这是不可接受的。有没有办法在O(N) 空间中做到这一点而不牺牲最后的矢量化求和?这个问题应该推广到如果一个矩阵是通过任何广播操作生成的,只是立即被求和折叠。

【问题讨论】:

  • 用numba 之类的东西编写你自己的代码。您描述的权衡是使用一组有限的标准工具的成本。
  • 如果freq 是单调的,可能会有一些傅立叶级数或泰勒级数展开会有所帮助,但对于Mathematics 堆栈来说,这更像是一个问题——刚刚拿出我的旧书和我的眼睛上釉。

标签: python arrays numpy


【解决方案1】:

好的,在数学栈上找到了here

只要freq 的形式为np.arange(m) + 1(在本例中为 m=4)

s = lambda x, m: np.sin(np.pi * m * x / 20)

f = lambda x, m: np.where(x == 0, 0, s(x, m + 1) * s(x, m) / s(x, 1))  
                 # ^^^ to fix divide by zero error at 0

f(np.arange(N), 4)
Out[]: 
array([0.00000000e+00, 2.65687576e+00, 3.07768354e+00, 1.48130525e+00,
       1.22464680e-16])

np.sin(2 * np.pi * freq * np.arange(N) / 20).sum(0)
Out[]: 
array([0.00000000e+00, 2.65687576e+00, 3.07768354e+00, 1.48130525e+00,
       1.11022302e-16])

当它非常接近零时(与最后一个点一样),您会得到浮点差异,但否则它应该可以工作。

【讨论】:

    猜你喜欢
    • 2022-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-20
    相关资源
    最近更新 更多