三次样条曲线插值的基本原理及其 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)