如何使用scipy.curve_fit将Python中的实验数据拟合为有限定义区域的反三角函数?

时间:2019-06-12 13:28:03

标签: python scipy trigonometry scipy-optimize

我正在尝试使用一个包含反正弦余弦函数的参数将一些实验数据拟合到非线性函数,因此,其定义范围从-1限制为-1。我使用scipy的curve_fit查找函数的参数,但返回以下错误:

RuntimeError: Optimal parameters not found: Number of calls to function has reached maxfev = 400.

我要适合的功能是这个:

def fitfunc(x, a):
    y = np.rad2deg(np.arccos(x*np.cos(np.deg2rad(a))))
    return y

为进行拟合,我为x和y分别提供了一个numpy数组,其中包含度值(这就是为什么函数包含往返弧度的转换)。

param, param_cov = curve_fit(fitfunc, xs, ys)

当我使用其他拟合函数(例如多项式)时,curve_fit返回一些值,仅当我使用包含反正弦余弦的函数时,才会出现上述错误。

我怀疑它不能适合数据点,因为根据反正弦余弦函数的参数,某些数据点不位于反正弦余弦的定义区域内。我尝试提高次数迭代(maxfev),但没有成功。

样本数据:

ys = np.array([113.46125, 129.4225, 140.88125, 145.80375, 145.4425, 
              146.97125, 97.8025, 112.91125, 114.4325, 119.16125, 
              130.13875, 134.63125, 129.4375, 141.99, 139.86, 
              138.77875, 137.91875, 140.71375])

xs = np.array([2.786427013, 3.325624466, 3.473013087, 3.598247534, 4.304280248,
               4.958273121, 2.679526725, 2.409388637, 2.606306639, 3.661558062,
               4.569923009, 4.836843789, 3.377013596, 3.664550526, 4.335401233,
               3.064199519, 3.97155254, 4.100567011])

1 个答案:

答案 0 :(得分:2)

正如HS-nebula在他的评论中所述,您需要定义a0的初始值a作为曲线拟合的开始猜测。此外,选择a0时要特别小心,因为np.arcos()仅在[-1,1]中定义,并且选择错误的a0会导致错误。

import numpy as np
from scipy.optimize import curve_fit

ys = np.array([113.46125,  129.4225, 140.88125, 145.80375,  145.4425, 146.97125,  
                 97.8025, 112.91125,  114.4325, 119.16125, 130.13875, 134.63125,
                129.4375,    141.99,    139.86, 138.77875, 137.91875, 140.71375])

xs = np.array([2.786427013, 3.325624466, 3.473013087, 3.598247534, 4.304280248, 4.958273121, 
               2.679526725, 2.409388637, 2.606306639, 3.661558062, 4.569923009, 4.836843789,
               3.377013596, 3.664550526, 4.335401233, 3.064199519, 3.97155254, 4.100567011])

def fit_func(x, a):
    a_in_rad         = np.deg2rad(a)
    cos_a_in_rad     = np.cos(a_in_rad)
    arcos_xa_product = np.arccos( x * cos_a_in_rad )
    return np.rad2deg(arcos_xa_product)

a0 = 80
param, param_cov = curve_fit(fit_func, xs, ys, a0, bounds = (0, 360))
print('Using curve we retrieve a value of a = ', param[0])

输出:

Using curve we retrieve a value of a =  100.05275506147824

但是,如果您选择a0=60,则会出现以下错误:

  

ValueError:残差在初始点不是有限的。

要能够使用具有所有a可能值的数据,建议使用HS-nebula进行规范化。