スプライン補間法とか

自分用メモ。

ラグランジュの補間法だと、たまに極端な山とかができてしまうので、スプラインにしてみる。

参考にしたのはここ。
補間法(スプライン)

ソースはこんな感じ。今度は線の描画付き。
[php]<?php $list = array(); for ($i=0;$i<=10;$i++) { $list = rand(1,9); }

$xx = $yy = array();

for ($i=0;$i<count($list);$i++) { $xx = $i * 20; $yy = $list[$i] * 10; }

$q = $r = $s = array(); spline_init(); for ($i=$xx[0];$i<=$xx[count($xx) - 1];$i++) { $xx2 = $i; $yy2[] = spline($i); }

$w = 200; $h = 100;

$im = imagecreatetruecolor($w, $h); $white = imagecolorallocate($im, 255, 255, 255); $black = imagecolorallocate($im, 0, 0, 0); $blue = imagecolorallocate($im, 0,0,255); imagefill($im, 0, 0, $white);

$x1 = $y1 = $x2 = $y2 = 0; for ($i=0;$i<count($xx2);$i++) {

$x1 = $x2; $y1 = $y2;

$x2 = $xx2[$i]; $y2 = $yy2[$i];

if ($i == 0) { continue; } imageline($im, $x1, $y1, $x2, $y2, $black);

}

for ($i=0;$i<count($xx);$i++) {

$x1 = $x2; $y1 = $y2;

$x2 = $xx[$i]; $y2 = $yy[$i];

if ($i == 0) { continue; } imageline($im, $x1, $y1, $x2, $y2, $blue); }

header('Content-Type: image/gif'); imagegif($im);

imagedestroy($im);

exit();

function spline_init() {

global $xx, $yy, $q, $r, $s;

$n = count($xx) - 1;

$h = $b = $d = $g = array();

for ($i=0;$i<$n;$i++) { $h[$i] = $xx[$i+1] - $xx[$i]; } for ($i=1;$i<$n;$i++) { $b[$i] = (double) 2.0 * ($h[$i] + $h[$i-1]); $d[$i] = (double) 3.0 * *1; return $res; }[/php]

*1:$yy[$i+1] - $yy[$i]) / $h[$i] - ($yy[$i] - $yy[$i-1]) / $h[$i-1]); }

$g[1] = $h[1] / $b[1]; for ($i=2;$i<$n - 1;$i++) { $g[$i] = $h[$i] / ($b[$i] - $h[$i-1] * $g[$i-1]); } $u[1] = $d[1] / $b[1]; for ($i=2;$i<$n;$i++) { $u[$i] = ($d[$i]- $h[$i-1] * $u[$i-1]) / ($b[$i] - $h[$i-1] * $g[$i-1]); }

$r[0] = $r[$n] = (double) 0.0; $r[$n-1] = $u[$n-1]; for ($i=$n - 2;$i >= 1; $i--) { $r[$i] = $u[$i] - $g[$i] * $r[$i+1]; }

for ($i=0;$i<$n;$i++) { $q[$i] = (double) ($yy[$i+1] - $yy[$i]) / $h[$i] - $h[$i] * ($r[$i+1] + 2.0 * $r[$i]) / 3.0; $s[$i] = (double) ($r[$i+1] - $r[$i]) / (3.0 * $h[$i]); }

return; }

function spline($x) { global $xx, $yy, $q, $r, $s; $n = count($xx) - 1; $m = -1; for ($i=1;$i<$n && $m < 0;$i++) { if ($x < $xx[$i]) { $m = $i - 1; } } if ($m < 0) { $m = $n - 1; }

$x2 = $x - $xx[$m]; $res = $yy[$m] + $x2 * ($q[$m] + $x2 * ($r[$m] + $s[$m] * $x2