Как построить таблицу поиска в C (компилятор SDCC) с линейной интерполяцией - PullRequest
3 голосов
/ 17 августа 2011

Для микроконтроллера LPC922 (с SDCC) я хочу создать таблицу соответствия с линейной интерполяцией. Предположим, я получил значения x и y, например

x=300 y=10,0201 
x=700 y=89,542 
x=800 y=126,452 
x=900 y=171,453 
x=1500 y=225,123

Как может выглядеть код для справочной таблицы с линейной интерполяцией, поэтому я получаю, например, для x = 850 правильное значение для y ((171 453 + 126 452) / 2)?

Ответы [ 3 ]

5 голосов
/ 17 августа 2011
typedef struct { double x; double y; } coord_t;

coord_t c[5] = 
{
    {300, 10.02},
    {700, 89.542},
    {800, 126.452}, 
    {900, 171.453}, 
    {1500,225.123}
};    

double interp( coord_t* c, double x, int n )
{
    int i;

    for( i = 0; i < n-1; i++ )
    {
        if ( c[i].x <= x && c[i+1].x >= x )
        {
            double diffx = x - c[i].x;
            double diffn = c[i+1].x - c[i].x;

            return c[i].y + ( c[i+1].y - c[i].y ) * diffx / diffn; 
        }
    }

    return 0; // Not in Range
}

int main(int argc, char** argv) 
{
    double y = interp( c, 850, 5 );
}
2 голосов
/ 17 августа 2011
double get_value(double x)
{
    /* NOTE: xs MUST be sorted */
    static const double xs[] = { 300, 700, 800, 900, 1500 };
    static const double ys[] = { 10.0201, 89.542, 126.452, 171.453, 225.123 };

    /* number of elements in the array */
    static const int count = sizeof(xs)/sizeof(xs[0]);

    int i;
    double dx, dy;

    if (x < xs[0]) {
        /* x is less than the minimum element
         * handle error here if you want */
        return ys[0]; /* return minimum element */
    }

    if (x > xs[count-1]) {
        return ys[count-1]; /* return maximum */
    }

    /* find i, such that xs[i] <= x < xs[i+1] */
    for (i = 0; i < count-1; i++) {
        if (xs[i+1] > x) {
            break;
        }
    }

    /* interpolate */
    dx = xs[i+1] - xs[i];
    dy = ys[i+1] - ys[i];
    return ys[i] + (x - xs[i]) * dy / dx;
}

Это можно довольно легко распространить на другие методы интерполяции , если хотите.Обратите внимание, что тогда вам, вероятно, придется расширить специальные случаи для приграничных регионов, однако вы захотите с этим справиться.Распространенным методом является линейная интерполяция, когда для предпочтительного метода недостаточно соседних значений.

Также, когда число значений начинает расти, я бы рекомендовал использовать метод бинарный поиск для вычисления начальной точки.Это не должно быть проблемой с этими несколькими значениями.

Обновление: поскольку OP работает на ограниченной платформе, вот версия выше с использованием libfixmath :

/* NOTE: xs MUST be sorted */
static const fix16_t xs[] = { 300<<16, 700<<16, 800<<16, 900<<16, 1500<<16 };
static const fix16_t ys[] = { (fix16_t)(65536.0*10.0201+0.5), (fix16_t)(65536.0*89.542+0.5), (fix16_t)(65536.0*126.452+0.5), (fix16_t)(65536.0*171.453+0.5), (fix16_t)(65536.0*225.123+0.5) };

fix16_t get_value_fix(fix16_t x)
{    
    /* number of elements in the array */
    static const int count = sizeof(xs)/sizeof(xs[0]);
    int i;
    fix16_t dx, dy;

    if (x < xs[0]) {
        /* x is less than the minimum element
         * handle error here if you want */
        return ys[0]; /* return minimum element */
    }

    if (x > xs[count-1]) {
        return ys[count-1]; /* return maximum */
    }

    /* find i, such that xs[i] <= x < xs[i+1] */
    for (i = 0; i < count-1; i++) {
        if (xs[i+1] > x) {
            break;
        }
    }

    /* interpolate */
    dx = fix16_sub(xs[i+1], xs[i]);
    dy = fix16_sub(ys[i+1], ys[i]);
    return fix16_add(ys[i],  fix16_div(fix16_mul(fix16_sub(x, xs[i]), dy), dx));
}
0 голосов
/ 17 августа 2011

Поместите все значения в массив. Затем найдите x .. если вы не нашли правильное значение, у вас есть индекс и индекс соседей, а затем рассчитайте значение по формуле ..

...