Skip to content

LPC Analysis of Speech

Autocorrelation and covariance LPC, bandwidth expansion, inverse filtering, stability enforcement, and a complete set of conversions between LPC representations (AR, reflection coefficients, line spectra, cepstra, impulse response, power spectrum, poles and zeros, etc.).

Core LPC analysis

v_lpcauto

V_LPCAUTO - Perform autocorrelation LPC analysis.

v_lpcauto

v_lpcauto(
    s, p=12, t=None, w="m", m=""
) -> tuple[ndarray, ndarray, ndarray]

Perform autocorrelation LPC analysis.

Parameters:

Name Type Description Default
s (array_like, shape(ns) or (ns, nch))

Input signal.

required
p int

LPC order. Default is 12.

12
t array_like

Frame size details [hop, anal, skip]. Default is entire signal.

None
w str or array_like

Window type or window vector. Default is 'm' (Hamming).

'm'
m str

Mode options: 'e' normalize window, 'j' joint analysis.

''

Returns:

Name Type Description
ar (ndarray, shape(nf, p + 1) or (nf, p + 1, nch))

AR coefficients with ar[:, 0] = 1.

e (ndarray, shape(nf) or (nf, nch))

Residual energy.

k (ndarray, shape(nf, 2))

First and last sample of analysis intervals (1-based).

Source code in pyvoicebox/v_lpcauto.py
def v_lpcauto(s, p=12, t=None, w='m', m='') -> tuple[np.ndarray, np.ndarray, np.ndarray]:
    """Perform autocorrelation LPC analysis.

    Parameters
    ----------
    s : array_like, shape (ns,) or (ns, nch)
        Input signal.
    p : int, optional
        LPC order. Default is 12.
    t : array_like, optional
        Frame size details [hop, anal, skip]. Default is entire signal.
    w : str or array_like, optional
        Window type or window vector. Default is 'm' (Hamming).
    m : str, optional
        Mode options: 'e' normalize window, 'j' joint analysis.

    Returns
    -------
    ar : ndarray, shape (nf, p+1) or (nf, p+1, nch)
        AR coefficients with ar[:, 0] = 1.
    e : ndarray, shape (nf,) or (nf, nch)
        Residual energy.
    k : ndarray, shape (nf, 2)
        First and last sample of analysis intervals (1-based).
    """
    s = np.asarray(s, dtype=float)
    if s.ndim == 1:
        s = s[:, np.newaxis]
    elif s.shape[0] == 1:
        s = s.T

    ns, nch = s.shape

    wnam = ['c', 'k', 'm', 'n', 'r', 'w', 's', 'v']
    wtypes = [10, 11, 3, 2, 1, 8, 3, 7]

    modee = 'e' in m
    modej = 'j' in m
    wch = isinstance(w, str)

    if wch:
        if modee:
            wopt = 'e'
        else:
            wopt = ''
        try:
            wch_idx = wnam.index(w)
        except ValueError:
            wch_idx = 2  # default to Hamming
        wch = wch_idx
    else:
        w = np.asarray(w, dtype=float).ravel()
        if modee:
            w = w / np.sqrt(np.dot(w, w))
        wch = False

    if t is None:
        t = np.array([[ns, ns, 0]])
    else:
        t = np.atleast_2d(np.asarray(t, dtype=float))

    nf_t, ng = t.shape
    if ng == 1:
        t = np.column_stack([t, t, np.zeros((nf_t, 1))])
    elif ng == 2:
        t = np.column_stack([t, np.zeros((nf_t, 1))])

    if nf_t == 1:
        nf = int(np.floor(1 + (ns - t[0, 1] - t[0, 2]) / t[0, 0]))
        t = np.tile(t, (nf, 1))
    else:
        nf = nf_t

    # Calculate analysis frame start/end (1-based)
    cumhop = np.cumsum(np.concatenate([[0], t[:nf-1, 0]])) + t[:, 2]
    k_out = np.round(np.column_stack([cumhop + 1, cumhop + t[:, 1]])).astype(int)
    kd = k_out[:, 1] - k_out[:, 0] + 1  # frame lengths
    ku = np.unique(kd)
    nk = len(ku)

    ar = np.zeros((nf, p + 1, nch) if not modej else (nf, p + 1))
    e = np.zeros((nf, nch) if not modej else (nf,))

    for ik in range(nk):
        kui = ku[ik]
        if wch is not False:
            win = v_windows(wtypes[wch], kui, wopt, 5).ravel()
        else:
            win = w[:kui]

        pk = min(p, kui)
        km = kd == kui
        nkm = np.sum(km)
        frame_indices = np.where(km)[0]

        if modej:
            ark = np.zeros((pk + 1, nkm))
            rr = np.zeros((pk + 1, nkm))

            for idx, fi in enumerate(frame_indices):
                start = k_out[fi, 0] - 1
                end = k_out[fi, 1]
                frame_data = s[start:end, :] * win[:end - start, np.newaxis]
                rr[0, idx] = np.sum(frame_data ** 2)
                for lag in range(1, pk + 1):
                    rr[lag, idx] = np.sum(frame_data[:kui - lag, :] * frame_data[lag:, :])

            ark[0, :] = 1.0
            ark[1, :] = -rr[1, :] / rr[0, :]
            ek = rr[0, :] * (ark[1, :] ** 2 - 1)
            for n in range(2, pk + 1):
                ka = (rr[n, :] + np.sum(rr[n-1:0:-1, :] * ark[1:n, :], axis=0)) / ek
                ark[1:n, :] = ark[1:n, :] + ka[np.newaxis, :] * ark[n-1:0:-1, :]
                ark[n, :] = ka
                ek = ek * (1 - ka ** 2)

            ar[frame_indices, :pk + 1] = ark.T
            e[frame_indices] = -ek
        else:
            for ch in range(nch):
                ark = np.zeros((pk + 1, nkm))
                rr = np.zeros((pk + 1, nkm))

                for idx, fi in enumerate(frame_indices):
                    start = k_out[fi, 0] - 1
                    end = k_out[fi, 1]
                    frame_data = s[start:end, ch] * win[:end - start]
                    rr[0, idx] = np.sum(frame_data ** 2)
                    for lag in range(1, pk + 1):
                        rr[lag, idx] = np.sum(frame_data[:kui - lag] * frame_data[lag:])

                ark[0, :] = 1.0
                ark[1, :] = -rr[1, :] / rr[0, :]
                ek = rr[0, :] * (ark[1, :] ** 2 - 1)
                for n in range(2, pk + 1):
                    ka = (rr[n, :] + np.sum(rr[n-1:0:-1, :] * ark[1:n, :], axis=0)) / ek
                    ark[1:n, :] = ark[1:n, :] + ka[np.newaxis, :] * ark[n-1:0:-1, :]
                    ark[n, :] = ka
                    ek = ek * (1 - ka ** 2)

                ar[frame_indices, :pk + 1, ch] = ark.T
                e[frame_indices, ch] = -ek

    # Squeeze single channel
    if nch == 1 and not modej:
        ar = ar[:, :, 0]
        e = e[:, 0]

    return ar, e, k_out

v_lpccovar

V_LPCCOVAR - Perform covariance LPC analysis.

v_lpccovar

v_lpccovar(
    s, p=12, t=None
) -> tuple[ndarray, ndarray, ndarray]

Perform covariance LPC analysis.

Parameters:

Name Type Description Default
s (array_like, shape(ns))

Input signal.

required
p int

LPC order. Default is 12.

12
t array_like

Frame specification. Default is [p+1, len(s)] (1-based).

None

Returns:

Name Type Description
ar (ndarray, shape(nf, p + 1))

AR coefficients with ar[:, 0] = 1.

e (ndarray, shape(nf, 4))

[Er, Es, Pr, Ps]: energy and power in residual and signal.

dc (ndarray, shape(nf))

DC component (only meaningful if computed).

Source code in pyvoicebox/v_lpccovar.py
def v_lpccovar(s, p=12, t=None) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
    """Perform covariance LPC analysis.

    Parameters
    ----------
    s : array_like, shape (ns,)
        Input signal.
    p : int, optional
        LPC order. Default is 12.
    t : array_like, optional
        Frame specification. Default is [p+1, len(s)] (1-based).

    Returns
    -------
    ar : ndarray, shape (nf, p+1)
        AR coefficients with ar[:, 0] = 1.
    e : ndarray, shape (nf, 4)
        [Er, Es, Pr, Ps]: energy and power in residual and signal.
    dc : ndarray, shape (nf,)
        DC component (only meaningful if computed).
    """
    s = np.asarray(s, dtype=float).ravel()
    ns = len(s)

    if t is None:
        t = np.array([[p + 1, ns]])  # 1-based
    else:
        t = np.atleast_2d(np.asarray(t, dtype=float))

    nf, ng = t.shape
    if ng % 2 == 1:
        # Add end column
        ends = np.concatenate([t[1:, 0] - 1, [ns]])
        t = np.column_stack([t, ends])

    ar = np.zeros((nf, p + 1))
    ar[:, 0] = 1.0
    e = np.zeros((nf, 4))
    dc = np.zeros(nf)

    for jf in range(nf):
        tj = t[jf, :]

        # Build sample indices (1-based to 0-based)
        ta = int(np.ceil(tj[0]))
        tb = int(np.floor(tj[1]))
        cs = np.arange(ta, tb + 1)  # 1-based indices

        for js in range(2, len(tj), 2):
            ta = int(np.ceil(tj[js]))
            tb = int(np.floor(tj[js + 1]))
            cs = np.concatenate([cs, np.arange(ta, tb + 1)])

        nc = len(cs)
        pp = min(p, nc)

        # Build data matrix (1-based indices: s(cs - 1), s(cs - 2), ..., s(cs - p))
        dm = np.zeros((nc, pp))
        for col in range(pp):
            dm[:, col] = s[cs - 1 - (col + 1)]  # cs is 1-based, so cs-1 is 0-based index

        sc = s[cs - 1]  # 0-based indexing
        aa = np.linalg.lstsq(dm, sc, rcond=None)[0]
        ar[jf, 1:pp + 1] = -aa

        residual = sc - dm @ aa
        e[jf, 0] = np.real(np.dot(sc, residual))
        e[jf, 1] = np.real(np.dot(sc, sc))
        e[jf, 2:4] = e[jf, :2] / nc

    return ar, e, dc

v_lpcconv

V_LPCCONV - Convert between LPC parameter sets (generates conversion string).

v_lpcconv

v_lpcconv(from_type, to_type) -> None

Generate conversion path between LPC parameter sets.

Parameters:

Name Type Description Default
from_type str

Source parameter type (2-char code).

required
to_type str

Target parameter type (2-char code).

required

Returns:

Name Type Description
path str

String describing the conversion path.

Source code in pyvoicebox/v_lpcconv.py
def v_lpcconv(from_type, to_type) -> None:
    """Generate conversion path between LPC parameter sets.

    Parameters
    ----------
    from_type : str
        Source parameter type (2-char code).
    to_type : str
        Target parameter type (2-char code).

    Returns
    -------
    path : str
        String describing the conversion path.
    """
    # This is a routing/dispatch function in MATLAB that generates eval strings.
    # In Python, direct function calls are preferred.
    # This is provided for API compatibility but is not typically used.
    raise NotImplementedError(
        "v_lpcconv generates MATLAB eval strings. "
        "In Python, call conversion functions directly, e.g., v_lpcar2rf(ar)."
    )

v_lpcbwexp

V_LPCBWEXP - Expand formant bandwidths of LPC filter.

v_lpcbwexp

v_lpcbwexp(ar, bw) -> ndarray

Expand formant bandwidths of LPC filter.

Parameters:

Name Type Description Default
ar (array_like, shape(nf, p + 1))

Autoregressive coefficients.

required
bw float

Bandwidth expansion factor. The radius of each pole is multiplied by exp(-bw*pi).

required

Returns:

Name Type Description
arx (ndarray, shape(nf, p + 1))

Bandwidth-expanded AR coefficients.

Source code in pyvoicebox/v_lpcbwexp.py
def v_lpcbwexp(ar, bw) -> np.ndarray:
    """Expand formant bandwidths of LPC filter.

    Parameters
    ----------
    ar : array_like, shape (nf, p+1)
        Autoregressive coefficients.
    bw : float
        Bandwidth expansion factor. The radius of each pole is multiplied
        by exp(-bw*pi).

    Returns
    -------
    arx : ndarray, shape (nf, p+1)
        Bandwidth-expanded AR coefficients.
    """
    ar = np.atleast_2d(np.asarray(ar, dtype=float))
    nf, p1 = ar.shape
    k = np.exp(-np.pi * np.arange(p1) * bw)
    arx = ar * k[np.newaxis, :]
    return arx

v_lpcstable

V_LPCSTABLE - Test AR coefficients for stability and stabilize if necessary.

v_lpcstable

v_lpcstable(ar) -> tuple[ndarray, ndarray]

Test AR coefficients for stability and stabilize if necessary.

Parameters:

Name Type Description Default
ar (array_like, shape(nf, p + 1))

Autoregressive coefficients.

required

Returns:

Name Type Description
m (ndarray, shape(nf))

Boolean mask identifying stable polynomials.

a (ndarray, shape(nf, p + 1))

Stabilized polynomials with a[:, 0] = 1.

