The module scikits.talkbox contains some C code for Levinson-Durbin recursion. Unfortunately, this code does not work in recent versions of Python, and I'd like to replace it with a pure-Python implementation. (Speed is not an issue, so long as it works.)
The docstring of the broken C function reads:
Levinson-Durbin recursion, to efficiently solve symmetric linear systems
with toeplitz structure.
Parameters
----------
r : array-like
input array to invert (since the matrix is symmetric Toeplitz, the
corresponding pxp matrix is defined by p items only). Generally the
autocorrelation of the signal for linear prediction coefficients
estimation. The first item must be a non zero real, and corresponds
to the autocorelation at lag 0 for linear prediction.
order : int
order of the recursion. For order p, you will get p+1 coefficients.
axis : int, optional
axis over which the algorithm is applied. -1 by default.
Returns
-------
a : array-like
the solution of the inversion (see notes).
e : array-like
the prediction error.
k : array-like
reflection coefficients.
Notes
-----
Levinson is a well-known algorithm to solve the Hermitian toeplitz
equation: ::
_ _
-R[1] = R[0] R[1] ... R[p-1] a[1]
: : : : :
: : : _ * :
-R[p] = R[p-1] R[p-2] ... R[0] a[p]
with respect to a. Using the special symmetry in the matrix, the inversion
can be done in O(p^2) instead of O(p^3).
Only double argument are supported: float and long double are internally
converted to double, and complex input are not supported at all.
I see that there's a function scipy.linalg.solve_toeplitz
which looks like what I want. However, it gives no way to specify the order, and takes a tuple of arrays as input.
I admit I'm somewhat out of my depth here, and don't fully understand what this code is supposed to do. Is there an easy way to replace a call to the broken C function with Numpy's solve_toeplitz
?
The scikits.talkbox
package also includes a module called py_lpc
, which contains a pure-Python implementation of the LPC estimation. It's not too difficult to adapt this.
def lpc2(signal, order):
"""Compute the Linear Prediction Coefficients.
Return the order + 1 LPC coefficients for the signal. c = lpc(x, k) will
find the k+1 coefficients of a k order linear filter:
xp[n] = -c[1] * x[n-2] - ... - c[k-1] * x[n-k-1]
Such as the sum of the squared-error e[i] = xp[i] - x[i] is minimized.
Parameters
----------
signal: array_like
input signal
order : int
LPC order (the output will have order + 1 items)"""
order = int(order)
if signal.ndim > 1:
raise ValueError("Array of rank > 1 not supported yet")
if order > signal.size:
raise ValueError("Input signal must have a lenght >= lpc order")
if order > 0:
p = order + 1
r = np.zeros(p, signal.dtype)
# Number of non zero values in autocorrelation one needs for p LPC
# coefficients
nx = np.min([p, signal.size])
x = np.correlate(signal, signal, 'full')
r[:nx] = x[signal.size-1:signal.size+order]
phi = np.dot(sp.linalg.inv(sp.linalg.toeplitz(r[:-1])), -r[1:])
return np.concatenate(([1.], phi)), None, None
else:
return np.ones(1, dtype = signal.dtype), None, None
This inverts the matrix without using any of the special Toeplitz properties, making it significantly slower, but works without any C code.