我正在尝试将模型拟合到我的风廓线数据集中,即不同海拔u(z)
的风速值z
。
该模型由两部分组成,我现在简化为:
u(z) = ust/k * ln(z/z0) for z < zsl
u(z) = a*z + b for z > zsl
在对数模型中,ust
和z0
是自由参数k
是固定的。 zsl
是表面层的高度,也不是先验的。
我想让这个模型适合我的数据,我已经尝试过不同的方法。到目前为止,我得到的最好结果是:
def two_layer(z,hsl,ust,z0,a,b):
return ust/0.4*(np.log(z/z0)) if z<hsl else a*z+b
two_layer = np.vectorize(two_layer)
def two_layer_err(p,z,u):
return two_layer(z,*p)-u
popt, pcov ,infodict, mesg, ier = optimize.leastsq(two_layer_err,[150.,0.3,0.002,0.1,10.],(wspd_hgt,prof),full_output=1)
# wspd_hgt are my measurements heights and
# prof are the corresponding wind speed values
这为我提供了所有参数的合理估计,除了zsl
,在拟合过程中没有改变。我想这与用作阈值而不是函数参数的事实有关。在优化过程中,有什么方法可以让zsl
变化吗?
我用numpy.piecewise尝试了一些东西,但是效果并不好,也许是因为我不太了解它,或者我可能完全离开这里因为它不适合我的事业。
对于这个想法,如果轴反转(z
绘制而不是u
),风廓线看起来像这样:
答案 0 :(得分:1)
我认为我终于有了解决这类问题的解决方案,我在回答similar question时遇到了。
解决方案似乎是在两个模型之间的切换处实施约束BehaviorRelay
。由于没有发布数据,因此我无法在您的模型上进行尝试,因此我将展示它在其他模型上的工作方式,并且您可以根据自己的情况进行调整。我使用编写的u1 == u2
包装器解决了这个问题,目的是使这种问题更加符合Python规范,称为scipy
。但是,如果愿意,您可以使用symfit
中的SLSQP算法来做同样的事情。
scipy
我认为您应该能够使此示例适应您的情况!
编辑:根据注释中的要求,也可以要求匹配的派生词。为此,上面的示例需要以下附加代码:
from symfit import parameters, variables, Fit, Piecewise, exp, Eq
import numpy as np
import matplotlib.pyplot as plt
t, y = variables('t, y')
m, c, d, k, t0 = parameters('m, c, d, k, t0')
# Help the fit by bounding the switchpoint between the models
t0.min = 0.6
t0.max = 0.9
# Make a piecewise model
y1 = m * t + c
y2 = d * exp(- k * t)
model = {y: Piecewise((y1, t <= t0), (y2, t > t0))}
# As a constraint, we demand equality between the two models at the point t0
# Substitutes t in the components by t0
constraints = [Eq(y1.subs({t: t0}), y2.subs({t: t0}))]
# Read the data
tdata, ydata = np.genfromtxt('Experimental Data.csv', delimiter=',', skip_header=1).T
fit = Fit(model, t=tdata, y=ydata, constraints=constraints)
fit_result = fit.execute()
print(fit_result)
plt.scatter(tdata, ydata)
plt.plot(tdata, fit.model(t=tdata, **fit_result.params).y)
plt.show()
这应该可以解决问题!因此,从编程的角度来看,这是非常可行的,尽管实际上取决于模型,实际上可能没有解决方案。