Source code in pyvoicebox/v_lpcstable.py
def v_lpcstable(ar) -> tuple[np.ndarray, np.ndarray]:
    """Test AR coefficients for stability and stabilize if necessary.

    Parameters
    ----------
    ar : array_like, shape (nf, p+1)
        Autoregressive coefficients.

    Returns
    -------
    m : ndarray, shape (nf,)
        Boolean mask identifying stable polynomials.
    a : ndarray, shape (nf, p+1)
        Stabilized polynomials with a[:, 0] = 1.
    """
    ar = np.atleast_2d(np.asarray(ar, dtype=float))
    nf, p1 = ar.shape

    # Ensure leading coefficient is 1
    mm = ar[:, 0] != 1
    if np.any(mm):
        ar = ar.copy()
        ar[mm, :] = ar[mm, :] / ar[mm, 0:1]

    if p1 == 1:
        m = np.ones(nf, dtype=bool)
    elif p1 == 2:
        m = np.abs(ar[:, 1]) < 1
    else:
        rf = ar.copy()
        k = rf[:, p1 - 1].copy()
        m = np.abs(k) < 1

        if np.any(m):
            d = (1 - k[m] ** 2) ** (-1)
            rf[np.ix_(m, range(1, p1 - 1))] = (
                (rf[np.ix_(m, range(1, p1 - 1))] -
                 k[m, np.newaxis] * rf[np.ix_(m, range(p1 - 2, 0, -1))]) *
                d[:, np.newaxis]
            )
            for j in range(p1 - 2, 1, -1):
                k_m = rf[m, j]
                still_stable = np.abs(k_m) < 1
                # Update m: only those that were True and remain stable
                m_indices = np.where(m)[0]
                m[m_indices[~still_stable]] = False
                if not np.any(m):
                    break
                d = (1 - k_m[still_stable] ** 2) ** (-1)
                m_indices = np.where(m)[0]
                rf[np.ix_(m_indices, range(1, j))] = (
                    (rf[np.ix_(m_indices, range(1, j))] -
                     k_m[still_stable, np.newaxis] * rf[np.ix_(m_indices, range(j - 1, 0, -1))]) *
                    d[:, np.newaxis]
                )

    # Stabilize unstable polynomials
    a = ar.copy()
    if not np.all(m):
        for i in np.where(~m)[0]:
            z = np.roots(a[i, :])
            k_mask = np.abs(z) > 1
            z[k_mask] = np.conj(z[k_mask]) ** (-1)
            a[i, :] = np.real(np.poly(z))

    return m, a

v_lpcifilt

V_LPCIFILT - Apply inverse filter to speech signal.

v_lpcifilt

v_lpcifilt(s, ar, t=None, dc=None, fade=None) -> ndarray

Apply inverse filter to speech signal.

Parameters:

Name Type Description Default
s (array_like, shape(ns))

Speech signal.

required
ar (array_like, shape(nf, p + 1))

AR coefficients, one row per frame.

required
t (array_like, shape(nf))

Index of first sample in each frame (1-based as in MATLAB).

None
dc (array_like, shape(nf) or scalar)

DC component to subtract from signal.

None
fade float

Number of samples for linear interpolation at frame boundaries.

None

Returns:

Name Type Description
u (ndarray, shape(ns))

Inverse filtered signal.

Source code in pyvoicebox/v_lpcifilt.py
def v_lpcifilt(s, ar, t=None, dc=None, fade=None) -> np.ndarray:
    """Apply inverse filter to speech signal.

    Parameters
    ----------
    s : array_like, shape (ns,)
        Speech signal.
    ar : array_like, shape (nf, p+1)
        AR coefficients, one row per frame.
    t : array_like, shape (nf,), optional
        Index of first sample in each frame (1-based as in MATLAB).
    dc : array_like, shape (nf,) or scalar, optional
        DC component to subtract from signal.
    fade : float, optional
        Number of samples for linear interpolation at frame boundaries.

    Returns
    -------
    u : ndarray, shape (ns,)
        Inverse filtered signal.
    """
    s = np.asarray(s, dtype=float).ravel()
    ar = np.atleast_2d(np.asarray(ar, dtype=float))
    nf, p1 = ar.shape
    ns = len(s)

    if dc is None:
        dc = np.zeros(nf)
    else:
        dc = np.asarray(dc, dtype=float).ravel()
        if len(dc) == 1:
            dc = np.full(nf, dc[0])

    if nf == 1:
        return lfilter(ar[0, :], [1.0], s - dc[0])

    p = p1 - 1

    if fade is None:
        fade = 0
    if t is None:
        t = p1 + np.arange(nf) * (ns - p) / nf

    t = np.asarray(t, dtype=float).ravel()

    u = np.zeros(ns)
    if fade < 1:
        # Last frame
        x0_start = max(0, int(np.ceil(t[nf - 1] - 1) - p))
        x0 = np.arange(x0_start, ns)
        if len(x0) > 0:
            u[x0] = lfilter(ar[nf - 1, :], [1.0], s[x0] - dc[nf - 1])

        # Middle frames
        for i in range(nf - 2, 0, -1):
            x0_start = max(0, int(np.ceil(t[i] - 1) - p))
            x0_end = int(np.ceil(t[i + 1] - 1))
            x0 = np.arange(x0_start, x0_end)
            if len(x0) > 0:
                u[x0] = lfilter(ar[i, :], [1.0], s[x0] - dc[i])

        # First frame
        x0 = np.arange(0, int(np.ceil(t[1] - 1)))
        if len(x0) > 0:
            u[x0] = lfilter(ar[0, :], [1.0], s[x0] - dc[0])

    return u

v_lpcrand

V_LPCRAND - Generate random stable polynomials.

v_lpcrand

v_lpcrand(p, n=1, bw=0) -> ndarray

Generate random stable polynomials.

Parameters:

Name Type Description Default
p int

Polynomial order.

required
n int

Number of polynomials. Default is 1.

1
bw float or array_like

Minimum pole bandwidth as fraction of sampling frequency. Default is 0.

0

Returns:

Name Type Description
ar (ndarray, shape(n, p + 1))

Random stable AR polynomials.

Source code in pyvoicebox/v_lpcrand.py
def v_lpcrand(p, n=1, bw=0) -> np.ndarray:
    """Generate random stable polynomials.

    Parameters
    ----------
    p : int
        Polynomial order.
    n : int, optional
        Number of polynomials. Default is 1.
    bw : float or array_like, optional
        Minimum pole bandwidth as fraction of sampling frequency. Default is 0.

    Returns
    -------
    ar : ndarray, shape (n, p+1)
        Random stable AR polynomials.
    """
    if p == 0:
        return np.ones((n, 1))

    bw = np.asarray(bw, dtype=float)
    if bw.ndim == 0:
        bw = float(bw)

    if bw == 0 if np.isscalar(bw) else not np.any(bw):
        ar = v_lpcrf2ar(2 * np.random.rand(n, p + 1) - 1)
    else:
        bw_arr = np.atleast_1d(bw)
        k = np.exp(-np.pi * bw_arr.reshape(-1, 1) * np.arange(p + 1))
        if k.shape[0] == 1:
            ar = v_lpcrf2ar(2 * np.random.rand(n, p + 1) - 1) * np.tile(k, (n, 1))
        else:
            ar = v_lpcrf2ar(2 * np.random.rand(n, p + 1) - 1) * k

    return ar

v_rootstab

V_ROOTSTAB - Determine number of polynomial roots outside, inside and on the unit circle.

v_rootstab

v_rootstab(p) -> tuple[int, int, int]

Determine number of polynomial roots outside, inside and on the unit circle.

Parameters:

Name Type Description Default
p array_like

Polynomial with real or complex coefficients.

required

Returns:

Name Type Description
no int

Number of roots outside the unit circle.

ni int

Number of roots inside the unit circle.

nc int

Number of roots lying on the unit circle.

Source code in pyvoicebox/v_rootstab.py
def v_rootstab(p) -> tuple[int, int, int]:
    """Determine number of polynomial roots outside, inside and on the unit circle.

    Parameters
    ----------
    p : array_like
        Polynomial with real or complex coefficients.

    Returns
    -------
    no : int
        Number of roots outside the unit circle.
    ni : int
        Number of roots inside the unit circle.
    nc : int
        Number of roots lying on the unit circle.
    """
    p = np.asarray(p, dtype=complex).ravel()

    no = 0
    nc = 0

    if np.all(p == 0):
        ni = 0
        return no, ni, nc

    # Trim leading zeros
    first_nonzero = np.argmax(p != 0)
    p = p[first_nonzero:]

    np0 = len(p)
    npd = 0
    nod = 0

    while len(p) > 1:
        n_p = len(p)
        # Normalize p
        norm = np.sqrt(np.real(np.dot(p, np.conj(p))))
        p = p / norm

        pf = np.conj(p[::-1])
        k = -p[-1] / pf[-1]
        q = p + k * pf
        q[-1] = 0.0  # force exact zero

        if np.all(q == 0):
            # Take derivative
            p = p[:-1] * np.arange(n_p - 1, 0, -1)
            if npd == 0:
                npd = n_p
                nod = no
        elif q[0] == 0:
            # |k|=1 and q != 0
            last_nonzero = np.max(np.where(q != 0)[0])
            q = q[:last_nonzero + 1]
            dr = -q[-1] / (pf[-1] * k)
            if abs(np.real(dr)) > abs(np.imag(dr)):
                cf = abs(np.real(dr))
            else:
                cf = 0.25 * abs(np.imag(dr))
            c = np.sqrt(1 + cf ** 2) - cf
            pad = np.zeros(n_p - len(q))
            q_padded = np.concatenate([pad, q])
            p = p / c + k * c * pf + q_padded
        elif abs(k) > 1:
            last_nonzero = np.max(np.where(q != 0)[0])
            q = q[:last_nonzero + 1]
            p = np.conj(q[::-1])
            no += n_p - len(p)
        else:
            last_nonzero = np.max(np.where(q != 0)[0])
            p = q[:last_nonzero + 1]

    if npd > 0:
        nc = npd - 1 - 2 * (no - nod)
    ni = np0 - 1 - nc - no

    return no, ni, nc

v_ccwarpf

V_CCWARPF - Warp cepstral coefficients.

v_ccwarpf

v_ccwarpf(f, n, s='ll') -> ndarray

Warp cepstral coefficients for frequency/representation changes.

Parameters:

Name Type Description Default
f array_like

[original_fs, new_fs]. If scalar, new_fs=1.

required
n array_like

[original_n, new_n]. If scalar, new_n=original_n.

required
s str

Two characters: s[0],s[1] = 'l' for linear, 'm' for mel frequency. Uppercase if c0 is included.

'll'

Returns:

Name Type Description
m ndarray

Warping matrix.

Source code in pyvoicebox/v_ccwarpf.py
def v_ccwarpf(f, n, s='ll') -> np.ndarray:
    """Warp cepstral coefficients for frequency/representation changes.

    Parameters
    ----------
    f : array_like
        [original_fs, new_fs]. If scalar, new_fs=1.
    n : array_like
        [original_n, new_n]. If scalar, new_n=original_n.
    s : str, optional
        Two characters: s[0],s[1] = 'l' for linear, 'm' for mel frequency.
        Uppercase if c0 is included.

    Returns
    -------
    m : ndarray
        Warping matrix.
    """
    f = np.atleast_1d(np.asarray(f, dtype=float))
    n = np.atleast_1d(np.asarray(n, dtype=int))

    if len(f) < 2:
        f = np.append(f, 1.0)
    if len(n) < 2:
        n = np.append(n, n[0])

    z = np.array([c < 'a' for c in s], dtype=bool)
    s_lower = s.lower()

    if s_lower == 'll':
        k = np.arange(1, n[1] - int(z[1]) + 1)
        ff = (np.arange(1, n[0] + 1) - int(z[0])) * f[1] / f[0]
        fa = 2 * np.sin(ff * np.pi) * ff / np.pi
        fb = ff ** 2
        ka = 1 - 2 * (k % 2)
        kb = k ** 2

        a = fa[:, np.newaxis] * ka[np.newaxis, :]
        b = fb[:, np.newaxis] - kb[np.newaxis, :]

        # Handle exact integer frequencies
        f0 = np.where(np.floor(ff) == ff)[0]
        if len(f0) > 0:
            for idx in f0:
                a[idx, :] = (ff[idx] == k).astype(float)
                b[idx, :] = 1.0

        m_mat = a / b

        if z[1]:
            col0 = np.ones(n[0])
            col0[1:] = 0.5 * fa[1:] / fb[1:]
            m_mat = np.column_stack([col0, m_mat])

        return m_mat

    raise NotImplementedError(f"Mode '{s}' not implemented, only 'll' supported.")

AR coefficient conversions

v_lpcar2am

V_LPCAR2AM - Convert AR coefficients to AR coefficient matrix.

v_lpcar2am

v_lpcar2am(ar, p=None) -> tuple[ndarray, ndarray]

Convert AR coefficients to AR coefficient matrix.

Parameters:

Name Type Description Default
ar (array_like, shape(nf, p0 + 1))

Autoregressive coefficients.

required
p int

Output order. Default is p0.

None

Returns:

Name Type Description
am (ndarray, shape(p + 1, p + 1, nf))

AR coefficient matrix (upper triangular with 1s on diagonal).

em (ndarray, shape(nf, p + 1))

Residual energy for each order.

