使用aryule的参数谱估计:Python和Matlab的区别

计算科学 matlab Python 信号处理
2021-12-17 00:57:40

我有一些代码说明了我的问题。从结果中可以看出——Matlab 比 python 快得多。在 Matlab 中执行 levinson durbin 递归的函数似乎是一个 Mex 文件。这可能是 Matlab 明显更快的原因吗?我如何使 Python 实现与 Matlab 相提并论,或者有人知道这样的版本是否已经存在?

在另一个问题上,python aryule 函数似乎无法处理不是单位方差的白噪声。例如,如果我要使用

X = 0.2*randn(1, 256000)

AR 系数的 python 估计值会不太准确。Matlab似乎没有这个问题。有没有办法在 Python 中实现它?

Matlab 实现

A=[1 -2.7607 3.8106 -2.6535 0.9238];
% AR(4) coefficients
y=filter(1,A,0.2*randn(256000,1));
%filter a white noise input to create AR(4) process
t = cputime;  
[ar_coeffs v]=aryule(y,4);
e = cputime-t;
disp(['Elapsed Time: ' num2str(e)]);
%compare the results in ar_coeffs to the vector A.
ar_coeffs

结果:

Elapsed Time: 0.14

Python 实现

from pylab import *
import scipy.signal
from spectrum import *
import time

# Create an AR model
a = [1, -2.7607, 3.8106, -2.6535, 0.9238]
# create some data based on these AR parameters
X = randn(1, 256000)
y = scipy.signal.lfilter([1], a, X)
# now, let us try to estimate the original AR parameters
t0 = time.time()
AR, P, k = aryule(y[0], 4)
print "Time elapsed: ", time.time()-t0
%compare the results in ar_coeffs to the vector A.
print(AR)

结果:

Time elapsed:  2.48965501785
2个回答

Python 代码比等价的 Matlab 代码慢的原因通常是在 Matlab 中,更多的计算是由以下库执行的

  1. 用低级语言编写,并且
  2. 高度优化。

幸运的是,你可以在 Python 中做同样的事情。

例如,Matlab 链接(并捆绑)英特尔的手动调整 MKL 库,而 Python(即 NumPy/SciPy)通常链接到通用系统 BLAS/LAPACK。经过一番争论(并且在向英特尔支付许可证后),您可以自己构建 NumPy/SciPy,以便它调用 MKL;在那之后,对于主要依赖于 BLAS/LAPACK 调用的任何东西,您都会获得大致相同的性能。您可以对OpenBLAS执行相同的操作,它具有与 MKL 相似的性能,但它是开源的,并且更易于构建 NumPy。使用此设置,我的机器上的 Python 代码需要 0.66 秒(它在 0.09 秒内运行您的 Matlab 代码)。

正如您所指出的,剩余的性能差异可能是由于 Matlab 的版本是作为 MEX 文件实现的(即,用 C 语言编写并预编译)。在 Python 中有几个选项可以做同样的事情,例如Cython正如 awesomebytes 雄辩地建议的那样,您可能希望避免使用 Spectrum(不再积极开发)并尝试使用相关函数,scipy.signal.correlate如果您不想弄脏 C。(LD 递归在 中实现scipy.linalg.solve_toeplitz)。您可能还想看看statsmodelnitime

如何使该过程更快?好吧,首先,如果您觉得有时间可以检查实施,我现在正在这样做。(警告:我需要截断链接,因为 stackexchange 不允许我拥有超过 2 个链接)

代码在这里:汇编。com /code/PySpectrum/subversion/nodes/37/trunk/src/spectrum

看看这个包,它已经包含一些 .c 代码来加快一些操作。如果需要,这可能会简化某些部分在 C 中的实现,以便稍后通过 Python 导入它。

我做了 svn checkout https://subversion.assembla.com/svn/PySpectrum/

我得到了:~/spectrumlib/PySpectrum/trunk/src/cpp$ ls init .py mydpss.c

mydpss.c 实现了一些子例程。也许可以在那里添加一些东西。

但是让我们看一下实际正在执行的代码: assembla 。com /code/PySpectrum/subversion/nodes/37/trunk/src/spectrum/yulewalker.py

