View Raw SPL
/*****************************************************************************
*                                                                            *
*   CCEPS.SPL     Copyright (C) 1999-2011 DSP Development Corporation        *
*                               All Rights Reserved                          *
*                                                                            *
*   Author:       Randy Race                                                 *
*                                                                            *
*   Synopsis:     Complex cepstrum calculation                               *
*                                                                            *
*   Revisions:     9 Jul 1999  RRR  Creation - from CEPSTRUM.MAC             *
*                  3 Dec 2011  RRR  ITERATE for multi-column iteration       *
*                                                                            *
*****************************************************************************/

#if @HELP_CCEPS

    CCEPS

    Purpose: Calculates the complex cepstrum

    Syntax:  CCEPS(s, n)

             s   - input series or array

             n   - an optional integer, the number of samples to use.
                   If n > length(s), the series is zero padded. Defaults
                   to length(s).


    Returns: A real series or array

             (c, d) = cceps(s)

             returns the cepstrum in C and the lag used to unwrap the
             phase in D.

    Example:
             W1: gtri(100, 1, 1/100)^3
             W2: w1-delay(w1, 60)/2
             W3: cceps(w1)
             W4: cceps(w1, 512)

             W2 adds a synthesized echo at 60 seconds to the data of
             W1.

             W3 displays a small peak at t == 60 indicating the
             presence of the echo. W4 performs the same calculation
             with the data padded to 512 samples.

    Example:

             W1: {1, -4.0996, 8.4057, -10.1765, 7.7801, -3.5142, 0.7939}
             W2: cceps(w1, 1024)

             returns the example listed in [2].

    Remarks:

            The complex cepstrum of a series is essentially
            IDFT(log(DFT(s))).  However, the complex log calculation
            requires the evaluation of of the continuous phase
            component.  CCEPS unwraps the phase using Shafer's
            Algorithm.  A line is subtracted from the unwrapped phase
            to remove the integer lag component.

                 (c, d) = cceps(s)

            returns both the cesptrum and the lag used to unwrap
            the phase such that:

                 icceps(c, d)

            ideally returns s if mean(s) > 0.


            CCEPS was tested successfully against the output from [2].


    See Also:
             Iceps
             Rceps


    References:

            [1] Oppenheim & Shafer
                Discrete-Time Signal Processing
                Prentice Hall, 1989
                pp 788-792

            [2] IEEE Press
                Programs for Digital Signal Processing
                IEEE Press, 1979
                Section 7
#endif


/* complex cepstrum with phase unwrapping */
ITERATE cceps(s, n)
{
        local f, m, p, c, d;

        if (argc < 2)
        {
                if (argc < 1) error("cceps - input series required");
                
                n = length(s);
        }
        
        if (n < 1) error("cceps - length must be >= 1");

        f = fft(s, n);

        /* unity dx for calculations below */
        setdeltax(f, 1.0);

        /* compute IDFT(log(DFT(s)) - use unwrapped phase */
        (p, d) = cepphase(f);

        c = log(mag(f)) + i * p;
        c = real(ifft(c));

        /* restore deltax */
        setdeltax(c, deltax(s));

        /* d is the delay used in the phase computation */
        return(c, d);
}


/* unwrap phase for cepstrum */
ITERATE cepphase(s)
{
        local p, m, n, r;

        /* standard phase unwrapping */
        p = unwrap(phase(s), pi);

        /* mid point */
        m = int(1 + length(s) / 2);

        /* integer delay is mid point phase value in multiples of pi */
        n = round(extract(p, m, 1) / pi);

        /* generate phase delay indices */
        r = gline(length(s), 1.0, 1 / (length(s)), 0);

        /* scale and subtract from unwrap phase */
        p = p - (2 * pi * r * n);

        /* make n a scalar */
        n = castint(n);

        /* return unwrapped phase and the lag value */
        return(p, n);
}