重采样,插值矩阵

9 投票
8 回答
14165 浏览
提问于 2025-04-15 16:43

我正在尝试对一些数据进行插值,以便绘图。比如说,给定N个数据点,我想生成一个“平滑”的图表,这个图表由大约10*N个插值数据点组成。

我的方法是生成一个N行10*N列的矩阵,然后计算原始数据向量和我生成的矩阵的内积,最终得到一个1行10*N列的向量。我已经算出了我想用来插值的数学公式,但我的代码运行得很慢。我对Python还不太熟悉,所以希望这里的一些专家能给我一些加速代码的建议。

我觉得问题的一部分在于,生成这个矩阵需要调用以下函数10*N^2次:

def sinc(x):
    import math
    try:
        return math.sin(math.pi * x) / (math.pi * x)
    except ZeroDivisionError:
        return 1.0

(这个内容来自于采样理论。简单来说,我是在尝试从样本重建一个信号,并将其上采样到更高的频率。)

这个矩阵是通过以下方式生成的:

def resampleMatrix(Tso, Tsf, o, f):
    from numpy import array as npar
    retval = []

    for i in range(f):
        retval.append([sinc((Tsf*i - Tso*j)/Tso) for j in range(o)])

    return npar(retval)

我在考虑把这个任务拆分成更小的部分,因为我不喜欢在内存中存放一个N^2的矩阵。我可能可以把'resampleMatrix'做成一个生成器函数,然后逐行计算内积,但我觉得这样做不会大幅提升我的代码速度,直到我开始将数据从内存中分页进出。

提前感谢你的建议!

8 个回答

1

如果你只是想“生成一个平滑的图”,那么我建议你使用简单的多项式样条曲线拟合:

对于任何两个相邻的数据点,可以通过这两个点的坐标以及它们左边和右边的两个额外点(不考虑边界点)来计算一个三次多项式函数的系数。这样就能生成一个平滑的曲线,并且曲线的斜率是连续的。虽然有一个简单的公式可以把4个坐标转换成4个多项式系数,但我不想剥夺你自己查找的乐趣哦;o)。

3

如果你想以一种比较通用且快速的方式来插值数据,样条函数或多项式是非常有用的。Scipy库里有一个叫做scipy.interpolate的模块,这个模块非常实用。你可以在官方页面找到很多例子。

9

这就是上采样。你可以查看关于重采样/上采样的帮助,里面有一些示例解决方案。

对于离线数据(比如你绘图时用的数据),有一种快速的方法是使用快速傅里叶变换(FFT)。这就是SciPy的resample()函数所做的事情。不过,它假设信号是周期性的,所以并不完全相同。你可以参考这篇文章

这是关于时域真实信号插值的第二个问题,确实很重要。这个插值算法只有在原始的x(n)序列在其完整时间区间内是周期性的情况下,才能提供正确的结果。

你的函数假设信号在定义范围之外的样本都是0,所以这两种方法会在中心点处偏离。如果你先在信号两边加上很多零,它会产生非常接近的结果。这里的图中显示的边缘之外还有更多的零:

enter image description here

对于重采样来说,立方插值是不正确的。这个例子是一个极端情况(接近采样频率),但正如你所看到的,立方插值甚至都不接近。对于较低的频率,它应该是相当准确的。

撰写回答