from correlation import CORRELATION
from levinson import LEVINSON

r = CORRELATION(X, maxlags=order, norm=norm)
A, P, k = LEVINSON(r, allow_singularity=allow_singularity)
return A, P, k

这就是正在执行的。让我们检查一下这里的慢速部分是什么。

所以我修改了 yulewalker.py 如下:

import time
print "Correlation calculation"
t0 = time.time()
r = CORRELATION(X, maxlags=order, norm=norm)
print "Time elapsed: ", time.time()-t0
print "Levinson calculation"
t1 = time.time()
A, P, k = LEVINSON(r, allow_singularity=allow_singularity)
print "Time elapsed: ", time.time()-t1
return A, P, k

我运行了你的 stackexchange 代码,我得到了:

./aryulespeed.py 
Correlation calculation
Time elapsed:  1.50509214401
Levinson calculation
Time elapsed:  0.000110864639282
Time elapsed:  1.50538802147
[-2.7616739   3.81292317 -2.65578205  0.9248034 ]

所以相关性计算是缓慢的部分!啊哈!这个人:汇编。com /code/PySpectrum/subversion/nodes/37/trunk/src/spectrum/correlation.py 似乎是胖子。

哦,看,代码中有一个有趣的注释:

Provides two correlation functions. :func:`CORRELATION` is slower than
:func:`xcorr`. However, the output is as expected by some other functions.
Ultimately, it should be replaced by :func:`xcorr`.

For real data, the behaviour of the 2 functions is identical. However, for
complex data, xcorr returns a 2-sides correlation.

也许我们应该尝试将这个 CORRELATION 交换为 xcorr!

所以我尝试了:

#! /usr/bin/env python
from pylab import *
import scipy.signal
from spectrum import *
import time

# The original imports
from spectrum.correlation import CORRELATION
from spectrum.levinson import LEVINSON
# The faster corr
from spectrum.correlation import xcorr

def superawesomearyule(X, order, norm='biased', allow_singularity=True):

    assert norm in ['biased', 'unbiased']
    import time
    print "Correlation calculation in superawesomearyule"
    t0 = time.time()
    #r = CORRELATION(X, maxlags=order, norm=norm) # Commenting you, slowwww     code!
    r = xcorr(X, maxlags=order, norm=norm)
    print "Time elapsed: ", time.time()-t0
    print "Levinson calculation"
    t1 = time.time()
    A, P, k = LEVINSON(r, allow_singularity=allow_singularity)
    print "Time elapsed: ", time.time()-t1
    return A, P, k



# Create an AR model
a = [1, -2.7607, 3.8106, -2.6535, 0.9238]
# create some data based on these AR parameters
X = randn(1, 256000)
y = scipy.signal.lfilter([1], a, X)
# now, let us try to estimate the original AR parameters
t0 = time.time()
#AR, P, k = aryule(y[0], 4)
AR, P, k = superawesomearyule(y[0], 4)
print "Time elapsed: ", time.time()-t0
#%compare the results in ar_coeffs to the vector A.
print(AR)

并执行:

./aryulespeed.py 
Correlation calculation in superawesomearyule
Time elapsed:  69.9396679401
Levinson calculation
Traceback (most recent call last):
  File "./aryulespeed.py", line 38, in <module>
    AR, P, k = superawesomearyule(y[0], 4)
  File "./aryulespeed.py", line 24, in superawesomearyule
    A, P, k = LEVINSON(r, allow_singularity=allow_singularity)
  File "/usr/local/lib/python2.7/dist-packages/spectrum/levinson.py", line     112, in LEVINSON
    if P <= 0 and allow_singularity==False:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

而且......哦,不:(花了69秒!!然后在莱文森上也坠毁了。

我认为给它一点爱可以在这里做一些事情。也许给它的开发者 Thomas Cokelaer 发一封邮件会有所帮助。

很抱歉,我现在不能在这个问题上投入更多时间。我希望这对您有所帮助:)

我还发现了这个 github 仓库: https ://github.com/RhysU/ar

其中有一个带有一些 python 绑定的 ar 实现。它也可能对您有所帮助。

祝你好运!