View Raw SPL
/*****************************************************************************
*                                                                            *
*   SGOLAY.SPL   Copyright (C) 2015 DSP Development Corporation              *
*                               All Rights Reserved                          *
*                                                                            *
*   Author:      Randy Race                                                  *
*                                                                            *
*   Synopsis:    Savitzky-Golay smoothing coefficients                       *
*                                                                            *
*   Revisions:    1 Jul 2015  RRR  Creation                                  *
*                                                                            *
*****************************************************************************/


#if @HELP_SGOLAY

    SGOLAY  

    Purpose: 
             Generates Savitzky-Golay smoothing filter coefficients.
                                                                        
    Format:  
             SGOLAY(d, N, w)

                d - Optional. An integer, the Savitzky-Golay polynomial degree.
                    Defaults to 3.

                N - Optional. An integer, the number of points for the
                    smoothing window. Defaults to d + 2 if d is odd, else
                    d + 3.

                w - Optional. A series, the weighting factors. Defaults to
                    all ones.
    Returns: 
             An NxN array, the Savitzky-Golay smoothing filter coefficients.

             (B, G) = sgolay(d, N, w) returns the smoothing filter coefficients
             and derivative coefficients as two separate arrays.

    Example:
             W1: sgolay()
             W2: sgolay(4, 9)

             W1 contains a 5x5 array of 3rd order Savitzky-Golay smoothing
             filter coefficients. W2 contains a 9x9 array of 4th order
             Savitzky-Golay smoothing coefficients.

    Example:
             (b, g) = sgolay(4, 9)

             B contains a 9x9 array of 4th order Savitzky-Golay smoothing 
             filter coefficients and G contains a 9x5 array of Savitzky-Golay
             derivative coefficients.

    Example:
             W1: gsweep(1000, 1/1000, 1, 50) + gnorm(1000, 1/1000)/5
             W2: sgolay(3, 21);
             W3: sgolayfilt(w1, w2)

             W2 contains a 3rd order, 21 point Savitzky-Golay smoothing filter.
             W3 process the data in W1 with the filter.

    Remarks:
             Savitzky-Golay filters perform data smoothing and preserve
             peak resolution by least squares fitting a D order polynomial
             to an N point sliding window. The data window, N, should be an
             odd value.

             See SGOLAYFILT to compute the Savitzky-Golay coefficients and
             filter input data in one step.

    See Also:
             Conv
             Filteq
             Linavg
             Movavg
             Sgolayfilt
#endif


/* compute Savitzky-Golay filter coefficients */
sgolay(d, N, w)
{
        local M, B, S, q, r;

        if (argc < 3)
        {
                if (argc < 2)
                {
                        if (argc < 1)
                        {
                                d = 3;
                        }
                
                        N = d + 2 + (d % 2 == 0);
                }

                w = ones(N, 1);
        }

        d = castint(d);
        N = castint(N);

        /* weights */
        w = diag(w);

        if (length(w) != N) error("sgolay - weights must be the same length as polynomial length");

        if (d >= N) error("sgolay - degree must less than polynomial length");

        M = (N - 1) / 2;

        S = fliplr(vander(-M..M, d + 1));

        /* G = S /^ ((S' *^ w) *^ S), but use compact QR for better accuracy */

        (q, r) = qr(sqrt(w) *^ S, 0);

        r = inv(r);

        /* derivative filters */
        G = S *^ r *^ r';

        /* smoothing filters */
        B = G *^ S' *^ w;

        return(B, G);
}