首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何利用FFT进行一维反褶积?

如何利用FFT进行一维反褶积?
EN

Stack Overflow用户
提问于 2019-10-25 09:40:27
回答 2查看 2K关注 0票数 1

问题

我试图用卷积定理来解卷积两个测量数据A和B。我知道,对于卷积,您应该对数据进行零点处理,以防止循环卷积。然而,我感到困惑的是,零填充是否也是反褶积所必需的。

问题

1.如何正确地根据卷积定理进行反褶积?

  1. 为什么下面的示例不起作用?

逼近

因为A和B是测量的,所以我为进一步的研究创造了一个例子。其思想是在模式scipy.signal.convolve中使用same创建B。

代码语言:javascript
复制
import numpy as np 
import matplotlib.pyplot as plt 
from scipy.signal import convolve
from scipy.fftpack import next_fast_len

# A, in the description above
A = np.array([1, 1, 1, 2, 1, 1])
# The result, I want to get from the deconvolution
kernel = np.array([0, 1, 2, 1, 0, 0]) 
#B, in the description above
B = convolve(kernel, data, mode='same') 

# Using the deconvolution theorem
f_A = np.fft.fft(A)
f_B = np.fft.fft(B)
# I know that you should use a regularization here 
r = f_B / f_A

# dk should be equal to kernel
dk = np.fft.ifft(r)

dk的结果是:

代码语言:javascript
复制
dk = array([ 2.28571429-9.25185854e-18j,  1.28571429+9.25185854e-18j,
       -0.71428571-9.25185854e-18j, -0.71428571+9.25185854e-18j,
        0.28571429-9.25185854e-18j,  1.28571429+9.25185854e-18j])

预计将:

代码语言:javascript
复制
dk = array([0, 1, 2, 1, 0, 0]) 
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-10-25 13:32:39

实际上,由于内核是以2.0为中心的1.02.01.0(模糊和膨胀),内核宽度为3。由于0.5上的数组A是非空的,所以在-1.6上,完全转换的数组paddedB是非空的。然而,函数scipy.signal.convolve(...,'same')返回一个集群化的卷积数组B(0..5)=paddedB(0..5)。因此,如果使用E 222 np.convolve() E 124选项(e 225),则与paddedB(-1) paddedB(6) 有关的信息丢失,恢复内核变得困难。

为了避免信息丢失,输出paddedB将被填充以包含卷积信号的支持,计算为函数A的支持和内核支持的Minkowski和。选项full of np.convolve() 直接计算 paddedB 而不丢失信息。

代码语言:javascript
复制
kernel=[1,2,1]
paddedB = convolve(kernel, A, mode='full')

为了利用卷积定理提取核,输入信号A将被填充以与函数paddedB的支持相匹配。

代码语言:javascript
复制
paddedA=np.zeros(paddedB.shape[0])
paddedA[kernel.shape[0]/2: kernel.shape[0]/2+A.shape[0]]=A[:]

# Using the deconvolution theorem
f_A = np.fft.fft(paddedA)
f_B = np.fft.fft(paddedB)
# I know that you should use a regularization here 
r = f_B / f_A

# dk should be equal to kernel
dk = np.fft.ifft(r)
# shift to get zero frequency in the middle:
dk=np.fft.fftshift(dk)

注意使用函数np.fft.fftshift()来获得中间的零频率。

代码语言:javascript
复制
import numpy as np 
import matplotlib.pyplot as plt 
from scipy.signal import convolve
from scipy.fftpack import next_fast_len

# A, in the description above
A = np.array([1, 1, 1, 2, 1, 1])

kernel=np.asarray([1,2,1])
paddedB = convolve(kernel, A, mode='full')
print paddedB

paddedA=np.zeros(paddedB.shape[0])
paddedA[kernel.shape[0]/2: kernel.shape[0]/2+A.shape[0]]=A[:]
#pad both signal and kernel. Requires the size of the kernel

# Using the deconvolution theorem
f_A = np.fft.fft(paddedA)
f_B = np.fft.fft(paddedB)
# I know that you should use a regularization here 
r = f_B / f_A

# dk should be equal to kernel
dk = np.fft.ifft(r)
# shift to get zero abscissa in the middle:
dk=np.fft.fftshift(dk)

print dk

