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

Mic*_*rie 7 c c++ spline gsl bspline

我正在尝试使用GNU科学库(GSL)绘制从A到B的平滑路径.我正在使用一个返回少量(在这种情况下为8)不规则间隔点(红色)的API,你可以在下图中看到:

返回点和GSL的预期结果

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

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

/* use uniform breakpoints on [0, 15] */
gsl_bspline_knots_uniform(0.0, 15.0, bw);
Run Code Online (Sandbox Code Playgroud)

在我的情况下,鉴于我给出的数据不稳定且间距不均匀,我是否必须使用非均匀结?我尝试使用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)...
}
Run Code Online (Sandbox Code Playgroud)

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

任何帮助或方向的指示将非常感激.

Viv*_*nda 3

第一:一维基础样条

给定一组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 样条拟合)。NCOEFFS < NDATA当数据包含噪声但似乎不属于您的情况时,这是一个不错的选择

系数数量不等于断点数量 的原因NCOEFFS=NBREAK+2与处理基础样条时未指定边界条件有关。鉴于人们通常更熟悉自然三次样条,值得评论的是自然三次样条施加了边界条件d^2f(x)/dx^2=0。这就是为什么使用三次多项式基础的自然三次样条的任何表示都将具有NCOEFFS=NBREAK这里有一个关于计算三次多项式系数给出的自由度的非常好的解释的链接,三次f(t)多项式系数代表自然的 b 样条曲线和强制、df(t)/dt和)连续性所需的方程数量d^2f(t)/dt^2

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

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

步骤 1:创建“数据”点集(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:现在构建“数据”点集(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=2等)。这就是NAG库选择断点以获得插值拟合的方式(意思是:通过数据点的拟合)。t=NDATA-1NBREAK=NDATA-2NCOEFFS=NDATA