将边界应用于Scipy优化Curvefit

时间:2018-10-08 13:58:46

标签: python numpy scipy curve-fitting

我正在尝试将简单的正弦波拟合到数据并应用边界以帮助约束拟合。

我使用的是发布在here上的第二个答案,该答案很好用,但是当我按照惯例应用范围时,例如:

def fit_sin(tt, yy):
    import scipy.optimize
    import numpy as np
    '''
    Fit sin to the input time sequence, and return dict of fitting parameters:
    "amp", "omega", "phase", "offset", "freq", "period" and "fitfunc"
    '''
    tt = np.array(tt)
    yy = np.array(yy)
    ff = np.fft.fftfreq(len(tt), (tt[1]-tt[0]))   # assume uniform spacing
    Fyy = abs(np.fft.fft(yy))
    guess_freq = abs(ff[np.argmax(Fyy[1:])+1])   # excluding the zero frequency "peak", which is related to offset
    guess_amp = np.std(yy) * 2.**0.5
    guess_offset = np.mean(yy)
    guess = np.array([guess_amp, 2.*np.pi*guess_freq, 0., guess_offset])

    def sinfunc(t, A, w, p, c):  return A * np.sin(w*t + p) + c
    boundary = ([-np.inf, -np.inf, -np.pi, -np.inf],[np.inf, np.inf, np.pi, np.inf])
    popt, pcov = scipy.optimize.curve_fit(sinfunc, tt, yy, p0=guess, bounds=boundary)
    A, w, p, c = popt
    f = w/(2.*np.pi)
    fitfunc = lambda t: A * np.sin(w*t + p) + c
    return {"amp": A, "omega": w, "phase": p, "offset": c, "freq": f, "period": 1./f, "fitfunc": fitfunc, "maxcov": np.max(pcov), "rawres": (guess,popt,pcov)}

我遇到以下错误:

RuntimeError: Optimal parameters not found: The maximum number of function evaluations is exceeded.

如果将边界设置为无穷大,并且将边界线更改为简单,

boundary = ([-np.inf, -np.inf, -np.inf, -np.inf],[np.inf, np.inf, np.inf, np.inf])

该功能有效。

要测试该功能,您可以执行以下操作:

import pylab as plt

N, amp, omega, phase, offset, noise = 500, 1., 2., .5, 4., 3
#N, amp, omega, phase, offset, noise = 50, 1., .4, .5, 4., .2
#N, amp, omega, phase, offset, noise = 200, 1., 20, .5, 4., 1
tt = numpy.linspace(0, 10, N)
tt2 = numpy.linspace(0, 10, 10*N)
yy = amp*numpy.sin(omega*tt + phase) + offset
yynoise = yy + noise*(numpy.random.random(len(tt))-0.5)

res = fit_sin(tt, yynoise)
print( "Amplitude=%(amp)s, Angular freq.=%(omega)s, phase=%(phase)s, offset=%(offset)s, Max. Cov.=%(maxcov)s" % res )

plt.plot(tt, yy, "-k", label="y", linewidth=2)
plt.plot(tt, yynoise, "ok", label="y with noise")
plt.plot(tt2, res["fitfunc"](tt2), "r-", label="y fit curve", linewidth=2)
plt.legend(loc="best")
plt.show()

尤其是我只是试图将拟合的阶段p限制在-np.pinp.pi之间,其他阶段可以是无穷大。

我在此功能上使用的实际数据是干净的,并且拟合很快且确实准确,但是当数据开始于+/- {{ 1}},它将适合np.pi淘汰。

我也不能手动捕获它,因为它适合成千上万个数据集,而我正在研究它们之间的相对相位差。

任何帮助表示感谢,谢谢。

1 个答案:

答案 0 :(得分:1)

我修复了该问题,对于一个引起麻烦的特定数据集,我的功能是拟合负振幅,然后迫使我的相位值比预期大np.pi

对于那些在正弦波拟合方面遇到类似麻烦的人,我将在这里留下这个答案!