Интерполяция на PHP

231
10 мая 2018, 06:20

Найдена функция на другом ЯП и исправлена под ситаксис php.

function interpol_lagr($x, $y, $argx, $smooth = 10)
{
    $num = 0;
    $denom = 0;
    $last = $y[count($y) - 1];
    for ($i = 1; $i <= $smooth; $i++) {
        $y[] = $y[0];
        array_unshift($y, $last);
    }
    foreach ($x as $i => $o_x) {
        $w[$i] = 1.0;
        foreach ($x as $k => $d_x)
            if ($k != $i) {
                $w[$i] *= ($o_x - $d_x);
            }
        $w[$i] = 1 / $w[$i];
    }
    foreach ($x as $i => $o_x) {
        if ($argx == $o_x) {
            return $y[$i];
        } else {
            $s = $w[$i] / ($argx - $o_x);
            $denom += $s;
            $num += $s * $y[$i];
        }
    }
    return $num / $denom;
}

Вызов

foreach ($data_nx as $x) {
    $inter[$x] = interpol_lagr($data_x, $data_y, $x);
}

где $data_nx - новые значения абциссы $data_x - старые значения абцисc(Массив) $data_y - старые значения оординат.(Массив)

Данные

$data_x       $data_y
1517443199    10285.10000000
1517702399    9199.96000000
1517961599    7652.14000000
1518220799    8683.92000000
1518479999    8903.00000000
1518739199    10000.09000000
1518998399    10383.43000000
1519257599    10437.60000000
1519516799    9694.51000000
1519775999    10569.04000000

$data_nx - массив созданный на основе $data_x но с добавленными значениями

Примерно так, на скорую руку

$det = ($data_x[1] - $data_x[0]) / 2;
for ($i = $data_x[0]; $i <= $data_x[count($data_x) - 1]; $i = $i + $det) {
    $data_nx[] = $i;
}

Цель - получение сглаженного графика (Т.е. нахождение промежуточных значений для этого). Пока-что грешу на сам алгоритм.

Результат до/после интерполяции

UPD1: Найдена статья на хабре по теме https://habr.com/post/130873/

Answer 1

Полином Лагранжа для N+1 точек имеет N-ю степень, и при его расчёте с такими большими значениями x, как указано, может произойти переполнение или обнуление (если принять, что функция вообще реализована верно). Это легко проверить, выведя численные значения результата.

Answer 2
class CubicSpline extends SmoothCurve
{
    private $splines = array();
    public function setCoords(&$arCoords, $step = 1, $minX = -1, $maxX = -1)
    {
        $this->splines = array();
        if(count($arCoords) < 4)
        {
            $this->errMsg = 'Too few arguments: need 4 points at least.';
            return false;
        }
        $this->prepareCoords($arCoords, $step, $minX, $maxX);
        $this->buildSpline($this->arX, $this->arY, count($this->arX));
    }
    public function process()
    {
        for ($x = $this->minX; $x <= $this->maxX; $x += $this->step)
        {
            $this->arCoords[$x] = $this->funcInterp($x);
        }
        return $this->arCoords;
    }
    private function buildSpline($x, $y, $n)
    {
        for ($i = 0; $i < $n; ++$i)
        {
            $this->splines[$i]['x'] = $x[$i];
            $this->splines[$i]['a'] = $y[$i];
        }
        $this->splines[0]['c'] = $this->splines[$n - 1]['c'] = 0;
        $alpha[0] = $beta[0] = 0;
        for ($i = 1; $i < $n - 1; ++$i)
        {
            $h_i = $x[$i] - $x[$i - 1];
            $h_i1 = $x[$i + 1] - $x[$i];
            $A = $h_i;
            $C = 2.0 * ($h_i + $h_i1);
            $B = $h_i1;
            $F = 6.0 * (($y[$i + 1] - $y[$i]) / $h_i1 - ($y[$i] - $y[$i - 1]) / $h_i);
            $z = ($A * $alpha[$i - 1] + $C);
            $alpha[$i] = - $B / $z;
            $beta[$i] = ($F - $A * $beta[$i - 1]) / $z;
        }
        for ($i = $n - 2; $i > 0; --$i)
        {
            $this->splines[$i]['c'] = $alpha[$i] * $this->splines[$i + 1]['c'] + $beta[$i];
        }
        for ($i = $n - 1; $i > 0; --$i)
        {
            $h_i = $x[$i] - $x[$i - 1];
            $this->splines[$i]['d'] = ($this->splines[$i]['c'] - $this->splines[$i - 1]['c']) / $h_i;
            $this->splines[$i]['b'] = $h_i * (2.0 * $this->splines[$i]['c'] + $this->splines[$i - 1]['c']) / 6.0 + ($y[$i] - $y[$i - 1]) / $h_i;
        }
    }
    private function funcInterp($x)
    {
        $n = count($this->splines);
        if ($x <= $this->splines[0]['x']) 
        $s = $this->splines[1];
        else
        if ($x >= $this->splines[$n - 1]['x'])
        {
            $s = $this->splines[$n - 1];
        }
        else
        {
            $i = 0;
            $j = $n - 1;
            while ($i + 1 < $j)
            {
                $k = $i + ($j - $i) / 2;
                if ($x <= $this->splines[$k]['x']) $j = $k;
                else $i = $k;
            }
            $s = $this->splines[$j];
        }
        $dx = ($x - $s['x']);
        return $s['a'] + ($s['b'] + ($s['c'] / 2.0 + $s['d'] * $dx / 6.0) * $dx) * $dx;
    }
}

Код взят с http://ross.pp.ru/graph/. Спасибо, @Akina за направление в сторону сплайна.

Результат

READ ALSO
PHP подключение к socks5 прокси через curl

PHP подключение к socks5 прокси через curl

Пытаюсь подключиться к socks5 прокси через curl, однако получаю ответ SOCKS : authentication failedПопробовал подключиться к прокси-серверу через скрипт Powershell...

222
Надежный вызов ping6 из php

Надежный вызов ping6 из php

Для IPv4 есть Net_ping

200
homestead-laravel. PHPmyAdmin

homestead-laravel. PHPmyAdmin

Провозился с Homestead очень многоСмог в конце разобраться

219
Не заносятся данные таблицу MySQL

Не заносятся данные таблицу MySQL

Весь код ниже работает кроме последней строкиВсе переменные выводятся правильно, но не заносятся в БД

179