數值計算學習之一:插值

      插值可能是用到最多和最簡單的一種數據處理方法了,最近學了一些插值方面的內容,因此做了一些插值的練習,設計了一個小實驗。

 

1.   實驗要求

1).算法需要的是針對同一組數據,採用拉格朗日法,牛頓插值法,分段線性插值法來進行比較不同算法下同一數據的精度情況或誤差情況;

2).針對三個算法的任意某一種算法,請分別考慮同一組數據進行插值時選擇不同的節點數來進行計算的誤差情況或精度情況;

3).針對三個算法的任意某一種算法,請分別考慮同一組數據進行插值時選擇不同的步長來進行計算時的精度或誤差。

2.   設計實現

針對實驗的要求,設計了一個Interpolation類來實現插值計算,包含三個函數getLagrangeResult,getNewtonResult,getPiecewiseLinearResult分別代表拉格朗日插值,牛頓插值,分段線性插值。

拉格朗日插值

拉格朗日插值公式原理如下所示:


根據拉格朗日插值公式給出了C++的代碼如下:

void Interpolation::getLagrangeResult(vector<float> &X,vector<float>&resY)

{

         //檢查X,Y是否相等

         if(xdata.size()!= ydata.size())

                   return;

 

         intdLength = xdata.size();

    int xLength= X.size();

         resY.resize(xLength);

        

         for(int k = 0;k < xLength;k++)

         {

                   floattemp = 0;

                   for(int i = 0;i <dLength;i++ )

                   {      

                            temp = ydata[i];

                            for(int j = 0;j<dLength;j++ )

                            {                                            

                                     float inc = xdata[i]-xdata[j];

                                     if(i!=j && inc != 0)                                                                              

                                               temp*= (X[k] - xdata[j])/inc;                                                                                                    

                            }

                            resY[k] += temp;

                   }                         

         }      

}

 

牛頓插值

牛頓插值的公式如下圖所示

根據牛頓插值公式給出了C++的代碼如下:

void Interpolation::getNewtonResult(vector<float> &X,vector<float>&resY)

{

         //檢查X,Y是否相等

         if(xdata.size()!= ydata.size())

                   return;

         //計算差商表

         intdLength = xdata.size();

         intxLength = X.size();

         resY.resize(xLength);

         float*df = new float[dLength];

         //初始化差商

         for(int i = 0;i < dLength;i++)

                   df[i] = ydata[i];

 

 

         //計算差商

         for(int i = 0;i < dLength-1;i++)

         {

                   floatprev = df[i];

                   for(int j = i+1;j < dLength;j++)

                   {      

                            float temp;

                            temp = df[j];

                            df[j]=(prev-df[j])/(xdata[j-i-1]-xdata[j]);

                            prev = temp;

                   }

         }

 

         //計算插值

          for(int i = 0;i <xLength;i++)

         {                

                   for(int j = 0;j < dLength-1;j++)

                   {

                            float temp = df[j];

                            for(int k = 0;k <j;k++)

                                temp *= X[i]-xdata[k];

 

                       resY[i] += temp;

                   }

          }

 

         delete[]df;

}

 

分段線性插值

分段線性插值,也就是線性的樣條插值,即將各個插值數據點用直線連接起來,公式如下所示:


根據分段線性插值公式給出了C++的代碼如下:

voidInterpolation::getPiecewiseLinearResult(vector<float>&X,vector<float> &resY)

{

         intdLength = xdata.size();

         intxLength = X.size();

         resY.resize(xLength);

        

         int idx= 0;

         floatdata = xdata[0];

         //計算最小值

         for(int i = 0;i < xLength;i++ )

         {

                   for(int j = 0;j < dLength;j++)

                   {

                            //minMax

                            if(xdata[j] < X[i])

                            {

                                     data =xdata[j];

                                     idx = j;

                            }

                   }

 

                   //插值      

                   intidx1 =(idx == xdata.size()-1) ? xdata.size()-2 : idx;

                   intidx2 = idx1+1;

 

                   resY[i] =

                            (X[i]-xdata[idx2])*ydata[idx1]/(xdata[idx1]-xdata[idx2])

                            +(X[i]-xdata[idx1])*ydata[idx2]/(xdata[idx2]-xdata[idx1]);

 

         }

}

 

3.   誤差分析

   對各個插值進行實驗分析,使用Qt開發了一個插值分析器,以Sin(x)爲目標函數,分別對各種情況下插值進行分析。

實驗一:

       在區間[0,6.28]之間,以採樣間隔爲1對插值目標函數進行採樣,分別採用拉格朗日插值法,牛頓插值法,分段線性插值法使用其步長0.2對其進行插值,插值曲線圖如下所示:


三種插值的誤差表如下所示:

分段線性插值

牛頓插值

拉格朗日插值

0.2

0.030375

0.011643

0.013884

0.4

0.05283

