我正在尝试使用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)/dt
和d^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=2
和t=NDATA-1
,例如NBREAK=NDATA-2
和NCOEFFS=NDATA
)。这就是NAG库如何选择断点以获得插值拟合(意味着:通过数据点的拟合)。
关于c++ - 使用GNU科学库(GSL)使用间距不均匀的点绘制2D B样条曲线路径,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24194909/