我试图使用GNU科学库(GSL)绘制从A到B的平滑路径。我使用的API返回一个不规则间隔的小数字(在本例中为8)点(红色),您可以在下图中看到:
紫色点表示我希望从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 ++库吗?
非常感谢任何方向的帮助或指示。
答案 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=NBREAK
。 Here is a link非常好地解释了由三次多项式的系数给出的自由度的计数,这些系数表示b样条的自然和强加f(t)
的连续性所需的方程的数量。 ,df(t)/dt
和d^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=2
和t=NDATA-1
,以便NBREAK=NDATA-2
和NCOEFFS=NDATA
)。这就是NAG库选择断点以获得插值拟合的含义(意思是:通过数据点的拟合)。