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

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

首先,可以使用GSL获得这种2D B样条曲线形状吗?我对B样条线了解不多,更不用说2D B样条线了。我能够获得显示的here的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科学库不适合这样做,那么有人可以推荐一个更合适的C/C++库吗?

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

最佳答案

第一:一维基础样条曲线

给定一组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=NBREAK的原因。 Here is a link很好地解释了由表示自然b样条的三次多项式的系数所给出的自由度的计数以及施加f(t)df(t)/dtd^2f(t)/dt^2的连续性所必需的方程数。

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

您拥有一组“数据”点(x_1, y_1)....(x_{NDATA},y_{NDATA}),并且想要构造一个参数拟合P(t)=( f_1(t), f_2(t) )。如果使用NCOEFFS<NDATA,B样条曲线拟合将不会遍历所有数据点(如果您仔细选择断点和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非参数拟合(这是GSL提供的)来绘制2D参数曲线问题。

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

关于c++ - 使用GNU科学库(GSL)使用间距不均匀的点绘制2D B样条曲线路径,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24194909/

10-11 15:24