timon_timonich


Заметки суриката

Я в этой жизни ничего не добился. Зато сам!


Previous Entry Share Next Entry
PHP. Линейная интерполяция или если по-русски красивое сглаживание графиков
timon_timonich
Закончил почти 9 часовое сражение с невообразомой херней, так как херня была крайне не стандартная, то решил поделиться с миром.

Вообще, вначале хотел пост обозвать  "Линейная интерполяция или Интерполяционный многочлен Лагранжа", но я сам толком не понимаю что это значит.

Работаю в данный момент над одним крупным проектом аналитической системы, как и в любой системе, здесь дофига графиков. Ниже пример.  



Ну график как график, куча значений и все такое, но вот прибило заказчику, хочу говорит, сглаженный график как в Экселе и все тут. И подкинул он мне мило ссылочку на википедию Интерполяционный_многочлен_Лагранжа Как бы я тоже слегка прибалдел, когда прочитал что от меня хотят. Ну думаю, ладно, фик с вами в интернете явно что-то есть готовое... Я искал долго, очень долго и самое забавное нифига не нашел, было пара решений на Си, но там использовались встроенные библиотеки. Долго думал что делать, потом подсказали, что на странице википедии, как бы есть код на Си, который можно легко переписать на PHP. Код мелкий, 24 строки всего, быстренько переделал и получилось вот что...



Обрадовался, показываю заказчику, на что мне выдается ответ, а чего по бокам прыжки огромные? Ну думаю жопа. Все вроде бы по формуле, что делать не особо понятно. Ладно, будем копать дальше. Вначале был найден эксельный файл, который тоже умеет это делать, но как оттуда выцепить алгоритм непонятно, да и вообще мне кажется, что в экселе это какие-то встроенные функции. Дальше наткнулся на очень прикольный проект на яваскрипте JSXGraph Надо будеть взять на заметку и попользовать его функционал в будущем. Тут я тоже нашел рабоющий пример интерполяции и решил переписать метод отсюда, в результате кстати получилось почти тоже самое что и на графике выше. Совсем я погрустнел, и пересмотрел множество запасных решений, нашел пару модулей для Perl, пытался найти консольную утилиту через которую можно было бы тоже данные подцепить, но ничего не получилось.. После долгих экспериментов выяснилось что если клонировать первичное и конечное значение в массиве координат, то крайние пики очень сильно сглаживаются. На выходе у меня получился вот такой вот график.  



Как видите пиков нет, все плавненько. Степень скругления можно задавать в параметре функции.. Код прилагаю снизу, в принципе все понятно. Пишу на случай, вдруг кому пригодится, чтобы не мучился как я..
/* значит так, входящие параметры это координаты Y и X для которого получаем Y
* массив координат x строится автоматом так как он у меня всегда массив [0 - кол-во значений Y]
* smooth - степень скругления, иначе на концах графика у нас огромные скачки...
*/
function lagrange_polynomial($y, $argx, $smooth = 10 ) { $num = 0; $denom = 0;     $x = range( -1*$smooth, count($y) + $smooth + 1 ); $last = $y[count($y)-1];   for( $i=1;$i<=$smooth;$i++) { $y[] = $y[0]; array_unshift( $y, $last); }   $len = count($y);   for ($i=0;$i<$len;$i++) { $w[$i] = 1.0; $xi = $x[$i]; for ($k=0;$k<$len;$k++) if ($k!=$i) { $w[$i] *= ($xi-$x[$k]); } $w[$i] = 1/$w[$i]; }   for ($i=0;$i<$len;$i++) { $xi = $x[$i]; if ( $argx==$xi ) { return $y[$i]; } else { $s = $w[$i]/( $argx-$xi ); $denom += $s; $num += $s*$y[$i]; } }   return $num/$denom; }
з.ы. Сервис для подсветки PHP код я искал дольше чем писал эту заметку, но все таки нашел http://highlight.hohli.com/ всем советую, отличный сервис!

?

Log in