View Raw SPL
/*****************************************************************************
* *
* DETREND.SPL Copyright (C) 1996, 2011 DSP Development Corporation *
* All Rights Reserved *
* *
* Author: Randy Race *
* *
* Synopsis: Remove a linear trend from a series or table *
* *
* Revisions: 18 Jan 1996 RRR Creation *
* 11 Feb 2011 RRR linear breakpoint option *
* *
*****************************************************************************/
#if @HELP_DETREND
DETREND
Purpose: Removes a linear trend line or mean value from a series.
Syntax: DETREND(x, opt, bp)
x - A series, the input.
opt - Optional, a string, the trend type.
"linear" : remove a linear trend (default)
"constant" : remove the mean value
bp - Optional, a series. A list of breakpoint indices
that determine the locations of a piecewise
continuous linear trend. Defaults to a single
regression line over the entire input series.
Returns: A series, the detrended output.
Example:
W1: gnorm(10, 1)
W2: W1 + 100
W3: detrend(w2, "constant")
W4: demean(w2)
W2 contains a 10 point random series with a mean of 10.
Both W3 and W4 remove the mean value to recover the
original series in W1
Example:
W1: gcos(1000, 1/1000, 10)
W2: 10 * gtri(length(w1), deltax(w1), 1)
W3: w1 + w2
W4: detrend(w3, maxidx(w2))
W3 contains a 1000 point cosine with a triangular linear
trend. W4 removes the trend and recovers W1 by setting a
breakpoint at the index of the apex of the triangle wave.
Remarks:
If breakpoints are specified, each point represents the
index shared by adjacent line segments. A piecewise
continuous regression line is computed for each segment.
If no breakpoints are specified, a trendline computed over
the entire input series is removed. This is equivalent to:
x - linreg(x)
See Also:
Demean
Linreg
Linfit
Polyit
#endif
/* remove a linear trend from a series */
ITERATE detrend(x, opt, bp)
{
local y, xv, xlen, blen, slen, n, a;
if (argc < 3)
{
if (argc < 2)
{
if (argc < 1) error("detrend - input series required");
opt = "linear";
}
bp = {};
if (isscalar(opt))
{
/* detrend(x, 10) */
bp = {opt};
opt = "linear";
}
}
if (isarray(opt))
{
/* detrend(x, bp) */
bp = opt;
opt = "linear";
}
if (tolower(opt) != "linear")
{
/* just remove mean */
y = demean(x);
}
else
{
wasxy = isxy(x);
/* remove piecewise continuous linear trend */
if (length(bp) > 0)
{
xlen = length(x);
/* remove dups */
bp = detrend_undup({0, bp, xlen-1});
blen = length(bp) - 1;
a = ravel(zeros(xlen, blen), ones(xlen, 1));
/* form regression lines */
loop (n = 1..blen)
{
slen = xlen - bp[n];
a[(1..slen) + bp[n], n] = (1..slen) / slen;
}
xv = yvals(x);
/* remove regression */
y = xv - a *^ (a \^ xv);
/* attributes */
y.deltax = x.deltax;
y.xoffset = x.xoffset;
y.vunits = x.vunits;
y.hunits = x.hunits;
}
else
{
/* remove full trendline */
y = x - linreg(x);
}
if (isxy(x))
{
/* reconstruct XY */
y = xy(xvals(x), y);
}
}
return(y);
}
/* sort and remove duplicates */
detrend_undup(s)
{
local r, d;
r = sort(s, 1);
d = extract(r - delay(r, 1), 2, -1);
r = delete(r, d == 0);
return(r);
}