C 增加采样的正确方法是什么?

C 增加采样的正确方法是什么?,c,math,signal-processing,sampling,resampling,C,Math,Signal Processing,Sampling,Resampling,我有一个75赫兹的样本阵列,我想把它们存储在128赫兹。如果它是64赫兹和128赫兹,这是非常简单的,我会把所有样本加倍。但是,如果取样器不是彼此的一小部分,那么正确的方法是什么呢?最简单的方法是将采样率增加到一个采样率,即两个采样率的LCM,然后再减少采样-这样可以得到整数增加采样率/减少采样率。在您的情况下,两个采样率中没有共同因素,因此您需要将采样率提高128到9.6 kHz,然后将采样率降低75到128 Hz。对于上采样,在每个采样之间插入1270个采样,然后应用合适的滤波器(37 Hz

我有一个75赫兹的样本阵列,我想把它们存储在128赫兹。如果它是64赫兹和128赫兹,这是非常简单的,我会把所有样本加倍。但是,如果取样器不是彼此的一小部分,那么正确的方法是什么呢?

最简单的方法是将采样率增加到一个采样率,即两个采样率的LCM,然后再减少采样-这样可以得到整数增加采样率/减少采样率。在您的情况下,两个采样率中没有共同因素,因此您需要将采样率提高128到9.6 kHz,然后将采样率降低75到128 Hz。对于上采样,在每个采样之间插入1270个采样,然后应用合适的滤波器(37 Hz LPF,Fs=9.6 kHz),然后通过每75个采样进行下采样。过滤器的设计是唯一棘手的部分,但是有在线工具可以帮助您完成这项艰巨的工作


或者看看处理重采样的第三方库,例如,..

您需要使用中间采样频率进行上采样和下采样,如@Paul所述。此外,需要在每次变换后对信号进行滤波,这可以通过线性插值实现,如下所示:

% Parameters
F = 2;
Fs1 = 75;
Fs3 = 128;
Fs2 = lcm(Fs1,Fs3);

% Original signal
t1 = 0:1/Fs1:1;
y1 = sin(2*pi*F*t1);

% Up-sampled signal
t2 = 0:1/Fs2:1;
y2 = interp1(t1,y1,t2);

% Down-sampled signal
t3 = 0:1/Fs3:1;
y3 = interp1(t2,y2,t3);

figure;
subplot(3,1,1);
plot(t1,y1,'b*-');
title(['Signal with sampling frequency of ', num2str(Fs1), 'Hz']);
subplot(3,1,2);
plot(t2,y2,'b*-');
title(['Signal with sampling frequency of ', num2str(Fs2), 'Hz']);
subplot(3,1,3);
plot(t3,y3,'b*-');
title(['Signal with sampling frequency of ', num2str(Fs3), 'Hz']);

您不需要先上采样再下采样


相反,可以使用足够宽的低通插值核(如加窗Sinc函数)以所需的时间间隔对所有新采样点进行插值。这通常是通过直接使用预先计算的多相滤波器组或通过滤波器表的附加线性插值来实现的。但是,如果性能不重要,则可以直接计算每个插值点的每个系数。

如果要避免过滤,则可以:

  • 将信号处理为一组连接的插值立方体曲线

    但这一点与使用线性插值相同。如果不了解有关信号和用途的更多信息,则无法构造
    有效的
    系数(在不损害信号精度的情况下),例如,如何构造此类立方体外观:

    在链接内的bullet#3中是我使用的系数。我认为有足够的,甚至为你的目的,所以你可以尝试他们。如果要执行自定义插值,请查看此处:

  • 创建一个函数,该函数可以在采样开始后的给定时间内返回信号中的点

    所以做些类似的事情

    double signal(double time);
    
    其中
    time
    是从采样开始的时间,单位为[s]。在该函数中,计算需要访问的4个示例

    ix = floor(time*75.0);
    
    为您提供曲线起点示例索引。立方体需要4个点,一个在曲线前,一个在曲线后。。。因此,对于插值立方点
    p0、p1、p2、p3
    使用样本
    ix-1、ix、ix+1、ix+2
    。计算立方系数
    a0、a1、a2、a3
    并计算立方曲线参数
    t
    (我使用范围
    )因此

    • 绿色-实际曲线段
    • aqua-实际曲线段控制点=75.0 Hz样本
    • 红曲线参数插值参数t
    • 灰色-实际时间
    对不起,我忘了画实际的输出信号点,它应该是绿色和灰色的交叉点

  • 只需使用1/128 s的时间步长对采样数据进行循环即可

    大概是这样的:

    double time,duration=samples*75.0,dt=1.0/128.0;
    double signal128[???];
    for (time=0.0,i=0;time<duration;i++,time+=dt)
     signal128[i]=signal(time);
    
    双倍时间,持续时间=samples*75.0,dt=1.0/128.0;
    双信号128[??];
    
    对于(time=0.0,i=0;将所有样本时间加倍不是将采样率加倍的正确方法。@interjay您能详细说明吗?答案已经说明了。重复样本会增加噪音。请参阅答案或谷歌以获得正确方法的上采样。最后完成编辑。用几何方法添加了问题的答案。我需要实现这个过滤器是纯C语言的,在我的设备中只有很少的RAM和CPU。有没有可能不用过滤就可以做到这一点?这取决于你的重采样需要什么样的质量和精度。你可以用线性插值来做粗略的重采样,但是会有一些伪像。我们在这里谈论的是什么样的信号?这是一个PPG(体积图)通道,它显示脉冲波。通常这是一个8位通道,但我有16位样本。如果我不过滤它(包括人造波),可能是吗它仍将比正确上采样的8位通道更精确?在这种情况下,这没有问题。我建议尝试简单的线性插值而不进行任何滤波,但您可能需要知道信号中的哪些特征很重要,以及它们是否因使用的重采样方案而降级。您可以首先要在MATLAB或Octave等工具中对此进行建模,以确保它对您的应用程序足够好。我会在
    for
    循环中使用与
    I
    的比较,这样您就不必担心舍入错误导致缓冲区溢出。在此处执行重采样插值的示例代码:
    double time,duration=samples*75.0,dt=1.0/128.0;
    double signal128[???];
    for (time=0.0,i=0;time<duration;i++,time+=dt)
     signal128[i]=signal(time);