事實上在實際使用中,高次插值顯然是很不適合的,高次插值將所有樣點包涵進一個插值函數中,這是次冪高的原因。高次計算復雜,而且剛開始的一點誤差會被方的很大。因此將整個區間分為若干個小區間,在每一個小區間進行插值這樣更好,實現容易,也方便在一些嵌入式設備上使用。有不少需要插值方法的場景是在嵌入式的應用中。
我以等距節點的二次插值為例,以每三個節點為一個子區間。
等距節點二次插值很好寫,由於每個區間只有三個插值節點,計算差商也不必使用拉格朗日插值中使用的遞歸,直接列表達式也很簡單(實際上等距節點二次插值就是只有三個節點的拉格朗日插值,只是此時在定義域內,有很多個拉格朗日插值函數,每個子區間對應一個)。遞歸的副作用相當的明顯,盡管寫成尾遞歸可以減小副作用,但是能避免遞歸還是避免吧。
分段插值函數可以表示為:
每一個插值函數表達式:
如上,不需要用遞歸求差商,方便很多。一個函數即可搞定。
""" @brief: 獲得分段二次插值函數 @param: x 插值節點的橫坐標集合 @param: fx 插值節點的縱坐標集合 @return: 參數所指定的插值節點集合對應的插值函數 """ def get_sub_two_interpolation_func(x = [], fx = []): def sub_two_interpolation_func(Lx): result = 0 for index in range(len(x)-2): if Lx >= x[index] and Lx <= x[index+2]: result = fx[index]*(Lx-x[index+1])*(Lx-x[index+2])/(x[index]-x[index+1])/(x[index]-x[index+2]) + \ fx[index+1]*(Lx-x[index])*(Lx-x[index+2])/(x[index+1]-x[index])/(x[index+1]-x[index+2]) + \ fx[index+2]*(Lx-x[index])*(Lx-x[index+1])/(x[index+2]-x[index])/(x[index+2]-x[index+1]) return result return sub_two_interpolation_func
""" demo: """ if __name__ == '__main__': ''' 插值節點, 這里用二次函數生成插值節點,每兩個節點x軸距離位10 ''' sr_x = [i for i in range(-50, 51, 10)] sr_fx = [i**2 for i in sr_x] Lx = get_sub_two_interpolation_func(sr_x, sr_fx) # 獲得插值函數 tmp_x = [i for i in range(-45, 45)] # 測試用例 tmp_y = [Lx(i) for i in tmp_x] # 根據插值函數獲得測試用例的縱坐標 ''' 畫圖 ''' import matplotlib.pyplot as plt plt.figure("play") ax1 = plt.subplot(111) 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()
插值函數圖像: