修正贝塞尔函数的Gnuplot拟合
我想在gnuplot中拟合我的数据,拟合关系中有第二类修改的贝塞尔函数。让我们假设它看起来像这样:修正贝塞尔函数的Gnuplot拟合,gnuplot,curve-fitting,data-fitting,bessel-functions,Gnuplot,Curve Fitting,Data Fitting,Bessel Functions,我想在gnuplot中拟合我的数据,拟合关系中有第二类修改的贝塞尔函数。让我们假设它看起来像这样: f(x)= A*x + b*besselk(1,b) fit A*x + B "datafile" via A, B (我用matlab或倍频程写的,我想用拟合找到的系数是A和b,其中一个在贝塞尔中)。但问题是gnuplot没有修改第二类贝塞尔函数 有人知道我该怎么做吗?最佳拟合策略通常是将非线性或非多项式问题简化为线性或多项式问题。特别是,线性问题总是只有一个解。因此,我们将理想地拟合f(x
f(x)= A*x + b*besselk(1,b)
fit A*x + B "datafile" via A, B
(我用matlab或倍频程写的,我想用拟合找到的系数是A和b,其中一个在贝塞尔中)。但问题是gnuplot没有修改第二类贝塞尔函数
有人知道我该怎么做吗?最佳拟合策略通常是将非线性或非多项式问题简化为线性或多项式问题。特别是,线性问题总是只有一个解。因此,我们将理想地拟合
f(x)=A*x+B
,其中B=B*besy1(B)
-这是针对第二类贝塞尔函数的,关于第二类修改的贝塞尔函数,请参见下面的编辑,这在Gnuplot中不可用。你是这样做的:
f(x)= A*x + b*besselk(1,b)
fit A*x + B "datafile" via A, B
一旦你有了B
,你就可以找到B
,它对应于y=x*besy1(x)
与B
在x=B
的交点。因为besy1(x)
是振荡的,所以可能会有几个结果,但根据提供数据的范围,您可以选择正确的结果。假设通过拟合得到B=1.2
,则[0:10]
间隔中的交点如下所示:
plot [0:10] x*besy1(x), 1.2
如果您感兴趣的区域约为x=4.65
,其中有一个交叉点的大致位置,请查找准确的交叉点。x*besy1(x)
和B
之间的距离在该区域将接近零,因此距离平方可以用一条抛物线近似,该抛物线具有明确的最小值:
plot [4.6:4.7] (x*besy1(x)-1.2)**2
您的最佳x=b
是该最小值的位置。您可以将其导出为数据并拟合到抛物线f(x)=a2*x**2+b2*x+c2
,最小值由f'(x)=0
给出,即x=-b2/(2.*a2)
:
这为最小值的位置提供了x=4.65447163370989
,对应于b=b*besy1(b)
中的最佳b
其准确性取决于二次拟合的优度,而这又取决于x值的最小范围有多窄。在这种情况下,范围[4.6:4.7]
导致二次拟合非常好,但并不完美(可以进一步缩小范围):
编辑
对于第二类修改过的贝塞尔函数,或者Gnuplot中没有的其他复杂函数,可以使用外部解析器。例如,请参阅我关于如何使用外部python代码解析函数的回答:
您可以使用scipy
从我的另一个答案(文件名test.py
)中修改Python脚本来访问函数:
在Gnuplot中,将其用作
kn(n,x) = real(system(sprintf("python test.py %g %g", n, x)))
然后,以上所有步骤都可以工作,只需将
besy1(x)
替换为kn(1,x)
谢谢您的详细回复!这是一个有趣的方法,但是我认为你写的“besy1(x)”不是第二类的修改Bessel,而是第二类的Bessel。我检查了这一点,因为我同时使用了gnuplot和matlab(matlab中有besselk),没有得到比较接近的结果。所以我猜您编写的besselly实际上不是修改过的?从verson 5.0开始,gnuplot可以从二进制共享库(.So或.dll)导入函数。选中“帮助导入”。如果你的数据集很大,那可能会快得多。@Miguel,你的贝塞尔函数反转方案有点复杂。这在本质上是相同的,并且直接给出了精确的(高达gnuplots拟合精度)解决方案:如果bl
是bessel(b)
,只需将b设置为其近似值,并设置样本2;通过b@KarlRatzsch使用1:(bl)拟合贝塞尔(b)“+”,我知道这有点复杂,但我想避免使用非多项式表达式进行拟合,这依赖于具有良好的初始值,特别是对于振荡函数。当然,你的解决方案在这种情况下也会起作用。@Miguel:恰恰相反。您的解决方案需要精确选择适合的区域。Mine(即gnuplots拟合算法)会自动执行此操作,达到机器精度。它只需要一个起始值,而不是另一个解(振荡函数可能会出现这种情况)。您可以使用一个合适的数值替代修改后的贝塞尔函数。有许多数学“烹饪书”,为各种函数编译线性代数近似。其中一个例子是Willial Press等人的数字Recipes。它还有一个免费的第一版在线版本。其中有一章介绍了贝塞尔函数的所有变化。Gnuplot在内部以同样的方式实现了贝塞尔函数(以及其他函数)。
kn(n,x) = real(system(sprintf("python test.py %g %g", n, x)))