Подгонка Gnuplot с модифицированными функциями Бесселя

Я хочу подогнать свои данные в gnuplot с подходящим отношением, в котором есть модифицированная функция Бесселя 2-го типа. Допустим, это выглядит примерно так:

f(x)= A*x + b*besselk(1,b)

(Я написал это в терминах matlab или октавы, а коэффициенты, которые я хочу найти с подгонкой, - это A и b, поэтому один из них находится IN the bessel). Но проблема в том, что gnuplot не имеет модифицированной функции bessel 2-го типа.

Кто-нибудь знает, как я могу это сделать?


person Poisonedhoney    schedule 15.08.2015    source источник
comment
Вы можете использовать подходящий числовой заменитель модифицированной функции Бесселя. Существует ряд кулинарных книг по математике, в которых собраны линейно-алгебраические приближения для всех видов функций. Одним из примеров является Числовые рецепты Виллиала Пресса и др. У него также есть веб-сайт с бесплатной онлайн-версией первого издания. В ней есть глава со всеми вариациями функций Бесселя. Gnuplot внутренне реализовал функцию Бесселя (и другие) аналогичным образом.   -  person Karl    schedule 16.08.2015


Ответы (1)


Лучшая подходящая стратегия - обычно сводить вашу нелинейную или неполиномиальную задачу к линейной или полиномиальной. В частности, линейная задача всегда имеет одно-единственное решение. Таким образом, мы идеально подошли бы f(x) = A*x + B, где B = b * besy1(b) - это для функций Бесселя второго типа, см. Ниже правку для модифицированных функций Бесселя второго типа, которые недоступны в Gnuplot. Вы делаете это так:

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):

set table "data_minimum"
plot [4.6:4.7] (x*besy1(x)-1.2)**2
unset table
fit [4.6:4.7] a2*x**2 + b2*x + c2 "data_minimum" via a2,b2,c2
print -b2/2./a2

Это дает x = 4.65447163370989 для положения минимума, что соответствует оптимальному b в B = b*besy1(b).

Точность этого будет зависеть от качества квадратичной аппроксимации, которая, в свою очередь, будет зависеть от того, насколько узким является ваш диапазон значений x. В этом случае диапазон [4.6:4.7] привел к тому, что квадратичное соответствие было неплохим, но не идеальным (вы можете сузить его еще больше):

plot [4.6:4.7] "data_minimum" t "data", a*x**2+b*x+c t "quadratic fit"

введите описание изображения здесь

Изменить

Для модифицированных функций Бесселя второго типа или других сложных функций, недоступных в Gnuplot, вы можете использовать внешний синтаксический анализатор. Например, см. Мой ответ о том, как использовать внешний код Python для анализа функций: Передача Функции Python для Gnuplot.

Вы можете использовать scipy для доступа к своей функции, изменяя скрипт Python из моего другого ответа (имя файла test.py):

import sys
from scipy.special import kn as kn

n=float(sys.argv[1])
x=float(sys.argv[2])

print kn(n,x)

и в Gnuplot используйте это как

kn(n,x) = real(system(sprintf("python test.py %g %g", n, x)))

тогда вся вышеуказанная процедура работает, просто заменяя besy1(x) на kn(1,x).

person Miguel    schedule 15.08.2015
comment
Спасибо за подробный ответ! Это интересный подход, однако я думаю, что написанный вами besy1 (x) НЕ является модифицированным Бесселем 2-го типа, а просто Бесселем 2-го типа. И я проверил это, потому что я использовал и gnuplot, и matlab (в Matlab есть besselk) и не получил сравнительно близких результатов. Так что я предполагаю, что написанное вами бесселли на самом деле не является модифицированным? - person Poisonedhoney; 15.08.2015
comment
Начиная с версии 5.0, gnuplot может импортировать функцию из двоичной разделяемой библиотеки (.so или .dll). Отметьте help import. Вероятно, это будет намного быстрее, если ваши наборы данных большие. - person Karl; 16.08.2015
comment
@Miguel, ваша схема инвертирования функции Бесселя немного сложна. Здесь это по сути то же самое и напрямую дает точное (с точностью до gnuplots) решение: если bl равно bessel(b), просто установите b на его приблизительное значение и выполните set sample 2; fit bessel(b)"+" using 1:(bl) via b. - person Karl; 16.08.2015
comment
@KarlRatzsch Я знаю, что это немного сложно, но я не хотел полагаться на использование неполиномных выражений для подгонки, которые полагаются на наличие хороших начальных значений, в частности для колебательных функций. Но, конечно, ваше решение также подойдет и в этом случае. - person Miguel; 16.08.2015
comment
@ Мигель: Напротив. Для вашего решения необходим точный выбор региона для посадки. Mine (то есть алгоритм подгонки gnuplots) автоматически делает это с точностью до машинной точности. Ему нужно только начальное значение, которое не позволяет ему уйти для другого решения (что может случиться с колеблющейся функцией). - person Karl; 16.08.2015
comment
@KarlRatzsch Надеюсь, это разрешит спор. Как вы, наверное, знаете, gnuplot внутренне полагается на подход, очень похожий на мое решение: минимизация xi ^ 2. Ваше исходное предположение эквивалентно тому, что я даю диапазон, в котором есть минимум квадрата расстояния, только вы должны убедиться, что ваш минимум уникален в области соответствия, например выполнив fit [xmin:xman] ..., убедившись, что есть только один минимум между xmin и xmax. Я согласен с тем, что ваше решение более точное, но вы должны убедиться, что применимо последнее утверждение. - person Miguel; 16.08.2015
comment
Нет, вы неправильно понимаете мой подход. Я не даю диапазона для подгонки. Значения x, предоставленные +, даже не используются. То, что он делает, на самом деле даже не подходит, он использует процедуру соответствия для поиска минимум (bessel(b) - bl)². - person Karl; 16.08.2015
comment
Я понял это после того, как написал. В этом случае вы должны убедиться, что размер шага алгоритма поиска достаточно мал по сравнению с размером области, где есть только один минимум. - person Miguel; 16.08.2015