Source code in pyvoicebox/v_lpcar2am.py
def v_lpcar2am(ar, p=None) -> tuple[np.ndarray, np.ndarray]:
    """Convert AR coefficients to AR coefficient matrix.

    Parameters
    ----------
    ar : array_like, shape (nf, p0+1)
        Autoregressive coefficients.
    p : int, optional
        Output order. Default is p0.

    Returns
    -------
    am : ndarray, shape (p+1, p+1, nf)
        AR coefficient matrix (upper triangular with 1s on diagonal).
    em : ndarray, shape (nf, p+1)
        Residual energy for each order.
    """
    ar = np.atleast_2d(np.asarray(ar, dtype=float))
    nf, p1 = ar.shape
    if np.any(ar[:, 0] != 1):
        ar = ar / ar[:, 0:1]
    p0 = p1 - 1
    if p is None:
        p = p0

    am = np.zeros((nf, p + 1, p + 1))
    em = np.ones((nf, p + 1))
    e = np.ones((nf,))
    rf = ar.copy()

    jj = 0
    if p >= p0:
        for jj_idx in range(p + 1 - p0):
            am[:, jj_idx:jj_idx + p0 + 1, jj_idx] = ar
        jj = p + 1 - p0
    else:
        for j in range(p0, p + 1, -1):
            k = rf[:, j]
            d = (1 - k ** 2) ** (-1)
            e = e * d
            rf[:, 1:j] = (rf[:, 1:j] - k[:, np.newaxis] * rf[:, j-1:0:-1]) * d[:, np.newaxis]
        jj = 0

    for jj_idx in range(jj, p):
        j = p + 1 - jj_idx
        k = rf[:, j]
        d = (1 - k ** 2) ** (-1)
        e = e * d
        rf[:, 1:j] = (rf[:, 1:j] - k[:, np.newaxis] * rf[:, j-1:0:-1]) * d[:, np.newaxis]
        am[:, jj_idx:, jj_idx] = rf[:, :j]
        em[:, jj_idx] = e

    em[:, -1] = e / (1 - rf[:, 1] ** 2)
    am[:, -1, -1] = 1.0

    # Permute to (p+1, p+1, nf)
    am = np.transpose(am, (2, 1, 0))

    return am, em

v_lpcar2cc

V_LPCAR2CC - Convert AR filter to complex cepstrum.

v_lpcar2cc

v_lpcar2cc(ar, np_out=None) -> tuple[ndarray, ndarray]

Convert AR filter to complex cepstrum.

Parameters:

Name Type Description Default
ar (array_like, shape(nf, n + 1))

AR coefficients, one frame per row.

required
np_out int

Number of cepstral coefficients to calculate. Default is n.

None

Returns:

Name Type Description
cc (ndarray, shape(nf, np_out))

Complex cepstral coefficients, excluding c(0).

c0 (ndarray, shape(nf, 1))

Coefficient c(0).

Source code in pyvoicebox/v_lpcar2cc.py
def v_lpcar2cc(ar, np_out=None) -> tuple[np.ndarray, np.ndarray]:
    """Convert AR filter to complex cepstrum.

    Parameters
    ----------
    ar : array_like, shape (nf, n+1)
        AR coefficients, one frame per row.
    np_out : int, optional
        Number of cepstral coefficients to calculate. Default is n.

    Returns
    -------
    cc : ndarray, shape (nf, np_out)
        Complex cepstral coefficients, excluding c(0).
    c0 : ndarray, shape (nf, 1)
        Coefficient c(0).
    """
    ar = np.atleast_2d(np.asarray(ar, dtype=float))
    nf, p1 = ar.shape
    p = p1 - 1
    if np_out is None:
        np_out = p

    cc = np.zeros((nf, np_out))
    if np.any(ar[:, 0] != 1):
        c0 = -np.log(ar[:, 0]).reshape(-1, 1)
        ar = ar / ar[:, 0:1]
    else:
        c0 = np.zeros((nf, 1))

    cm = 1.0 / np.arange(1, np_out + 1)
    if np_out > p:
        xm = -np.arange(1, p + 1, dtype=float)
        nz = np_out - p
        for k in range(nf):
            inp = np.concatenate([ar[k, 1:p1] * xm, np.zeros(nz)])
            cc[k, :] = lfilter([1.0], ar[k, :], inp) * cm
    else:
        p1_out = np_out + 1
        xm = -np.arange(1, np_out + 1, dtype=float)
        for k in range(nf):
            cc[k, :] = lfilter([1.0], ar[k, :], ar[k, 1:p1_out] * xm) * cm

    return cc, c0

v_lpcar2db

V_LPCAR2DB - Convert AR coefficients to power spectrum in dB.

v_lpcar2db

v_lpcar2db(ar, np_out=None) -> tuple[ndarray, ndarray]

Convert AR coefficients to power spectrum in dB.

Parameters:

Name Type Description Default
ar (array_like, shape(nf, n))

AR coefficients, one frame per row.

required
np_out int

Size of output spectrum is np_out+1. Default is n-1.

None

Returns:

Name Type Description
db (ndarray, shape(nf, np_out + 1))

Power spectrum in dB from DC to Nyquist.

f (ndarray, shape(np_out + 1))

Normalized frequencies (0 to 0.5).

Source code in pyvoicebox/v_lpcar2db.py
def v_lpcar2db(ar, np_out=None) -> tuple[np.ndarray, np.ndarray]:
    """Convert AR coefficients to power spectrum in dB.

    Parameters
    ----------
    ar : array_like, shape (nf, n)
        AR coefficients, one frame per row.
    np_out : int, optional
        Size of output spectrum is np_out+1. Default is n-1.

    Returns
    -------
    db : ndarray, shape (nf, np_out+1)
        Power spectrum in dB from DC to Nyquist.
    f : ndarray, shape (np_out+1,)
        Normalized frequencies (0 to 0.5).
    """
    ar = np.atleast_2d(np.asarray(ar, dtype=float))
    nf, p1 = ar.shape
    if np_out is None:
        np_out = p1 - 1

    ff = v_rfft(ar.T, 2 * np_out).T
    db = -10 * np.log10(np.real(ff * np.conj(ff)))
    f = np.arange(np_out + 1) / (2 * np_out)

    return db, f

v_lpcar2ff

V_LPCAR2FF - Convert AR coefficients to complex spectrum.

v_lpcar2ff

v_lpcar2ff(ar, np_out=None) -> tuple[ndarray, ndarray]

Convert AR coefficients to complex spectrum.

Parameters:

Name Type Description Default
ar (array_like, shape(nf, n))

AR coefficients, one frame per row.

required
np_out int

Size of output spectrum is np_out+1. Default is n-1.

None

Returns:

Name Type Description
ff (ndarray, shape(nf, np_out + 1))

Complex spectrum from DC to Nyquist.

f (ndarray, shape(np_out + 1))

Normalized frequencies (0 to 0.5).

Source code in pyvoicebox/v_lpcar2ff.py
def v_lpcar2ff(ar, np_out=None) -> tuple[np.ndarray, np.ndarray]:
    """Convert AR coefficients to complex spectrum.

    Parameters
    ----------
    ar : array_like, shape (nf, n)
        AR coefficients, one frame per row.
    np_out : int, optional
        Size of output spectrum is np_out+1. Default is n-1.

    Returns
    -------
    ff : ndarray, shape (nf, np_out+1)
        Complex spectrum from DC to Nyquist.
    f : ndarray, shape (np_out+1,)
        Normalized frequencies (0 to 0.5).
    """
    ar = np.atleast_2d(np.asarray(ar, dtype=float))
    nf, p1 = ar.shape
    if np_out is None:
        np_out = p1 - 1

    ff = v_rfft(ar.T, 2 * np_out).T ** (-1)
    f = np.arange(np_out + 1) / (2 * np_out)

    return ff, f

v_lpcar2fm

V_LPCAR2FM - Convert autoregressive coefficients to formant freq+amp+bw.

v_lpcar2fm

v_lpcar2fm(
    ar, t=None
) -> tuple[ndarray, ndarray, ndarray, ndarray]

Convert autoregressive coefficients to formant frequencies, amplitudes and bandwidths.

Parameters:

Name Type Description Default
ar (array_like, shape(nf, p + 1))

Autoregressive coefficients.

required
t float

Threshold. If t>0, poles with bandwidth > t*frequency are ignored. If t<=0, poles with bandwidth > -t are ignored.

None

Returns:

Name Type Description
n (ndarray, shape(nf))

Number of formants found per frame.

f (ndarray, shape(nf, m))

Formant frequencies in normalized Hz.

a (ndarray, shape(nf, m))

Formant amplitudes.

b (ndarray, shape(nf, m))

Formant bandwidths in normalized Hz.

Source code in pyvoicebox/v_lpcar2fm.py
def v_lpcar2fm(ar, t=None) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
    """Convert autoregressive coefficients to formant frequencies, amplitudes and bandwidths.

    Parameters
    ----------
    ar : array_like, shape (nf, p+1)
        Autoregressive coefficients.
    t : float, optional
        Threshold. If t>0, poles with bandwidth > t*frequency are ignored.
        If t<=0, poles with bandwidth > -t are ignored.

    Returns
    -------
    n : ndarray, shape (nf,)
        Number of formants found per frame.
    f : ndarray, shape (nf, m)
        Formant frequencies in normalized Hz.
    a : ndarray, shape (nf, m)
        Formant amplitudes.
    b : ndarray, shape (nf, m)
        Formant bandwidths in normalized Hz.
    """
    ar = np.atleast_2d(np.asarray(ar, dtype=float))
    nf, p1 = ar.shape
    p = p1 - 1

    zz = v_lpcar2zz(ar)
    ig = np.imag(zz) <= 0
    n = p - np.sum(ig, axis=1)
    mn = int(np.max(n))

    # Remove redundant columns
    if mn < p:
        # Sort so that ig=True comes first (non-formant poles)
        ix = np.argsort(ig.astype(int), axis=1)
        zz_new = np.zeros((nf, mn), dtype=complex)
        ig_new = np.zeros((nf, mn), dtype=bool)
        for i in range(nf):
            zz_new[i, :] = zz[i, ix[i, :mn]]
            ig_new[i, :] = ig[i, ix[i, :mn]]
        zz = zz_new
        ig = ig_new

    zz_safe = zz.copy()
    zz_safe[ig] = 1.0  # prevent infinities
    f = np.angle(zz_safe) * 0.5 / np.pi
    b = -np.log(np.abs(zz_safe)) / np.pi

    if t is not None:
        if t > 0:
            ig = ig | (b > t * f)
        else:
            ig = ig | (b + t > 0)

    f[ig] = 0.0
    b[ig] = 0.0
    n = f.shape[1] - np.sum(ig, axis=1) if f.size > 0 else np.zeros(nf, dtype=int)
    m = int(np.max(n)) if np.any(n > 0) else 0

    if m == 0:
        return n, np.zeros((nf, 0)), np.zeros((nf, 0)), np.zeros((nf, 0))

    # Sort: non-ignored values first, by frequency
    sort_key = ig.astype(float) + f
    ix = np.argsort(sort_key, axis=1)

    zz_out = np.zeros((nf, m), dtype=complex)
    f_out = np.zeros((nf, m))
    b_out = np.zeros((nf, m))
    ig_out = np.zeros((nf, m), dtype=bool)
    for i in range(nf):
        zz_out[i, :] = zz[i, ix[i, :m]]
        f_out[i, :] = f[i, ix[i, :m]]
        b_out[i, :] = b[i, ix[i, :m]]
        ig_out[i, :] = ig[i, ix[i, :m]]

    # Calculate gain
    pw = -2j * np.pi * np.arange(p1)
    a_out = np.zeros((nf, m))
    for i in range(nf):
        for j in range(m):
            val = np.sum(ar[i, :] * np.exp(pw * f_out[i, j]))
            a_out[i, j] = np.abs(val) ** (-1)

    return n, f_out, a_out, b_out

v_lpcar2im

V_LPCAR2IM - Convert AR coefficients to impulse response.

v_lpcar2im

v_lpcar2im(ar, np_out=None) -> ndarray

Convert AR coefficients to impulse response.

Parameters:

Name Type Description Default
ar (array_like, shape(nf, p + 1))

AR coefficients, one frame per row.

required
np_out int

Number of impulse response samples minus 1. Default is p.

None

Returns:

Name Type Description
im (ndarray, shape(nf, np_out + 1))

Impulse response.

Source code in pyvoicebox/v_lpcar2im.py
def v_lpcar2im(ar, np_out=None) -> np.ndarray:
    """Convert AR coefficients to impulse response.

    Parameters
    ----------
    ar : array_like, shape (nf, p+1)
        AR coefficients, one frame per row.
    np_out : int, optional
        Number of impulse response samples minus 1. Default is p.

    Returns
    -------
    im : ndarray, shape (nf, np_out+1)
        Impulse response.
    """
    ar = np.atleast_2d(np.asarray(ar, dtype=float))
    nf, p1 = ar.shape
    if np_out is None:
        np_out = p1 - 1

    im = np.zeros((nf, np_out + 1))
    x = np.zeros(np_out + 1)
    x[0] = 1.0
    for k in range(nf):
        im[k, :] = lfilter([1.0], ar[k, :], x)
    return im

v_lpcar2ls

V_LPCAR2LS - Convert AR polynomial to line spectrum pair frequencies.

v_lpcar2ls

v_lpcar2ls(ar) -> ndarray

Convert AR polynomial to line spectrum pair frequencies.

Parameters:

Name Type Description Default
ar (array_like, shape(nf, p + 1))

Autoregressive coefficients.

required

Returns:

Name Type Description
ls (ndarray, shape(nf, p))

Line spectrum pair frequencies in normalized Hz (0 to 0.5).

Source code in pyvoicebox/v_lpcar2ls.py
def v_lpcar2ls(ar) -> np.ndarray:
    """Convert AR polynomial to line spectrum pair frequencies.

    Parameters
    ----------
    ar : array_like, shape (nf, p+1)
        Autoregressive coefficients.

    Returns
    -------
    ls : ndarray, shape (nf, p)
        Line spectrum pair frequencies in normalized Hz (0 to 0.5).
    """
    ar = np.atleast_2d(np.asarray(ar, dtype=float))
    nf, p1 = ar.shape
    p = p1 - 1
    p2 = p // 2
    d = 0.5 / np.pi
    ls = np.zeros((nf, p))

    if p % 2:  # odd order
        for k in range(nf):
            aa = np.append(ar[k, :], 0.0)
            r = aa + aa[::-1]
            q = aa - aa[::-1]
            fr = np.sort(np.angle(np.roots(r)))
            # deconv q by [1, 0, -1]
            q_deconv = _deconv(q, np.array([1.0, 0.0, -1.0]))
            fq = np.sort(np.angle(np.roots(q_deconv)))
            fq = np.append(fq, 0.0)
            f = np.zeros(p + 1)
            f[0::2] = fr[p2 + 1:p + 1]
            f[1::2] = fq[p2:p]
            f = f[:p]
            ls[k, :] = d * f
    else:  # even order
        for k in range(nf):
            aa = np.append(ar[k, :], 0.0)
            r = aa + aa[::-1]
            q = aa - aa[::-1]
            r_deconv = _deconv(r, np.array([1.0, 1.0]))
            q_deconv = _deconv(q, np.array([1.0, -1.0]))
            fr = np.sort(np.angle(np.roots(r_deconv)))
            fq = np.sort(np.angle(np.roots(q_deconv)))
            f = np.zeros(p)
            f[0::2] = fr[p2:p]
            f[1::2] = fq[p2:p]
            ls[k, :] = d * f

    return ls

