View Raw SPL
/*****************************************************************************
*                                                                            *
*   LINEXPAVG.SPL  Copyright (C) 2012 DSP Development Corporation            *
*                               All Rights Reserved                          *
*                                                                            *
*   Author:        Randy Race                                                *
*                                                                            *
*   Synopsis:      Exponential moving average with zero phase                *
*                                                                            *
*   Revisions:     11 Jul 2012  RRR  Creation                                *
*                                                                            *
*****************************************************************************/


#if @HELP_LINEXPAVG

    LINEXPAVG

    Purpose: Computes the exponential moving average with zero phase shift.

    Syntax:  LINEXPAVG(s, a, yi)

               s - A series, the input data.

               a - Optional. A real, the smoothing factor where 0 <= a <= 1.
                   Defaults to 1.0, no averaging.

              yi - Optional. A real, the initial value. Defaults to s[1],
                   the first input value.

    Alternate Syntax:

             LINEXPAVG(s, N, yi)

               s - A series, the input data.

               N - Optional. An integer, the effective number of points
                   to average where N >= 1. Defaults to 1, no averaging.

              yi - Optional. A real, the initial value. Defaults to s[1],
                   the first input value.

    Returns: A series, the zero phase exponential moving average.

    Example:
             W1: 1..5
             W2: linexpavg(w1, 0.5)

             W2 == {1.40625, 2.015625, 2.632813, 3.066406, 3.033203}

             The X offset of the result is 1.0.

    Example:
             W1: 1..5
             W2: linexpavg(w1, 3)

             W2 == {1.40625, 2.015625, 2.632813, 3.066406, 3.033203}

             Same as above except the smoothing factor is in the form of
             the effective number of points to smooth. The effective number
             of points, N is related to A, the smoothing factor by:

             N = (2 / a) - 1

    Example:
             W1: integ(gnorm(1000, 1/100))
             W2: expavg(w1, 0.3)
             W3: linexpavg(w1, 0.3);overp(w1, lred);overp(w2, lgreen)

             W1 contains 1000 samples of synthesized data.

             W2 performs a standard exponential moving average.

             W3 performs zero phase exponential moving average by
             reversing the original data, computing an exponential
             moving average, reversing the result and computing another
             exponential point moving average.  Compared to the
             standard exponential moving average, the peaks of the
             resulting smoothed series line up with the original data.

    Remarks:
             LINEXPAVG computes zero phase exponential moving average
             by reversing the input series, computing the exponential
             point moving average, reversing the result and computing
             another exponential moving average. The reversal steps
             help ensure the peak locations of the original data are
             preserved.

             The effective number of points to average used by the
             exponential moving average is related to the smoothing
             factor by:

             N = (2 / a) - 1

             where N is the number of points to average as with the
             standard moving average. If the smoothing parameter of
             EXPMOVAVG is an integer greater or equal to 1, it is
             assumed to be the effective number of bits as determined
             above.

             See EXPMOVAVG for more details on the exponential moving average.

    See Also:
             Movavg
             Expmovavg
             Reverse
#endif


/* compute zero phase exponential moving average */
ITERATE linexpavg(s, a, yi)
{
        local y;

        if (argc < 3)
        {
                if (argc < 2)
                {
                        if (argc < 1) error("linexpavg - input series required");
                        
                        a = 1;
                }

                yi = s[1];
        }

        /* zero phase computation by time reversal */
        y = expmovavg(rev(expmovavg(rev(s), a, yi)), a, yi);

        return(y);
}