curve_fit failing on even a sine waveにも記載されているとおり、最小二乗法をもとにしたcurve_fitは(私は理論を含めた理由は理解できていませんが)正弦関数のフィッティングには向いていません。
よって代わりにFFTをベースにした方法でフィッティングするとよいでしょう。
以下はHow do I fit a sine curve to my data with pylab and numpy?の回答をもとにしたコード例です。
Python
1import numpy as np
2import matplotlib.pyplot as plt
3#from scipy.optimize import curve_fit
4import numpy, scipy.optimize
5
6
7# サンプルデータ
8x = np.arange(0,10, 0.1)
9y = 2 * np.sin(3 * x + 4) + 5
10
11
12def fit_sin(tt, yy):
13 '''Fit sin to the input time sequence, and return fitting parameters "amp", "omega", "phase", "offset", "freq", "period" and "fitfunc"'''
14 tt = numpy.array(tt)
15 yy = numpy.array(yy)
16 ff = numpy.fft.fftfreq(len(tt), (tt[1]-tt[0])) # assume uniform spacing
17 Fyy = abs(numpy.fft.fft(yy))
18 guess_freq = abs(ff[numpy.argmax(Fyy[1:])+1]) # excluding the zero frequency "peak", which is related to offset
19 guess_amp = numpy.std(yy) * 2.**0.5
20 guess_offset = numpy.mean(yy)
21 guess = numpy.array([guess_amp, 2.*numpy.pi*guess_freq, 0., guess_offset])
22
23 def sinfunc(t, A, w, p, c): return A * numpy.sin(w*t + p) + c
24 popt, pcov = scipy.optimize.curve_fit(sinfunc, tt, yy, p0=guess)
25 A, w, p, c = popt
26 f = w/(2.*numpy.pi)
27 fitfunc = lambda t: A * numpy.sin(w*t + p) + c
28 return {"amp": A, "omega": w, "phase": p, "offset": c, "freq": f, "period": 1./f, "fitfunc": fitfunc, "maxcov": numpy.max(pcov), "rawres": (guess,popt,pcov)}
29
30
31res = fit_sin(x, y)
32y_fit = res['fitfunc'](x)
33
34
35# グラフの描画
36plt.scatter(x, y, c="r", s=5, label="data")
37plt.plot(x, y_fit, c='b', linewidth=1, label="fitting")
38plt.legend()
39plt.show()

バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2022/10/17 10:13