8

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

从 GSL 返回的点数和期望的结果

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

首先,这种 2D B-Spline 形状是否可以通过使用 GSL 获得?我对 B-Splines 了解不多,更不用说 2D B-Splines。我能够让此处显示的 B-Splines 示例运行并毫无问题地创建平滑的 .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++ 库吗?

任何有关方向的帮助或指示将不胜感激。

4

1 回答 1

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

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

最后:使用 b-splines 拟合参数曲线

您拥有一组“数据”点(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-splines 来拟合它们。这适合会给你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 非参数拟合(这是 GSL 提供的)中映射了 2D 参数曲线问题。

最后一点是第1步和第2步中断点的选择(以及基分量的个数NCOEFFS)。只要覆盖范围t\in[1, NDATA]NCOEFFS <= NDATA,断点的选择是任意的。我相信,如果您选择{1, 3, ..., NDATA-2, NDATA }适合的断点,则将通过数据点(请注意,我跳过了内部点等t=2and )。这就是NAG库如何选择断点来获得插值拟合(意思是:通过数据点的拟合)。t=NDATA-1NBREAK=NDATA-2NCOEFFS=NDATA

于 2014-06-14T07:09:08.480 回答