v_lpcar2pf

V_LPCAR2PF - Convert AR coefficients to power spectrum.

v_lpcar2pf

v_lpcar2pf(ar, np_out=None) -> tuple[ndarray, ndarray]

Convert AR coefficients to power spectrum.

Parameters:

Name Type Description Default
ar (array_like, shape(nf, n))

AR coefficients, one frame per row.

required
np_out int

Size of output spectrum is np_out+1. Default is n-1.

None

Returns:

Name Type Description
pf (ndarray, shape(nf, np_out + 1))

Power spectrum from DC to Nyquist.

f (ndarray, shape(np_out + 1))

Normalized frequencies (0 to 0.5).

Source code in pyvoicebox/v_lpcar2pf.py
def v_lpcar2pf(ar, np_out=None) -> tuple[np.ndarray, np.ndarray]:
    """Convert AR coefficients to power spectrum.

    Parameters
    ----------
    ar : array_like, shape (nf, n)
        AR coefficients, one frame per row.
    np_out : int, optional
        Size of output spectrum is np_out+1. Default is n-1.

    Returns
    -------
    pf : ndarray, shape (nf, np_out+1)
        Power spectrum from DC to Nyquist.
    f : ndarray, shape (np_out+1,)
        Normalized frequencies (0 to 0.5).
    """
    ar = np.atleast_2d(np.asarray(ar, dtype=float))
    nf, p1 = ar.shape
    if np_out is None:
        np_out = p1 - 1

    pf = np.abs(v_rfft(ar.T, 2 * np_out).T) ** (-2)
    f = np.arange(np_out + 1) / (2 * np_out)

    return pf, f

v_lpcar2pp

V_LPCAR2PP - Convert AR filter to power spectrum polynomial in cos(w).

v_lpcar2pp

v_lpcar2pp(ar) -> ndarray

Convert AR filter to power spectrum polynomial in cos(w).

Parameters:

Name Type Description Default
ar (array_like, shape(nf, p + 1))

Autoregressive coefficients.

required

Returns:

Name Type Description
pp (ndarray, shape(nf, p + 1))

Power spectrum polynomial coefficients in cos(w).

Source code in pyvoicebox/v_lpcar2pp.py
def v_lpcar2pp(ar) -> np.ndarray:
    """Convert AR filter to power spectrum polynomial in cos(w).

    Parameters
    ----------
    ar : array_like, shape (nf, p+1)
        Autoregressive coefficients.

    Returns
    -------
    pp : ndarray, shape (nf, p+1)
        Power spectrum polynomial coefficients in cos(w).
    """
    ar = np.atleast_2d(np.asarray(ar, dtype=float))
    nf, p1 = ar.shape
    ra = v_lpcar2ra(ar)
    tp = _chebyshev_matrix(p1)
    pp = ra @ tp
    return pp

v_lpcar2ra

V_LPCAR2RA - Convert AR filter to inverse filter autocorrelation coefficients.

v_lpcar2ra

v_lpcar2ra(ar) -> ndarray

Convert AR filter to inverse filter autocorrelation coefficients.

Parameters:

Name Type Description Default
ar (array_like, shape(nf, p + 1))

Autoregressive coefficients.

required

Returns:

Name Type Description
ra (ndarray, shape(nf, p + 1))

Inverse filter autocorrelation coefficients.

Source code in pyvoicebox/v_lpcar2ra.py
def v_lpcar2ra(ar) -> np.ndarray:
    """Convert AR filter to inverse filter autocorrelation coefficients.

    Parameters
    ----------
    ar : array_like, shape (nf, p+1)
        Autoregressive coefficients.

    Returns
    -------
    ra : ndarray, shape (nf, p+1)
        Inverse filter autocorrelation coefficients.
    """
    ar = np.atleast_2d(np.asarray(ar, dtype=float))
    nf, p1 = ar.shape
    ra = np.zeros((nf, p1))
    for i in range(p1):
        ra[:, i] = np.sum(ar[:, :p1 - i] * ar[:, i:], axis=1)
    return ra

v_lpcar2rf

V_LPCAR2RF - Convert autoregressive coefficients to reflection coefficients.

v_lpcar2rf

v_lpcar2rf(ar) -> ndarray

Convert autoregressive coefficients to reflection coefficients.

Parameters:

Name Type Description Default
ar (array_like, shape(nf, p + 1))

Autoregressive coefficients with ar[:, 0] = 1.

required

Returns:

Name Type Description
rf (ndarray, shape(nf, p + 1))

Reflection coefficients with rf[:, 0] = 1.

Source code in pyvoicebox/v_lpcar2rf.py
def v_lpcar2rf(ar) -> np.ndarray:
    """Convert autoregressive coefficients to reflection coefficients.

    Parameters
    ----------
    ar : array_like, shape (nf, p+1)
        Autoregressive coefficients with ar[:, 0] = 1.

    Returns
    -------
    rf : ndarray, shape (nf, p+1)
        Reflection coefficients with rf[:, 0] = 1.
    """
    ar = np.atleast_2d(np.asarray(ar, dtype=float))
    nf, p1 = ar.shape
    if p1 == 1:
        return np.ones((nf, 1))

    # Normalize so first coefficient is 1
    if np.any(ar[:, 0] != 1):
        ar = ar / ar[:, 0:1]

    rf = ar.copy()
    for j in range(p1 - 1, 1, -1):
        k = rf[:, j]
        d = (1 - k ** 2) ** (-1)
        rf[:, 1:j] = (rf[:, 1:j] - k[:, np.newaxis] * rf[:, j-1:0:-1]) * d[:, np.newaxis]

    return rf

v_lpcar2rr

V_LPCAR2RR - Convert autoregressive coefficients to autocorrelation coefficients.

v_lpcar2rr

v_lpcar2rr(ar, p=None) -> ndarray

Convert autoregressive coefficients to autocorrelation coefficients.

Parameters:

Name Type Description Default
ar (array_like, shape(nf, n + 1))

Autoregressive coefficients including 0th coefficient.

required
p int

Number of output coefficients. Default is n.

None

Returns:

Name Type Description
rr (ndarray, shape(nf, p + 1))

Autocorrelation coefficients including 0th order coefficient.

Source code in pyvoicebox/v_lpcar2rr.py
def v_lpcar2rr(ar, p=None) -> np.ndarray:
    """Convert autoregressive coefficients to autocorrelation coefficients.

    Parameters
    ----------
    ar : array_like, shape (nf, n+1)
        Autoregressive coefficients including 0th coefficient.
    p : int, optional
        Number of output coefficients. Default is n.

    Returns
    -------
    rr : ndarray, shape (nf, p+1)
        Autocorrelation coefficients including 0th order coefficient.
    """
    ar = np.atleast_2d(np.asarray(ar, dtype=float))
    k = ar[:, 0] ** (-2)
    if ar.shape[1] == 1:
        return k.reshape(-1, 1)

    if p is not None:
        rr, _ = v_lpcrf2rr(v_lpcar2rf(ar), p)
        return rr * k[:, np.newaxis]
    else:
        rr, _ = v_lpcrf2rr(v_lpcar2rf(ar))
        return rr * k[:, np.newaxis]

v_lpcar2zz

V_LPCAR2ZZ - Convert AR filter to z-plane poles.

v_lpcar2zz

v_lpcar2zz(ar) -> ndarray

Convert AR filter to z-plane poles.

Parameters:

Name Type Description Default
ar (array_like, shape(nf, p + 1))

Autoregressive coefficients.

required

Returns:

Name Type Description
zz (ndarray, shape(nf, p))

Z-plane poles.

Source code in pyvoicebox/v_lpcar2zz.py
def v_lpcar2zz(ar) -> np.ndarray:
    """Convert AR filter to z-plane poles.

    Parameters
    ----------
    ar : array_like, shape (nf, p+1)
        Autoregressive coefficients.

    Returns
    -------
    zz : ndarray, shape (nf, p)
        Z-plane poles.
    """
    ar = np.atleast_2d(np.asarray(ar, dtype=float))
    nf, p1 = ar.shape
    zz = np.zeros((nf, p1 - 1), dtype=complex)
    for k in range(nf):
        zz[k, :] = np.roots(ar[k, :])
    return zz

Reflection coefficient conversions

v_lpcrf2aa

V_LPCRF2AA - Convert reflection coefficients to area function.

v_lpcrf2aa

v_lpcrf2aa(rf) -> ndarray

Convert reflection coefficients to area function.

Parameters:

Name Type Description Default
rf (array_like, shape(nf, p + 1))

Reflection coefficients.

required

Returns:

Name Type Description
aa (ndarray, shape(nf, p + 2))

Area function, normalized so aa[:, -1] = 1.

Source code in pyvoicebox/v_lpcrf2aa.py
def v_lpcrf2aa(rf) -> np.ndarray:
    """Convert reflection coefficients to area function.

    Parameters
    ----------
    rf : array_like, shape (nf, p+1)
        Reflection coefficients.

    Returns
    -------
    aa : ndarray, shape (nf, p+2)
        Area function, normalized so aa[:, -1] = 1.
    """
    rf = np.atleast_2d(np.asarray(rf, dtype=float))
    nf, p1 = rf.shape
    # MATLAB: aa = fliplr(cumprod([ones(1,size(rf,1)); fliplr((1-rf)./(1+rf)).']).')
    ratios = ((1 - rf) / (1 + rf))[:, ::-1]  # flip left-right
    # Prepend column of ones (for glottis boundary)
    ratios_with_ones = np.column_stack([np.ones((nf, 1)), ratios])
    # Cumulative product along columns
    aa = np.cumprod(ratios_with_ones, axis=1)
    # Flip left-right
    aa = aa[:, ::-1]
    return aa

v_lpcrf2ao

V_LPCRF2AO - Convert reflection coefficients to area ratios.

v_lpcrf2ao

v_lpcrf2ao(rf) -> ndarray

Convert reflection coefficients to area ratios.

Parameters:

Name Type Description Default
rf array_like

Reflection coefficients.

required

Returns:

Name Type Description
ao ndarray

Area ratios.

Source code in pyvoicebox/v_lpcrf2ao.py
def v_lpcrf2ao(rf) -> np.ndarray:
    """Convert reflection coefficients to area ratios.

    Parameters
    ----------
    rf : array_like
        Reflection coefficients.

    Returns
    -------
    ao : ndarray
        Area ratios.
    """
    rf = np.asarray(rf, dtype=float)
    ao = (1 - rf) / (1 + rf)
    return ao

v_lpcrf2ar

V_LPCRF2AR - Convert reflection coefficients to autoregressive coefficients.

v_lpcrf2ar

v_lpcrf2ar(rf) -> ndarray

Convert reflection coefficients to autoregressive coefficients.

Parameters:

Name Type Description Default
rf (array_like, shape(nf, p + 1))

Reflection coefficients.

required

Returns:

Name Type Description
ar (ndarray, shape(nf, p + 1))

Autoregressive coefficients with ar[:, 0] = 1.

Source code in pyvoicebox/v_lpcrf2ar.py
def v_lpcrf2ar(rf) -> np.ndarray:
    """Convert reflection coefficients to autoregressive coefficients.

    Parameters
    ----------
    rf : array_like, shape (nf, p+1)
        Reflection coefficients.

    Returns
    -------
    ar : ndarray, shape (nf, p+1)
        Autoregressive coefficients with ar[:, 0] = 1.
    """
    rf = np.atleast_2d(np.asarray(rf, dtype=float))
    nf, p1 = rf.shape
    p = p1 - 1

    if p == 0:
        return np.ones((nf, 1))

    # arf: forward filter, arr: reverse filter
    arf = np.zeros((nf, p1))
    arf[:, 0] = 1.0
    arr = np.zeros((nf, p1))
    arr[:, p] = rf[:, p]  # arr(:,p1) in MATLAB (1-based)
    cr = np.zeros((nf, p))

    for k in range(1, p):
        # MATLAB: rk=rf(:,(p1-k)*ones(1,k)); -> rf column index p1-k (1-based) = p-k (0-based)
        rk = rf[:, p - k:p - k + 1]  # shape (nf, 1), broadcast later

        # MATLAB: cr(:,1:k)=arr(:,p2-k:p1);  p2=p1+1, so p2-k = p1+1-k (1-based) = p-k (0-based)
        # arr columns p-k to p (0-based), that's k+1 columns... wait
        # MATLAB p2-k:p1 in 1-based: (p1+1-k):p1, that's k elements
        # 0-based: (p1-k):(p1-1) inclusive, i.e. (p-k+1-1)=p-k to p-1... wait
        # p1+1-k to p1 in 1-based = p1-k to p1-1 in 0-based = indices p-k to p (0-based, last p1 col is index p)
        # MATLAB arr(:,p2-k:p1) where p2=p1+1: indices p1+1-k to p1, 1-based
        # 0-based: p1-k to p1-1, which is p-k+1-1? No.
        # p1 = p+1. MATLAB 1-based indices: p1+1-k = p+2-k to p1 = p+1.
        # That's k elements: p+2-k, p+3-k, ..., p+1
        # 0-based: p+1-k, p+2-k, ..., p. That's k elements.
        cr[:, :k] = arr[:, p + 1 - k:p + 1]

        # MATLAB: arr(:,p1-k:p)=arr(:,p1-k:p)+rk.*arf(:,1:k);
        # p1-k in 1-based = p-k in 0-based. p in 1-based = p-1 in 0-based
        # So arr columns p-k to p-1 (0-based), k elements
        arr[:, p - k:p] = arr[:, p - k:p] + rk * arf[:, :k]

        # MATLAB: arf(:,2:k+1)=arf(:,2:k+1)+rk.*cr(:,1:k);
        # 2 to k+1 in 1-based = 1 to k in 0-based, k elements
        arf[:, 1:k + 1] = arf[:, 1:k + 1] + rk * cr[:, :k]

    r1 = rf[:, 0:1]  # shape (nf, 1)
    ar = arf + r1 * arr

    return ar

