【问题标题】:Generating correlated random potential using fast Fourier transform使用快速傅里叶变换生成相关随机势
【发布时间】:2019-08-26 17:57:09
【问题描述】:

我想在具有指定自相关函数的一维或二维空间中生成一个随机势,并且根据一些数学推导,包括 Wiener-Khinchin 定理和傅里叶变换的性质,事实证明这可以使用以下等式: 其中phi(k) 均匀分布在区间 [0, 1) 中。而这个功能满足,就是保证产生的势永远是真实的。 自相关函数应该不会影响我在这里做的事情,我取一个简单的高斯分布。

phi(k)的相位项和条件的选择基于以下属性

  1. 相位项的模数必须为 1(根据 Wiener-Khinchin 定理,即函数的自相关的傅里​​叶变换等于该函数的傅里叶变换的模数);

    李>
  2. 实函数的傅里叶变换必须满足(通过直接检查积分形式的傅里叶变换的定义)。

  3. 产生的电位和自相关都是真实的。

通过结合这三个属性,该术语只能采用上述形式。

相关数学可以参考以下pdf的p.16: https://d-nb.info/1007346671/34

我使用均匀分布随机生成了一个numpy数组,并将数组的负数与原始数组连接起来,使其满足上述phi(k)的条件。然后我执行了 numpy(逆)快速傅里叶变换。

我试过一维和二维的情况,下面只显示一维的情况。

import numpy as np
from numpy.fft import fft, ifft
import matplotlib.pyplot as plt

## The Gaussian autocorrelation function 
def c(x, V0, rho):
    return V0**2 * np.exp(-x**2/rho**2) 

x_min, x_max, interval_x = -10, 10, 10000
x = np.linspace(x_min, x_max, interval_x, endpoint=False)

V0 = 1
## the correlation length
rho = 1 

## (Uniformly) randomly generated array for k>0
phi1 = np.random.rand(int(interval_x)/2)
phi = np.concatenate((-1*phi1[::-1], phi1))
phase = np.exp(2j*np.pi*phi)

C = c(x, V0, rho) 
V = ifft(np.power(fft(C), 0.5)*phase)
plt.plot(x, V.real)
plt.plot(x, V.imag)
plt.show()

并且情节类似于如下所示: .

然而,生成的势能变得复杂,虚部与实部在一个数量级上,这是意料之外的。我已经检查了很多次数学,但我找不到任何问题。所以我在想这是否与实现问题有关,例如数据点是否足够密集以进行快速傅里叶变换等。

【问题讨论】:

    标签: python arrays numpy fft


    【解决方案1】:

    您对fft(更准确地说,DFT)的运作方式存在一些误解。 首先请注意,DFT 假设序列的样本被索引为0, 1, ..., N-1,其中N 是样本数。相反,您生成一个对应于索引-10000, ..., 10000 的序列。其次,请注意实数序列的 DFT 将生成对应于0N/2 的“频率”的实数值。您似乎也没有考虑到这一点。

    我不会详细介绍,因为这超出了此 stackexchange 站点的范围。

    只是为了进行完整性检查,下面的代码会生成一个序列,该序列具有实值序列的 DFT (FFT) 所期望的属性:

    • 正负频率的共轭对称,
    • 对应于频率0N/2的实值元素
    • 序列假定对应于索引0N-1

    如你所见,这个序列的ifft确实生成了一个实值序列

    from scipy.fftpack import ifft
    
    N = 32 # number of samples
    n_range = np.arange(N) # indices over which the sequence is defined
    n_range_positive = np.arange(int(N/2)+1) # the "positive frequencies" sample indices
    n_range_negative = np.arange(int(N/2)+1, N) # the "negative frequencies" sample indices
    
    # generate a complex-valued sequence with the properties expected for the DFT of a real-valued sequence
    abs_FFT_positive = np.exp(-n_range_positive**2/100)
    phase_FFT_positive =  np.r_[0, np.random.uniform(0, 2*np.pi, int(N/2)-1), 0] # note last frequency has zero phase
    FFT_positive = abs_FFT_positive * np.exp(1j * phase_FFT_positive)
    FFT_negative = np.conj(np.flip(FFT_positive[1:-1]))
    FFT = np.r_[FFT_positive, FFT_negative] # this is the final FFT sequence
    
    # compute the IFFT of the above sequence
    IFFT = ifft(FFT)
    
    #plot the results
    
    plt.plot(np.abs(FFT), '-o', label = 'FFT sequence (abs. value)')
    plt.plot(np.real(IFFT), '-s', label = 'IFFT (real part)')
    plt.plot(np.imag(IFFT), '-x', label = 'IFFT (imag. part)')
    plt.legend()
    

    【讨论】:

    • 感谢您的回答。这应该如何适应二维情况?我尝试将统一生成的矩阵类似地连接如下:统一生成矩阵matrix1matrix2,然后沿着axis=0np.zerosmatrix1np.zerosmatrix2,在正确的维度,然后定义matrix3 = np.flipur(flipld(matrix2))matrix4 = np.flipur(flipld(matrix1)),并沿着axis=1连接上面的两个矩阵,最上面的np.zeros,然后是中间的np.zeros。但这似乎效果不佳。
    • 我猜,但是,没有必要将每个样本对应到一个整数索引?我的索引方式也如 Paul Panzer 的另一个答案所示。
    • @Sato 有必要将每个样本映射到具有0N-1 的整数索引。这就是fft/ifft 所期望的。我在另一个答案中看到了一个非零虚部,因此我不明白你为什么声称“它有效”。我强烈建议您先熟悉 1D 案例,然后再进行 2D。完成此操作后,进行 2D 案例将是一个简单(尽管乏味)的练习。
    • 当我调整连接数组的方式并取x_min, x_max, interval_x = -10, 10, 10000时,实部的数量级为1e-1,而虚部的数量级为1e-19,所以我想有人可能会说它通过将更多样本添加到一个狭窄的范围内起作用了吗?
    • 谢谢。我将尝试先更仔细地查看 1D 案例。
    【解决方案2】:

    连接时需要更加小心:

    phi1 = np.random.rand(int(interval_x)//2-1)
    phi = np.concatenate(([0], phi1, [0], -phi1[::-1]))
    

    第一个元素是偏移量(零频率模式)。 “负”频率出现在中点之后。

    这给了我

    【讨论】:

    • 不同的是我在 0 做镜像:phi1, phi2, phi3 -> -phi3,-phi2,-phi1,0,phi1,phi2,phi3 等. (它环绕零的左边),你在两个网格点之间进行:phi1,phi2,phi3 -> -phi3,-phi2,-phi1,phi1,phi2,phi3 这不是 fft 中频率的排列方式。
    • 我明白了。那么左边的第一个 [0] 呢?我知道如果没有最左边的 [0],维度就不会是正确的,但为什么它必须为零呢?
    • 我说的零是左零。按照惯例,那个零剩下的所有东西都在最后。仅当 fft 的阶数为偶数时才会出现另一个零。它必须为零,因为它与 phi 和 -phi 的模式相同(它在 n/2,所以你会得到类似 exp(2pi k(n/2)/n) 的东西,它恰好与exp(2pi k(-n/2)/n)
    • 谢谢。以及如何将其调整为二维情况?我尝试用以下方式类似地连接统一生成的矩阵:统一生成矩阵matrix1matrix2,然后沿着axis=0np.zerosmatrix1np.zerosmatrix2连接,在正确的维度上,然后定义matrix3 = np.flipur(flipld(matrix2))matrix4 = np.flipur(flipld(matrix1)),并沿着axis=1连接上面的两个矩阵,最上面的np.zeros,然后是中间的np.zeros。但这似乎效果不佳。
    • 我将这些矩阵中的每一个都翻转了两次,因为根据数学计算,phi(-k) = -phi(k),当 k 是多维时,“另一边的元素"应该对应于关于“原点”的镜像,k = (0,0)。
    猜你喜欢
    • 2011-07-12
    • 2017-09-14
    • 2012-12-10
    • 2010-12-13
    • 2013-03-31
    • 2012-05-25
    • 2015-08-19
    • 2020-03-29
    • 1970-01-01
    相关资源
    最近更新 更多