python_matlab_样条插值求未知曲线的函数解析式

一、问题引入

对于给出如下的离散的数据点,现在想根据如下的数据点来推测x=5时的值,我们应该采用什么方法呢?

用于拟合样条函数的数据:
x          f ( x)
3.0 2.5
4.5 1.0
7.0 2.5
9.0 0.5
   我们知道在平面上两个点确定一条直线,三个点确定一条抛物线(假设曲线的类型是抛物线),那么现在有四个点,我们很自然的会想到,既然两个点确定一条直线,那么最简单的方法就是,两个点之间连一条线,两个点之间连一条线,最后得到的一种折线图如下:这样我们只要确定x=5时的直线,把自变量的值带进去,就显然会得到预测的函数值。但是,这种方法显然具有很明显的缺陷:曲线不够光滑,连接点处的斜率变化过大。可能会导致函数的一阶导数不连续。那么我们应该如何解决这个问题呢?

二次样条的原理

我们会想到既然直线不行,那么我们就用曲线来近似的代替和描述。最简单的曲线是二次函数,如果我们用二次函数:aX^2+bx+c来描述曲线,最后的结果可能会好一点,下图中一共有4个点,可以分成3个区间。每一个区间都需要一个二次函数来描述,一共需要9个未知数。下面的任务就是找出9个方程。

如下图所示:一共有x0,x1,x2,x3四个点,三个区间,每个区间上都有一个方程。

1>曲线方程在节点处的值必须相等,即函数在x1,x2两个点处的值必须符合两个方程,这里一共是4个方程:

a1*x1^2+b1*x1+c1=f(x1)

a2*x1^2+b2*x1+c2=f(x1)

a2*x2^2+b2*x2+c2=f(x2)

a3*x2^2+b3*x2+c3=f(x2)

2>第一个端点和最后一个端点必须过第一个和最后一个方程:这里一共是2个方程

3>节点处的一阶导数的值必须相等。这里为两个方程。

2*a1*x1+b1=2*a2*x1+b2

2*a2*x2+b2=2*a3*x2+b3

4>在这里假设第一个方程的二阶导数为0:这里为一个方程:

a1=0

上面是对应的9个方程,现在只要把九个方程联立求解,最后就可以实现预测x=5处节点的值。

下面是写成矩阵的形式,由于a1=0,所以未知数的个数少了一个。

下面是二次样条的python实现,最后将结果绘制在图上。

  1 import numpy as np
  2 import matplotlib.pyplot as plt
  3 from pylab import mpl
  4 """
  5 三次样条实现:
  6 函数x的自变量为:3, 4.5, 7, 9
  7 因变量为:2.5, 1 2.5, 0.5
  8 """
  9 x = [3, 4.5, 7, 9]
 10 y = [2.5, 1, 2.5, 0.5]
 11
 12
 13 """
 14 功能:完后对三次样条函数求解方程参数的输入
 15 参数:要进行三次样条曲线计算的自变量
 16 返回值:方程的参数
 17 """
 18 def calculateEquationParameters(x):
 19 #parameter为二维数组,用来存放参数,sizeOfInterval是用来存放区间的个数
 20 parameter = []
 21 sizeOfInterval=len(x)-1;
 22 i = 1
 23 #首先输入方程两边相邻节点处函数值相等的方程为2n-2个方程
 24 while i < len(x)-1:
 25 data = init(sizeOfInterval*4)
 26 data[(i-1)*4] = x[i]*x[i]*x[i]
 27 data[(i-1)*4+1] = x[i]*x[i]
 28 data[(i-1)*4+2] = x[i]
 29 data[(i-1)*4+3] = 1
 30 data1 =init(sizeOfInterval*4)
 31 data1[i*4] =x[i]*x[i]*x[i]
 32 data1[i*4+1] =x[i]*x[i]
 33 data1[i*4+2] =x[i]
 34 data1[i*4+3] = 1
 35 temp = data[2:]
 36 parameter.append(temp)
 37 temp = data1[2:]
 38 parameter.append(temp)
 39 i += 1
 40 # 输入端点处的函数值。为两个方程, 加上前面的2n - 2个方程,一共2n个方程
 41 data = init(sizeOfInterval * 4 - 2)
 42 data[0] = x[0]
 43 data[1] = 1
 44 parameter.append(data)
 45 data = init(sizeOfInterval * 4)
 46 data[(sizeOfInterval - 1) * 4 ] = x[-1] * x[-1] * x[-1]
 47 data[(sizeOfInterval - 1) * 4 + 1] = x[-1] * x[-1]
 48 data[(sizeOfInterval - 1) * 4 + 2] = x[-1]
 49 data[(sizeOfInterval - 1) * 4 + 3] = 1
 50 temp = data[2:]
 51 parameter.append(temp)
 52 # 端点函数一阶导数值相等为n-1个方程。加上前面的方程为3n-1个方程。
 53 i=1
 54 while i < sizeOfInterval:
 55 data = init(sizeOfInterval * 4)
 56 data[(i - 1) * 4] = 3 * x[i] * x[i]
 57 data[(i - 1) * 4 + 1] = 2 * x[i]
 58 data[(i - 1) * 4 + 2] = 1
 59 data[i * 4] = -3 * x[i] * x[i]
 60 data[i * 4 + 1] = -2 * x[i]
 61 data[i * 4 + 2] = -1
 62 temp = data[2:]
 63 parameter.append(temp)
 64 i += 1
 65 # 端点函数二阶导数值相等为n-1个方程。加上前面的方程为4n-2个方程。且端点处的函数值的二阶导数为零,为两个方程。总共为4n个方程。
 66 i = 1
 67 while i < len(x) - 1:
 68 data = init(sizeOfInterval * 4)
 69 data[(i - 1) * 4] = 6 * x[i]
 70 data[(i - 1) * 4 + 1] = 2
 71 data[i * 4] = -6 * x[i]
 72 data[i * 4 + 1] = -2
 73 temp = data[2:]
 74 parameter.append(temp)
 75 i += 1
 76 return parameter
 77
 78
 79
 80 """
 81 对一个size大小的元组初始化为0
 82 """
 83 def init(size):
 84 j = 0;
 85 data = []
 86 while j < size:
 87 data.append(0)
 88 j += 1
 89 return data
 90
 91 """
 92 功能:计算样条函数的系数。
 93 参数:parametes为方程的系数,y为要插值函数的因变量。
 94 返回值:三次插值函数的系数。
 95 """
 96
 97 def solutionOfEquation(parametes,y):
 98 sizeOfInterval = len(x) - 1;
 99 result = init(sizeOfInterval*4-2)