v_lpcrf2is

V_LPCRF2IS - Convert reflection coefficients to inverse sines.

v_lpcrf2is

v_lpcrf2is(rf) -> ndarray

Convert reflection coefficients to inverse sines.

Parameters:

Name Type Description Default
rf array_like

Reflection coefficients.

required

Returns:

Name Type Description
is_coef ndarray

Inverse sine coefficients.

Source code in pyvoicebox/v_lpcrf2is.py
def v_lpcrf2is(rf) -> np.ndarray:
    """Convert reflection coefficients to inverse sines.

    Parameters
    ----------
    rf : array_like
        Reflection coefficients.

    Returns
    -------
    is_coef : ndarray
        Inverse sine coefficients.
    """
    rf = np.asarray(rf, dtype=float)
    is_coef = np.arcsin(rf) * 2 / np.pi
    return is_coef

v_lpcrf2la

V_LPCRF2LA - Convert reflection coefficients to log areas.

v_lpcrf2la

v_lpcrf2la(rf) -> ndarray

Convert reflection coefficients to log areas.

Parameters:

Name Type Description Default
rf (array_like, shape(nf, p + 1))

Reflection coefficients.

required

Returns:

Name Type Description
la (ndarray, shape(nf, p + 2))

Log areas, normalized so la[:, -1] = 0.

Source code in pyvoicebox/v_lpcrf2la.py
def v_lpcrf2la(rf) -> np.ndarray:
    """Convert reflection coefficients to log areas.

    Parameters
    ----------
    rf : array_like, shape (nf, p+1)
        Reflection coefficients.

    Returns
    -------
    la : ndarray, shape (nf, p+2)
        Log areas, normalized so la[:, -1] = 0.
    """
    rf = np.atleast_2d(np.asarray(rf, dtype=float))
    nf, p1 = rf.shape
    r = np.clip(rf, -1 + 1e-6, 1 - 1e-6)
    lo = np.log((1 - r) / (1 + r))
    cs = np.cumsum(lo[:, ::-1], axis=1).T  # cumsum along flipped columns
    la = np.column_stack([np.zeros((nf, 1)), cs.T])[:, ::-1]
    return la

v_lpcrf2lo

V_LPCRF2LO - Convert reflection coefficients to log area ratios.

v_lpcrf2lo

v_lpcrf2lo(rf) -> ndarray

Convert reflection coefficients to log area ratios.

Parameters:

Name Type Description Default
rf array_like

Reflection coefficients.

required

Returns:

Name Type Description
lo ndarray

Log area ratios (limited to about +-14.5).

Source code in pyvoicebox/v_lpcrf2lo.py
def v_lpcrf2lo(rf) -> np.ndarray:
    """Convert reflection coefficients to log area ratios.

    Parameters
    ----------
    rf : array_like
        Reflection coefficients.

    Returns
    -------
    lo : ndarray
        Log area ratios (limited to about +-14.5).
    """
    rf = np.asarray(rf, dtype=float)
    r = np.clip(rf, -1 + 1e-6, 1 - 1e-6)
    lo = np.log((1 - r) / (1 + r))
    return lo

v_lpcrf2rr

V_LPCRF2RR - Convert reflection coefficients to autocorrelation coefficients.

v_lpcrf2rr

v_lpcrf2rr(rf, p=None) -> tuple[ndarray, ndarray]

Convert reflection coefficients to autocorrelation coefficients.

Parameters:

Name Type Description Default
rf (array_like, shape(nf, n + 1))

Reflection coefficients, one row per frame.

required
p int

Number of autocorrelation coefficients to calculate. Default is n.

None

Returns:

Name Type Description
rr (ndarray, shape(nf, p + 1))

Autocorrelation coefficients.

ar (ndarray, shape(nf, n + 1))

AR filter coefficients.

Source code in pyvoicebox/v_lpcrf2rr.py
def v_lpcrf2rr(rf, p=None) -> tuple[np.ndarray, np.ndarray]:
    """Convert reflection coefficients to autocorrelation coefficients.

    Parameters
    ----------
    rf : array_like, shape (nf, n+1)
        Reflection coefficients, one row per frame.
    p : int, optional
        Number of autocorrelation coefficients to calculate. Default is n.

    Returns
    -------
    rr : ndarray, shape (nf, p+1)
        Autocorrelation coefficients.
    ar : ndarray, shape (nf, n+1)
        AR filter coefficients.
    """
    rf = np.atleast_2d(np.asarray(rf, dtype=float))
    nf, p1 = rf.shape
    p0 = p1 - 1

    if p0 == 0:
        rr = np.ones((nf, 1))
        ar = np.ones((nf, 1))
        return rr, ar

    a = rf[:, 1:2].copy()  # shape (nf, 1)
    rr = np.zeros((nf, p1))
    rr[:, 0] = 1.0
    rr[:, 1] = -a[:, 0]
    e = a[:, 0] ** 2 - 1.0

    for n in range(2, p0 + 1):
        k = rf[:, n]
        rr[:, n] = k * e - np.sum(rr[:, n-1:0:-1] * a, axis=1)
        new_col = k.copy()
        a = np.column_stack([a + k[:, np.newaxis] * a[:, n-2::-1], new_col])
        e = e * (1 - k ** 2)

    ar = np.column_stack([np.ones((nf, 1)), a])
    r0 = np.sum(rr * ar, axis=1) ** (-1)
    rr = rr * r0[:, np.newaxis]

    if p is not None:
        if p < p0:
            rr = rr[:, :p + 1]
        elif p > p0:
            rr = np.column_stack([rr, np.zeros((nf, p - p0))])
            af = -ar[:, p1-1:0:-1]
            for i in range(p0 + 1, p + 1):
                rr[:, i] = np.sum(af * rr[:, i - p0:i], axis=1)

    return rr, ar

Cepstral coefficient conversions

v_lpccc2ar

V_LPCCC2AR - Convert complex cepstrum to AR coefficients.

v_lpccc2ar

v_lpccc2ar(cc) -> ndarray

Convert complex cepstrum to AR coefficients.

Parameters:

Name Type Description Default
cc (array_like, shape(nf, p))

Complex cepstral coefficients.

required

Returns:

Name Type Description
ar (ndarray, shape(nf, p + 1))

Autoregressive coefficients.

Source code in pyvoicebox/v_lpccc2ar.py
def v_lpccc2ar(cc) -> np.ndarray:
    """Convert complex cepstrum to AR coefficients.

    Parameters
    ----------
    cc : array_like, shape (nf, p)
        Complex cepstral coefficients.

    Returns
    -------
    ar : ndarray, shape (nf, p+1)
        Autoregressive coefficients.
    """
    cc = np.atleast_2d(np.asarray(cc, dtype=float))
    nf, p = cc.shape
    rp = -np.arange(1, p + 1, dtype=float)
    cc = cc * rp[np.newaxis, :]

    if p < 2:
        ar = np.column_stack([np.ones((nf, 1)), cc[:, 0:1]])
    else:
        ar = np.zeros((nf, p + 1))
        ar[:, 0] = 1.0
        ar[:, 1] = cc[:, 0]
        ar[:, 2] = (cc[:, 1] + cc[:, 0] ** 2) / 2.0
        for k in range(3, p + 1):
            ar[:, k] = (cc[:, k - 1] + np.sum(cc[:, :k - 1] * ar[:, k - 1:0:-1], axis=1)) / k

    return ar

v_lpccc2cc

V_LPCCC2CC - Extrapolate complex cepstrum.

v_lpccc2cc

v_lpccc2cc(cc, np_out=None) -> ndarray

Extrapolate complex cepstrum.

Parameters:

Name Type Description Default
cc (array_like, shape(nf, p))

Complex cepstral coefficients.

required
np_out int

Output number of coefficients. Default is p.

None

Returns:

Name Type Description
c (ndarray, shape(nf, np_out))

Extrapolated complex cepstral coefficients.

Source code in pyvoicebox/v_lpccc2cc.py
def v_lpccc2cc(cc, np_out=None) -> np.ndarray:
    """Extrapolate complex cepstrum.

    Parameters
    ----------
    cc : array_like, shape (nf, p)
        Complex cepstral coefficients.
    np_out : int, optional
        Output number of coefficients. Default is p.

    Returns
    -------
    c : ndarray, shape (nf, np_out)
        Extrapolated complex cepstral coefficients.
    """
    cc = np.atleast_2d(np.asarray(cc, dtype=float))
    p = cc.shape[1]
    if np_out is None:
        np_out = p

    if np_out <= p:
        c = cc[:, :np_out]
    else:
        from pyvoicebox.v_lpcar2cc import v_lpcar2cc
        from pyvoicebox.v_lpccc2ar import v_lpccc2ar
        c, _ = v_lpcar2cc(v_lpccc2ar(cc), np_out)

    return c

v_lpccc2db

V_LPCCC2DB - Convert complex cepstrum to dB power spectrum.

v_lpccc2db

v_lpccc2db(
    cc, np_out=None, nc=None, c0=None
) -> tuple[ndarray, ndarray]

Convert complex cepstrum to dB power spectrum.

Parameters:

Name Type Description Default
cc (array_like, shape(nf, n))

Complex cepstral coefficients excluding c(0).

required
np_out int

Size of output spectrum is np_out+1. Default is n.

None
nc int

Highest cepstral coefficient to use. Set nc=-1 to use n coefficients.

None
c0 (array_like, shape(nf, 1))

Cepstral coefficient c(0). Default is 0.

None

Returns:

Name Type Description
db (ndarray, shape(nf, np_out + 1))

Power spectrum from DC to Nyquist in dB.

f ndarray

Normalized frequencies (0 to 0.5).

Source code in pyvoicebox/v_lpccc2db.py
def v_lpccc2db(cc, np_out=None, nc=None, c0=None) -> tuple[np.ndarray, np.ndarray]:
    """Convert complex cepstrum to dB power spectrum.

    Parameters
    ----------
    cc : array_like, shape (nf, n)
        Complex cepstral coefficients excluding c(0).
    np_out : int, optional
        Size of output spectrum is np_out+1. Default is n.
    nc : int, optional
        Highest cepstral coefficient to use. Set nc=-1 to use n coefficients.
    c0 : array_like, shape (nf, 1), optional
        Cepstral coefficient c(0). Default is 0.

    Returns
    -------
    db : ndarray, shape (nf, np_out+1)
        Power spectrum from DC to Nyquist in dB.
    f : ndarray
        Normalized frequencies (0 to 0.5).
    """
    cc = np.atleast_2d(np.asarray(cc, dtype=float))
    nf, mc = cc.shape
    if np_out is None:
        np_out = mc
    if nc is not None and nc == -1:
        nc = mc
    if c0 is None:
        c0 = np.zeros((nf, 1))
    else:
        c0 = np.asarray(c0, dtype=float).reshape(nf, 1)

    k = 10.0 / np.log(10)

    if nc is None:
        nc = np_out
    if nc == mc:
        combined = np.column_stack([c0, cc])
        db = k * 2 * np.real(v_rfft(combined.T, 2 * np_out).T)
    else:
        combined = np.column_stack([c0, v_lpccc2cc(cc, nc)])
        db = k * 2 * np.real(v_rfft(combined.T, 2 * np_out).T)

    f = np.linspace(0, 0.5, np_out + 1)
    return db, f

v_lpccc2ff

V_LPCCC2FF - Convert complex cepstrum to complex spectrum.

v_lpccc2ff

v_lpccc2ff(
    cc, np_out=None, nc=None, c0=None
) -> tuple[ndarray, ndarray]

Convert complex cepstrum to complex spectrum.

Parameters:

Name Type Description Default
cc (array_like, shape(nf, n))

Complex cepstral coefficients excluding c(0).

required
np_out int

Size of output spectrum is np_out+1. Default is n.

None
nc int

Number of cepstral coefficients to use. Set nc=-1 to use n.

None
c0 (array_like, shape(nf, 1))

Cepstral coefficient c(0). Default is 0.

None

Returns:

Name Type Description
ff (ndarray, shape(nf, np_out + 1))

Complex spectrum from DC to Nyquist.

f ndarray

Normalized frequencies (0 to 0.5).

