1次元ガウシアンのスプライン補間を試す
スプライン補間とは、グラフ上の点を多項式を用いて曲線をでつなぐアルゴリズムで、 3次関数を用いる3次スプライン補間が一般的です。 本稿では、次式で与えられる1次元ガウシアンを、与えられた10点を用いてスプライン補間を行います。
式(1)で与えられるガウシアンから10点を用意し、この点を用いてスプライン補間を行います。
計算結果
赤線は式(1)の、青の四角は与えた10点、
青線が与えた10点を用いたスプライン補間。
おおよそ、元のガウシアンと一致していることがわかります。
スプライン補間に関する参考ページ
■ 3次スプライン補間法(横田壽 氏)
■ 3 スプライン補間(山本昌志 氏)
C言語プログラムソース
中心アルゴリズムはpspline.c -- スプライン補間(Hidekazu Ito 氏)から拝借しております。
/*
1次元ガウス分布のスプライン補間
(2012.01.01)
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>
#include <fstream>
using namespace std;
/***********************************************************
pspline.c -- スプライン補間
Hidekazu Ito 氏
http://chaste.web.fc2.com/Reference.files/Algo.html
***********************************************************/
/* 周期関数用 */
#define N 10
double xs[N + 1],
ys[N + 1],
zs[N + 1];
void maketable(double xs[], double ys[], double zs[])
{
int i;
double t;
static double h[N + 1], d[N + 1], w[N + 1];
for (i = 0; i < N; i++) {
h[i] = xs[i + 1] - xs[i];
w[i] = (ys[i + 1] - ys[i]) / h[i];
}
w[N] = w[0];
for (i = 1; i < N; i++) d[i] = 2 * (xs[i + 1] - xs[i - 1]);
d[N] = 2 * (h[N - 1] + h[0]);
for (i = 1; i <= N; i++) zs[i] = w[i] - w[i - 1];
w[1] = h[0]; w[N - 1] = h[N - 1]; w[N] = d[N];
for (i = 2; i < N - 1; i++) w[i] = 0;
for (i = 1; i < N; i++) {
t = h[i] / d[i];
zs[i + 1] = zs[i + 1] - zs[i] * t;
d[i + 1] = d[i + 1] - h[i] * t;
w[i + 1] = w[i + 1] - w[i] * t;
}
w[0] = w[N]; zs[0] = zs[N];
for (i = N - 2; i >= 0; i--) {
t = h[i] / d[i + 1];
zs[i] = zs[i] - zs[i + 1] * t;
w[i] = w[i] - w[i + 1] * t;
}
t = zs[0] / w[0]; zs[0] = t; zs[N] = t;
for (i = 1; i < N; i++)
zs[i] = (zs[i] - w[i] * t) / d[i];
}
double spline(double t, double xs[], double ys[], double zs[])
{
int i, j, k;
double d, h, period;
period = xs[N] - xs[0];
while (t > xs[N]) t -= period;
while (t < xs[0]) t += period;
i = 0; j = N;
while (i < j) {
k = (i + j) / 2;
if (xs[k] < t) i = k + 1; else j = k;
}
if (i > 0) i--;
h = xs[i + 1] - xs[i];
d = t - xs[i];
return (((zs[i + 1] - zs[i]) * d / h + zs[i] * 3) * d
+ ((ys[i + 1] - ys[i]) / h
- (zs[i] * 2 + zs[i + 1]) * h)) * d + ys[i];
}
int main(void)
{
//1次元ガウシアン
ofstream ofs( "Gaussian1.data" );
for (int i=0; i<=N; i++)
{
xs[i] = -1.0 + 2.0 * double(i)/double(N);
ys[i] = exp( -10.0 * pow(xs[i],2));
ofs << xs[i] << " " << ys[i] << endl;
}
ofs.close();
maketable(xs, ys, zs);
ofstream ofs1_2( "Gaussian1_2.data" );
for (double x = -1.0; x <= 1.0; x+=0.01)
{
ofs1_2 << x << " " << exp( -10.0 * pow(x,2)) << " " << spline(x, xs, ys, zs) << endl;
}
ofs1_2.close();
}



