View Raw SPL
/*****************************************************************************
* *
* SGOLAYFILT.SPL Copyright (C) 2015 DSP Development Corporation *
* All Rights Reserved *
* *
* Author: Randy Race *
* *
* Synopsis: Savitzky-Golay smoothing filering *
* *
* Revisions: 1 Jul 2015 RRR Creation *
* *
*****************************************************************************/
#if @HELP_SGOLAYFILT
SGOLAYFILT
Purpose:
Filters a series with a Savitzky-Golay smoothing filter.
Format:
SGOLAYFILT(x, d, n, w)
x - A series, the input series to smooth.
d - Optional. An integer or array. If an integer, the
Savitzky-Golay polynomial degree. If an array, the
explicit Savitzky-Golay coefficients. Defaults to the
integer 3, design and process a 3rd order filter.
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:
A series, the result of filtering the input data with the
smoothing filter.
Example:
W1: gsweep(1000, 1/1000, 1, 50) + gnorm(1000, 1/1000)/5
W2: sgolayfilt(w1)
W3: linavg(w1, 10)
W4: w2;overp(w3, lred)
W1 contains 1000 samples of a noisy swept sinewave from 1 Hz
to 50Hz.
W2 filters the data in W1 with a 3rd order 5 point Savitzky-Golay
filter.
W3 filters the data in W1 with a 10 point zero phase moving
average
W4 graphically compares the two results. The Savitzky-Golay
filter more accurately preserves the peak heights of the
high frequency oscillations of the input data.
Example:
W1: gsweep(1000, 1/1000, 1, 50) + gnorm(1000, 1/1000)/5
W2: sgolayfilt(w1, 3, 11)
W3: linavg(w1, 10)
W4: w2;overp(w3, lred)
Same as above except a 3rd order 11 point Savitzky-Golay filter
is used.
Example:
W1: gsweep(1000, 1/1000, 1, 50) + gnorm(1000, 1/1000)/5
W2: linavg(w1, 10)
W3: sgolay(3, 11);
W4: sgolayfilt(w1, w3);overp(w2, lred);
Similar to above except the Savitzky-Golay filter coefficients
are given as an explicit input array.
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.
If the filter coefficients are explicit, the window length N and
weights w are ignored if provided.
See Also:
Conv
Filteq
Linavg
Movavg
Sgolay
#endif
static sgolay_coef = {};
/* filter data with Savitzky-Golay length N order d design */
sgolayfilt(x, d, N, w)
{
local M, L, B, y, yit, yot, yss;
if (argc < 4)
{
if (argc < 3)
{
if (argc < 2)
{
if (argc < 1) error("sgolayfilt - input series required");
d = 3;
}
if (isarray(d))
{
N = length(d);
}
else
{
N = d + 2 + (d % 2 == 0);
}
}
w = ones(N, 1);
}
L = length(x);
if (isarray(d))
{
/* assume coefficients already given */
B = d;
N = length(B);
}
else
{
/* design filter */
B = sgolay(d, N, w);
}
/* local copy */
sgolay_coef = B;
/* filter - use static copy of coefficients for column iteration */
y = sgolayfilt_filt(x);
sgolay_coef = {};
if (outargc > 1)
{
return(y, B);
}
else
{
return(y);
}
}
/* Savitzky-Golay filtering, coefficients in static variable sgolay_coef */
ITERATE sgolayfilt_filt(x)
{
local M, L, y, yit, yot, yss;
/*
* filter coefficients in static sgolay_coef so we can column iterate
* on the input but use all columns of the coefficients
*/
L = length(x);
N = length(sgolay_coef);
if (L <= N + 1) error("sgolayfilt - filter length too long");
M = floor((N-1) / 2);
/* input on transients */
yit = sgolay_coef[1..M+1, ..] *^ x[1..N];
/* input off transients */
yot = sgolay_coef[M+1..2*M+1, ..] *^ x[L-N+1..L];
/* steady state */
yss = extract(filteq(sgolay_coef[.., M+1], {1}, x), N+1, length(x) - length(yit) - length(yot));
/* combine */
y = {yit, yss, yot};
/* properties */
setxoffset(y, xoffset(x));
setdeltax(y, deltax(x));
setvunits(y, getvunits(x));
sethunits(y, gethunits(x));
return(y);
}