【问题标题】:Resample a numpy array重新采样一个 numpy 数组
【发布时间】:2015-05-19 01:34:35
【问题描述】:

像

这样的数组很容易重新采样
 a = numpy.array([1,2,3,4,5,6,7,8,9,10])

带有一个整数重采样因子。例如,因子为 2:

b = a[::2]    # [1 3 5 7 9]

但是对于非整数重采样因子,它并不那么容易工作:

c = a[::1.5]    # [1 2 3 4 5 6 7 8 9 10]  => not what is needed...

应该是(使用线性插值):

[1 2.5 4 5.5 7 8.5 10]

或(通过取数组中最近的邻居)

[1 3 4 6 7 9 10]

如何使用非整数重采样因子对 numpy 数组进行重采样?

应用示例:音频信号重采样/重调

【问题讨论】:

  • 期望的行为是什么?数组中的线性插值还是最近邻?
  • @wflynny 两者都可以工作......如果最近的邻居,可能甚至没有必要在内存中复制数组,只是数组的新“视图”可能是可能的,对吧? (最后我可能会使用线性插值以获得更好的质量)
  • 可能必须使用 scipy.interpolate.interp1d 或 scipy 中的其他插值例程之一
  • “重采样”是描述::2 索引方式的一种不同寻常的方式。 numpy 数组(和 Python 列表)主要不被视为样本(尽管它们的值可能代表其他东西的样本)。
  • @hpaulj 我使用了重采样这个词,因为我使用 numpy 数组来存储 .WAV 文件中包含的音频数据。对这个数组执行此操作在音频中称为“重采样”/或“重调”,这取决于我们如何使用它。

标签: python arrays numpy audio resampling


【解决方案1】:

NumPy 有 numpy.interp 进行线性插值:

In [1]: numpy.interp(np.arange(0, len(a), 1.5), np.arange(0, len(a)), a)
Out[1]: array([  1. ,   2.5,   4. ,   5.5,   7. ,   8.5,  10. ])

SciPy 有 scipy.interpolate.interp1d 可以进行线性和最近插值(尽管哪个点最近可能不明显):

In [2]: from scipy.interpolate import interp1d
In [3]: xp = np.arange(0, len(a), 1.5)
In [4]: lin = interp1d(np.arange(len(a)), a)

In [5]: lin(xp)
Out[5]: array([  1. ,   2.5,   4. ,   5.5,   7. ,   8.5,  10. ])

In [6]: nearest = interp1d(np.arange(len(a)), a, kind='nearest')

In [7]: nearest(xp)
Out[7]: array([  1.,   2.,   4.,   5.,   7.,   8.,  10.])

【讨论】:

    【解决方案2】:

    由于scipy.signal.resample可以是very slow,所以我搜索了其他适用于音频的算法。

    似乎 Erik de Castro Lopo 的 SRC(又名 Secret Rabbit Code 又名 libsamplerate)是可用的最佳重采样算法之一。

    • 是scikit的scikit.samplerate使用的,但是这个库好像安装起来比较复杂(Windows下放弃了)。

    • 幸运的是,有一个易于使用且易于安装的 Python 包装器 libsamplerate,由 Tino Wagner 制作:https://pypi.org/project/samplerate/。使用pip install samplerate 安装。用法:

      import samplerate
      from scipy.io import wavfile
      sr, x = wavfile.read('input.wav')  # 48 khz file
      y = samplerate.resample(x, 44100 * 1.0 / 48000, 'sinc_best')  
      

    许多重采样解决方案的有趣阅读/比较: http://signalsprocessed.blogspot.com/2016/08/audio-resampling-in-python.html


    附录:重采样频率扫描(20hz 到 20khz)的频谱图比较:

    1) 原创

    2) 使用 libsamplerate / samplerate 模块重新采样

    3) 使用numpy.interp(“一维线性插值”)重新采样:

    【讨论】:

      【解决方案3】:

      由于您提到这是来自音频 .WAV 文件的数据,您可能会查看 scipy.signal.resample。

      使用傅里叶方法沿给定轴重新采样 x 到 num 样本。

      重新采样的信号从与x 相同的值开始,但被采样 间距为len(x) / num * (spacing of x)。因为一个 使用傅里叶方法,假设信号是周期性的。

      您的线性阵列a 不适合对此进行测试,因为它在外观上不是周期性的。但考虑sin 数据:

      x=np.arange(10)
      y=np.sin(x)
      y1, x1 =signal.resample(y,15,x)  # 10 pts resampled at 15
      

      比较一下

      y1-np.sin(x1) # or
      plot(x, y, x1, y1)
      

      【讨论】:

      【解决方案4】:

      如果你想要整数采样

      a = numpy.array([1,2,3,4,5,6,7,8,9,10])
      factor = 1.5
      x = map(int,numpy.round(numpy.arange(0,len(a),factor)))
      sampled = a[x]
      

      【讨论】:

      • 也不错!就速度而言,您认为它比其他解决方案更有效吗?
      • 可能不会比 scipy / numpy 解决方案快。只是给你选择。
      【解决方案5】:

      在信号处理中,您可以将重采样视为基本上重新缩放数组并使用最接近、线性、三次等方法插入缺失值或具有非整数索引的值。

      使用scipy.interpolate.interp1d,可以使用如下函数实现一维重采样

      def resample(x, factor, kind='linear'):
          n = np.ceil(x.size / factor)
          f = interp1d(np.linspace(0, 1, x.size), x, kind)
          return f(np.linspace(0, 1, n))
      

      例如:

      a = np.array([1,2,3,4,5,6,7,8,9,10])
      resample(a, factor=1.5, kind='linear')
      

      产量

      array([ 1. ,  2.5,  4. ,  5.5,  7. ,  8.5, 10. ])
      

      和

      a = np.array([1,2,3,4,5,6,7,8,9,10])
      resample(a, factor=1.5, kind='nearest')
      

      产量

      array([ 1.,  2.,  4.,  5.,  7.,  8., 10.])
      

      【讨论】:

        猜你喜欢
        • 2020-05-22
        • 2021-11-24
        • 2012-10-25
        • 1970-01-01
        • 2014-06-18
        • 1970-01-01
        • 2019-01-02
        • 1970-01-01
        • 2013-12-17
        相关资源
        最近更新 更多