0.012888

0.015407

0.6

0.05976

0.009239

0.011076

0.8

0.044179

0.00426

0.005125

1

0

0

0

1.2

0.077003

0.002628

0.003188

1.4

0.116848

0.003495

0.004262

1.6

0.117407

0.002952

0.00362

1.8

0.078116

0.001581

0.001952

2

1.19E-07

0

0

2.2

0.052835

0.001276

0.001601

2.4

0.073437

0.00192

0.002431

2.6

0.06711

0.001826

0.002337

2.8

0.040233

0.001097

0.001421

3

2.98E-08

0

2.24E-07

3.2

0.01991

0.001105

0.001475

3.4

0.037492

0.001853

0.002521

3.6

0.044887

0.001964

0.00273

3.8

0.03464

0.001315

0.001875

4

1.79E-07

5.96E-08

2.38E-07

4.2

0.074349

0.001653

0.002518

4.4

0.113951

0.00311

0.004948

4.6

0.115615

0.003711

0.00623

4.8

0.077665

0.002812

0.005053

5

2.38E-07

0

1.79E-07

5.2

0.060432

0.004628

0.010248

5.4

0.085644

0.010115

0.026654

5.6

0.080048

0.014223

0.049481

5.8

0.049285

0.012952

0.077924

6

3.87E-07

1.19E-07

0.109671

6.2

0.060424

0.033817

0.140428

    由實驗結果可得,在本實驗條件下,線性插值誤差較大,牛頓插值和拉格朗日插值表現較爲相近。

實驗二:

       在區間[0,6.28]之間,以採樣間隔爲0.25,0.5,1對插值目標函數進行採樣,採用分段線性插值法對其使用其步長0.2對其進行插值實驗,插值曲線和誤差表如下所示:

 

三種採樣間隔如下表所示:

採樣間隔1

採樣間隔0.5

採樣間隔0.25

0.2

0.030375

0.006899

0.000746

0.4

0.05283

0.005878

0.002801

0.6

0.05976

0.012808

0.004332

0.8

0.044179

0.020703

0.003751

1

0

0

0

1.2

0.077003

0.028159

0.004557

1.4

0.116848

0.01916

0.007359

1.6

0.117407

0.019718

0.007482

1.8

0.078116

0.029271

0.004799

2

1.19E-07

5.96E-08

5.96E-08

2.2

0.052835

0.023529

0.004178

2.4

0.073437

0.014826

0.005151

2.6

0.06711

0.0085

0.003754

2.8

0.040233

0.010927

0.001435

3

2.98E-08

0

1.49E-08

3.2

0.01991

0.002733

4.20E-05

3.4

0.037492

0.003139

0.001793

3.6

0.044887

0.010533

0.003426

3.8

0.03464

0.017463

0.003248

4

1.79E-07

5.96E-08

5.96E-08

4.2

0.074349

0.026482

0.004224

4.4

0.113951

0.018217

0.007088

4.6

0.115615

0.019882

0.007456

4.8

0.077665

0.029798

0.004945

5

2.38E-07

1.19E-07

5.96E-08

5.2

0.060432

0.025884

0.004522

5.4

0.085644

0.016548

0.005867

5.6

0.080048

0.010951

0.004631

5.8

0.049285

0.014737

0.002096

6

3.87E-07

1.49E-07

5.96E-08

6.2

0.060424

0.025876

0.000663

由實驗結果可得,隨着插值節點的密集,誤差明顯變小。

實驗三:

在區間[0,6.28]之間,以採樣間隔爲1對插值目標函數進行採樣,採用分段線性插值法使用其步長0.2,0.5,0.8對其進行插值實驗,插值曲線和誤差表如下所示:


三種不同步長的誤差如下圖所示:

步長0.2

步長0.5

步長0.8

0.2

0.030375

0.5

0.05869

0.8

0.044179

0.4

0.05283

1

0

1.6

0.117407

0.6

0.05976

1.5

0.122111

2.4

0.073437

0.8

0.044179

2

0

3.2

0.01991

1

0

2.5

0.073263

4

0

1.2

0.077003

3

0

4.8

0.077665

1.4

0.116848

3.5

0.042942

5.6

0.080048

1.6

0.117407

4

0

1.8

0.078116

4.5

0.119667

2

1.19E-07

5

0

2.2

0.052835

5.5

0.08637

2.4

0.073437

6

0

2.6

0.06711

2.8

0.040233

3

2.98E-08

3.2

0.01991

3.4

0.037492

3.6

0.044887

3.8

0.03464

4

1.79E-07

4.2

0.074349

4.4

0.113951

4.6

0.115615

4.8

0.077665

5

2.38E-07

5.2

0.060432

5.4

0.085644

5.6

0.080048

5.8

0.049285

6

3.87E-07

6.2

0.060424

由實驗結果可得,步長越小,得到的插值結果越精確。

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章