计算FFT幅度的不确定度

use*_*448 10 python numpy fft uncertainty

我的Python编程问题如下:

我想创建一个测量结果数组.每个结果可以描述为正态分布,其中平均值是测量结果本身,标准偏差是其不确定性.

伪代码可以是:

x1 = N(result1, unc1)
x2 = N(result2, unc2)
...

x = array(x1, x2, ..., xN)
Run Code Online (Sandbox Code Playgroud)

比我想计算x 的FFT:

f = numpy.fft.fft(x)
Run Code Online (Sandbox Code Playgroud)

我想要的是x中包含的测量的不确定性是通过FFT计算传播的,因此f是一个幅度阵列及其不确定性,如下所示:

f = (a +/- unc(a), b +/- unc(b), ...)
Run Code Online (Sandbox Code Playgroud)

你能建议我这样做吗?

War*_*ser 14

通过阵列的离散傅立叶变换计算的每个傅里叶系数x是元素的线性组合x; 请参阅维基百科页面上关于离散傅立叶变换的 X_k公式,我将其写为

X_k = sum_(n=0)^(n=N-1) [ x_n * exp(-i*2*pi*k*n/N) ]
Run Code Online (Sandbox Code Playgroud)

(也就是说,X是离散傅立叶变换x.)如果x_n正态分布为均值mu_n和方差sigma_n**2,那么一小部分代数表明X_k的方差是x_n的方差之和

Var(X_k) = sum_(n=0)^(n=N-1) sigma_n**2
Run Code Online (Sandbox Code Playgroud)

换句话说,每个傅立叶系数的方差是相同的; 它是测量方差的总和x.

用你的符号,unc(z)标准偏差在哪里z,

unc(X_0) = unc(X_1) = ... = unc(X_(N-1)) = sqrt(unc(x1)**2 + unc(x2)**2 + ...)
Run Code Online (Sandbox Code Playgroud)

(注意,X_k 的大小分布Rice分布.)

这是一个演示此结果的脚本.在此示例中,x值的标准偏差从0.01线性增加到0.5.

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


np.random.seed(12345)

n = 16
# Create 'x', the vector of measured values.
t = np.linspace(0, 1, n)
x = 0.25*t - 0.2*t**2 + 1.25*np.cos(3*np.pi*t) + 0.8*np.cos(7*np.pi*t)
x[:n//3] += 3.0
x[::4] -= 0.25
x[::3] += 0.2

# Compute the Fourier transform of x.
f = fft(x)

num_samples = 5000000

# Suppose the std. dev. of the 'x' measurements increases linearly
# from 0.01 to 0.5:
sigma = np.linspace(0.01, 0.5, n)

# Generate 'num_samples' arrays of the form 'x + noise', where the standard
# deviation of the noise for each coefficient in 'x' is given by 'sigma'.
xn = x + sigma*np.random.randn(num_samples, n)

fn = fft(xn, axis=-1)

print "Sum of input variances: %8.5f" % (sigma**2).sum()
print
print "Variances of Fourier coefficients:"
np.set_printoptions(precision=5)
print fn.var(axis=0)

# Plot the Fourier coefficient of the first 800 arrays.
num_plot = min(num_samples, 800)
fnf = fn[:num_plot].ravel()
clr = "#4080FF"
plt.plot(fnf.real, fnf.imag, 'o', color=clr, mec=clr, ms=1, alpha=0.3)
plt.plot(f.real, f.imag, 'kD', ms=4)
plt.grid(True)
plt.axis('equal')
plt.title("Fourier Coefficients")
plt.xlabel("$\Re(X_k)$")
plt.ylabel("$\Im(X_k)$")
plt.show()
Run Code Online (Sandbox Code Playgroud)

打印输出是

Sum of input variances:  1.40322

Variances of Fourier coefficients:
[ 1.40357  1.40288  1.40331  1.40206  1.40231  1.40302  1.40282  1.40358
  1.40376  1.40358  1.40282  1.40302  1.40231  1.40206  1.40331  1.40288]
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,傅立叶系数的样本方差全部(近似)与测量方差的总和相同.

这是脚本生成的图.黑色钻石是单个x矢量的傅里叶系数.蓝点是800实现的傅里叶系数x + noise.您可以看到每个傅立叶系数周围的点云大致对称并且具有相同的"大小"(当然,除了真实系数之外,在该图中显示为实轴上的水平线).

傅里叶系数的图