100 i=1
101 while i<sizeOfInterval:
102 result[(i-1)*2]=y[i]
103 result[(i-1)*2+1]=y[i]
104 i+=1
105 result[(sizeOfInterval-1)*2]=y[0]
106 result[(sizeOfInterval-1)*2+1]=y[-1]
107 a = np.array(calculateEquationParameters(x))
108 b = np.array(result)
109 for data_x in b:
110 print(data_x)
111 return np.linalg.solve(a,b)
112
113 """
114 功能:根据所给参数,计算三次函数的函数值:
115 参数:parameters为二次函数的系数,x为自变量
116 返回值:为函数的因变量
117 """
118 def calculate(paremeters,x):
119 result=[]
120 for data_x in x:
121 result.append(paremeters[0]*data_x*data_x*data_x+paremeters[1]*data_x*data_x+paremeters[2]*data_x+paremeters[3])
122 return result
123
124
125 """
126 功能:将函数绘制成图像
127 参数:data_x,data_y为离散的点.new_data_x,new_data_y为由拉格朗日插值函数计算的值。x为函数的预测值。
128 返回值:空
129 """
130 def Draw(data_x,data_y,new_data_x,new_data_y):
131 plt.plot(new_data_x, new_data_y, label="拟合曲线", color="black")
132 plt.scatter(data_x,data_y, label="离散数据",color="red")
133 mpl.rcParams[‘font.sans-serif‘] = [‘SimHei‘]
134 mpl.rcParams[‘axes.unicode_minus‘] = False
135 plt.title("三次样条函数")
136 plt.legend(loc="upper left")
137 plt.show()
138
139
140 result=solutionOfEquation(calculateEquationParameters(x),y)
141 new_data_x1=np.arange(3, 4.5, 0.1)
142 new_data_y1=calculate([0,0,result[0],result[1]],new_data_x1)
143 new_data_x2=np.arange(4.5, 7, 0.1)
144 new_data_y2=calculate([result[2],result[3],result[4],result[5]],new_data_x2)
145 new_data_x3=np.arange(7, 9.5, 0.1)
146 new_data_y3=calculate([result[6],result[7],result[8],result[9]],new_data_x3)
147 new_data_x=[]
148 new_data_y=[]
149 new_data_x.extend(new_data_x1)
150 new_data_x.extend(new_data_x2)
151 new_data_x.extend(new_data_x3)
152 new_data_y.extend(new_data_y1)
153 new_data_y.extend(new_data_y2)
154 new_data_y.extend(new_data_y3)
155 Draw(x,y,new_data_x,new_data_y)

二次插值

二次样条函数运行之后的结果如下,从图像中,我们可以看出,二次样条在函数的连接处的曲线是光滑的。这时候,我们将x=5输入到函对应的函数端中,就可以预测相应的函数值。但是,这里还有一个问题,就是二次样条函数的前两个点是直线,而且函数的最后一个区间内看起来函数凸出很高。我们还想解决这些问题,这时候,我们想是否可以用三次样条函数来进行函数的模拟呢?

三次样条的原理:

三次样条的原理和二次样条的原理相同,我们用函数aX^3+bX^2+cX+d这个函数来进行操作,这里一共是4个点,分为3个区间,每个区间一个三次样条函数的话,一共是12个方程,只要我们找出这12个方程,这个问题就算解决了。

1>内部节点处的函数值应该相等,这里一共是4个方程。

2>函数的第一个端点和最后一个端点,应该分别在第一个方程和最后一个方程中。这里是2个方程。

3>两个函数在节点处的一阶导数应该相等。这里是两个方程。

4>两个函数在节点处的二阶导数应该相等,这里是两个方程。

5>端点处的二阶导数为零,这里是两个方程。

a1=0

b1=0

三次样条的phthon实现

  1 import numpy as np
  2 import matplotlib.pyplot as plt
  3 from pylab import mpl
  4 """
  5 三次样条实现:
  6 函数x的自变量为:3,   4.5, 7,    9
  7       因变量为:2.5, 1   2.5,  0.5
  8 """
  9 x = [3, 4.5, 7, 9]
 10 y = [2.5, 1, 2.5, 0.5]
 11
 12
 13 """
 14 功能:完后对三次样条函数求解方程参数的输入
 15 参数:要进行三次样条曲线计算的自变量
 16 返回值:方程的参数
 17 """
 18 def calculateEquationParameters(x):
 19     #parameter为二维数组,用来存放参数,sizeOfInterval是用来存放区间的个数
 20     parameter = []
 21     sizeOfInterval=len(x)-1;
 22     i = 1
 23     #首先输入方程两边相邻节点处函数值相等的方程为2n-2个方程
 24     while i < len(x)-1:
 25         data = init(sizeOfInterval*4)
 26         data[(i-1)*4] = x[i]*x[i]*x[i]
 27         data[(i-1)*4+1] = x[i]*x[i]
 28         data[(i-1)*4+2] = x[i]
 29         data[(i-1)*4+3] = 1
 30         data1 =init(sizeOfInterval*4)
 31         data1[i*4] =x[i]*x[i]*x[i]
 32         data1[i*4+1] =x[i]*x[i]
 33         data1[i*4+2] =x[i]
 34         data1[i*4+3] = 1
 35         temp = data[2:]
 36         parameter.append(temp)
 37         temp = data1[2:]
 38         parameter.append(temp)
 39         i += 1
 40    # 输入端点处的函数值。为两个方程, 加上前面的2n - 2个方程,一共2n个方程
 41     data = init(sizeOfInterval * 4 - 2)
 42     data[0] = x[0]
 43     data[1] = 1
 44     parameter.append(data)
 45     data = init(sizeOfInterval * 4)
 46     data[(sizeOfInterval - 1) * 4 ] = x[-1] * x[-1] * x[-1]
 47     data[(sizeOfInterval - 1) * 4 + 1] = x[-1] * x[-1]
 48     data[(sizeOfInterval - 1) * 4 + 2] = x[-1]
 49     data[(sizeOfInterval - 1) * 4 + 3] = 1
 50     temp = data[2:]
 51     parameter.append(temp)
 52     # 端点函数一阶导数值相等为n-1个方程。加上前面的方程为3n-1个方程。
 53     i=1
 54     while i < sizeOfInterval:
 55         data = init(sizeOfInterval * 4)
 56         data[(i - 1) * 4] = 3 * x[i] * x[i]
 57         data[(i - 1) * 4 + 1] = 2 * x[i]
 58         data[(i - 1) * 4 + 2] = 1
 59         data[i * 4] = -3 * x[i] * x[i]
 60         data[i * 4 + 1] = -2 * x[i]
 61         data[i * 4 + 2] = -1
 62         temp = data[2:]
 63         parameter.append(temp)
 64         i += 1
 65     # 端点函数二阶导数值相等为n-1个方程。加上前面的方程为4n-2个方程。且端点处的函数值的二阶导数为零,为两个方程。总共为4n个方程。
 66     i = 1
 67     while i < len(x) - 1:
 68         data = init(sizeOfInterval * 4)
 69         data[(i - 1) * 4] = 6 * x[i]
 70         data[(i - 1) * 4 + 1] = 2
 71         data[i * 4] = -6 * x[i]
 72         data[i * 4 + 1] = -2
 73         temp = data[2:]
 74         parameter.append(temp)
 75         i += 1
 76     return parameter
 77
 78
 79
 80 """
 81 对一个size大小的元组初始化为0
 82 """
 83 def init(size):
 84     j = 0;
 85     data = []
 86     while j < size:
 87         data.append(0)
 88         j += 1
 89     return data
 90
 91 """
 92 功能:计算样条函数的系数。
 93 参数:parametes为方程的系数,y为要插值函数的因变量。
 94 返回值:三次插值函数的系数。
 95 """
 96
 97 def solutionOfEquation(parametes,y):
 98     sizeOfInterval = len(x) - 1;
 99     result = init(sizeOfInterval*4-2)
100     i=1
101     while i<sizeOfInterval:
102         result[(i-1)*2]=y[i]
103         result[(i-1)*2+1]=y[i]
104         i+=1
105     result[(sizeOfInterval-1)*2]=y[0]
106     result[(sizeOfInterval-1)*2+1]=y[-1]
107     a = np.array(calculateEquationParameters(x))
108     b = np.array(result)
109     for data_x in b:
110         print(data_x)
111     return np.linalg.solve(a,b)
112
113 """
114 功能:根据所给参数,计算三次函数的函数值:
115 参数:parameters为二次函数的系数,x为自变量
116 返回值:为函数的因变量
117 """
118 def calculate(paremeters,x):
119     result=[]
120     for data_x in x:
121         result.append(paremeters[0]*data_x*data_x*data_x+paremeters[1]*data_x*data_x+paremeters[2]*data_x+paremeters[3])
122     return  result
123
124
125 """
126 功能:将函数绘制成图像
127 参数:data_x,data_y为离散的点.new_data_x,new_data_y为由拉格朗日插值函数计算的值。x为函数的预测值。
128 返回值:空
129 """
130 def  Draw(data_x,data_y,new_data_x,new_data_y):
131         plt.plot(new_data_x, new_data_y, label="拟合曲线", color="black")
132         plt.scatter(data_x,data_y, label="离散数据",color="red")
133         mpl.rcParams[‘font.sans-serif‘] = [‘SimHei‘]
134         mpl.rcParams[‘axes.unicode_minus‘] = False
135         plt.title("三次样条函数")
136         plt.legend(loc="upper left")
137         plt.show()
138
139
140 result=solutionOfEquation(calculateEquationParameters(x),y)
141 new_data_x1=np.arange(3, 4.5, 0.1)
142 new_data_y1=calculate([0,0,result[0],result[1]],new_data_x1)
143 new_data_x2=np.arange(4.5, 7, 0.1)
144 new_data_y2=calculate([result[2],result[3],result[4],result[5]],new_data_x2)
145 new_data_x3=np.arange(7, 9.5, 0.1)
146 new_data_y3=calculate([result[6],result[7],result[8],result[9]],new_data_x3)
147 new_data_x=[]
148 new_data_y=[]
149 new_data_x.extend(new_data_x1)
150 new_data_x.extend(new_data_x2)
151 new_data_x.extend(new_data_x3)
152 new_data_y.extend(new_data_y1)
153 new_data_y.extend(new_data_y2)
154 new_data_y.extend(new_data_y3)
155 Draw(x,y,new_data_x,new_data_y)

三次插值

三次样条函数运行结果如下:
 

原文转自:https://blog.csdn.net/deramer1/article/details/79034201

原文地址:https://www.cnblogs.com/YiYA-blog/p/10485791.html

时间: 2024-10-10 04:25:12

python_matlab_样条插值求未知曲线的函数解析式的相关文章

求最大值和scanf函数的使用以及函数的声明

