最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - Bicubic spline interpolation of a gaussian - Stack Overflow

programmeradmin1浏览0评论

I am trying to perform 2D bicubic spline interpolation following this article (pg 15 sec 6.2 Bicubic Interpolation)

My test -- I have a gaussian function defined on the interval $ x,y \in [-1,1] $ and I want to use the bicubic interpolation method to get a reasonable interpolation of the function.

This is my implementation so far -

import numpy as np  
from numdifftools import Hessian, Gradient

def gaussian(pt):
    x, y = pt
    return np.exp(-x**2 - y**2)

A_inv = np.array([
    [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
    [0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0],
    [-3,3,0,0,-2,-1,0,0,0,0,0,0,0,0,0,0],
    [2,-2,0,0,1,1,0,0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0],
    [0,0,0,0,0,0,0,0,-3,3,0,0,-2,-1,0,0],
    [0,0,0,0,0,0,0,0,2,-2,0,0,1,1,0,0],
    [-3,0,3,0,0,0,0,0,-2,0,-1,0,0,0,0,0],
    [0,0,0,0,-3,0,3,0,0,0,0,0,-2,0,-1,0],
    [9,-9,-9,9,6,3,-6,-3,6,-6,3,-3,4,2,2,1],
    [-6,6,6,-6,-3,-3,3,3,-4,4,-2,2,-2,-2,-1,-1],
    [2,0,-2,0,0,0,0,0,1,0,1,0,0,0,0,0],
    [0,0,0,0,2,0,-2,0,0,0,0,0,1,0,1,0],
    [-6,6,6,-6,-4,-2,4,2,-3,3,-3,3,-2,-1,-2,-1],
    [4,-4,-4,4,2,2,-2,-2,2,-2,2,-2,1,1,1,1]
])


def get_coefficient_tensor(func_array):
    alpha_array = A_inv @ func_array
    return np.array([
        [alpha_array[0], alpha_array[1], alpha_array[2], alpha_array[3]],
        [alpha_array[4], alpha_array[5], alpha_array[6], alpha_array[7]],
        [alpha_array[8], alpha_array[9], alpha_array[10], alpha_array[11]],
        [alpha_array[12], alpha_array[13], alpha_array[14], alpha_array[15]]
    ]).T

def constructed_function(x, y, x_range, y_range, func_array):
    ''' 
    Returns the value of the constructed interpolation function at the point (x,y)

    Parameters:
    x : float
        x coordinate of the point
    y : float
        y coordinate of the point
    x_range : list / touple of 2 floats
        range of the x coordinate of the current square grid being considered
    y_range : list / touple of 2 floats
        range of the y coordinate of the current square grid being considered
    func_array : numpy array of size 16
        array containing the user defined quantities - 16x1 dimensional array
            - first 4 elements are the values of the function at the 4 corners of the square
            - next 8 elements are the values of the partial derivatives in the two directions at the 4 corners of the square (susceptibilities)
            - last 4 elements are the values of the mixed partial derivatives at the 4 corners of the square (I don't know how to interpret this yet)
    '''
    t = (x - x_range[0]) / (x_range[1] - x_range[0])
    u = (y - y_range[0]) / (y_range[1] - y_range[0])
    coefficient_tensor = get_coefficient_tensor(func_array)
    return np.sum([
        coefficient_tensor[i,j] * t**i * u**j for i in range(4) for j in range(4)
    ])

def get_func_array(func, x_range, y_range):
    # function values at the 4 corners
    f_00 = func([x_range[0], y_range[0]])   
    f_01 = func([x_range[0], y_range[1]])
    f_10 = func([x_range[1], y_range[0]])
    f_11 = func([x_range[1], y_range[1]])

    # partial derivatives at the 4 corners
    f_x_00, f_y_00 = Gradient(func)([x_range[0], y_range[0]])
    f_x_01, f_y_01 = Gradient(func)([x_range[0], y_range[1]])
    f_x_10, f_y_10 = Gradient(func)([x_range[1], y_range[0]])
    f_x_11, f_y_11 = Gradient(func)([x_range[1], y_range[1]])

    # cross partial derivatives at the 4 corners
    f_xy_00 = Hessian(func)([x_range[0],y_range[0]])[0,1] 
    f_xy_01 = Hessian(func)([x_range[0],y_range[1]])[0,1] 
    f_xy_10 = Hessian(func)([x_range[1],y_range[0]])[0,1] 
    f_xy_11 = Hessian(func)([x_range[1],y_range[1]])[0,1] 
    return np.array([f_00,f_01,f_10,f_11,f_x_00,f_x_01,f_x_10,f_x_11,f_y_00,f_y_01,f_y_10,f_y_11,f_xy_00,f_xy_01,f_xy_10,f_xy_11]).T
                                      

x_range = [-1,1]
y_range = [-1,1]

xs = np.linspace(x_range[0], x_range[1], 100)
ys = np.linspace(y_range[0], y_range[1], 100)

X, Y = np.meshgrid(xs, ys)

func_array = get_func_array(gaussian, x_range, y_range)

Z = np.array([
    constructed_function(x, y, x_range, y_range, func_array) for x in xs for y in ys
]).reshape(X.shape)

Z_actual = np.array([
    gaussian([x,y]) for x in xs for y in ys
]).reshape(X.shape)

When I visualize the Z_interpolated (green), it is very different from Z_actual (red) -- not only are the derivatives the wrong magnitude at the corners, they are also the wrong sign.

I want the interpolation scheme to better capture the derivatives at the four points I have specified it.

Is this a limitation of the bicubic spline or is there an error in the implementation?

Should I include more grid points? I feel like since it is a piecewise interpolation scheme should it really improve things?

发布评论

评论列表(0)

  1. 暂无评论