使用GNU Scientific Library(GSL)使用不均匀间隔的点绘制2D B样条曲线路径

时间:2014-06-12 22:30:54

标签: c++ c gsl spline bspline

我试图使用GNU科学库(GSL)绘制从A到B的平滑路径。我使用的API返回一个不规则间隔的小数字(在本例中为8)点(红色),您可以在下图中看到:

returned points and desired result from GSL

紫色点表示我希望从GSL返回的点数。

首先,使用GSL可以获得这种2D B样条形状吗?我不太了解B-Splines,更不用说2D B-Splines。我能够显示运行的B-Splines示例here并创建一个平滑的.ps文件而没有问题,但该示例使用带有以下代码的统一断点:

/* use uniform breakpoints on [0, 15] */
gsl_bspline_knots_uniform(0.0, 15.0, bw);

在我的情况下,鉴于我给出的数据不稳定且间距不均匀,我是否必须使用非均匀结?我尝试使用gsl_bspline_knots(),以便在以下测试代码中使用非统一断点,但我真的不确定这是否是正确的方向。

#define NCOEFFS 8 // not sure what this number should be - number of data points?
#define NBREAK   (NCOEFFS - 2)
const size_t nbreak = NBREAK;

int main (void) {

    // (example code)...

    gsl_vector *non_uniform = gsl_vector_alloc(nbreak);

    // create some random breakpoint values
    for (i=0; i<nbreak; i++) {
        double val = gsl_ran_gaussian(r, 2.0);
        printf("val: %f\n", val);
        gsl_vector_set(non_uniform, i, val);
    }

    gsl_bspline_knots(non_uniform, bw);

    // (more example code)...
}

此外,如何在2D x / y坐标空间中翻译上述用于绘制B样条的示例?如果GNU Scientific Library不适合这个,有人可以推荐一个更合适的C / C ++库吗?

非常感谢任何方向的帮助或指示。

1 个答案:

答案 0 :(得分:2)

首先: 1D Basis splines

给定一组NBREAK个断点(t_1, ..., t_{NBREAK}),有NCOEFFS=NBREAK+2个三次b样条曲线组件B_j(t)。即使在断点处,这些函数及其一阶和二阶导数也始终是连续的。因此,线性组合f(t) = \sum m_j B_j(t)给出的任何拟合也将共享这些属性(类似于自然三次样条)。 b样条组件的数量NCOEFFS不必等于数据点的数量NDATA。如果NCOEFFS < NDATA,您将使用最小二乘最小化来获得拟合(GSL文档有一个很好的最小二乘计算示例,以获得b样条拟合here)。当数据包含噪音时,NCOEFFS < NDATA是不错的选择

系数的数量不等于断点数NCOEFFS=NBREAK+2的原因与在处理基准样条时未指定边界条件的事实有关。鉴于人们通常更熟悉自然三次样条,值得评论natural cubic splines强加边界条件d^2f(x)/dx^2=0。这就是为什么使用三次多项式基的任何自然三次样条的表示都会有NCOEFFS=NBREAKHere is a link非常好地解释了由三次多项式的系数给出的自由度的计数,这些系数表示b样条的自然和强加f(t)的连续性所需的方程的数量。 ,df(t)/dtd^2f(t)/dt^2)。

最后:使用b样条拟合参数曲线

你有一套&#34;数据&#34;点(x_1, y_1)....(x_{NDATA},y_{NDATA})并且您想要构建参数拟合P(t)=( f_1(t), f_2(t) )。如果NCOEFFS<NDATA(如果您仔细选择断点并NCOEFFS=N_DATA可以要求,则B样条拟合不会通过所有数据点)。在我的研究中,我只使用一维非参数拟合(y=f(x)),但我相信这个参数情况类似。我会尝试以下

步骤1:创建一组&#34;数据&#34;点(t, x) = {(1, x_1), (2, x_2)...(NDATA, x_{NDATA})}并使用gsl 1D b样条拟合它们。这种匹配将为您f_1(t) = sum_{i=1}^{NCOEFFS} mx_j B_j(t)提供t \in [1,NDATA]

第2步:现在构建一组&#34;数据&#34;点(t, y) = {(1, y_1), (2, y_2)...(NDATA, y_{NDATA})}并使用b样条拟合它们。这将为您f_2(t) = sum_{i=1}^{NCOEFFS} my_j B_j(t)提供t \in [1,NDATA]

现在绘制P(t)=( f_1(t), f_2(t) ), t \in [1,NDATA]。基本上,我在2个1D非参数拟合中绘制了2 D参数曲线问题(这是GSL提供的)。

最后一点是在步骤1和步骤2中选择断点(以及基础组件的数量NCOEFFS)。只要涵盖范围t\in[1, NDATA]NCOEFFS <= NDATA,断点的选择是任意的。我相信如果您选择断点为{1, 3, ..., NDATA-2, NDATA },则拟合将通过数据点(请注意我跳过了内部点t=2t=NDATA-1,以便NBREAK=NDATA-2NCOEFFS=NDATA)。这就是NAG库选择断点以获得插值拟合的含义(意思是:通过数据点的拟合)。