当插值的要求涉及到对插值函数导数的要求时,普通插值问题就变为埃尔米特插值问题。拉格朗日插值和牛顿插值的要求较低,只需要插值函数的函数值在插值点与被插函数的值相等,以此来使得在其它非插值节点插值函数的值能接近被插函数。但是有时候要求会更高,不仅要插值函数与被插函数在插值节点函数值相等,而且要求它们的导数相等。

  其实此时的情况并没有变得复杂,解决这个问题的思路与拉格朗日插值法的思路是相同的,不同点在于插值条件的约束函数增加了导数一项,原来由于0~n插值节点有n+1个插值节点,需要求出n+1个线性方程的解,(因为实打实的去求这样一个线性方程组的难度颇高)也就是需要构造一个不超过n+1-1 = n次的多项式,这里减1是因为n次多项式会解出n+1个解,还有一个常数。

  当每一个插值节点再有一个对于导数的约束条件时,此时线性方程变成了2*(n + 1)= 2n + 2个,也就是需要构造一个不超过2n+1次的多项式。

  构造出的埃尔米特插值函数应该是这样一个形式:

  可以看出就是再拉格朗日插值函数的基础上添加对导数的约束。

  构造埃尔米特插值的关键时构造基函数

  如何构造这两个基函数我并不了解,但是可以想办法网上凑,只需要他们满足以下约束即可:

  

  我在这里贴一个满足要求的

  

  其中为拉格朗日插值基函数的平方。

  将以上两个基函数带入埃尔米特插值多项式便得到了插值函数。

  开始贴代码:

  首先贴的是拉格朗日插值基函数:

  

"""
@brief: 获得拉格朗日插值基函数
@param: xi xi为第i个插值节点的横坐标
@param: x_set 整个插值节点集合
@return: 返回值为参数xi对应的插值基函数
"""
def get_li(xi, x_set = []):
def li(Lx):
W = 1; c = 1
for each_x in x_set:
if each_x == xi:
continue
W = W * (Lx - each_x) for each_x in x_set:
if each_x == xi:
continue
c = c * (xi - each_x) # 这里一定要转成float类型,否则极易出现严重错误. 原因就不说了(截断误差)
return W / float(c)
return li

  

  接着根据插值节点获得埃尔米特插值多项式需要的两个基函数:

  

"""
@brief: 获得埃尔米特插值基函数α(x) notice: 非求导部分基函数
@param: xi xi为第i个插值节点的横坐标
@param: x_set 整个插值节点集合
@return: 返回值为参数xi对应的插值基函数
""" def get_basis_func_alpha(xi, x_set = []): def basis_func_alpha(x):
tmp_sum = 0
for each_x in x_set:
if each_x == xi:
continue
tmp_sum = tmp_sum + 1/float(xi - each_x) return (1 + 2*(xi-x) * tmp_sum) * ((get_li(xi, x_set))(x)) ** 2 return basis_func_alpha """
@brief: 获得埃尔米特插值基函数β(x) notice: 求导部分基函数
@param: xi xi为第i个插值节点的横坐标
@param: x_set 整个插值节点集合
@return: 返回值为参数xi对应的插值基函数
"""
def get_basis_func_beta(xi, x_set = []):
return lambda x : (x - xi) * ((get_li(xi, x_set))(x)) ** 2

  最后便可以构造埃尔米特插值函数了:

  

"""
@brief: 获得埃尔米特插值函数
@param: x 插值节点的横坐标集合
@param: fx 插值节点的纵坐标集合
@param: deriv 插值节点的导数集合
@return: 参数所指定的插值节点集合对应的插值函数
notice:
经过对拉格朗日插值法, 牛顿插值法, 埃尔米特插值法的测试发现, 内插效果很好,
外插基本无法使用,误差极大(不能叫误差, 应该叫错误).
"""
def get_Hermite_interpolation(x = [], fx = [], deriv = []):
set_of_func_alpha = [] # α(x)基函数集合
set_of_func_beta = [] # β(x)基函数集合
for each in x: # 获得每个插值点的基函数
tmp_func = get_basis_func_alpha(each, x)
set_of_func_alpha.append(tmp_func) # 将集合x中的每个元素对应的插值基函数保存
tmp_func = get_basis_func_beta(each, x)
set_of_func_beta.append(tmp_func) # 将集合x中的每个元素对应的插值基函数保存 def Hermite_interpolation(Hx):
result = 0
for index in range(len(x)):
result = result + fx[index]*set_of_func_alpha[index](Hx) + deriv[index]*set_of_func_beta[index](Hx) #根据根据拉格朗日插值法计算Lx的值
return result return Hermite_interpolation

    下面看一下效果:

  

  对以上几个插值节点进行插值后获得了如下效果:

  

  效果非常棒。

  以上图像的测试代码如下:

  

"""
demo:
"""
if __name__ == '__main__': ''' 插值节点, 这里用二次函数生成插值节点,每两个节点x轴距离位10 '''
import math
sr_x = [(i * math.pi) + (math.pi / 2) for i in range(-3, 3)]
sr_fx = [math.sin(i) for i in sr_x]
deriv = [0 for i in sr_x] # 导数都为 0
Hx = get_Hermite_interpolation(sr_x, sr_fx, deriv) # 获得插值函数
tmp_x = [i * 0.1 * math.pi for i in range(-20, 20)] # 测试用例
tmp_y = [Hx(i) for i in tmp_x] # 根据插值函数获得测试用例的纵坐标 ''' 画图 '''
import matplotlib.pyplot as plt
plt.figure("play")
ax1 = plt.subplot(211)
plt.sca(ax1)
plt.plot(sr_x, sr_fx, linestyle = ' ', marker='o', color='b')
plt.plot(tmp_x, tmp_y, linestyle = '--', color='r')
plt.show()

  通过观察以上的原理观察,实际上在以后遇到更高要求的插值问题时,比如要求插值函数与被插函数三次,四次导数相等,我们也是可以利用类似的方法,只是构造相应的基函数可能需要一番功夫,计算复杂度也会上升。