/* ============================================================================ Name : MaxNumber.c Author : lf Version : Copyright : Your copyright notice Description : 求最大值和scanf函数的使用以及函数的声明 ==========================================================

输入6个人的成绩放入到一个一维数组中,然后打印出平均分,最后按成绩 从大到小打印。三个功能(输入是一个函数,求平均分是一个函数,排序是一个 函数)都用函数实现,最后在main方法中调用。

/*5.输入6个人的成绩放入到一个一维数组中,然后打印出平均分,最后按成绩从大到小打印.三个功能(输入是一个函数,求平均分是一个函数,排序是一个函数)都用函数实现,最后在main方法中调用.*/ #include <stdio.h> int inputScore(){ int score; scanf("%d",&score); return score;} double avg(int scores[],int length){ int i,score = 0;

√n求单值欧拉函数

基本定理: 首先看一下核心代码: 核心代码 原理解析: 当初我看不懂这段代码,主要有这么几个问题: 1.定理里面不是一开始写了一个n*xxx么?为什么代码里没有*n? 2.ans不是*(prime[i]-1)么?为什么到了第二个while循环变成*prime[i]了? 3.定理里面不是要/pi么?为什么代码里没有/pi????????????? 公式化简 首先我们来分析一下整个程序的原理,如果把程序的原理搞明白了,这三个问题也就自然而然的解决了 这个程序的原理是基于唯一分解定理: 那么我们可以把

c程序设计 8.12 用牛顿迭代法求根。方程为:ax^3+bx^2+cx+d=0 ,系数a,b,c,d由主函数输入。求X在1附近的一个实根。求出后由主函数输出.

//https://baike.baidu.com/item/%E7%89%9B%E9%A1%BF%E8%BF%AD%E4%BB%A3%E6%B3%95/10887580?fr=aladdin#4 //百度牛顿迭代法 #include <stdio.h> #include <math.h> double solut(double a,double b,double c,double d) { double x1=1,x,f,f1; //迭代 do { x=x1; f=((a*x+b

编程算法 - 求1+2+...+n(函数继承) 代码(C++)

求1+2+...+n(函数继承) 代码(C++) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 求1+2+...+n, 要求不能使用乘除法\for\while\if\else\switch\case等关键字及条件判断语句(A?B:C). 可以使用函数继承, 通过递归调用, 每次递归值减1, 使用求反运算(!), 即非0为0, 0为1. 代码: /* * main.cpp * * Created on: 2014.7.12 * Author: spik

编程算法 - 求1+2+...+n(函数指针) 代码(C++)

求1+2+...+n(函数指针) 代码(C++) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 求1+2+...+n, 要求不能使用乘除法\for\while\if\else\switch\case等关键字及条件判断语句(A?B:C). 可以使用函数指针求解, 通过递归调用, 每次递归值减1, 使用求反运算(!), 即非0为0, 0为1. 代码: /* * main.cpp * * Created on: 2014.7.12 * Author: sp

C++_第七章函数的基本知识_求阶乘的子函数_ 函数参数类型为数组_ 求数组内所有元素和、部分元素和的方法_实现了先从键盘输入到一个数组中,再用for循环取读出数组中的元素 for循环也可以用break来结束循环的

/* 第七章函数的基本知识 */ /*01)c++对于返回值有一定的限制:可以是常量.变量.指针.结构对象或表达式,但不可以是数组02)c++返回数组的方法:将数组作为结构会对象组成部分来返回03)函数遇到return则结束该函数04)如果一个函数的两房额参数类型相同,则必须分别制定每个参数的类型,而不能像声明常规变量那样,将声明组合在一起05)*/ //本代码注意double类型的写法以及double和int类型数据的转换 1 #include <iostream> 2 3 void che

求转子曲线所包围的封闭区域的面积

问题 碰到这样的问题,感觉很神奇. 定子方程,短幅内摆线方程: {x1y1=(R?r)sinτ+esin(z2τ)?resinθ=(R?r)cosτ?ecos(z2τ)+recosθ 与定子曲线方程共轭的转子曲线方程: {x2=x1cos(φ?ψ)?y1sin(φ?ψ)?esin(ψ)y2=x1sin(φ?ψ)+y1cos(φ?ψ)?ecos(ψ) 其中: 1. R=48.78 为导圆半径, 2. r=8.13 为滚圆半径, 3. z2=z1?1 为转子头数. 4. e=7.05 为偏心距, 5

求数组差/交集函数-php数组函数(二)

求数组差集函数 函数只检查了多维数组中的一维.可以用 array_diff($array1[0], $array2[0]) 检查更深的维度. u:自定义函数比较,a(association):同时比较键和值. 自定义函数callable $value_compare_func必须返回一个小于零,等于零,或大于零的整数.其中返回零代表两个数相等. 对比数组值的函数 array_diff 对比(===) array1,array2···的值(value),返回在 $array1 中但是不在其他 ar