如果不可能获得paddedB,而且B是唯一可用的数据,则可以尝试通过将B填充为零或平滑B的最后值来重建paddedB。这需要对内核大小进行一些估计。

代码语言:javascript
复制
B = convolve(A,kernel, mode='same')
paddedB=np.zeros(A.shape[0]+kernel.shape[0]-1)
paddedB[kernel.shape[0]/2: kernel.shape[0]/2+B.shape[0]]=B[:]
print paddedB

最后,窗户可以同时应用于paddedA和paddedB,这意味着在对内核进行估计时,中间的值更重要。例如,Parzen / de la Vallée Poussin窗口:

代码语言:javascript
复制
import numpy as np 
import matplotlib.pyplot as plt 
from scipy.signal import convolve
from scipy.fftpack import next_fast_len
from scipy.signal import tukey
from scipy.signal import parzen

# A, in the description above
A = np.array([1, 1, 1, 2, 1, 1])

kernel=np.asarray([1,2,1])
paddedB = convolve(kernel, A, mode='full')
print paddedB


B = convolve(A,kernel, mode='same')
estimatedkernelsize=3
paddedB=np.zeros(A.shape[0]+estimatedkernelsize-1)
paddedB[estimatedkernelsize/2: estimatedkernelsize/2+B.shape[0]]=B[:]
print paddedB

paddedA=np.zeros(paddedB.shape[0])
paddedA[estimatedkernelsize/2: estimatedkernelsize/2+A.shape[0]]=A[:]

#applying window
#window=tukey(paddedB.shape[0],alpha=0.1,sym=True) #if longer signals, should be enough.
window=parzen(paddedB.shape[0],sym=True)
windA=np.multiply(paddedA,window)
windB=np.multiply(paddedB,window)


# Using the deconvolution theorem
f_A = np.fft.fft(windA)
f_B = np.fft.fft(windB)
# I know that you should use a regularization here 
r = f_B / f_A

# dk should be equal to kernel
dk = np.fft.ifft(r)
# shift to get the zero abscissa in the middle:
dk=np.fft.fftshift(dk)

print dk

然而,由于A的大小很小,估计的内核还远远不够完善:

代码语言:javascript
复制
[ 0.08341737-6.93889390e-17j -0.2077029 +0.00000000e+00j
 -0.17500324+0.00000000e+00j  1.18941919-2.77555756e-17j
  2.40994395+6.93889390e-17j  0.66720653+0.00000000e+00j
 -0.15972098+0.00000000e+00j  0.02460791+2.77555756e-17j]
票数 2
EN

Stack Overflow用户

发布于 2020-03-30 04:33:50

代码语言:javascript
复制
# I had to modify the listed code for it to work under Python3. 
# I needed to upgrade to the scipy-1.4.1 and numpy-1.18.2
# and to avoid a TypeError: slice indices must be integers
# I needed to change / to // in the line marked below
import numpy as np 
import matplotlib.pyplot as plt 
from scipy.signal import convolve 
from scipy.fftpack import next_fast_len 
# A, in the description above 
A = np.array([1, 1, 1, 2, 1, 1]) 
kernel=np.asarray([1,2,1]) 
paddedB = convolve(kernel, A, mode='full') 
print(paddedB)
paddedA=np.zeros(paddedB.shape[0]) 
# note // instead of / below
paddedA[kernel.shape[0]//2: kernel.shape[0]//2+A.shape[0]]=A[:] 
#pad both signal and kernel. Requires the size of the kernel 
# Using the deconvolution theorem 
f_A = np.fft.fft(paddedA) 
f_B = np.fft.fft(paddedB) # I know that you should use a regularization here 
r = f_B / f_A 
# dk should be equal to kernel 
dk = np.fft.ifft(r) 
# shift to get zero abscissa in the middle: 
dk=np.fft.fftshift(dk) 
print(dk)
# this gives:
#(py36) bash-3.2$ python decon.py
#[1 3 4 5 6 5 3 1]
#[ 1.11022302e-16+0.j -1.11022302e-16+0.j -9.62291355e-17+0.j
# 1.00000000e+00+0.j  2.00000000e+00+0.j  1.00000000e+00+0.j
# 9.62291355e-17+0.j -1.11022302e-16+0.j]
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58555981

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档