주어진 관측값
여기서
측정값 사이 구간에서
을 이용해서 smoothing spline을 구하자. 이 경우 한 구간에서 spline의 미분은 인접 spline 2차 계수의 선형보간으로 표현할 수 있다.
따라서
따라서 smoothing spline을 찾는 문제는
여기에 1차 도함수의 연속성을 요구하면
계속...
Ref: https://monoceros.physics.muni.cz/~jancely/NM/Texty/Numerika/CubicSmoothingSpline.pdf



struct Spline {
double x, y;
double a, b, c, d;
double eval(double t) {
return d + (c + (b + a*t)*t)*t;
}
void toBezier(const double h, CPoint Q[4]) {
double xp[4], yp[4];
toBezier(h, xp, yp);
for (int i = 0; i < 4; i++)
Q[i] = CPoint(int(xp[i]+.5), int(yp[i]+.5));
}
void toBezier(const double h, double xp[4], double yp[4]) {
xp[0] = x;
xp[1] = x + h/3;
xp[2] = x + 2*h/3;
xp[3] = x + h;
yp[0] = d;
yp[1] = d + c * h / 3;
yp[2] = d + (2 * c + b * h) * h / 3;
yp[3] = d + (c + (b + a * h) * h) * h;
}
};
void solveFiveDiag(std::vector<double> &u,
std::vector<double> &v,
std::vector<double> &w,
std::vector<double> &q)
{
const int n = u.size();
u[0] = 0; //u[1]은 외부에서;
v[1] = v[1]/u[1];
w[1] = w[1]/u[1];
for (int j = 2; j < n; j++) {
u[j] = u[j] - u[j-2] * w[j-2] * w[j-2] - u[j-1] * v[j-1] * v[j-1];
v[j] = (v[j] - u[j-1]*v[j-1]*w[j-1])/u[j];
w[j] = w[j] / u[j];
}
//forward substitution
q[1] = q[1] - v[0] * q[0];
for (int j = 2; j < n; j++)
q[j] = q[j] - v[j-1] * q[j-1] - w[j-2] * q[j-2];
for (int j = 1; j < n; j++)
q[j] = q[j] / u[j];
// back substitution
q[n] = 0;
// q[n-1]은 외부에서 정해짐;
for (int j = n-2; j > 0; j--)
q[j] = q[j] - v[j] * q[j+1] - w[j]*q[j+2];
}
std::vector<Spline> SmoothingSpline1(
std::vector<double> &x, //n+1
std::vector<double> &y, //n+1
std::vector<double> &sigma, //n+1
double alpha, double beta)
{
const int n = x.size()-1;
std::vector<Spline> S(x.size());
for (int i = x.size(); i-->0;)
S[i].x = x[i], S[i].y = y[i];
std::vector<double> h(n), r(x.size()), q(x.size()), u(n), v(n), w(n);
h[0] = x[1] - x[0];
r[0] = 3 / h[0];
r[n] = 0;
for (int i = 1; i < n; i++) {
h[i] = x[i+1] - x[i];
r[i] = 3/h[i];
q[i] = (y[i+1] - y[i])*r[i] - (y[i] - y[i-1])*r[i-1];
}
//
double mu = 2 * beta / (3 * alpha);
for (int i = 1; i < n; i++) {
double ui = SQR(r[i-1]) * sigma[i-1]
+ SQR(r[i-1] + r[i]) * sigma[i] + SQR(r[i]) * sigma[i+1];
u[i] = mu * ui + 2 * (x[i+1] - x[i-1]);
double vi = -(r[i-1] + r[i]) * r[i] * sigma[i]
- r[i] * (r[i] + r[i+1]) * sigma[i+1];
v[i] = mu * vi + h[i];
w[i] = mu * r[i] * r[i+1] * sigma[i+1];
}
solveFiveDiag(u, v, w, q);
S[0].d = S[0].y - mu * r[0] * q[1] * sigma[0];
double S1d = S[1].y - mu * ((-r[0] - r[1]) * q[1] + r[1] * q[2]) * sigma[1];
S[0].a = q[1] / (3 * h[0]);
S[0].b = 0;
S[0].c = (S1d - S[0].d) / h[0] - q[1] * h[0] / 3;
for (int j = 1; j < n; j++) {
S[j].a = (q[j+1] - q[j]) / (3 * h[j]);
S[j].b = q[j];
S[j].c = (q[j] + q[j-1]) * h[j-1] + S[j-1].c;
S[j].d = r[j-1] * q[j-1] - (r[j-1] + r[j]) * q[j] + r[j] * q[j+1];
S[j].d = y[j] - mu * S[j].d * sigma[j];
}
return S;
}
'Computational Geometry' 카테고리의 다른 글
Alpha Shape (1) | 2024.07.14 |
---|---|
Approximate Convex Hull (0) | 2024.06.29 |
Catmull-Rom Spline (2) (0) | 2024.06.21 |
Minimum Volume Box (0) | 2024.06.16 |
Natural Cubic Spline: revisited (0) | 2024.06.14 |