[英]How can i optimize my sinus fitting when using bounds?
i'm trying to do a sinus-fit on a given part of a curve.我正在尝试对曲线的给定部分进行正弦拟合。 There a two restrictions.
有两个限制。 First the offset of my fitted sinus-curve should be 0, second the amplitude of my fitted sinus-curve should be identically to the minimum value of my original data.
首先我拟合的正弦曲线的偏移量应该是 0,其次我拟合的正弦曲线的幅度应该与我的原始数据的最小值相同。
When i'm using my code below, the fitting looks like in the picture i added ( 1 ).当我使用下面的代码时,配件看起来像我添加的图片 ( 1 )。 In my opinion the period of the sinus-function should be higher.
在我看来,窦函数的周期应该更高。 The fitted curve only matches at the minimum with my original data, the fitting-curve isn't wide enough.
拟合曲线仅与我的原始数据最低匹配,拟合曲线不够宽。 When i don't use the bounds for c and A my fitting looks good ( 2 ).
当我不使用 c 和 A 的边界时,我的拟合看起来不错( 2 )。 What am i doing wrong?
我究竟做错了什么? Is there a way to modify the fitting so that the sinus-curves fits better when using the bounds for A and c?
有没有办法修改拟合,以便在使用 A 和 c 的边界时正弦曲线更适合?
Edit: Something thing I mentioned is, that the fitting extremely depends on the start value of the amplitude (ff_guess).编辑:我提到的事情是,拟合非常依赖于振幅的起始值(ff_guess)。 When I manually change it to X (eg. 10 or 30), than the fitted sinus curve always shows an amplitude near to X (10.3 or 32.5).
当我手动将其更改为 X(例如 10 或 30)时,拟合的正弦曲线始终显示接近 X(10.3 或 32.5)的幅度。 Is there any setting I haven't considered yet, that prevents the optimizer from varying the amplitude value?
有没有我还没有考虑过的设置,可以防止优化器改变幅度值?
import matplotlib.pyplot as plt
from matplotlib.ticker import FormatStrFormatter
from matplotlib.pyplot import figure, rcParams
import numpy as np
from scipy.optimize import curve_fit
#Time
t = [313.544, 313.545, 313.546, 313.547, 313.548, 313.549, 313.55, 313.551, 313.552, 313.553, 313.554, 313.555, 313.556, 313.557, 313.558, 313.559, 313.56, 313.561, 313.562, 313.563, 313.564, 313.565, 313.566, 313.567,]
#y-Values
s = [0.911188, -0.43135, -1.80997, -3.27816, -4.85784, -6.59428, -8.2214, -9.53617, -10.6892, -11.6003, -12.0844, -12.0524, -11.9749, -11.4891, -10.6131, -9.49873, -8.1154, -6.41442, -5.09357, -3.99165, -2.72991, -1.71446, -0.56306, 0.440741]
#fourier frequency
ff = np.fft.fftfreq(len(t), (t[1]-t[0]))
#fourier amplitude
fa = abs(np.fft.fft(s, len(t)))
#Position of maximum Amplitude
pos_amax = np.argmax(fa[1:])+1
#Frequency at maximum Amplitude (w/2pi)
ff_max = abs(ff[pos_amax])
ff_guess = ff_max
T_guess = 1000/ff_max
#A_guess = np.std(s) *2. **0.5
A_guess = min(s)
#c_guess = np.mean(s)
c_guess = 0
#First Guess for all paramters
f_guess = np.array([A_guess, 2*np.pi*ff_guess, 0., c_guess])
#Sinus_Curve
def sin_func(t, A, w, phi, c):
return A * np.sin(w*t + phi) + c
#Defining Bounds for A and c
c_bound = 0.1
A_bound = min(s)
#Bounds Array for curve_fit
param_bounds=([1.01*A_bound, -np.inf, -np.inf, -1*c_bound],[0.99*A_bound, np.inf, np.inf, c_bound])
popt, pcov = curve_fit(sin_func, t, s, p0=f_guess, bounds=param_bounds, maxfev=10000000)
#popt, pcov = curve_fit(sin_func, t, s, p0=f_guess, maxfev=10000000)
#
A, w, phi, c = popt
f = w/(2.*np.pi)
T = 1000/f
t = np.array(t)
s = np.array(s)
plt.figure(1)
#Generate Sinus Function
s_fit = A * np.sin(w*t + phi) + c
#Plotting
rcParams['figure.figsize'] =10, 5
fig, ax = plt.subplots()
plt.plot(t, s, "b", label="Original")
plt.plot(t, s_fit, 'k--', label="Fitting")
ytitle='ytitle'
xtitle='xtitle'
ax.set(xlabel=xtitle, ylabel=ytitle)
ax.xaxis.set_major_formatter(FormatStrFormatter('%.2f'))
ax.yaxis.set_major_formatter(FormatStrFormatter('%.2f'))
ax.grid()
#Sidetext
ausgabe = ("Sinus-Fit \nAmplitude = {:.2f} m/s^2 \nPeriode = {:.2f} ms \nOffset = {:.2f} m/s^2".format(A, abs(T), c))
plt.text(0.795, 0.7, ausgabe, family="sans-serif", fontsize=10, ha='left', va='top', transform=fig.transFigure)
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.85, box.height])
plt.show()
If the amplitude is fixed and offset is supposedly zero, why fitting them in the first place.如果振幅是固定的并且偏移量应该为零,那么为什么首先要拟合它们。 Moreover, there is no need for fft to estimate parameters, as there is a simple linear method.
此外,fft 不需要估计参数,因为有一个简单的线性方法。
Looks like this:看起来像这样:
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
from scipy.integrate import cumtrapz
#Time
t = np.array([
313.544, 313.545, 313.546, 313.547, 313.548, 313.549, 313.55,
313.551, 313.552, 313.553, 313.554, 313.555, 313.556, 313.557,
313.558, 313.559, 313.56, 313.561, 313.562, 313.563, 313.564,
313.565, 313.566, 313.567
])
# ~t -= 313.544
#y-Values
s = np.array([
0.911188, -0.43135, -1.80997, -3.27816, -4.85784, -6.59428,
-8.2214, -9.53617, -10.6892, -11.6003, -12.0844, -12.0524,
-11.9749, -11.4891, -10.6131, -9.49873, -8.1154, -6.41442,
-5.09357, -3.99165, -2.72991, -1.71446, -0.56306, 0.440741
])
amp = np.max( np.abs( s ) )
def sine(t, w, f ):
return amp * np.sin( w * t + f )
Sy = cumtrapz( s, x=t, initial = 0 )
SSy = cumtrapz( Sy, x=t, initial = 0 )
VMXT = np.array( [ s, t, np.ones( len( t ) ) ] )
VMX = np.transpose( VMXT )
A = np.dot( VMXT, VMX )
SV = np.dot( VMXT, SSy )
AI = np.linalg.inv( A )
alpha = np.dot( AI , SV )
wstart = np.sqrt( -1 / alpha[0] )
VMXT = np.array( [ np.sin( wstart * t ), np.cos( wstart * t ) ] )
VMX = np.transpose( VMXT )
A = np.dot( VMXT, VMX )
SV = np.dot( VMXT, s )
AI = np.linalg.inv( A )
alpha = np.dot( AI , SV )
phistart = np.arctan2( alpha[1], alpha[0] )
op, cv = curve_fit( sine, t, s, p0=( wstart, phistart ) )
print( op )
yth = sine( t, *op )
fig = plt.figure()
ax = fig.add_subplot( 1, 1, 1 )
ax.plot( t, s )
ax.plot( t, yth )
plt.show()
Works just fine.工作得很好。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.