C语言实现matlab的interp2,函数

  项目要用到matlab中的Vq = interp2(X,Y,V,Xq,Yq)函数,即把一个已知经纬度和对应值的矩阵,插值变换到一个给定经纬度网格中,也就是对给定网格填值,需要用到插值,这里使用双线性内插法。

*(这只是一个初步完成代码,仅供参考)

以下是对应C代码和测试程序:

  1 //************************************
  2 // 函数名称: inter_linear()
  3 // 函数说明:计算两点之间某一给定点的值,(x0,y0)->(x1,y1),已知x(x0<x<x1),求y
  4 // 返 回 值: double
  5 // 参    数: double x0,y0,x1,y1/*in*/    两个点的坐标(x0,y0)(x1,y1)
  6 
  7 // 作    者:WSS
  8 // 作成日期:2019/09/05
  9 
 10 //************************************
 11 double inter_linear(double x0, double y0, double x1, double y1, double x)
 12 {
 13     double a0, a1, y;
 14     a0 = (x - x1) / (x0 - x1);
 15     a1 = (x - x0) / (x1 - x0);
 16     y = a0*y0 + a1*y1;
 17     return y;
 18 }
  1 //************************************
  2 // 函数名称: interp2d()
  3 // 函数说明:二维插值,同matlab的interp2()功能
  4 // 返 回 值: double
  5 // 参    数: x,y分别为长度为m和n的向量(一维数组),z为矩阵(对应的二维数组(m,n))
  6 //           a,b分别为长度为asize和bsize的向量(一维数组),out_result为矩阵(对应的二维数组(asize,bsize))
  7 
  8 // 作    者:WSS
  9 // 作成日期:2019/09/05
 10 
 11 //************************************
 12 int interp2d(double *x, double *y, double *z, int m, int n, double *a, double *b, int asize,int bsize,double *out_result)
 13 {
 14     //a,b是待插值的矩阵行和列,遍历a,取出行,遍历b取出列,将插值计算后的值存储在out_result中
 15     double pointa = 0;
 16     double pointb = 0;
 17     double w1, w2,w;
 18     const int nu_val = -9999;
 19     int tempi = 0;
 20     int tempj =0;
 21     for (int i = 0; i < asize; ++i)
 22     {
 23         for (int j = 0; j < bsize; ++j)
 24         {
 25             // 找到网格点位置
 26             pointa = a[i];
 27             pointb = b[j];
 28             //确定pointa pointb所在的位置
 29             for (int p = 0; p < m-1; ++p)
 30             {
 31                 if (pointa < x[0]||pointa>x[m-1])//范围外的值不进行插值处理
 32                 {
 33                     tempi = nu_val;
 34                     break;
 35                 }
 36                 else if (pointa == x[m - 1])
 37                 {
 38                     tempi = m - 1;
 39                     break;
 40                 }
 41                 else if(pointa >= x[p] && pointa < x[p+1])//x升序
 42                 {
 43                     tempi = p;
 44                     break;
 45                 }
 46             }
 47             for (int q = 0; q < n - 1; ++q)
 48             {
 49                 if (pointb< y[0] || pointb>y[n- 1])//范围外的值不进行插值处理
 50                 {
 51                     tempj = nu_val;
 52                     break;
 53                 }
 54                 else if (pointb == y[n - 1])
 55                 {
 56                     tempj = n - 1;
 57                     break;
 58                 }
 59                 else if (pointb >= y[q] && pointb < y[q + 1])//y升序
 60                 {
 61                     tempj = q;
 62                     break;
 63                 }
 64             }
 65             if (tempj == nu_val || tempi == nu_val)
 66             {
 67                 out_result[i*bsize + j] = nu_val;
 68             }
 69             else
 70             {
 71                 //如果四个点,有一个点为-9999,就不进行插值了
 72                 if(z[tempi*n + tempj]<-900||z[tempi*n + tempj + 1]<-900||z[(tempi + 1)*n + tempj]<-900||z[(tempi + 1)*n + tempj + 1]<-900)
 73                 {
 74                     out_result[i*bsize + j] = nu_val;
 75                 }
 76                 else
 77                 {
 78                     //cout << tempi << " " << tempj << endl;
 79                     /**************x方向进行插值*************/
 80                     if (x[tempi] == pointa)
 81                     {
 82                         //取网格节点值
 83                         w1 = z[tempi*n + tempj];
 84                         w2 = z[tempi*n + tempj + 1];
 85                         //y方向进行插值
 86                         if (y[tempj] == pointb)
 87                         {
 88                             w = w1;
 89                         }
 90                         else
 91                         {
 92                             w = inter_linear(y[tempj], w1, y[tempj + 1], w2, pointb);
 93                         }
 94                     }
 95                     else
 96                     {
 97                         //x方向进行插值
 98                         w1 = inter_linear(x[tempi], z[tempi*n + tempj], x[tempi + 1], z[(tempi + 1)*n + tempj], pointa);
 99                         w2 = inter_linear(x[tempi], z[tempi*n + tempj + 1], x[tempi + 1], z[(tempi + 1)*n + tempj + 1], pointa);
100                         /*******y方向进行插值********/
101 
102                         if (y[tempj] == pointb)
103 
104                         {
105 
106                             //取网格节点值
107 
108                             w = w1;
109 
110                         }
111                         else
112                         {
113                             //进行插值(y)
114 
115                             w = inter_linear(y[tempj], w1, y[tempj + 1], w2, pointb);
116                         }
117                     }
118                     out_result[i*bsize + j] = w;
119                 }
120 
121             }
122 
123 
124         }
125     }
126     return 0;
127 }

测试函数:

 1 int main()
 2 {
 3     //插值函数测试
 4     int ret = 0;
 5     double a1[5] = { 10, 20, 30, 40, 50 };
 6     double a2[6] = {1,2,4,6,8,9};
 7     double z[30] ;
 8     for (int i = 0; i < 5; ++i)
 9     {
10         for (int j = 0; j < 6; ++j)
11         {
12             z[i*6+j] = a1[i]+a2[j];
13         }
14     }
15 
16     double b1[10] = { 10, 20, 30, 40, 50, 10, 20, 30, 40, 50 };
17     double b2[18] = { 0, 2, 4, 6, 8, 10, 0, 2, 4, 6, 8, 10, 0, 2, 4, 6, 8, 10 };
18     double zout[180];
19     ret = interp2d(a1, a2, z, 5, 6, b1, b2, 10, 18, zout);
20     for (int i = 0; i < 5; ++i)
21     {
22         for (int j = 0; j < 6; j++)
23         {
24             cout << z[i * 6 + j] << " ";
25         }
26         cout << endl;
27     }
28     cout << endl;
29     for (int i = 0; i < 10; ++i)
30     {
31         for (int j = 0; j <18; j++)
32         {
33             cout << zout[i *18 + j] << " ";
34         }
35         cout << endl;
36     }
37  return 0;
38 }