埃尔米特插值问题——用Python进行数值计算的更多相关文章

  1. python与数值计算环境搭建

    数值计算的编程的软件很多种,也见过一些编程绘图软件的对比. 利用Python进行数值计算,需要用到numpy(矩阵) ,scipy(公式符号), matplotlib(绘图)这些工具包. 1.Linu ...

  2. 复化梯形求积分——用Python进行数值计算

    用程序来求积分的方法有很多,这篇文章主要是有关牛顿-科特斯公式. 学过插值算法的同学最容易想到的就是用插值函数代替被积分函数来求积分,但实际上在大部分场景下这是行不通的. 插值函数一般是一个不超过n次 ...

  3. 牛顿插值法——用Python进行数值计算

    拉格朗日插值法的最大毛病就是每次引入一个新的插值节点,基函数都要发生变化,这在一些实际生产环境中是不合适的,有时候会不断的有新的测量数据加入插值节点集, 因此,通过寻找n个插值节点构造的的插值函数与n ...

  4. Python 3 数值计算

    Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:43:06) [MSC v.1600 32 bit (Intel)] on win32Type & ...

  5. 分段二次插值——用Python进行数值计算

    事实上在实际使用中,高次插值显然是很不适合的,高次插值将所有样点包涵进一个插值函数中,这是次幂高的原因.高次计算复杂,而且刚开始的一点误差会被方的很大.因此将整个区间分为若干个小区间,在每一个小区间进 ...

  6. 拉格朗日插值法——用Python进行数值计算

    插值法的伟大作用我就不说了.... 那么贴代码? 首先说一下下面几点: 1. 已有的数据样本被称之为 "插值节点" 2. 对于特定插值节点,它所对应的插值函数是必定存在且唯一的(关 ...

  7. 用python做数值计算

    http://sebug.net/paper/books/scipydoc/scipy_intro.html http://www.cnblogs.com/weilq/p/3432817.html h ...

  8. Python进行数值计算

    1.计算积分 (1)计算定积分 from scipy import integrate #定义函数def half_circle(x): return (1-x**2)**0.5 pi_half, e ...

  9. Python生态环境简介[转]

    Python生态环境简介 作者: Mir Nazim 原文: Python Ecosystem - An Introduction 译者: dccrazyboy  原译: Python生态环境简介 当 ...

随机推荐

  1. shell运算符

    原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用. expr 是一款表达式计算工具,使用它能完成表达式的求值操作. #!/bin/bash v ...

  2. java基础_集合List与Set接口

    List接口继承了Collection的方法  当然也有自己特有的方法向指定位置添加元素   add(索引,添加的元素); 移除指定索引的元素   remove(索引) 修改指定索引的元素   set ...

  3. Java多线程基础——对象及变量并发访问

    在开发多线程程序时,如果每个多线程处理的事情都不一样,每个线程都互不相关,这样开发的过程就非常轻松.但是很多时候,多线程程序是需要同时访问同一个对象,或者变量的.这样,一个对象同时被多个线程访问,会出 ...

  4. 【小计】新人Tostring前忘记Null判断的处理

    ToString和string.Concat(可屏蔽Null的异常)性能相差不大,一些中小项目完全可以用Concat(新人容易忘记判断Null的情况,遇到太多了,所以建议重写tostring方法,内部 ...

  5. .NET同步与异步之相关背景知识(六)

    在之前的五篇随笔中,已经介绍了.NET 类库中实现并行的常见方式及其基本用法,当然.这些基本用法远远不能覆盖所有,也只能作为一个引子出现在这里.以下是前五篇随笔的目录: .NET 同步与异步之封装成T ...

  6. MVC还是MVVM?或许VMVC更适合WinForm客户端

    最近开始重构一个稍嫌古老的C/S项目,原先采用的技术栈是『WinForm』+『WCF』+『EF』.相对于现在铺天盖地的B/S架构来说,看上去似乎和Win95一样古老,很多新入行的,可能就没有见过经典的 ...

  7. Unicode 和 UTF-8 有何区别?

    Unicode符号范围 (一个字符两个字节)     | UTF-8编码方式 (十六进制)     | (二进制) —————————————————————– 这儿有四个字节从-----00 00 ...

  8. 服务治理要先于SOA

      讲在前面的话: 若企业缺乏对服务变更的控制和规则,那么一个服务在经过几个项目之后,就很有可能被随意更改成多个版本,将来变成什么样更是无法预测.久而久之,降低了服务重用的可能性,提高了服务利用的成本 ...

  9. MySQL Workbench建表时 PK NN UQ BIN UN ZF AI 的含义

    [转自网络]https://my.oschina.net/cers/blog/292191 PK Belongs to primary key 作为主键 NN Not Null 非空 UQ Uniqu ...

  10. 怎样在Dos里切换盘符

    一:在Dos里切换盘符 a:在电脑左下角右击显示图片;(我用的是win10系统,其他系统类似) b:点击运行,输入cmd; c:点击确定: d:输入盘符:(如f:) 或F: 只写字母,不写分号是不行的 ...