三次样条曲线插值的基本原理及其 C#实现
三次样条曲线插值的基本原理及其 C#实现
作 者: simxpert
2018.5.14
I
三次样条曲线插值的基本原理及其 C#实现
作者简介:
本人长期从事结构强度仿真计算方面的学习和工作,可以为您解决各种结构强度仿真分
析以及专业计算软件定制方面的工作。
扫描二维码可添加本人微信:
II
三次样条曲线插值的基本原理及其 C#实现
目 录
1. 简介 .................................................................................................... 1
2. 三次样条插值的基本数学原理 ......................................................... 1
2.1. 插值的问题的提出 .................................................................... 1
2.2. 插值函数的待定系数变量和约束方程 .................................... 2
2.3. 插值函数的最终表达式 ............................................................ 3
2.4. 添加边界条件求解 mi ............................................................... 3
2.5. 根据插值函数进行插值计算 .................................................... 4
3. 三次样条插值函数的 C#实现 ............................................................ 4
4. SPLine 类的使用方法 ......................................................................... 6
5. 附录 1‐SPLine 类的源代码 ................................................................. 7
6. 附录 2‐Chase 类的源代码 ................................................................ 11
III
三次样条曲线插值的基本原理及其 C#实现
三次样条曲线插值的数学原理及其 C#实现
作者: simxpert
1. 简介
在工程实践中经常会用到插值,最简单的插值是在相邻的两个样本点之间线
性插值,有时候希望精度高一点,一般都会用三次样条曲线插值。
本文先从理论上讲解三次样条插值的数学原理,然后讲解使用 C#实现三次
样条插值算法的基本过程,最后以实例对算法进行验证。
2. 三次样条插值的基本数学原理
本文并不打算详细讲解完整的三次样条曲线的推导过程,只是梳理一下三次
样条曲线差值的大概的脉络,详细的推导过程可以参考随意一本数值计算教程。
2.1. 插值的问题的提出
在给定的区间[a,b]上有 N 个点,已知其横坐标为:a=x0
三次样条曲线插值的基本原理及其 C#实现
2.2. 插值函数的待定系数变量和约束方程
为了得到精度比较高而且过渡比较平滑的曲线,最常见的就是使用三次样条
插值。如果我们把前面讲的子区间的线性函数提升为 3 次多项式:
xaxaxaaxSi
)(
3
2
1
2
0
3
(1)
为了保证曲线的连续性和光滑性,必须要对每个区间的插值函数提出一些要求,
这些要求包括:
1).连续性。除了两个边界节点外,任意一个节点 xi 同时属于[xi-1,xi]和[xi,xi+1]这两
个相邻的子区间。我们必须要保证在用这两个区间上的插值函数计算出来的 xi 的
纵坐标值相等,而且要等于已知的 yi 值。即:
Si-1(xi)=Si(xi)=yi,i=1,2,…,n-1。
(2)
式(2)包含了 2n-2 个方程,再加两个边界点上 S0(x0)=y0,Sn-1(xn)=yn,共计得到 2n
个方程。
2).一阶导数和二阶导数连续。这个约束条件是为了保证插值函数的曲线足够的
光滑。除了两头的节点外,任意一个中间节点的一阶导数和二阶导数必须连续。
即:
xS
i
(
1
'
i
)
'
(
xS
ii
,i=1,2,…,n-1
)
'‘
xS
i
i
(
1
)
xS
i
'’
(
i
,i=1,2,…,n-1
)
(3)
(4)
式(3),(4)可以得到 2n-2 个方程。
由于上述约束条件总计可以得到 4n-2 个方程。从(1)式可以看出,每个插值
函数有 4 个未知的待定系数,[a,b]区间内有 n 个子区间,故一共有 4n 个未知待
定系数。未知的变量的数目比约束方程的数目多 2,也就是说我们还缺少两个约
束条件。
缺少的这两个约束条件可以由边界条件来指定。也就是在两个边界点上各施
加一个边界条件。边界条件是是人为指定的,常见的边界条件有 4 种,这个我们
2
三次样条曲线插值的基本原理及其 C#实现
在后面会提到。
2.3. 插值函数的最终表达式
根据前面的论述,我们只要求出每个子区间的插值函数的 4 个系数 a0, a1,
a2,a3 就能完全确定这 n 个插值函数。但是实际中,为了数学推导的方便,我们
并不会直接求出这 4 个变量,而是采取了间接的表达方式来描述每个插值函数。
不同的推导方法,得到的表达形式也各不相同,常见的有三转角法,三弯矩
法,B 样条基函数法等方法。本文并不打算进行详细的推导。因为没必要,任何
一本数值计算的书上都可以找到非常详细的。在这里我直接给出推导结果:
yxS
i
)(
i
(
0
xx
i
h
i
)
y
i
0
1
x
i
(
1
h
i
x
)
hm
ii
(
1
xx
i
h
i
)
(5)
hm
i
i
1
(
1
x
i
1
h
i
x
)
其中
x
,[x
i
x
i
],
xh
i
i
1
1
ix
,
i
1,0
,...,
n
。
1
(x)
(2x
1)(x
x
)(,1)-
2
1
xx
(
2
)1
(6)
式(5)就是插值函数的最终表达式。式(5)看起来比(1)复杂多了,其实仔细看,如
果全部展开,仍然是一个三次多项式。在这个公式中,只有 im 是未知的,其他都
可以根据已知条件直接算出来的。剩下的任务就是如何求出 im 。
我们把(5)所代表的插值函数代入到之前说的约束条件中(2),(3),(4)中,经过
整理,可以得到式(7):
m
ii
1
m
2
i
m
ii
1
g
i
,i=1,2,…n-1.
(7)
其中
i
h
i
hh
i
i
1
,
i
-1
i
,
g
i
2.4. 添加边界条件求解 mi
(3
i
yy
i
i
1
i
h
i
1
y
i
1
h
i
y
i
。
)
前面讲过,我们还需要添加两个边界条件才能求解出位置系数。常见的边界
3
三次样条曲线插值的基本原理及其 C#实现
条件大概有三、四种。本文不打算涉及所有的边界条件,只选用比较常用的第二
类边界条件(又叫”自然边界条件”):两个边界点的二阶导数为给定的值,其中最
常见给定值为 0,即在两个边界点上有:
xS
( 0
''
0'
)
0
,
nxS
(''
1n'
)
0
(8)
根据式(7),结合边界条件(8),可以推导出求解系数 mi 的矩阵:
2
2
1
2
3
2
2
4
3
2
2
n
2
n
1
m
1
m
2
m
3
m
n
m
n
2
1
=
1g
1
n
2
1
m
0
g
2
g
3
g
n
g
n
2
1
(9)
从上面的公式中λ, μ, g 都是可以根据已知条件算出来的,只有 mi 是未知
量。式(9)中的矩阵是一个典型的严格对角占优的对角方程组,可以用追赶法很快
得到解。
2.5. 根据插值函数进行插值计算
在根据 2.4 章中的(9)式求得 mi 之后,代入到 2.3 章中的式(5),即得到所有
的子区间上的插值函数 Si(x)。
对于一个给定的待插值点 xt,我们先要确定 xt 落入到哪个子区间,然后调用
该子区间的插值函数 Si(x)即可求出 xt 对应的插值 yt。
3. 三次样条插值函数的 C#实现
在 C#中实现了三次样条插值函数,实现过程封装在 SPLine 类中。SPLine
类的成员变量为:
class SPLine
{
double[] Xi;//存储已知点的x值
double[] Yi;//存储已知点的y值;
double[] A;//存储追赶法矩阵中的A
4
三次样条曲线插值的基本原理及其 C#实现
double[] B; //存储追赶法矩阵中的B
double[] C; //存储追赶法矩阵中的C
double[] H;//存储前面公式中的hi
double[] Lamda;//存储前面公式中的λi
double[] Mu;//存储μi
double[] G;//存储gi
double[] M;//存储待求的未知量mi
int N;//已知点的总数
int n;//n=N-1。 n为区间数,N为点数。
}
成员函数介绍:
private void GetH()
功能是求取前文中的h。hi=xi-xi-1。
private void GetLamda_Mu_G()
功能是根据已知条件求出λ, μ, g。计算公式见第3页中间的公式。
private void GetABC()
功能是求出追赶法中的矩阵里面的A,B,C,至于追赶法里面的A,B,C是怎么回
事,这里简单给一个截图:
数组A,B,C分别保存的是上图中的a,b,c。
上图中的待求变量x对应本文中的待求变量m。上图中的d对应本文中的数组G。
private double fai0(double x)
private double fai1(double x)
这两个函数对应2.3章中的式(6)中的两个三次多项式。
5
private int GetSection(double x)