三次样条插值(Cubic Spline Interpolation)及代码实现(C语言)

三次样条插值(Cubic Spline Interpolation)及代码实现(C语言)样条插值是一种工业设计中常用的 得到平滑曲线的一种插值方法 三次样条又是其中用的较为广泛的一种 本篇介绍力求用容易理解的方式 介绍一下三次样条插值的原理 并附 C 语言的实现代码 1 三次样条曲线原理假设有以下节点 1 1 定义样条曲线是一个分段定义的公式 给定 n 1 个数据点 共有 n 个区间 三次样条方程满足以下条件 a 在每个分段区间 i 0 1

样条插值是一种工业设计中常用的、得到平滑曲线的一种插值方法,三次样条又是其中用的较为广泛的一种。本篇介绍力求用容易理解的方式,介绍一下三次样条插值的原理,并附C语言的实现代码。


1. 三次样条曲线原理

假设有以下节点

image

1.1 定义

样条曲线image 是一个分段定义的公式。给定n+1个数据点,共有n个区间,三次样条方程满足以下条件:

a. 在每个分段区间image (i = 0, 1, …, n-1,x递增), image 都是一个三次多项式。

b. 满足image (i = 0, 1, …, n )

c. image ,导数image ,二阶导数image 在[a, b]区间都是连续的,即image曲线是光滑的。

所以n个三次多项式分段可以写作:

image ,i = 0, 1, …, n-1

其中ai, bi, ci, di代表4n个未知系数。

1.2 求解

已知:

a. n+1个数据点[xi, yi], i = 0, 1, …, n

b. 每一分段都是三次多项式函数曲线

c. 节点达到二阶连续

d. 左右两端点处特性(自然边界,固定边界,非节点边界)

根据定点,求出每段样条曲线方程中的系数,即可得到每段曲线的具体表达式。

插值和连续性:

image, 其中 i = 0, 1, …, n-1

微分连续性:

image , 其中 i = 0, 1, …, n-2

样条曲线的微分式:

imageimage

将步长三次样条插值(Cubic Spline Interpolation)及代码实现(C语言) 带入样条曲线的条件:

a. 由image (i = 0, 1, …, n-1)推出

image

b. 由image (i = 0, 1, …, n-1)推出

image

c. 由 image (i = 0, 1, …, n-2)推出

三次样条插值(Cubic Spline Interpolation)及代码实现(C语言)

由此可得:

image

d. 由 image (i = 0, 1, …, n-2)推出

image

image ,则

a. image 可写为:

image ,推出

image

b. 将ci, di带入 image 可得:

image

c. 将bi, ci, di带入image (i = 0, 1, …, n-2)可得:

image

端点条件

由i的取值范围可知,共有n-1个公式, 但却有n+1个未知量m 。要想求解该方程组,还需另外两个式子。所以需要对两端点x0和xn的微分加些限制。 选择不是唯一的,3种比较常用的限制如下。

a. 自由边界(Natural)

首尾两端没有受到任何让它们弯曲的力,即image 。具体表示为image 和 image

则要求解的方程组可写为:

imageimage 

b. 固定边界(Clamped)

首尾两端点的微分值是被指定的,这里分别定为A和B。则可以推出

image

image

将上述两个公式带入方程组,新的方程组左侧为

image

c. 非节点边界(Not-A-Knot)

指定样条曲线的三次微分匹配,即

image

image

根据image 和image ,则上述条件变为

image

image

新的方程组系数矩阵可写为:

image

右下图可以看出不同的端点边界对样条曲线的影响:

image

1.3 算法总结

假定有n+1个数据节点

image

a. 计算步长image (i = 0, 1, …, n-1)

b. 将数据节点和指定的首位端点条件带入矩阵方程

c. 解矩阵方程,求得二次微分值image。该矩阵为三对角矩阵,具体求法参见我的上篇文章:三对角矩阵的求解。

d. 计算样条曲线的系数:

image

其中i = 0, 1, …, n-1

e. 在每个子区间image 中,创建方程

image


2. C语言实现

用C语言写了一个三次样条插值(自然边界)的S-Function,代码如下:

三次样条插值(Cubic Spline Interpolation)及代码实现(C语言)

#define S_FUNCTION_NAME cubic #define S_FUNCTION_LEVEL 2 #include "simstruc.h" #include "malloc.h" //方便使用变量定义数组大小 static void mdlInitializeSizes(SimStruct *S) { /*参数只有一个,是n乘2的定点数组[xi, yi]: * [ x1,y1; * x2, y2; * ..., ...; * xn, yn; */ ssSetNumSFcnParams(S, 1); if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) return; ssSetNumContStates(S, 0); ssSetNumDiscStates(S, 0); if (!ssSetNumInputPorts(S, 1)) return; //输入是x ssSetInputPortWidth(S, 0, 1); ssSetInputPortRequiredContiguous(S, 0, true); ssSetInputPortDirectFeedThrough(S, 0, 1); if (!ssSetNumOutputPorts(S, 1)) return; //输出是S(x) ssSetOutputPortWidth(S, 0, 1); ssSetNumSampleTimes(S, 1); ssSetNumRWork(S, 0); ssSetNumIWork(S, 0); ssSetNumPWork(S, 0); ssSetNumModes(S, 0); ssSetNumNonsampledZCs(S, 0); ssSetSimStateCompliance(S, USE_DEFAULT_SIM_STATE); ssSetOptions(S, 0); } static void mdlInitializeSampleTimes(SimStruct *S) { ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); ssSetOffsetTime(S, 0, 0.0); } #define MDL_INITIALIZE_CONDITIONS #if defined(MDL_INITIALIZE_CONDITIONS) static void mdlInitializeConditions(SimStruct *S) { } #endif #define MDL_START #if defined(MDL_START) static void mdlStart(SimStruct *S) { } #endif /* MDL_START */ static void mdlOutputs(SimStruct *S, int_T tid) { const real_T *map = mxGetPr(ssGetSFcnParam(S,0)); //获取定点数据 const int_T *mapSize = mxGetDimensions(ssGetSFcnParam(S,0)); //定点数组维数 const real_T *x = (const real_T*) ssGetInputPortSignal(S,0); //输入x real_T *y = ssGetOutputPortSignal(S,0); //输出y int_T step = 0; //输入x在定点数中的位置 int_T i; real_T yval; for (i = 0; i < mapSize[0]; i++) { if (x[0] >= map[i] && x[0] < map[i + 1]) { step = i; break; } } cubic_getval(&yval, mapSize, map, x[0], step); y[0] = yval; } //自然边界的三次样条曲线函数 void cubic_getval(real_T* y, const int_T* size, const real_T* map, const real_T x, const int_T step) { int_T n = size[0]; //曲线系数 real_T* ai = (real_T*)malloc(sizeof(real_T) * (n-1)); real_T* bi = (real_T*)malloc(sizeof(real_T) * (n-1)); real_T* ci = (real_T*)malloc(sizeof(real_T) * (n-1)); real_T* di = (real_T*)malloc(sizeof(real_T) * (n-1)); real_T* h = (real_T*)malloc(sizeof(real_T) * (n-1)); //x的?? /* M矩阵的系数 *[B0, C0, ... *[A1, B1, C1, ... *[0, A2, B2, C2, ... *[0, ... An-1, Bn-1] */ real_T* A = (real_T*)malloc(sizeof(real_T) * (n-2)); real_T* B = (real_T*)malloc(sizeof(real_T) * (n-2)); real_T* C = (real_T*)malloc(sizeof(real_T) * (n-2)); real_T* D = (real_T*)malloc(sizeof(real_T) * (n-2)); //等号右边的常数矩阵 real_T* E = (real_T*)malloc(sizeof(real_T) * (n-2)); //M矩阵 real_T* M = (real_T*)malloc(sizeof(real_T) * (n)); //包含端点的M矩阵 int_T i; //计算x的步长 for ( i = 0; i < n -1; i++) { h[i] = map[i + 1] - map[i]; } //指定系数 for( i = 0; i< n - 3; i++) { A[i] = h[i]; //忽略A[0] B[i] = 2 * (h[i] + h[i+1]); C[i] = h[i+1]; //忽略C(n-1) } //指定常数D for (i = 0; i 
  
    =0; i--) { X[i] = D[i] - C[i] * X[i+1]; } } #define MDL_UPDATE #if defined(MDL_UPDATE) static void mdlUpdate(SimStruct *S, int_T tid) { } #endif #define MDL_DERIVATIVES #if defined(MDL_DERIVATIVES) static void mdlDerivatives(SimStruct *S) { } #endif static void mdlTerminate(SimStruct *S) { } #ifdef MATLAB_MEX_FILE #include "simulink.c" #else #include "cg_sfun.h" #endif 
  


