【问题标题】:Bilinear interpolation of 2d data using c / awk / shell [closed]使用 c / awk / shell 对 2d 数据进行双线性插值 [关闭]
【发布时间】:2014-02-15 21:44:04
【问题描述】:

有谁知道使用这些语言 c / awk /shell / c++ 中的任何一种对数据进行双线性插值

我的数据文件,这个文件没有排序不知道怎么办:(文件很大

 row col data 
 20 14 91 
 21 15 95
 21 14 162 
 20 15 210

我希望输出像这样的 0.5 列间隔和 0.2 行间隔

 20 14 91 
 20 14.5 150.5
 20 15 210
 20.2 14.5 146.1
 .....
 .....
 .....
 21 14 162
 21 14.5 128.5
 21 15 95 

请帮忙

【问题讨论】:

  • 额外的data 来自哪里,比如150.5?这很不清楚。
  • 亲爱的 Jotne 很清楚你不知道什么是双线性插值,非常感谢你的反对票..
  • 我没有给你反对票,你应该责备别人。
  • 对不起,Jotne,我脾气暴躁..原谅我..
  • 20 和 14 的起始行和列值是否重要,或者您的“非常大的文件”实际上是否从 (0,0) 开始?是否使用了所有行和列,或者这是某种稀疏数组? “非常大”有多大——难道不能把整个文件读入一个基本的二维数组吗?

标签: c++ c shell awk


【解决方案1】:

(已编辑以允许移动目标。)

以下适用于您的(非常有限!)样本数据集。它的工作原理是这样的:

  1. 将数据集加载到内存中,并以简单的结构存储。
  2. 对于每个行/列数据项,找到所需的下一项:(row,col>=1)、(row>=1,col) 和 (row>=1,col>=1)。未经测试(因为缺乏数据),但它应该使用最接近的值。
  3. 如果所有四个数据点都已知,则从左到右和从上到下进行插值。

由于您的样本数据集非常小,因此很难提出优化建议。如果连续行和列之间的距离未知(数据是随机顺序的,如您的示例所示),最好尝试将整个文件读入内存。

如果您的数据是按预先排序的,您可以在开始时读取一行,然后在每个循环中读取下一行。此外,如果数据也按排序,您可以跳过整个find_set 例程,并立即调用interpolate 获取后续项目。

所有printf 语句周围的绒毛是因为标准C printf 格式说明符不提供您首选的输出格式。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_ITEM    25

struct data_t {
    int row;
    int col;
    int data;
} array[MAX_ITEM];

int n_item = 0;

// interpolate A > B
//             v   v
//             C > D
void interpolate (int A, int B, int C, int D)
{
    int i,j, deltaCol,deltaRow;
    float a,b, delta_AC, delta_BD, value;

    a = array[A].data;
    b = array[B].data;

    deltaCol = 2*(array[B].col-array[A].col);
    deltaRow = 5*(array[C].row-array[A].row);

    delta_AC = (array[C].data-array[A].data)/(float)deltaRow;
    delta_BD = (array[D].data-array[B].data)/(float)deltaRow;

    // rows
    for (j=0; j<=deltaRow; j++)
    {
        // columns
        for (i=0; i<=deltaCol; i++)
        {
            if (j % 5)
                printf ("%.1f ", array[A].row+(j/5.0f));
            else
                printf ("%d ", array[A].row+j/5);
            if (i % 2)
                printf ("%.1f ", array[A].col+(i/2.0f));
            else
                printf ("%d ", array[A].col+i/2);

            value = a+(b-a)*((float)i/deltaCol);
            if ((int)(100*value+0.5) % 100)
                printf ("%.1f\n", value);
            else
                printf ("%d\n", (int)(value+0.5f));

        }
        a += delta_AC;
        b += delta_BD;
    }
}

// For a start row/col A find B,C,D
// where B = A(0,>=1), C=A(>=1,0), D=A(>=1,>=1)
void interpolate_from (int A)
{
    int i, B=-1, C=-1, D=-1;

    for (i=0; i<n_item; i++)
    {
        if (i == A) continue;
        if (array[A].row == array[i].row)
        {
            if (array[A].col < array[i].col || (B != -1 && array[i].col < array[B].col))
            {
                B = i;
            }
        } else
        if (array[A].row < array[i].row)
        {
            if (array[A].col == array[i].col)
            {
                C = i;
            } else
            {
                if (array[A].col < array[i].col || (D != -1 && array[i].col < array[D].col))
                {
                    D = i;
                }
            }
        }
        if (B+1 && C+1 && D+1)
        {
            interpolate (A,B,C,D);
            return;
        }
    }

}

int main (void)
{
    int i,j,k;
    FILE *f;

    f = fopen ("data.txt", "r");
    while (n_item < MAX_ITEM && fscanf (f, "%d %d %d", &i,&j, &k) == 3)
    {
        array[n_item].row = i;
        array[n_item].col = j;
        array[n_item].data = k;
        n_item++;
    }
    fclose (f);

    for (i=0; i<n_item; i++)
        interpolate_from (i);

    printf ("\n");
    return 0;
}

使用修改后的数据集

20 14 91
21 14 162
21 18 95
20 18 210

输出是:

20 14 91
20 14.5 105.9
20 15 120.8
20 15.5 135.6
...

(等--运行查看结果)

【讨论】:

  • 解释:这是一个非常简单的双线性插值,从行到行,从列到列。在一张纸上画出你的数字,然后手动推导出每行的增量应该是多少。然后,使用这些数字,从左到右按列插入。修改后的程序适用于您的原始数据集和新数据集 - 但请注意,数字仍应形成正方形。
【解决方案2】:

听起来像是sort -k1 -k2 -g data.txt 的工作。

【讨论】:

  • 我的问题很清楚我正在寻找双线性插值而不是sort
  • @Peter 很抱歉,我以为你有完整的数据集,只是出了问题。无论如何,您都需要在开始之前进行排序;然后你可以用一个程序来填补空白。由于您与要填写的数字不一致,因此我不知道您要填写哪些;但我认为你可以一次性处理它。
  • 没关系,谢谢回复
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-02
  • 1970-01-01
  • 2021-04-12
  • 1970-01-01
相关资源
最近更新 更多