Source code in pyvoicebox/v_lpccc2ff.py
def v_lpccc2ff(cc, np_out=None, nc=None, c0=None) -> tuple[np.ndarray, np.ndarray]:
    """Convert complex cepstrum to complex spectrum.

    Parameters
    ----------
    cc : array_like, shape (nf, n)
        Complex cepstral coefficients excluding c(0).
    np_out : int, optional
        Size of output spectrum is np_out+1. Default is n.
    nc : int, optional
        Number of cepstral coefficients to use. Set nc=-1 to use n.
    c0 : array_like, shape (nf, 1), optional
        Cepstral coefficient c(0). Default is 0.

    Returns
    -------
    ff : ndarray, shape (nf, np_out+1)
        Complex spectrum from DC to Nyquist.
    f : ndarray
        Normalized frequencies (0 to 0.5).
    """
    cc = np.atleast_2d(np.asarray(cc, dtype=float))
    nf, mc = cc.shape
    if np_out is None:
        np_out = mc
    if nc is not None and nc == -1:
        nc = mc
    if c0 is None:
        c0 = np.zeros((nf, 1))
    else:
        c0 = np.asarray(c0, dtype=float).reshape(nf, 1)

    if nc is None:
        nc = np_out
    if nc == mc:
        combined = np.column_stack([c0, cc])
        ff = np.exp(v_rfft(combined.T, 2 * np_out).T)
    else:
        combined = np.column_stack([c0, v_lpccc2cc(cc, nc)])
        ff = np.exp(v_rfft(combined.T, 2 * np_out).T)

    f = np.linspace(0, 0.5, np_out + 1)
    return ff, f

v_lpccc2pf

V_LPCCC2PF - Convert complex cepstrum to power spectrum.

v_lpccc2pf

v_lpccc2pf(
    cc, np_out=None, nc=None, c0=None
) -> tuple[ndarray, ndarray]

Convert complex cepstrum to power spectrum.

Parameters:

Name Type Description Default
cc (array_like, shape(nf, n))

Complex cepstral coefficients excluding c(0).

required
np_out int

Size of output spectrum is np_out+1. Default is n.

None
nc int

Highest cepstral coefficient to use. Set nc=-1 to use n.

None
c0 (array_like, shape(nf, 1))

Cepstral coefficient c(0). Default is 0.

None

Returns:

Name Type Description
pf (ndarray, shape(nf, np_out + 1))

Power spectrum from DC to Nyquist.

f ndarray

Normalized frequencies (0 to 0.5).

Source code in pyvoicebox/v_lpccc2pf.py
def v_lpccc2pf(cc, np_out=None, nc=None, c0=None) -> tuple[np.ndarray, np.ndarray]:
    """Convert complex cepstrum to power spectrum.

    Parameters
    ----------
    cc : array_like, shape (nf, n)
        Complex cepstral coefficients excluding c(0).
    np_out : int, optional
        Size of output spectrum is np_out+1. Default is n.
    nc : int, optional
        Highest cepstral coefficient to use. Set nc=-1 to use n.
    c0 : array_like, shape (nf, 1), optional
        Cepstral coefficient c(0). Default is 0.

    Returns
    -------
    pf : ndarray, shape (nf, np_out+1)
        Power spectrum from DC to Nyquist.
    f : ndarray
        Normalized frequencies (0 to 0.5).
    """
    cc = np.atleast_2d(np.asarray(cc, dtype=float))
    nf, mc = cc.shape
    if np_out is None:
        np_out = mc
    if nc is not None and nc == -1:
        nc = mc
    if c0 is None:
        c0 = np.zeros((nf, 1))
    else:
        c0 = np.asarray(c0, dtype=float).reshape(nf, 1)

    if nc is None:
        nc = np_out
    if nc == mc:
        combined = np.column_stack([c0, cc])
        pf = np.exp(2 * np.real(v_rfft(combined.T, 2 * np_out).T))
    else:
        combined = np.column_stack([c0, v_lpccc2cc(cc, nc)])
        pf = np.exp(2 * np.real(v_rfft(combined.T, 2 * np_out).T))

    f = np.linspace(0, 0.5, np_out + 1)
    return pf, f

Other conversions

v_lpcaa2ao

V_LPCAA2AO - Convert area function to area ratios.

v_lpcaa2ao

v_lpcaa2ao(aa) -> ndarray

Convert area function to area ratios.

Parameters:

Name Type Description Default
aa (array_like, shape(nf, p + 2))

Area function.

required

Returns:

Name Type Description
ao (ndarray, shape(nf, p + 1))

Area ratios.

Source code in pyvoicebox/v_lpcaa2ao.py
def v_lpcaa2ao(aa) -> np.ndarray:
    """Convert area function to area ratios.

    Parameters
    ----------
    aa : array_like, shape (nf, p+2)
        Area function.

    Returns
    -------
    ao : ndarray, shape (nf, p+1)
        Area ratios.
    """
    aa = np.atleast_2d(np.asarray(aa, dtype=float))
    p1 = aa.shape[1]
    ao = aa[:, :p1 - 1] / aa[:, 1:p1]
    return ao

v_lpcaa2dl

V_LPCAA2DL - Convert area coefficients to DCT of log area.

v_lpcaa2dl

v_lpcaa2dl(aa) -> ndarray

Convert area coefficients to DCT of log area.

Parameters:

Name Type Description Default
aa (array_like, shape(nf, p + 2))

Area coefficients.

required

Returns:

Name Type Description
dl (ndarray, shape(nf, p))

DCT of log area.

Source code in pyvoicebox/v_lpcaa2dl.py
def v_lpcaa2dl(aa) -> np.ndarray:
    """Convert area coefficients to DCT of log area.

    Parameters
    ----------
    aa : array_like, shape (nf, p+2)
        Area coefficients.

    Returns
    -------
    dl : ndarray, shape (nf, p)
        DCT of log area.
    """
    aa = np.atleast_2d(np.asarray(aa, dtype=float))
    nf, p2 = aa.shape
    # log(aa(:,2:p2-1) ./ aa(:,p2*ones(1,p2-2)))
    inner = aa[:, 1:p2 - 1] / aa[:, -1:]
    dl = v_rdct(np.log(inner).T).T
    return dl

v_lpcaa2rf

V_LPCAA2RF - Convert vocal tract areas to reflection coefficients.

v_lpcaa2rf

v_lpcaa2rf(aa) -> ndarray

Convert vocal tract areas to reflection coefficients.

Parameters:

Name Type Description Default
aa (array_like, shape(nf, p + 2))

Vocal tract areas.

required

Returns:

Name Type Description
rf (ndarray, shape(nf, p + 1))

Reflection coefficients.

Source code in pyvoicebox/v_lpcaa2rf.py
def v_lpcaa2rf(aa) -> np.ndarray:
    """Convert vocal tract areas to reflection coefficients.

    Parameters
    ----------
    aa : array_like, shape (nf, p+2)
        Vocal tract areas.

    Returns
    -------
    rf : ndarray, shape (nf, p+1)
        Reflection coefficients.
    """
    aa = np.atleast_2d(np.asarray(aa, dtype=float))
    nf, p2 = aa.shape
    rf = (aa[:, 1:p2] - aa[:, :p2 - 1]) / (aa[:, 1:p2] + aa[:, :p2 - 1])
    return rf

v_lpcao2rf

V_LPCAO2RF - Convert area ratios to reflection coefficients.

v_lpcao2rf

v_lpcao2rf(ao) -> ndarray

Convert area ratios to reflection coefficients.

Parameters:

Name Type Description Default
ao array_like

Area ratios.

required

Returns:

Name Type Description
rf ndarray

Reflection coefficients.

Source code in pyvoicebox/v_lpcao2rf.py
def v_lpcao2rf(ao) -> np.ndarray:
    """Convert area ratios to reflection coefficients.

    Parameters
    ----------
    ao : array_like
        Area ratios.

    Returns
    -------
    rf : ndarray
        Reflection coefficients.
    """
    ao = np.asarray(ao, dtype=float)
    rf = (1 - ao) / (1 + ao)
    return rf

v_lpccw2zz

V_LPCCW2ZZ - Power spectrum roots to LPC poles.

v_lpccw2zz

v_lpccw2zz(cw) -> ndarray

Convert power spectrum cos(w) roots to LPC z-plane poles.

Parameters:

Name Type Description Default
cw array_like

Roots of the power spectrum polynomial pp(cos(w)).

required

Returns:

Name Type Description
zz ndarray

LPC z-plane poles.

Source code in pyvoicebox/v_lpccw2zz.py
def v_lpccw2zz(cw) -> np.ndarray:
    """Convert power spectrum cos(w) roots to LPC z-plane poles.

    Parameters
    ----------
    cw : array_like
        Roots of the power spectrum polynomial pp(cos(w)).

    Returns
    -------
    zz : ndarray
        LPC z-plane poles.
    """
    cw = np.asarray(cw, dtype=complex)
    zs = np.sqrt(cw ** 2 - 1)
    zz = cw - np.sign(np.real(np.conj(cw) * zs)) * zs
    return zz

v_lpcdb2pf

V_LPCDB2PF - Convert decibel power spectrum to power spectrum.

v_lpcdb2pf

v_lpcdb2pf(db) -> ndarray

Convert decibel power spectrum to power spectrum.

Parameters:

Name Type Description Default
db array_like

Power spectrum in dB.

required

Returns:

Name Type Description
pf ndarray

Power spectrum (linear scale).

Source code in pyvoicebox/v_lpcdb2pf.py
def v_lpcdb2pf(db) -> np.ndarray:
    """Convert decibel power spectrum to power spectrum.

    Parameters
    ----------
    db : array_like
        Power spectrum in dB.

    Returns
    -------
    pf : ndarray
        Power spectrum (linear scale).
    """
    db = np.asarray(db, dtype=float)
    pf = np.exp(db * np.log(10) / 10)
    return pf

v_lpcdl2aa

V_LPCDL2AA - Convert DCT of log area to area coefficients.

v_lpcdl2aa

v_lpcdl2aa(dl) -> ndarray

Convert DCT of log area to area coefficients.

Parameters:

Name Type Description Default
dl (array_like, shape(nf, p))

DCT of log area.

required

Returns:

Name Type Description
aa (ndarray, shape(nf, p + 2))

Area coefficients with aa[:, 0] = 0 and aa[:, -1] = 1.

Source code in pyvoicebox/v_lpcdl2aa.py
def v_lpcdl2aa(dl) -> np.ndarray:
    """Convert DCT of log area to area coefficients.

    Parameters
    ----------
    dl : array_like, shape (nf, p)
        DCT of log area.

    Returns
    -------
    aa : ndarray, shape (nf, p+2)
        Area coefficients with aa[:, 0] = 0 and aa[:, -1] = 1.
    """
    dl = np.atleast_2d(np.asarray(dl, dtype=float))
    nf, p = dl.shape
    aa = np.column_stack([
        np.zeros((nf, 1)),
        np.exp(v_irdct(dl.T).T),
        np.ones((nf, 1))
    ])
    return aa

v_lpcff2pf

V_LPCFF2PF - Convert complex spectrum to power spectrum.

v_lpcff2pf

v_lpcff2pf(ff) -> ndarray

Convert complex spectrum to power spectrum.

Parameters:

Name Type Description Default
ff array_like

Complex spectrum.

required

Returns:

Name Type Description
pf ndarray

Power spectrum.

Source code in pyvoicebox/v_lpcff2pf.py
def v_lpcff2pf(ff) -> np.ndarray:
    """Convert complex spectrum to power spectrum.

    Parameters
    ----------
    ff : array_like
        Complex spectrum.

    Returns
    -------
    pf : ndarray
        Power spectrum.
    """
    ff = np.asarray(ff, dtype=complex)
    pf = np.abs(ff) ** 2
    return pf

v_lpcfq2zz

V_LPCFQ2ZZ - Convert frequencies and Q factors to z-plane poles.

v_lpcfq2zz

v_lpcfq2zz(f, q=None) -> ndarray

Convert frequencies and Q factors to z-plane poles.

Parameters:

Name Type Description Default
f (array_like, shape(nf, pf))

Frequencies in normalized Hz.

required
q (array_like, shape(nf, pq))

Q factors.

None

Returns:

Name Type Description
zz (ndarray, shape(nf, pf + pq))

Z-plane poles.

Source code in pyvoicebox/v_lpcfq2zz.py
def v_lpcfq2zz(f, q=None) -> np.ndarray:
    """Convert frequencies and Q factors to z-plane poles.

    Parameters
    ----------
    f : array_like, shape (nf, pf)
        Frequencies in normalized Hz.
    q : array_like, shape (nf, pq), optional
        Q factors.

    Returns
    -------
    zz : ndarray, shape (nf, pf+pq)
        Z-plane poles.
    """
    f = np.atleast_2d(np.asarray(f, dtype=float))
    nf, pf = f.shape

    if q is None:
        pq = 0
    else:
        q = np.atleast_2d(np.asarray(q, dtype=float))
        pq = q.shape[1]

    zz = np.zeros((nf, pf + pq), dtype=complex)

    if pq > 0:
        ii = np.arange(pq)
        zz[:, 2 * ii] = np.exp(np.pi * f[:, :pq] * (2j - q ** (-1)))
        zz[:, 2 * ii + 1] = np.conj(zz[:, 2 * ii])

    if pf > pq:
        ii = np.arange(pq, pf)
        zz[:, ii + pq] = np.exp(-2 * np.pi * f[:, ii])

    return zz

v_lpcim2ar

V_LPCIM2AR - Convert impulse response to AR coefficients.

v_lpcim2ar

v_lpcim2ar(im) -> ndarray

Convert impulse response to AR coefficients.

Parameters:

Name Type Description Default
im (array_like, shape(nf, p + 1))

Impulse response.

required

Returns:

Name Type Description
ar (ndarray, shape(nf, p + 1))

Autoregressive coefficients.

Source code in pyvoicebox/v_lpcim2ar.py
def v_lpcim2ar(im) -> np.ndarray:
    """Convert impulse response to AR coefficients.

    Parameters
    ----------
    im : array_like, shape (nf, p+1)
        Impulse response.

    Returns
    -------
    ar : ndarray, shape (nf, p+1)
        Autoregressive coefficients.
    """
    im = np.atleast_2d(np.asarray(im, dtype=float))
    nf, p1 = im.shape
    ar = np.zeros((nf, p1))
    wz = np.zeros(p1)
    wz[0] = 1.0
    for k in range(nf):
        T = toeplitz(wz, im[k, :] / im[k, 0])
        ar[k, :] = solve(T.T, wz)
    return ar

