Как приспособить экспериментальные данные в Python к обратной тригонометрической функции с ограниченной областью определения, используя scipy.curve_fit? - PullRequest
0 голосов
/ 12 июня 2019

Я пытаюсь подогнать некоторые экспериментальные данные к нелинейной функции с одним параметром, который включает функцию арккосинуса, которая поэтому ограничена в своей области определения от -1 до 1. Я использую Scipy's 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 соответственнокоторые содержат значения в градусах (поэтому функция содержит преобразование в радианы и обратно).

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 Ответ

2 голосов
/ 14 июня 2019

Поскольку HS-туманность упоминается в его комментариях, вам нужно определить начальное значение 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-туманности .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...