Python 2D卷积,不强制周期性边界

时间:2015-08-21 04:55:31

标签: python numpy fft convolution

我对疾病问题进行建模,其中2D景观中的每个个体都具有由(径向基)核函数描述的传递性。我的目标是将内核与人口密度进行卷积,以便输出捕获整个环境中的传输风险。

我使用NumPy的2D FFT和反FFT函数执行卷积。但是,这会强制结果中的周期性/包裹边界条件,这不适合我的模型。有没有办法在原始固定边界的范围内进行卷积?

import numpy as np
import random
from math import *
import matplotlib.pyplot as plt

''' Landscape parameters ''' 
L = 10.
nx = 100
dx = L/nx
hs = .5 * dx  # half-step
ulist = np.linspace(hs, L-hs, nx)

''' Radial Basis Function Kernel '''
alpha = 1.
i, j = ulist.reshape(nx,1), ulist.reshape(1,nx)
r = np.minimum(i-ulist[0], L-i+ulist[0])**2 + np.minimum(j-ulist[0], L-j+ulist[0])**2
rbf = sqrt(1 / (2 * alpha ** 2))
ker = np.exp(-(rbf * r) ** 2)
ker = ker/np.sum(ker)

''' Population Density '''
ido = np.random.randint(nx, size=(1000,2)).astype(np.int)
og = np.zeros((nx,nx))
np.add.at(og, (ido[:,0], ido[:,1]), 1)

''' Convolution via FFT and inverse-FFT '''
v1 = np.fft.fft2(ker)
v2 = np.fft.fft2(og)
v0 = np.fft.ifft2(v1*v2)
dd = np.abs(v0)

plt.plot(ido[:,1], ido[:,0], 'ko', alpha=.5)
plt.imshow(dd, origin='origin')
plt.show()

2 个答案:

答案 0 :(得分:2)

为了做你想做的事,你需要用{0}来填充og,然后相应地展开ker(因为它已经周期性地移动了,你只需要将它扩展到更适合的大小og)。

填充og(300x300): padded <code>og</code> 原始ker(100x100): original <code>ker</code> 扩展ker(300x300): expanded <code>ker</code>

代码:

pad = 100
og = np.pad(og, pad, mode='constant')
new_ker = np.zeros_like(og)
new_ker[:nx//2,:nx//2] = ker[:nx//2,:nx//2]
new_ker[:nx//2,-nx//2:] = ker[:nx//2,-nx//2:]
new_ker[-nx//2:,:nx//2] = ker[-nx//2:,:nx//2]
new_ker[-nx//2:,-nx//2:] = ker[-nx//2:,-nx//2:]
ker = new_ker

# doesn't change
v1 = np.fft.fft2(ker)
v2 = np.fft.fft2(og)
v0 = np.fft.ifft2(v1*v2)

# unpadding the result
v0 = v0[pad:-pad,pad:-pad]

(对于凌乱的扩展,很抱歉,你可以在生成内核时直接进行扩展。我只想分离扩展部分。)

原始结果: enter image description here 填充结果: padded result

如果您不介意使用scipy,它可以为您完成所有这些(包括边界条件的其他变体)。有关更多选项,请参阅fftconvolveconvolve2d。请注意,必须预先滚动内核才能使用这些功能(也就是说,最大值应位于中心,而不是在角落中)。示例代码(产生与上面手动填充相同的结果):

# unroll the kernel (again, can be done directly when generating `ker`)
ker = np.roll(ker, 50, 0)
ker = np.roll(ker, 50, 1)

from scipy.signal import fftconvolve
dd = fftconvolve(og, ker, mode='same')

答案 1 :(得分:2)

每当您使用基于fft的方法时,您总是会根据定义在问题中引入周期性问题。

如果您不想要这个,首先应该在计算级别之前在数学建模级别定义您想要的内容。

请记住一些技巧,根据我的经验,在许多情况下非常有用:

- 将您的问题嵌入更大的2d空间以减少周期性影响。换句话说,尽可能地推动周期性边界以模拟“自由空间”。情况。

- 改为使用离散余弦变换。余弦变换具有模拟边界条件的效果。它的工作原理就像在每个边界之外都有镜像反射的数据。在某些问题中,这用于模拟反射边界条件。