v_lpcis2rf

V_LPCIS2RF - Convert inverse sines to reflection coefficients.

v_lpcis2rf

v_lpcis2rf(is_coef) -> ndarray

Convert inverse sines to reflection coefficients.

Parameters:

Name Type Description Default
is_coef array_like

Inverse sine coefficients.

required

Returns:

Name Type Description
rf ndarray

Reflection coefficients.

Source code in pyvoicebox/v_lpcis2rf.py
def v_lpcis2rf(is_coef) -> np.ndarray:
    """Convert inverse sines to reflection coefficients.

    Parameters
    ----------
    is_coef : array_like
        Inverse sine coefficients.

    Returns
    -------
    rf : ndarray
        Reflection coefficients.
    """
    is_coef = np.asarray(is_coef, dtype=float)
    rf = np.sin(is_coef * np.pi / 2)
    return rf

v_lpcla2rf

V_LPCLA2RF - Convert log areas to reflection coefficients.

v_lpcla2rf

v_lpcla2rf(la) -> ndarray

Convert log areas to reflection coefficients.

Parameters:

Name Type Description Default
la (array_like, shape(nf, p + 2))

Log areas.

required

Returns:

Name Type Description
rf (ndarray, shape(nf, p + 1))

Reflection coefficients.

Source code in pyvoicebox/v_lpcla2rf.py
def v_lpcla2rf(la) -> np.ndarray:
    """Convert log areas to reflection coefficients.

    Parameters
    ----------
    la : array_like, shape (nf, p+2)
        Log areas.

    Returns
    -------
    rf : ndarray, shape (nf, p+1)
        Reflection coefficients.
    """
    la = np.atleast_2d(np.asarray(la, dtype=float))
    nf, p2 = la.shape
    rf = -np.tanh((la[:, :p2 - 1] - la[:, 1:p2]) / 2)
    return rf

v_lpclo2rf

V_LPCLO2RF - Convert log area ratios to reflection coefficients.

v_lpclo2rf

v_lpclo2rf(lo) -> ndarray

Convert log area ratios to reflection coefficients.

Parameters:

Name Type Description Default
lo array_like

Log area ratios.

required

Returns:

Name Type Description
rf ndarray

Reflection coefficients.

Source code in pyvoicebox/v_lpclo2rf.py
def v_lpclo2rf(lo) -> np.ndarray:
    """Convert log area ratios to reflection coefficients.

    Parameters
    ----------
    lo : array_like
        Log area ratios.

    Returns
    -------
    rf : ndarray
        Reflection coefficients.
    """
    lo = np.asarray(lo, dtype=float)
    rf = -np.tanh(lo / 2)
    return rf

v_lpcls2ar

V_LPCLS2AR - Convert line spectrum pair frequencies to AR polynomial.

v_lpcls2ar

v_lpcls2ar(ls) -> ndarray

Convert line spectrum pair frequencies to AR polynomial.

Parameters:

Name Type Description Default
ls (array_like, shape(nf, p))

Line spectrum pair frequencies (0 to 0.5 normalized Hz).

required

Returns:

Name Type Description
ar (ndarray, shape(nf, p + 1))

Autoregressive coefficients.

Source code in pyvoicebox/v_lpcls2ar.py
def v_lpcls2ar(ls) -> np.ndarray:
    """Convert line spectrum pair frequencies to AR polynomial.

    Parameters
    ----------
    ls : array_like, shape (nf, p)
        Line spectrum pair frequencies (0 to 0.5 normalized Hz).

    Returns
    -------
    ar : ndarray, shape (nf, p+1)
        Autoregressive coefficients.
    """
    ls = np.atleast_2d(np.asarray(ls, dtype=float))
    nf, p = ls.shape
    p1 = p + 1
    p2 = p1 * 2
    ar = np.zeros((nf, p1))

    for k in range(nf):
        le = np.exp(ls[k, :] * np.pi * 2j)
        lf = np.concatenate([[1], le, [-1], np.conj(le[::-1])])
        y = np.real(np.poly(lf[0:p2:2]))
        x = np.real(np.poly(lf[1:p2:2]))
        ar[k, :] = (x[:p1] + y[:p1]) / 2.0

    return ar

v_lpcpf2cc

V_LPCPF2CC - Convert power spectrum to complex cepstrum.

v_lpcpf2cc

v_lpcpf2cc(
    pf, np_out=None, f=None
) -> tuple[ndarray, ndarray]

Convert power spectrum to complex cepstrum.

Parameters:

Name Type Description Default
pf (array_like, shape(nf, n))

Power spectrum, uniformly spaced DC to Nyquist.

required
np_out int

Number of cepstral coefficients to calculate. Default is n-1.

None
f (array_like, shape(n))

Frequencies of pf columns.

None

Returns:

Name Type Description
cc (ndarray, shape(nf, np_out))

Complex cepstral coefficients.

c0 (ndarray, shape(nf, 1))

Zeroth cepstral coefficient.

Source code in pyvoicebox/v_lpcpf2cc.py
def v_lpcpf2cc(pf, np_out=None, f=None) -> tuple[np.ndarray, np.ndarray]:
    """Convert power spectrum to complex cepstrum.

    Parameters
    ----------
    pf : array_like, shape (nf, n)
        Power spectrum, uniformly spaced DC to Nyquist.
    np_out : int, optional
        Number of cepstral coefficients to calculate. Default is n-1.
    f : array_like, shape (n,), optional
        Frequencies of pf columns.

    Returns
    -------
    cc : ndarray, shape (nf, np_out)
        Complex cepstral coefficients.
    c0 : ndarray, shape (nf, 1)
        Zeroth cepstral coefficient.
    """
    pf = np.atleast_2d(np.asarray(pf, dtype=float))
    nf, nq = pf.shape
    if np_out is None:
        np_out = nq - 1

    if f is None:
        cc = v_rsfft(np.log(pf).T).T / (2 * nq - 2)
        c0 = cc[:, 0:1] * 0.5
        cc[:, nq - 1] = cc[:, nq - 1] * 0.5
        if np_out > nq - 1:
            cc = np.column_stack([cc[:, 1:nq], np.zeros((nf, np_out - nq + 1))])
        else:
            cc = cc[:, 1:np_out + 1]
    else:
        f = np.asarray(f, dtype=float)
        nm = min(np_out, nq - 1)
        cos_matrix = np.cos(2 * np.pi * f[:, np.newaxis] * np.arange(nm + 1)[np.newaxis, :])
        cc = 0.5 * np.linalg.lstsq(cos_matrix, np.log(pf).T, rcond=None)[0].T
        c0 = cc[:, 0:1]
        cc = cc[:, 1:]
        if np_out > nq - 1:
            cc = np.column_stack([cc, np.zeros((nf, np_out - nq + 1))])

    return cc, c0

v_lpcpf2ff

V_LPCPF2FF - Convert power spectrum to complex spectrum.

v_lpcpf2ff

v_lpcpf2ff(
    pf, np_out=None, fi=None
) -> tuple[ndarray, ndarray]

Convert power spectrum to complex spectrum.

Parameters:

Name Type Description Default
pf (array_like, shape(nf, n))

Power spectrum.

required
np_out int

Number of complex cepstral coefficients to use.

None
fi array_like

Vector of frequencies.

None

Returns:

Name Type Description
ff (ndarray, shape(nf, n))

Complex spectrum.

fo ndarray

Vector of frequencies.

Source code in pyvoicebox/v_lpcpf2ff.py
def v_lpcpf2ff(pf, np_out=None, fi=None) -> tuple[np.ndarray, np.ndarray]:
    """Convert power spectrum to complex spectrum.

    Parameters
    ----------
    pf : array_like, shape (nf, n)
        Power spectrum.
    np_out : int, optional
        Number of complex cepstral coefficients to use.
    fi : array_like, optional
        Vector of frequencies.

    Returns
    -------
    ff : ndarray, shape (nf, n)
        Complex spectrum.
    fo : ndarray
        Vector of frequencies.
    """
    pf = np.atleast_2d(np.asarray(pf, dtype=float))
    nf, nq = pf.shape
    if fi is None:
        if np_out is None:
            np_out = nq - 1
    else:
        if np_out is None:
            np_out = nq - 1

    cc, c0 = v_lpcpf2cc(pf, np_out, fi)
    if fi is None:
        fi_val = nq - 1
    else:
        fi_val = fi
    fx, fo = v_lpccc2ff(cc, fi_val, nc=-1, c0=c0)
    ff = np.sqrt(pf) * np.exp(1j * np.angle(fx))

    return ff, fo

v_lpcpf2rr

V_LPCPF2RR - Convert power spectrum to autocorrelation coefficients.

v_lpcpf2rr

v_lpcpf2rr(pf, p=None) -> ndarray

Convert power spectrum to autocorrelation coefficients.

Parameters:

Name Type Description Default
pf (array_like, shape(nf, p2))

Power spectrum.

required
p int

Number of output coefficients minus 1. Default is p2-2.

None

Returns:

Name Type Description
rr (ndarray, shape(nf, p + 1))

Autocorrelation coefficients.

Source code in pyvoicebox/v_lpcpf2rr.py
def v_lpcpf2rr(pf, p=None) -> np.ndarray:
    """Convert power spectrum to autocorrelation coefficients.

    Parameters
    ----------
    pf : array_like, shape (nf, p2)
        Power spectrum.
    p : int, optional
        Number of output coefficients minus 1. Default is p2-2.

    Returns
    -------
    rr : ndarray, shape (nf, p+1)
        Autocorrelation coefficients.
    """
    pf = np.atleast_2d(np.asarray(pf, dtype=float))
    nf, p2 = pf.shape
    if p is None:
        p = p2 - 2

    # MATLAB: ir = v_irfft(pf,[],2) -- irfft along rows (dim 2)
    # Transpose to columns, apply irfft along dim 0, transpose back
    ir = v_irfft(pf.T).T
    if p > p2 - 2:
        rr = np.column_stack([ir[:, :p2 - 1], np.zeros((nf, p + 2 - p2))])
    else:
        rr = ir[:, :p + 1]

    return rr

v_lpcpp2cw

V_LPCPP2CW - Convert power spectrum polynomial to power spectrum zeros.

v_lpcpp2cw

v_lpcpp2cw(pp) -> ndarray

Convert power spectrum polynomial in cos(w) to power spectrum zeros.

Parameters:

Name Type Description Default
pp (array_like, shape(nf, p + 1))

Power spectrum polynomial coefficients.

required

Returns:

Name Type Description
cw (ndarray, shape(nf, p))

Power spectrum zeros (roots of the polynomial).

Source code in pyvoicebox/v_lpcpp2cw.py
def v_lpcpp2cw(pp) -> np.ndarray:
    """Convert power spectrum polynomial in cos(w) to power spectrum zeros.

    Parameters
    ----------
    pp : array_like, shape (nf, p+1)
        Power spectrum polynomial coefficients.

    Returns
    -------
    cw : ndarray, shape (nf, p)
        Power spectrum zeros (roots of the polynomial).
    """
    pp = np.atleast_2d(np.asarray(pp, dtype=complex))
    nf, p1 = pp.shape
    cw = np.zeros((nf, p1 - 1), dtype=complex)
    for k in range(nf):
        cw[k, :] = np.roots(pp[k, :])
    return cw

v_lpcpp2pz

V_LPCPP2PZ - Convert power spectrum polynomial to power spectrum zeros.

v_lpcpp2pz

v_lpcpp2pz(pp) -> ndarray

Convert power spectrum polynomial in cos(w) to power spectrum zeros.

Parameters:

Name Type Description Default
pp array_like

Power spectrum polynomial coefficients (single polynomial).

required

Returns:

Name Type Description
pz ndarray

Power spectrum zeros (roots of the polynomial).

Source code in pyvoicebox/v_lpcpp2pz.py
def v_lpcpp2pz(pp) -> np.ndarray:
    """Convert power spectrum polynomial in cos(w) to power spectrum zeros.

    Parameters
    ----------
    pp : array_like
        Power spectrum polynomial coefficients (single polynomial).

    Returns
    -------
    pz : ndarray
        Power spectrum zeros (roots of the polynomial).
    """
    pp = np.asarray(pp, dtype=complex).ravel()
    pz = np.roots(pp)
    return pz

v_lpcpz2zz

V_LPCPZ2ZZ - Power spectrum roots to LPC poles.

v_lpcpz2zz

v_lpcpz2zz(pz) -> ndarray

Convert power spectrum roots to LPC z-plane poles.

Parameters:

Name Type Description Default
pz array_like

Roots of the power spectrum polynomial pp(cos(w)).

required

Returns:

Name Type Description
zz ndarray

LPC z-plane poles.

Source code in pyvoicebox/v_lpcpz2zz.py
def v_lpcpz2zz(pz) -> np.ndarray:
    """Convert power spectrum roots to LPC z-plane poles.

    Parameters
    ----------
    pz : array_like
        Roots of the power spectrum polynomial pp(cos(w)).

    Returns
    -------
    zz : ndarray
        LPC z-plane poles.
    """
    pz = np.asarray(pz, dtype=complex)
    zs = np.sqrt(pz ** 2 - 1)
    zz = pz - np.sign(np.real(np.conj(pz) * zs)) * zs
    return zz

v_lpcra2ar

V_LPCRA2AR - Convert inverse filter autocorrelation coefficients to AR filter.

v_lpcra2ar

v_lpcra2ar(ra, tol=1e-08) -> ndarray

Convert inverse filter autocorrelation coefficients to AR filter.