3. 例子

以y=sin(x)为例,  x步长为1,x取值范围是[0,9]。对它使用三次样条插值,插值前后对比如下:

三次样条插值(Cubic Spline Interpolation)及代码实现(C语言)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/207235.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午2:16
下一篇 2026年3月19日 下午2:16


相关推荐

  • java md5加密源码_javaMD5加密源码

    java md5加密源码_javaMD5加密源码packageutil;importjava.security.MessageDigest;importjava.security.NoSuchAlgorithmException;publicclassMD5Tool{/***该方法将指定的字符串用MD5算法加密后返回。*@params*@return*/publicstaticStringgetMD5Encoding(…

    2022年7月14日
    24
  • 【智能制造】同济大学张曙教授:未来工厂;三论智能制造(经典长篇解读)

    【智能制造】同济大学张曙教授:未来工厂;三论智能制造(经典长篇解读)三论智能制造(经典长篇解读)周宏仁 知识自动化知识自动化中国这几年信息化的发展已经出现很多概念和热点,从云计算到物联网,智慧城市到大数据,到现在的人工智能这一波热浪。这些热浪一定要落地下来,为制造业服务。对于中国人工智能的发展而言,最重要的问题还是要解决中国的制造业发展问题。如果制造业的智能化上不去,中国国民经济的脊梁就不够坚实。论智能制造发展的三个阶段首先需要理解,什么是智能制造?按照百科定义,

    2022年7月25日
    7
  • 算法导论 — 15.5 最优二叉搜索树

    算法导论 — 15.5 最优二叉搜索树笔记 二叉搜索树满足如下性质 假设 xxx 是二叉搜索树中的一个结点 如果 lll 是 xxx 的左子树的一个结点 那么 l key x keyl key x keyl key x key 如果 rrr 是 xxx 的右子树的一个结点 那么 r key x keyr key x keyr key x key 也就是说 二叉搜索树中的任意一个结点 它的左子树中的所有结点都不大于它 它的右子树中

    2026年3月17日
    1
  • vc中关于 directx的配置,和dxsdk_extras(directshow)

    vc中关于 directx的配置,和dxsdk_extras(directshow)

    2021年12月13日
    62
  • Java环境搭建(windows版、超详细)

    Java环境搭建(windows版、超详细)java 环境搭建为大家主要介绍 java 的环境搭建 本人 Windows 系统 那就给大家讲一下在 windows 系统下搭建 java 的开发环境 JDK 的介绍 jdk JavaDevelopm 是 Java 语言的软件开发工具包 主要用于移动设备 嵌入式设备上的 java 应用程序 JDK 包含的基本组件包括 javac 编译器 将源程序转成字节码 jar 打包工具 将相关的类文件打包成一个文件 javadoc 文档生成器 从源码注释中提取文档

    2026年3月17日
    4
  • linux常用的20个命令面试_docker常见面试问题

    linux常用的20个命令面试_docker常见面试问题什么是linux多用户,多任务,支持多线程和多CPU的操作系统linux的应用领域:免费,稳定,高效的,一般运行在大型服务器上用xshell连接虚拟机的步骤:1.setup设置虚拟机IP为10.10.10.10重启网卡:servicenetworerestart2.在Windows系统打开网络和共享中心,更改适配器设置,把vmnet1的ipv4的IP改成10.10.10.13.打开xshell,输入ssh10.10.10.10/根目录:一般根目录下只存放目录,有且只有一个根目

    2025年8月13日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号