2

MATLAB のquantiz関数 (xd はデシメートされた信号) を python/scipyに変換するにはどうすればよいですか?

アルゴリズムを完全なパッケージに変換するために、Python と scipy、numpy、pygtk、matplotlib などのライブラリを使用して、音声処理用に MATLAB で開発したアルゴリズムをソフトウェア パッケージに実装しようとしています。

アルゴリズム開発に scipy を使用していますが、Python で「信号を量子化する」ための適切な関数が見つかりません。

[I,xq] = quantiz(xd,1:step:1-step, -1:step:1);

これをpythonで書くにはどうすればよいでしょうか?

4

1 に答える 1

5

ドキュメントを見ると、非常に単純な関数であり、Python で簡単に記述できます。面倒だったので、欠落している「e」を追加するように関数の名前を変更しました。ともかく:

def quantize(signal, partitions, codebook):
    indices = []
    quanta = []
    for datum in signal:
        index = 0
        while index < len(partitions) and datum > partitions[index]:
            index += 1
        indices.append(index)
        quanta.append(codebook[index])
    return indices, quanta

ドキュメントの例で試してみてください:

>>> index, quants = quantize([3, 34, 84, 40, 23], range(10, 90, 10), range(10, 100, 10))
>>> index
[0, 3, 8, 3, 2]
>>> quants
[10, 40, 90, 40, 30]

わずかに効率的ですが柔軟性の低いバージョンの場合、範囲をバイパスして数学のみを使用できます。

from __future__ import division
import math

def opt_quantize(signal, num_quanta, partition_start, partition_step,
                 codebook_start, codebook_step):
    indices = []
    quanta = []
    for datum in signal:
        index = int(math.floor((datum - partition_start) / partition_step + 1))
        if index < 0:
            index = 0
        if index >= num_quanta:
            index = num_quanta - 1
        indices.append(index)
        quanta.append(codebook_start + codebook_step * index)
    return indices, quanta

ドキュメントの例で試してみてください:

>>> index, quants = opt_quantize([3, 34, 84, 40, 23], 9, 10, 10, 10, 10)
>>> index
[0, 3, 8, 4, 2]
>>> quants
[10, 40, 90, 50, 30]

したがって、浮動小数点エラーのためにデータが正確にパーティション上にある場合、結果はわずかに異なりますが、パーティション上に何もない場合は機能します。


n は信号の長さ、m は O(mn) から O(n) までの分割数です。これにより、パフォーマンスが大幅に向上するはずです。もっとうまくやれるでしょうか?

はい。新しい数学ベースのアプローチにより、コードは簡単にベクトル化され、Numpy に大変な作業を行わせることができます。

import numpy as np

def np_quantize(signal, num_quanta, partition_start, partition_step,
                codebook_start, codebook_step):
    signal = np.asarray(signal, dtype=float)
    indices = np.empty_like(signal, dtype=int)
    np.floor_divide((signal - partition_start + partition_step), \
                    partition_step, indices)
    np.clip(indices, 0, num_quanta - 1, indices)
    quanta = np.asarray(indices, dtype=float) * codebook_step + codebook_start
    return indices, quanta

たまたまベンチマークを行ったところ、最適化のたびに速度が低下しているように見えるため、何かひどく間違っているか、定数を償却するのに十分な大きさのデータでテストしていません。

~$ python -m timeit -s 'from quantize import orig_quantize' 'orig_quantize([-3, -2, -1, 0, 1, 2, 3], [-0.5, 0.5], [-1, 0, 1])'
100000 loops, best of 3: 8.58 usec per loop
~$ python -m timeit -s 'from quantize import opt_quantize' 'opt_quantize([-3, -2, -1, 0, 1, 2, 3], 3, -0.5, 1, -1, 1)'
100000 loops, best of 3: 10.8 usec per loop
~$ python -m timeit -s 'from quantize import np_quantize' 'np_quantize([-3, -2, -1, 0, 1, 2, 3], 3, -0.5, 1, -1, 1)'
10000 loops, best of 3: 57.4 usec per loop

キックのために、Cythonと Numpyを使用してみました。

cimport cython
cimport numpy as np

cdef extern from "math.h":
    float floorf(float)


@cython.boundscheck(False)
def cynp_quantize(np.ndarray[float, ndim=1] signal, int num_quanta,
                  float partition_start, float partition_step,
                  float codebook_start, float codebook_step):
    cdef int i
    cdef int index
    cdef np.ndarray[np.int_t, ndim=1] indices = np.empty_like(signal, dtype=int)
    cdef np.ndarray[float, ndim=1] quanta = np.empty_like(signal)
    for i in range(signal.shape[0]):
        index = <int>floorf((signal[i] - partition_start)
                            / partition_step + 1.0)
        if index < 0:
            index = 0
        if index >= num_quanta:
            index = num_quanta - 1
        indices[i] = index
        quanta[i] = codebook_start + index * codebook_step
    return indices, quanta

私が収集した情報によると、Cython は実験的に OpenMP もサポートしており、複数のスレッドですべてを実行できます。ただし、スレッドの有無にかかわらず、この Cython ソリューションのパフォーマンスをテストできませんでした (結果をコンパイルするために必要なヘッダー ファイルがありません)。

于 2013-04-13T04:57:36.120 に答える