Uses a Newton-Raphson iteration (Wilson's algorithm).

Parameters:

Name Type Description Default
ra (array_like, shape(n, p + 1))

Each row is the second half of the autocorrelation of the coefficients of a stable AR filter of order p.

required
tol float

Tolerance relative to ra[0]. Default is 1e-8.

1e-08

Returns:

Name Type Description
ar (ndarray, shape(n, p + 1))

AR filter coefficients.

Source code in pyvoicebox/v_lpcra2ar.py
def v_lpcra2ar(ra, tol=1e-8) -> np.ndarray:
    """Convert inverse filter autocorrelation coefficients to AR filter.

    Uses a Newton-Raphson iteration (Wilson's algorithm).

    Parameters
    ----------
    ra : array_like, shape (n, p+1)
        Each row is the second half of the autocorrelation of the
        coefficients of a stable AR filter of order p.
    tol : float, optional
        Tolerance relative to ra[0]. Default is 1e-8.

    Returns
    -------
    ar : ndarray, shape (n, p+1)
        AR filter coefficients.
    """
    ra = np.atleast_2d(np.asarray(ra, dtype=float))
    imax = 20
    nf, pp = ra.shape

    ar = np.zeros((nf, pp))
    for n in range(nf):
        xa = ra[n, :].copy()
        ax = np.zeros(pp)
        ax[0] = np.sqrt(xa[0] + 2 * np.sum(xa[1:]))

        i = imax
        while i > 0:
            t1 = hankel(ax)
            t2 = toeplitz(ax, np.concatenate([[ax[0]], np.zeros(pp - 1)]))
            ct = ax @ t1
            # MATLAB: ax = (xa+ct)/(t1+t2) means ax * (t1+t2) = (xa+ct)
            # Equivalent to solving (t1+t2)^T * ax^T = (xa+ct)^T
            ax = np.linalg.solve((t1 + t2).T, xa + ct)
            err = np.max(np.abs(ct - xa))
            if err <= tol * xa[0]:
                i = min(i - 1, 1)  # do one more iteration
            else:
                i -= 1

        ar[n, :] = ax

    return ar

v_lpcra2pf

V_LPCRA2PF - Convert inverse filter autocorrelation to power spectrum.

v_lpcra2pf

v_lpcra2pf(ra, np_out=None) -> ndarray

Convert inverse filter autocorrelation to power spectrum.

Parameters:

Name Type Description Default
ra (array_like, shape(nf, p + 1))

Inverse filter autocorrelation coefficients.

required
np_out int

Number of output frequencies minus 1. Default is p.

None

Returns:

Name Type Description
pf (ndarray, shape(nf, np_out + 2))

Power spectrum.

Source code in pyvoicebox/v_lpcra2pf.py
def v_lpcra2pf(ra, np_out=None) -> np.ndarray:
    """Convert inverse filter autocorrelation to power spectrum.

    Parameters
    ----------
    ra : array_like, shape (nf, p+1)
        Inverse filter autocorrelation coefficients.
    np_out : int, optional
        Number of output frequencies minus 1. Default is p.

    Returns
    -------
    pf : ndarray, shape (nf, np_out+2)
        Power spectrum.
    """
    ra = np.atleast_2d(np.asarray(ra, dtype=float))
    nf, p1 = ra.shape
    if np_out is None:
        np_out = p1 - 1
    pp = 2 * np_out + 2

    if pp >= 2 * p1:
        # Zero-pad and mirror
        data = np.column_stack([ra, np.zeros((nf, pp - 2 * p1 + 1)), ra[:, p1 - 1:0:-1]])
        pf = np.abs(v_rfft(data.T).T) ** (-1)
    else:
        data = np.column_stack([ra[:, :np_out + 2], ra[:, np_out:0:-1]])
        pf = np.abs(v_rfft(data.T).T) ** (-1)

    return pf

v_lpcra2pp

V_LPCRA2PP - Convert inverse filter autocorrelation to power spectrum polynomial.

v_lpcra2pp

v_lpcra2pp(ra) -> ndarray

Convert inverse filter autocorrelation to power spectrum polynomial in cos(w).

Parameters:

Name Type Description Default
ra (array_like, shape(nf, p + 1))

Inverse filter autocorrelation coefficients.

required

Returns:

Name Type Description
pp (ndarray, shape(nf, p + 1))

Power spectrum polynomial coefficients.

Source code in pyvoicebox/v_lpcra2pp.py
def v_lpcra2pp(ra) -> np.ndarray:
    """Convert inverse filter autocorrelation to power spectrum polynomial in cos(w).

    Parameters
    ----------
    ra : array_like, shape (nf, p+1)
        Inverse filter autocorrelation coefficients.

    Returns
    -------
    pp : ndarray, shape (nf, p+1)
        Power spectrum polynomial coefficients.
    """
    ra = np.atleast_2d(np.asarray(ra, dtype=float))
    nf, p1 = ra.shape
    tp = _chebyshev_matrix(p1)
    pp = ra @ tp
    return pp

v_lpcrr2am

V_LPCRR2AM - Convert autocorrelation coefficients to AR coefficient matrix.

v_lpcrr2am

v_lpcrr2am(rr) -> tuple[ndarray, ndarray]

Convert autocorrelation coefficients to AR coefficient matrix.

Parameters:

Name Type Description Default
rr (array_like, shape(nf, p + 1))

Autocorrelation coefficients.

required

Returns:

Name Type Description
am (ndarray, shape(p + 1, p + 1, nf))

AR coefficient matrix.

em (ndarray, shape(nf, p + 1))

Residual energy for each order.

Source code in pyvoicebox/v_lpcrr2am.py
def v_lpcrr2am(rr) -> tuple[np.ndarray, np.ndarray]:
    """Convert autocorrelation coefficients to AR coefficient matrix.

    Parameters
    ----------
    rr : array_like, shape (nf, p+1)
        Autocorrelation coefficients.

    Returns
    -------
    am : ndarray, shape (p+1, p+1, nf)
        AR coefficient matrix.
    em : ndarray, shape (nf, p+1)
        Residual energy for each order.
    """
    rr = np.atleast_2d(np.asarray(rr, dtype=float))
    nf, p1 = rr.shape
    p = p1 - 1

    am = np.zeros((nf, p1, p1))
    em = np.zeros((nf, p1))
    am[:, p, p] = 1.0
    em[:, p] = rr[:, 0]

    ar = np.ones((nf, p1))
    ar[:, 1] = -rr[:, 1] / rr[:, 0]
    e = rr[:, 0] * (ar[:, 1] ** 2 - 1)

    for n in range(2, p + 1):
        q = p1 - n
        em[:, q] = -e
        am[:, q:p1, q] = ar[:, :n]
        k = (rr[:, n] + np.sum(rr[:, n-1:0:-1] * ar[:, 1:n], axis=1)) / e
        ar[:, 1:n] = ar[:, 1:n] + k[:, np.newaxis] * ar[:, n-1:0:-1]
        ar[:, n] = k
        e = e * (1 - k ** 2)

    em[:, 0] = -e
    am[:, :, 0] = ar

    # Permute to (p+1, p+1, nf)
    am = np.transpose(am, (2, 1, 0))

    return am, em

v_lpcrr2ar

V_LPCRR2AR - Convert autocorrelation coefficients to AR coefficients.

v_lpcrr2ar

v_lpcrr2ar(rr) -> tuple[ndarray, ndarray]

Convert autocorrelation coefficients to AR coefficients.

Parameters:

Name Type Description Default
rr (array_like, shape(nf, p + 1))

Autocorrelation coefficients.

required

Returns:

Name Type Description
ar (ndarray, shape(nf, p + 1))

AR coefficients.

e (ndarray, shape(nf))

Residual energy.

Source code in pyvoicebox/v_lpcrr2ar.py
def v_lpcrr2ar(rr) -> tuple[np.ndarray, np.ndarray]:
    """Convert autocorrelation coefficients to AR coefficients.

    Parameters
    ----------
    rr : array_like, shape (nf, p+1)
        Autocorrelation coefficients.

    Returns
    -------
    ar : ndarray, shape (nf, p+1)
        AR coefficients.
    e : ndarray, shape (nf,)
        Residual energy.
    """
    rr = np.atleast_2d(np.asarray(rr, dtype=float))
    nf, p1 = rr.shape
    p = p1 - 1

    ar = np.ones((nf, p1))
    ar[:, 1] = -rr[:, 1] / rr[:, 0]
    e = rr[:, 0] * (ar[:, 1] ** 2 - 1)

    for n in range(2, p + 1):
        k = (rr[:, n] + np.sum(rr[:, n-1:0:-1] * ar[:, 1:n], axis=1)) / e
        ar[:, 1:n] = ar[:, 1:n] + k[:, np.newaxis] * ar[:, n-1:0:-1]
        ar[:, n] = k
        e = e * (1 - k ** 2)

    e = -e
    return ar, e

v_lpcss2zz

V_LPCSS2ZZ - Convert s-plane poles to z-plane poles.

v_lpcss2zz

v_lpcss2zz(ss, nr=None) -> ndarray

Convert s-plane poles to z-plane poles.

Parameters:

Name Type Description Default
ss (array_like, shape(n, q))

S-plane pole positions in normalized-Hz units.

required
nr int

Number of poles that should NOT be supplemented by conjugate pairs. If nr=-1, conjugate of any column containing a non-real number.

None

Returns:

Name Type Description
zz (ndarray, shape(n, p))

Z-plane poles.

Source code in pyvoicebox/v_lpcss2zz.py
def v_lpcss2zz(ss, nr=None) -> np.ndarray:
    """Convert s-plane poles to z-plane poles.

    Parameters
    ----------
    ss : array_like, shape (n, q)
        S-plane pole positions in normalized-Hz units.
    nr : int, optional
        Number of poles that should NOT be supplemented by conjugate pairs.
        If nr=-1, conjugate of any column containing a non-real number.

    Returns
    -------
    zz : ndarray, shape (n, p)
        Z-plane poles.
    """
    ss = np.atleast_2d(np.asarray(ss, dtype=complex))
    if nr is not None and nr < ss.shape[1]:
        if nr >= 0:
            ss = np.column_stack([ss, np.conj(ss[:, nr:])])
        else:
            # Conjugate of columns containing non-real numbers
            has_imag = np.any(np.imag(ss) != 0, axis=0)
            ss = np.column_stack([ss, np.conj(ss[:, has_imag])])
    zz = np.exp(2 * np.pi * ss)
    return zz

v_lpczz2ar

V_LPCZZ2AR - Convert z-plane poles to AR coefficients.

v_lpczz2ar

v_lpczz2ar(zz) -> ndarray

Convert z-plane poles to AR coefficients.

Parameters:

Name Type Description Default
zz (array_like, shape(nf, p))

Z-plane poles.

required

Returns:

Name Type Description
ar (ndarray, shape(nf, p + 1))

AR coefficients.

Source code in pyvoicebox/v_lpczz2ar.py
def v_lpczz2ar(zz) -> np.ndarray:
    """Convert z-plane poles to AR coefficients.

    Parameters
    ----------
    zz : array_like, shape (nf, p)
        Z-plane poles.

    Returns
    -------
    ar : ndarray, shape (nf, p+1)
        AR coefficients.
    """
    zz = np.atleast_2d(np.asarray(zz, dtype=complex))
    nf, p = zz.shape
    ar = np.zeros((nf, p + 1))
    for k in range(nf):
        ar[k, :] = np.real(np.poly(zz[k, :]))
    return ar

v_lpczz2cc

V_LPCZZ2CC - Convert poles to complex cepstrum.

v_lpczz2cc

v_lpczz2cc(zz, np_out=None) -> ndarray

Convert poles to complex cepstrum.

Parameters:

Name Type Description Default
zz (array_like, shape(nf, p))

Z-plane poles.

required
np_out int

Number of cepstral coefficients. Default is p.

None

Returns:

Name Type Description
cc (ndarray, shape(nf, np_out))

Complex cepstral coefficients.

Source code in pyvoicebox/v_lpczz2cc.py
def v_lpczz2cc(zz, np_out=None) -> np.ndarray:
    """Convert poles to complex cepstrum.

    Parameters
    ----------
    zz : array_like, shape (nf, p)
        Z-plane poles.
    np_out : int, optional
        Number of cepstral coefficients. Default is p.

    Returns
    -------
    cc : ndarray, shape (nf, np_out)
        Complex cepstral coefficients.
    """
    zz = np.atleast_2d(np.asarray(zz, dtype=complex))
    nf, p = zz.shape
    if np_out is None:
        np_out = p

    cc = np.zeros((nf, np_out))
    yy = zz.T.copy()  # shape (p, nf)

    if p < 2:
        cc[:, 0] = np.real(zz).ravel()
        for k in range(1, np_out):
            yy = yy * zz.T
            cc[:, k] = np.real(yy).ravel() / (k + 1)
    else:
        cc[:, 0] = np.sum(np.real(yy), axis=0)
        for k in range(1, np_out):
            yy = yy * zz.T
            cc[:, k] = np.sum(np.real(yy), axis=0) / (k + 1)

    return cc

v_lpczz2ss

V_LPCZZ2SS - Convert z-plane poles to s-plane poles.

v_lpczz2ss

v_lpczz2ss(zz) -> ndarray

Convert z-plane poles to s-plane poles.

Parameters:

Name Type Description Default
zz array_like

Z-plane poles.

required

Returns:

Name Type Description
ss ndarray

S-plane poles in normalized Hz units.

Source code in pyvoicebox/v_lpczz2ss.py
def v_lpczz2ss(zz) -> np.ndarray:
    """Convert z-plane poles to s-plane poles.

    Parameters
    ----------
    zz : array_like
        Z-plane poles.

    Returns
    -------
    ss : ndarray
        S-plane poles in normalized Hz units.
    """
    zz = np.asarray(zz, dtype=complex)
    ss = np.log(np.maximum(np.abs(zz), 1e-8) * np.exp(1j * np.angle(zz))) * 0.5 / np.pi
    return ss