无论是下采样还是过采样,您都在尝试在非采样时间点上重建信号...因此您必须做出一些假设。
采样定理告诉您,如果您采样一个信号,并知道其没有频率分量超过采样频率的一半,则可以连续完全地恢复整个时间段内的信号。有一种使用`sinc()`函数(即`sin(x)/x`)来重构信号的方法。
`sinc()`(确实是`sin(M_PI/Sampling_period*x)/M_PI/x`)是具有以下属性的函数:
1. 当 `x == 0.0` 时,它的值为1,当 `x == k*Sampling_period` 时,它的值为0,其中 `k == 0, +-1, +-2, ...`
2. 它没有超过由`Sampling_period`导出的采样频率的一半的频率分量。
因此,如果您认为函数`F_x(x) = Y[k]*sinc(x/Sampling_period - k)`的总和是等于位置`k`的采样值且在其他采样值处为0的`sinc()`函数,并对样本中的所有k求和,则将获得具有不具有超过采样频率一半的频率分量的最佳连续函数,并具有与样本集相同的值。
这样说,您可以在任何位置重新采样此函数,从而获得重新采样数据的最佳方法。
这绝对是一种复杂的重采样数据的方法(它也有不是因果的问题,因此无法实时实现),过去使用了几种简化插值的方法。您必须为每个采样点构造所有`sinc()`函数并将它们相加。然后,您必须将结果函数重新采样到新的采样点,并将其作为结果给出。
下面是刚才描述的插值方法的示例。它接受一些输入数据(`in_sz`个样本)并使用前面描述的方法输出插值数据(我假设极值相同,这使得`N+1`个样本等于`N+1`个样本,并且这使得代码中的有些复杂计算变得更加复杂(如果要进行普通的`N个样本->M个样本`转换,请将其更改为`in_sz/out_sz`)。
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
double sinc(double x)
{
x *= M_PI;
if (x == 0.0) return 1.0;
return sin(x)/x;
}
double sinc_approx(double in[], size_t in_sz, double x)
{
int i;
double res = 0.0;
for (i = 0; i < in_sz; i++)
res += in[i] * sinc(x - i);
return res;
}
void resample_sinc(
double in[],
size_t in_sz,
double out[],
size_t out_sz)
{
int i;
double dx = (double) (in_sz-1) / (out_sz-1);
for (i = 0; i < out_sz; i++)
out[i] = sinc_approx(in, in_sz, i*dx);
}
int main()
{
double in[] = {
0.0, 1.0, 0.5, 0.2, 0.1, 0.0,
};
const size_t in_sz = sizeof in / sizeof in[0];
const size_t out_sz = 5;
double out[out_sz];
int i;
for (i = 0; i < in_sz; i++)
printf("in[%d] = %.6f\n", i, in[i]);
resample_sinc(in, in_sz, out, out_sz);
for (i = 0; i < out_sz; i++)
printf("out[%.6f] = %.6f\n", (double) i * (in_sz-1)/(out_sz-1), out[i]);
return EXIT_SUCCESS;
}