【问题标题】:C++: replicating matlab's interp1 spline interpolation functionC++:复制matlab的interp1样条插值函数
【发布时间】:2014-07-11 20:28:32
【问题描述】:

谁能给我一些指导来复制 MATLAB 的 interp1 函数,使用样条插值?我尝试在wikipedia page 上密切复制该算法,但结果并不完全匹配。

#include <stdio.h>
#include <stdint.h>

#include <iostream>
#include <vector>
//MATLAB: interp1(x,test_array,query_points,'spline')

int main(){

    int size = 10;

    std::vector<float> test_array(10);
    test_array[0] = test_array[4] = test_array[8] = 1;
    test_array[1] = test_array[3] = test_array[5] = test_array[7] = test_array[9] = 4;
    test_array[2] = test_array[6] = 7;

    std::vector<float> query_points;
    for (int i = 0; i < 10; i++)
        query_points.push_back(i +.05);

    int n = (size - 1);

    std::vector<float> a(n+1);
    std::vector<float> x(n+1);  //sample_points vector
    for (int i = 0; i < (n+1); i++){
        x[i] = i + 1.0;
        a[i] = test_array[i];
    }

    std::vector<float> b(n);
    std::vector<float> d(n);
    std::vector<float> h(n);
        for (int i = 0; i < (n); ++i)
            h[i] = x[i+1] - x[i];

    std::vector<float> alpha(n);
        for (int i = 1; i < n; ++i)
            alpha[i] = ((3 / h[i]) * (a[i+1] - a[i])) - ((3 / h[i-1]) * (a[i] - a[i-1]));

    std::vector<float> c(n+1);
    std::vector<float> l(n+1);
    std::vector<float> u(n+1);
    std::vector<float> z(n+1);

    l[0] = 1.0;
    u[0] = z[0] = 0.0;

    for (int i = 1; i < n; ++i){
        l[i] = (2 * (x[i+1] - x[i-1])) - (h[i-1] * u[i-1]);
        u[i] = h[i] / l[i];
        z[i] = (alpha[i] - (h[i-1] * z[i-1])) / l[i];
    }

    l[n] = 1.0;
    z[n] = c[n] = 0.0;

    for (int j = (n - 1); j >= 0; j--){
        c[j] = z[j] - (u[j] * c[j+1]);
        b[j] = ((a[j+1] - a[j]) / h[j]) - ((h[j] / 3) * (c[j+1] + (2 * c[j])));
        d[j] = (c[j+1] - c[j]) / (3 * h[j]);
    }


    std::vector<float> output_array(10);
    for (int i = 0; i < n-1; i++){
        float eval_point = (query_points[i] - x[i]);
        output_array[i] =   a[i] + (eval_point * b[i]) + ( eval_point * eval_point * c[i]) + (eval_point * eval_point * eval_point * d[i]); 
        std::cout << output_array[i] << std::endl;
    }

    system("pause");
    return 0;
}

【问题讨论】:

  • 这么多……指针!你甚至不离开main() 为什么你需要指针而不是本地数组或向量?
  • @cyber 我现在使用向量
  • @kandre - 上帝保佑你。我现在将跟踪您的代码,因为它更具可读性。

标签: c++ algorithm matlab interpolation


【解决方案1】:

事后看来,您的代码似乎是根据维基百科文章正确编码的。但是,您需要了解有关 interp1 的一些信息,我认为您在使用它来检查您的答案时没有考虑到这一点。


当您指定 spline 标志时,MATLAB 的 interp1 假定端点条件是 not-a-knot。 Wikipedia 上指定的算法是自然样条 的代码。

因此,这可能就是您的积分不匹配的原因。 FWIW,请咨询:http://www.cs.tau.ac.il/~turkel/notes/numeng/spline_note.pdf 并查看最后一页的图表。您会看到非结样条曲线和自然样条曲线具有相同的形状,但当您的数据仅包含样条曲线的端点时具有不同的 y 值。但是,如果端点之间有数据点,所有不同类型的样条曲线(或多或少)都具有相同的 y 值。

为了完整起见,这里是从我上面引用的PDF注释中提取的图:

如果您想使用自然样条线,请使用csape 而不是interp1。这提供了一个三次样条带有结束条件。你像这样调用csape

pp = csape(x,y);

xy 是为样条曲线定义的控制点。默认情况下,这会返回一个 natural 样条曲线,这就是您所追求的,并且是一个 ppform 类型的结构。然后,您可以使用fnval 找出样条曲线的计算结果:

yval = fnval(pp, xval);

xvalyval 是输入 x 坐标,输出在此特定 x 处针对样条进行评估。

使用它,然后检查您的代码是否与csape 提供的值匹配。


小提示

您需要 MATLAB 中的曲线拟合工具箱才能使用csape。如果你没有这个,那么很遗憾,这个方法是行不通的。

【讨论】:

  • 非常感谢您的详细回答。理想情况下,我会尝试找出非结条件。我的代码与 csape 函数输出不完全匹配,而 interp1 和 csape 结果几乎相同,除了您所说的端点。
  • @kandre 好的。今晚晚些时候我会仔细看看你的代码。敬请期待!
【解决方案2】:

我认为 MATLAB CODER 支持 interp1
只需使用 CODER 生成 C 代码,即可获得所需的一切。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多