Numpy fft算法产生不精确的结果
我正在尝试实现基于dft(离散傅里叶变换)矩阵分解的fft(快速傅里叶变换)。在下面的代码中,fft和直接方法(即:将dft矩阵直接与v相乘)都被实现,以测试我的fft实现的有效性Numpy fft算法产生不精确的结果,numpy,matplotlib,fft,dft,cmath,Numpy,Matplotlib,Fft,Dft,Cmath,我正在尝试实现基于dft(离散傅里叶变换)矩阵分解的fft(快速傅里叶变换)。在下面的代码中,fft和直接方法(即:将dft矩阵直接与v相乘)都被实现,以测试我的fft实现的有效性 import numpy as n import cmath, math import matplotlib.pyplot as plt v=n.array([1,-1,2,-3]) w=v N=len(v) t=[0]*N M=n.zeros((N,N),dtype=complex) z=n.exp(2j*mat
import numpy as n
import cmath, math
import matplotlib.pyplot as plt
v=n.array([1,-1,2,-3])
w=v
N=len(v)
t=[0]*N
M=n.zeros((N,N),dtype=complex)
z=n.exp(2j*math.pi/N)
for a in range(N):
for b in range(N):
M[a][b]=n.exp(2j*math.pi*a*b/N)
print (n.dot(v,M))
plt.plot(n.dot(v,M))
def f(x):
x=n.concatenate([x[::2],x[1::2]])
return x
while (w!=f(v)).any():
v=f(v)
print(v)
a=2
while a<=N:
for k in range(N/a):
for y in range(a/2):
t[y]=v[a*k+y]
for i in range(a/2):
v[a*k+i]+=v[a*k+i+a/2]*(z**i)
v[a*k+i+a/2]=t[i]-v[a*k+i+a/2]*(z**i)
a*=2
print(v)
plt.plot(v)
plt.show()
将numpy作为n导入
导入cmath、数学
将matplotlib.pyplot作为plt导入
v=n.数组([1,-1,2,-3])
w=v
N=len(v)
t=[0]*N
M=n.0((n,n),dtype=complex)
z=n.exp(2j*math.pi/n)
对于范围(N)内的a:
对于范围(N)内的b:
M[a][b]=n.exp(2j*math.pi*a*b/n)
印刷品(n.dot(v,M))
plt.绘图(n.dot(v,M))
def f(x):
x=n.连接([x[::2],x[1::2]]
返回x
而(w!=f(v)).any():
v=f(v)
印刷品(五)
a=2
而a似乎问题不在于算法,而在于v的声明(感谢@kazemakase)。试一试
相反。至少对我来说,这些曲线会出现在彼此的顶部:
编辑
这是一段相当长的旅程。我无法找出你的代码出了什么问题,但看起来有几个错误,dft和fft都有。最后,我根据[本文档]()(第6-9页包含您需要的所有信息)编写了自己的fft版本。也许你可以通过这个算法找出你的问题所在。位反转的算法可以在中找到(或者在中找到)。我测试了不同长度的线性向量的代码——如果发现任何错误,请告诉我
import numpy as np
import cmath
def bit_reverse(x,n):
"""
Reverse the last n bits of x
"""
##from https://stackoverflow.com/a/12682003/2454357
##formstr = '{{:0{}b}}'.format(n)
##return int(formstr.format(x)[::-1],2)
##from https://stackoverflow.com/a/5333563/2454357
return sum(1<<(n-1-i) for i in range(n) if x>>i&1)
def permute_vector(v):
"""
Permute vector v such that the indices of the result
correspond to the bit-reversed indices of the original.
Returns the permuted input vector and the number of bits used.
"""
##check that len(v) == 2**n
##and at the same time find permutation length:
L = len(v)
comp = 1
bits = 0
while comp<L:
comp *= 2
bits += 1
if comp != L:
raise ValueError('permute_vector: wrong length of v -- must be 2**n')
rindices = [bit_reverse(i,bits)for i in range(L)]
return v[rindices],bits
def dft(v):
N = v.shape[0]
a,b = np.meshgrid(
np.linspace(0,N-1,N,dtype=np.complex128),
np.linspace(0,N-1,N,dtype=np.complex128),
)
M = np.exp((-2j*np.pi*a*b)/N)
return np.dot(M,v)
def fft(v):
w,bits = permute_vector(v)
N = w.shape[0]
z=np.exp(np.array(-2j,dtype=np.complex128)*np.pi/N)
##starting fft
for i in range(bits):
dist = 2**i ##distance between 'exchange pairs'
group = dist*2 ##size of sub-groups
for start in range(0,N,group):
for offset in range(group//2):
pos1 = start+offset
pos2 = pos1+dist
alpha1 = z**((pos1*N//group)%N)
alpha2 = z**((pos2*N//group)%N)
w[pos1],w[pos2] = w[pos1]+alpha1*w[pos2],w[pos1]+alpha2*w[pos2]
return w
if __name__ == '__main__':
#test the fft
for n in [2**i for i in range(1,5)]:
print('-'*25+'n={}'.format(n)+'-'*25)
v = np.linspace(0,n-1,n, dtype=np.complex128)
print('v = ')
print(v)
print('fft(v) = ')
print(fft(v))
print('dft(v) = ')
print(dft(v))
print('relative error:')
print(abs(fft(v)-dft(v))/abs(dft(v)))
这是一个很好的挑战——我学到了很多!例如,您可以在线验证代码的结果。问题似乎不在于算法,而在于v的声明(谢谢@kazemakase)。试一试
相反。至少对我来说,这些曲线会出现在彼此的顶部:
编辑
这是一段相当长的旅程。我无法找出你的代码出了什么问题,但看起来有几个错误,dft和fft都有。最后,我根据[本文档]()(第6-9页包含您需要的所有信息)编写了自己的fft版本。也许你可以通过这个算法找出你的问题所在。位反转的算法可以在中找到(或者在中找到)。我测试了不同长度的线性向量的代码——如果发现任何错误,请告诉我
import numpy as np
import cmath
def bit_reverse(x,n):
"""
Reverse the last n bits of x
"""
##from https://stackoverflow.com/a/12682003/2454357
##formstr = '{{:0{}b}}'.format(n)
##return int(formstr.format(x)[::-1],2)
##from https://stackoverflow.com/a/5333563/2454357
return sum(1<<(n-1-i) for i in range(n) if x>>i&1)
def permute_vector(v):
"""
Permute vector v such that the indices of the result
correspond to the bit-reversed indices of the original.
Returns the permuted input vector and the number of bits used.
"""
##check that len(v) == 2**n
##and at the same time find permutation length:
L = len(v)
comp = 1
bits = 0
while comp<L:
comp *= 2
bits += 1
if comp != L:
raise ValueError('permute_vector: wrong length of v -- must be 2**n')
rindices = [bit_reverse(i,bits)for i in range(L)]
return v[rindices],bits
def dft(v):
N = v.shape[0]
a,b = np.meshgrid(
np.linspace(0,N-1,N,dtype=np.complex128),
np.linspace(0,N-1,N,dtype=np.complex128),
)
M = np.exp((-2j*np.pi*a*b)/N)
return np.dot(M,v)
def fft(v):
w,bits = permute_vector(v)
N = w.shape[0]
z=np.exp(np.array(-2j,dtype=np.complex128)*np.pi/N)
##starting fft
for i in range(bits):
dist = 2**i ##distance between 'exchange pairs'
group = dist*2 ##size of sub-groups
for start in range(0,N,group):
for offset in range(group//2):
pos1 = start+offset
pos2 = pos1+dist
alpha1 = z**((pos1*N//group)%N)
alpha2 = z**((pos2*N//group)%N)
w[pos1],w[pos2] = w[pos1]+alpha1*w[pos2],w[pos1]+alpha2*w[pos2]
return w
if __name__ == '__main__':
#test the fft
for n in [2**i for i in range(1,5)]:
print('-'*25+'n={}'.format(n)+'-'*25)
v = np.linspace(0,n-1,n, dtype=np.complex128)
print('v = ')
print(v)
print('fft(v) = ')
print(fft(v))
print('dft(v) = ')
print(dft(v))
print('relative error:')
print(abs(fft(v)-dft(v))/abs(dft(v)))
这是一个很好的挑战——我学到了很多!例如,您可以在线验证代码的结果。是否在python 2上运行?不要忽略警告。ComplexWarning:将复数值强制转换为实数将丢弃虚部v[a*k+i+a/2]=t[i]-v[a*k+i+a/2]*(z**i)
敲钟?(提示:您为M
设置了正确的dtype
。也可以尝试v
。)看起来解决方案实际上是在v
的声明中(谢谢@kazemakase)。请尝试v=n.array([1,-1,2,-3],dtype=complex)
。至少对我来说,这些曲线彼此重叠。@ThomasKühn Hi Thomas,请在您的答案下查看我的评论。@kazemakase适用于我在文章中显示的内容,但不适用于v=[1,2,3,4,5,6,7,8],并且在我为v设置数据类型后,警告仍然会显示。您是否在python 2上运行?不要忽略这些警告。ComplexWarning:将复数值强制转换为实数将丢弃虚部v[a*k+i+a/2]=t[i]-v[a*k+i+a/2]*(z**i)
敲钟?(提示:您为M
设置了正确的dtype
。也可以尝试v
。)看起来解决方案实际上是在v
的声明中(谢谢@kazemakase)。请尝试v=n.array([1,-1,2,-3],dtype=complex)
。至少对我来说,这些曲线彼此重叠。@ThomasKühn Hi Thomas,请在你的答案下查看我的评论。@kazemakase对我在文章中显示的内容有效,但对v=[1,2,3,4,5,6,7,8]无效。在我设置了v的数据类型后,警告仍然会显示出来。谢谢你的建议。我照你说的做了,它对你展示的那一个有效,但对[1,2,3,4,5,6,7,8]@pxc3110没有链接到你尝试实现的算法吗?基本思想是离散傅里叶矩阵exp(2jpia*b/N)可以分解为单位矩阵、对角矩阵和奇数置换矩阵。非常感谢!我喜欢你学到了一些东西,这是这个网站的主要观点。下面的链接提供了实际的实现,而不是理论部分:我想你可能也想看看这个?谢谢你的建议。我照你说的做了,它对你展示的那一个有效,但对[1,2,3,4,5,6,7,8]@pxc3110没有链接到你尝试实现的算法吗?基本思想是离散傅里叶矩阵exp(2jpia*b/N)可以分解为单位矩阵、对角矩阵和奇数置换矩阵。非常感谢!我喜欢你学到了一些东西,这是这个网站的主要观点。下面的链接提供了实际的实现,而不是理论部分:我想你可能也想看看这个?
-------------------------n=2-------------------------
v =
[ 0.+0.j 1.+0.j]
fft(v) =
[ 1. +0.00000000e+00j -1. -1.22464680e-16j]
dft(v) =
[ 1. +0.00000000e+00j -1. -1.22464680e-16j]
relative error:
[ 0. 0.]
-------------------------n=4-------------------------
v =
[ 0.+0.j 1.+0.j 2.+0.j 3.+0.j]
fft(v) =
[ 6. +0.00000000e+00j -2. +2.00000000e+00j -2. -4.89858720e-16j
-2. -2.00000000e+00j]
dft(v) =
[ 6. +0.00000000e+00j -2. +2.00000000e+00j -2. -7.34788079e-16j
-2. -2.00000000e+00j]
relative error:
[ 0.00000000e+00 0.00000000e+00 1.22464680e-16 3.51083347e-16]
-------------------------n=8-------------------------
v =
[ 0.+0.j 1.+0.j 2.+0.j 3.+0.j 4.+0.j 5.+0.j 6.+0.j 7.+0.j]
fft(v) =
[ 28. +0.00000000e+00j -4. +9.65685425e+00j -4. +4.00000000e+00j
-4. +1.65685425e+00j -4. -7.10542736e-15j -4. -1.65685425e+00j
-4. -4.00000000e+00j -4. -9.65685425e+00j]
dft(v) =
[ 28. +0.00000000e+00j -4. +9.65685425e+00j -4. +4.00000000e+00j
-4. +1.65685425e+00j -4. -3.42901104e-15j -4. -1.65685425e+00j
-4. -4.00000000e+00j -4. -9.65685425e+00j]
relative error:
[ 0.00000000e+00 6.79782332e-16 7.40611132e-16 1.85764404e-15
9.19104080e-16 3.48892999e-15 3.92837008e-15 1.35490975e-15]
-------------------------n=16-------------------------
v =
[ 0.+0.j 1.+0.j 2.+0.j 3.+0.j 4.+0.j 5.+0.j 6.+0.j 7.+0.j
8.+0.j 9.+0.j 10.+0.j 11.+0.j 12.+0.j 13.+0.j 14.+0.j 15.+0.j]
fft(v) =
[ 120. +0.00000000e+00j -8. +4.02187159e+01j -8. +1.93137085e+01j
-8. +1.19728461e+01j -8. +8.00000000e+00j -8. +5.34542910e+00j
-8. +3.31370850e+00j -8. +1.59129894e+00j -8. +2.84217094e-14j
-8. -1.59129894e+00j -8. -3.31370850e+00j -8. -5.34542910e+00j
-8. -8.00000000e+00j -8. -1.19728461e+01j -8. -1.93137085e+01j
-8. -4.02187159e+01j]
dft(v) =
[ 120. +0.00000000e+00j -8. +4.02187159e+01j -8. +1.93137085e+01j
-8. +1.19728461e+01j -8. +8.00000000e+00j -8. +5.34542910e+00j
-8. +3.31370850e+00j -8. +1.59129894e+00j -8. -6.08810394e-14j
-8. -1.59129894e+00j -8. -3.31370850e+00j -8. -5.34542910e+00j
-8. -8.00000000e+00j -8. -1.19728461e+01j -8. -1.93137085e+01j
-8. -4.02187159e+01j]
relative error:
[ 0.00000000e+00 1.09588741e-15 1.45449990e-15 6.36716793e-15
8.53211992e-15 9.06818284e-15 1.30922044e-14 5.40949529e-15
1.11628436e-14 1.23698141e-14 1.50430426e-14 3.02428869e-14
2.84810617e-14 1.16373983e-14 1.10680934e-14 3.92841628e-15]