基于径向基函数(RBF)的函数插值

基于径向基函数的函数插值

1. 函数插值

函数插值问题: 用形式简单的插值函数 f ^ ( x ) \hat f(x) 近似原函数

( 1 ) \qquad(1) 设函数 y = f ( x ) y=f(x) 在某个区间上有定义,并且已知该区间上的一些数据点 { x i , y i } \{x_i,y_i\} 严格满足 y i = f ( x i ) , i = 1 , , N y_i=f(x_i),i=1,\cdots,N ,这些数据点称为“控制节点”或“插值节点

( 2 ) \qquad(2) 如果存在一个形式上比较简单(比如 n n 次多项式)的函数 f ^ ( x ) \hat f(x) ,使得 f ^ ( x i ) = y i , i = 1 , , N \hat f(x_i)=y_i,i=1,\cdots,N 都成立,就称 f ^ ( x ) \hat f(x) f ( x ) f(x) 的插值函数。

\qquad 典型的函数插值方法:拉格朗日插值、牛顿插值、 H e r m i t e Hermite 插值、样条插值等。

与“函数逼近”的主要区别:
插值函数 f ^ ( x ) \hat f(x) 必须经过“插值节点”,也就是要满足 f ^ ( x i ) = y i , i = 1 , , N \hat f(x_i)=y_i,i=1,\cdots,N

2. RBF函数插值

\qquad 与拉格朗日插值之类的常规函数插值不同,基于核函数的函数插值“通过引入核函数”来刻画数据的局部化特征

\qquad 径向基函数 ( R a d i a l   B a s i s   F u n c t i o n , R B F ) (Radial\ Basis\ Function,RBF) 就是一类特殊的基函数,最常用的就是“高斯基函数”,定义为:

φ ( x ) = e x 2 2 σ 2 \qquad\qquad\qquad\varphi(x)=e^{-\frac{x^2}{2\sigma^2}}   (以一维情况为例)

\qquad 在这里插入图片描述
RBF函数插值:  f ^ ( x ) = i = 1 N w i φ ( x x i ) \hat f(x)=\displaystyle\sum_{i=1}^Nw_i\varphi(\parallel x-x_i\parallel)

\qquad 假设有 N N 个插值节点,也就是已知 { x j , y j } j = 1 N \{x_j,y_j\}\big |_{j=1}^N ,其中 f ^ ( x j ) = y j = f ( x j ) \hat f(x_j)=y_j=f(x_j) ,如下图所示。
\qquad 在这里插入图片描述

图中,红色实线为真实函数曲线,绿色空心圆圈代表插值节点 ( x j , y j ) (x_j,y_j) 蓝色实心点为RBF插值所求得的权值 w j w_j

\qquad { x j , y j } j = 1 N \{x_j,y_j\}\big |_{j=1}^N 带入方程 f ^ ( x ) = i = 1 N w i φ ( x x i ) \hat f(x)=\displaystyle\sum_{i=1}^Nw_i\varphi(\parallel x-x_i\parallel) ,可得到:

[ φ 11 φ 12 φ 1 N φ 21 φ 22 φ 2 N φ 11 φ 12 φ 1 N ] Φ [ w 1 w 2 w N ] W = [ y 1 y 2 y N ] y \qquad\qquad\underbrace{\left[ \begin{matrix} \varphi_{11} & \varphi_{12} & \cdots & \varphi_{1N} \\ \varphi_{21} & \varphi_{22} & \cdots & \varphi_{2N} \\ \vdots & \vdots & &\vdots \\ \varphi_{11} & \varphi_{12} & \cdots & \varphi_{1N} \end{matrix} \right] }_{\Phi}\underbrace{ \left[ \begin{matrix} w_1 \\ w_2 \\ \vdots \\ w_N \end{matrix} \right]}_{\bold W}=\underbrace{\left[ \begin{matrix} y_1 \\ y_2 \\ \vdots \\ y_N \end{matrix} \right]}_{\bold y} ,其中 φ j i = φ ( x j x i ) \varphi_{ji}=\varphi(\parallel x_j-x_i\parallel)

