所以我得到了一个信号,我尝试使用两种我认为应该在数值上等效的方法来拟合曲线,但显然不是。

方法 1:通过最小二乘法显式拟合正弦曲线:

def curve(x, a0, a1, b1, a2, b2):
  return a0 + a1*np.cos(x/720*2*math.pi) + b1*np.sin(x/720*2*math.pi) + a2*np.cos(x/720*2*math.pi*2) + b2*np.sin(x/720*2*math.pi*2)

def fit_curve(xdata, ydata):
  guess = [10, 0, 0, 0, 0]
  params, params_covariance = optimize.curve_fit(curve, xdata, ydata, guess)
  return params, params_covariance

方法 2:使用内置 FFT 算法来做同样的事情 :
  f = np.fft.rfft(y,3)
  curve = np.fft.irfft(f, width)

我有两个问题。第一个是次要的,FFT 是“超出规模”,所以我应用了一个缩放因子 mean(y)/mean(curve) 来修复它,这有点小技巧。我不确定为什么会这样。

我的主要问题是我相信这些应该产生几乎相同的结果,但他们没有。显式拟合每次都会产生比 FFT 结果更紧密的拟合——我的问题是, 应该是吗?

最佳答案

可以使用线性代数找到离散傅立叶变换系数,但我认为只有更好地理解 DFT 才有用。下面的代码演示了这一点。找到正弦序列的系数和相位需要做更多的工作,但应该不会太难。代码注释中引用的维基百科文章可能会有所帮助。

请注意,不需要 scipy.optimize.curve_fit ,甚至不需要线性最小二乘法。事实上,虽然我在下面使用了 numpy.linalg.solve,但这是不必要的,因为 basis 是一个酉矩阵乘以比例因子。

from __future__ import division, print_function

import numpy

# points in time series
n= 101
# final time (initial time is 0)
tfin= 10

# *end of changeable parameters*

# stepsize
dt= tfin/(n-1)
# sample count
s= numpy.arange(n)
# signal; somewhat arbitrary
y= numpy.sinc(dt*s)
# DFT
fy= numpy.fft.fft(y)
# frequency spectrum in rad/sample
wps= numpy.linspace(0,2*numpy.pi,n+1)[:-1]

# basis for DFT
# see, e.g., http://en.wikipedia.org/wiki/Discrete_Fourier_transform#equation_Eq.2
# and section "Properties -> Orthogonality"; the columns of 'basis' are the u_k vectors
# described there
basis= 1.0/n*numpy.exp(1.0j * wps * s[:,numpy.newaxis])

# reconstruct signal from DFT coeffs and basis
recon_y= numpy.dot(basis,fy)

# expect yerr to be "small"
yerr= numpy.max(numpy.abs(y-recon_y))
print('yerr:',yerr)

# find coefficients by fitting to basis
lin_fy= numpy.linalg.solve(basis,y)

# fyerr should also be "small"
fyerr= numpy.max(numpy.abs(fy-lin_fy))
print('fyerr',fyerr)

在我的系统上,这给出了
yerr: 2.20721480995e-14
fyerr 1.76885950227e-13

在 Ubuntu 14.04 和 Python 2.7 和 3.4 上测试。

关于python - 傅立叶分量的FFT与最小二乘拟合?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23561856/

10-13 07:37