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/ondaytobewhoyouwant/p/8989497.html

                  https://blog.csdn.net/flyingleo1981/article/details/53008931    c語言實現 

                  https://blog.csdn.net/guanmao4322/article/details/85054189    原理及matlab實現

                  https://blog.csdn.net/zb1165048017/article/details/48311603    原理及matlab實現(有手稿喲)

                  https://blog.csdn.net/u012856866/article/details/23952819       c++實現


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM