尝试对音频进行下采样

信息处理 下采样
2022-02-15 14:03:44

我正在尝试从44100Hz8000Hz,我不确定我在这里做错了什么。 44100/80005.5125,所以我对小数余数有点担心,这导致我的实现播放速度比预期的要慢一些。似乎我需要以某种方式使用小数余数来弥补这一点,但我不确定如何......

def downsample
  s = low_pass_filtered_signal_by_half_target_sample_rate
  samples_to_discard = (sample_rate.to_f / target_sample_rate).floor //   (44100.0 / 8000.0).floor

  s1_n = 0
  for (n = 0; n < N; n++) {
     if (n % samples_to_discard == 0) {
       s1[s1_n] = averaged(n, samples_to_discard)
       s1_n += 1
    }
  }
end

def averaged(start_index, samples_to_discard)
  sum = 0
    for (n = start_index, n < start_index + samples_to_discard; n++) {
      sum += s[n] || 0
    }
  sum / samples_to_discard
end
2个回答

首先,您需要在样本之间进行插值,而不仅仅是保留和丢弃样本(这会在非整数下采样期间引入可怕的抖动噪声)。

然后,如果原始音频数据包含大约或高于 4000 Hz(采样率的一半)的频谱,您将需要在插值之前或结合低通滤波器到较低的采样率,否则会出现混叠。

低通滤波加插值的一种很好的组合方法是使用加窗 Sinc 函数作为插值内核,其中 Sinc 被缩放为具有适当低通削减的理想“砖墙”或矩形滤波器的变换-关闭频率。缩放 Sinc 函数上的窗口宽度将控制频率截止的过渡宽度。

首先,确保您的信号通过合适的低通滤波器被限制在 4kHz 范围内,这样就不会出现混叠问题。其次,如果您不是在寻找“完全”准确的样本,那么请使用一个相当简单的重新采样函数,例如截断的 sinc 插值器......

模拟重建的方程是:

xr(t)=nx[n]sinc((tnT1)/T1)
该数学推导表示模拟低通重构滤波器的输出,该滤波器由脉冲序列驱动,该脉冲序列由从以原始采样率 (44100 Hz) 采样 x(t) 获得的 x[n] 样本加权,并且T1是那个采样周期。sinc(x) 是 sin(x)/x 的缩写

你重新采样这个重构信号的方程是:

x[m]=nx[n]sinc((mT2nT1)/T1)
对于 m=0,1,...,以新速率 (8000 hz) 下采样信号的长度和T2是它的时期。必须为每个输出 m 值计算 n 的内部总和,这是生成重采样信号 x[m] 所必需的

尽管上面的公式在数学上描述了采样率转换,但有时最好使用简单的技术,而不是多速率滤波器组的多相实现,例如如下所示的线性插值:假设原始信号将有足够的带宽限制,您将得到比较满意的结果。

注意:您提到了不成比例的播放时间,我不确定确切的原因,但由于分数转换,您可能在输出中有 1 个过量或 1 个缺失样本。考虑在 44100 赫兹时长度为 10.000 的原始信号,并将其转换为 8000 的速率将产生 1814.058 个样本,这些样本可能会四舍五入到 1814。有很多技巧可以克服这个实际问题,具体取决于您的整体架构。但我不确定这是否会在短时间的播放中造成明显的延迟。

下面是简单线性插值器的 matlab 代码,您可以从绘制的频谱中看到,几乎没有错误,这是因为您实际上是在对已经低通的信号进行下采样(首先,您拥有比必要更多的信息)

T1 = 1/44100;
T2 = 1/8000;
t1 = [0:T1:2];
t2 = [0:T2:2];

x = sin(2*pi*1451*t1)+0.21*cos(2*pi*853*t1);  % generate a test signal
figure,stem(x); axis([ 1 length(x) -1.3 1.3]);    % sufficiently low pass

L = 80;
M = 441;
K = M/L;
xd = zeros(1,floor(length(x)/K));
%x = filter(fir1(64,1/(2*K)),1,x);      % optionally band limit x to avoid aliasing otherwise linear interpolator will be insufficient.

for n=1:length(xd)   % you can vectorize this code for buffered processing
        m = K*n;
       mi = floor(m);
        d = m - mi;
    xd(n) = x(mi+1)*(d) + (1-d)*x(mi);  % simplest linear interpolator
end

figure,stem(xd); axis([ 1 length(xd) -1.43 1.43]);
figure,plot(abs(fft(x,1024)));
figure,plot(abs(fft(xd,1024)));

% FINALY PLAY THEM to hear resulting signal
sound(x,44100,16);
sound(xd,8000,16); % seems OK