\qquad
\qquad 其中, Φ = [ φ j i ] \Phi=[\varphi_{ji}] 插值矩阵。因为 φ j i = φ ( x j x i ) = φ i j \varphi_{ji}=\varphi(\parallel x_j-x_i\parallel)=\varphi_{ij} ,因此插值矩阵是对称的。对于高斯核函数而言,插值矩阵的对角线元素的值为 1 1

\qquad 将线性方程组记为 Φ W = y \Phi\bold W=\bold y ,该方程组的第 j j 行为:

f ^ ( x j ) = y j = w 1 φ ( x j x 1 ) + w 2 φ ( x j x 2 ) + + w N φ ( x j x N ) \qquad\qquad\hat f(x_j)=y_j=w_1\varphi(\parallel x_j-x_1\parallel)+w_2\varphi(\parallel x_j-x_2\parallel)+\cdots+w_N\varphi(\parallel x_j-x_N\parallel)

\qquad 因此,可求出 R B F RBF 插值的系数为: W = Φ 1 y \bold W=\Phi^{-1}\bold y ,其示意图如下图所示。

Micchelli定理可以保证采用高斯函数时,插值矩阵 Φ \Phi 是可逆的(只要插值节点互不相同)。

\qquad 在这里插入图片描述

代码实现

import numpy as np
import matplotlib.pyplot as plt

def gen_data(x1,x2):
    y_sample = np.sin(np.pi*x1/2)+np.cos(np.pi*x1/3)
    y_all = np.sin(np.pi*x2/2)+np.cos(np.pi*x2/3)
    return y_sample, y_all

def kernel_interpolation(y_sample,x1,sig):
    gaussian_kernel = lambda x,c,h: np.exp(-(x-x[c])**2/(2*(h**2)))
    num = len(y_sample)
    w = np.zeros(num)
    int_matrix = np.asmatrix(np.zeros((num,num)))
    for i in range(num):
        int_matrix[i,:] = gaussian_kernel(x1,i,sig)  
    w = int_matrix.I * np.asmatrix(y_sample).T      
    return w

def kernel_interpolation_rec(w,x1,x2,sig):
    gkernel = lambda x,xc,h: np.exp(-(x-xc)**2/(2*(h**2)))
    num = len(x2)
    y_rec = np.zeros(num)
    for i in range(num):
        for k in range(len(w)):
            y_rec[i] = y_rec[i] + w[k]*gkernel(x2[i],x1[k],sig)
    return y_rec

if __name__ == '__main__':
    snum = 20   # control point数量
    ratio = 20  # 总数据点数量:snum*ratio
    sig = 1		# 核函数宽度
    xs = -8
    xe = 8
    x1 = np.linspace(xs,xe,snum)
    x2 = np.linspace(xs,xe,(snum-1)*ratio+1)
    y_sample, y_all = gen_data(x1,x2)
    plt.figure(1)
    w = kernel_interpolation(y_sample,x1,sig)   
    y_rec = kernel_interpolation_rec(w,x1,x2,sig)
    plt.plot(x2,y_rec,'k')
    plt.plot(x2,y_all,'r:')        
    plt.ylabel('y')
    plt.xlabel('x')
    for i in range(len(x1)):        
        plt.plot(x1[i],y_sample[i],'go',markerfacecolor='none')        
        
    plt.legend(labels=['reconstruction','original','control point'],loc='lower left')
    plt.title('kernel interpolation:$y=sin(\pi x/2)+cos(\pi x/3)$')       
    plt.show()

运行结果:
在这里插入图片描述

在相同区间、分别采用 8 , 12 , 16 , 20 8,12,16,20 个控制节点 ( c o n t r o l   p o i n t ) (control\ point) 进行函数插值的结果
显然,插值节点过少,无法体现整个函数的特征;插值节点越多,函数插值的结果越精确

在这里插入图片描述

扩大插值区间范围,控制节点 ( c o n t r o l   p o i n t ) (control\ point) 也需要增加数量,才能保持函数插值的准确性

猜你喜欢

转载自blog.csdn.net/xfijun/article/details/105670892