forked from floybix/hydromad
-
Notifications
You must be signed in to change notification settings - Fork 20
/
filter_tv.R
93 lines (88 loc) · 2.65 KB
/
filter_tv.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
## hydromad: Hydrological Modelling and Analysis of Data
##
## Copyright (c) Felix Andrews <felix@nfrac.org>
##
## time-varying recursive filter
#' Recursive filter with time-varying coefficient
#'
#' This is simply an AR(1) recursive filter with a time-varying recession rate.
#'
#'
#' @param x numeric vector or time series.
#' @param a numeric vector the same length as \code{x}, giving the filter
#' coefficient at each time step.
#' @param init value for \code{x[0]}.
#' @return a numeric vector or time series, like \code{x}.
#' @note If there are internal missing values, these are skipped over in the
#' calculation, maintaining the "state": the value of \code{y[i-1]} after any
#' missing values is the value from just before them. This behaviour is
#' different from \code{\link{filter}}, which drops the state back to 0.
#' @author Felix Andrews \email{felix@@nfrac.org}
#' @seealso \code{\link{filter}}
#' @keywords ts
#' @examples
#'
#' ## The non-compiled function is this simple, if there are no NAs:
#' ftv2 <- function(x, a, init = 0) {
#' y <- x
#' y[1] <- x[1] + a[1] * init
#' for (i in 2:length(x)) {
#' y[i] <- x[i] + a[i] * y[i - 1]
#' }
#' return(y)
#' }
#' ## make a sine wave filter
#' a <- sin(pi * seq(0, 3 * pi, length = 100)) * 0.2 + 0.9
#' plot.ts(a, ylim = c(0, 1.2))
#' ## response to a unit impluse
#' x <- c(1, rep(0, 99))
#' y <- filter_tv(x, a)
#' plot.ts(y, log = "y")
#' stopifnot(isTRUE(all.equal(y, ftv2(x, a))))
#' ## treatment of missing values
#' x[15:20] <- NA
#' plot.ts(filter_tv(x, a), log = "y")
#' @useDynLib hydromad ar1_tv
#' @export
filter_tv <-
function(x, a, init = 0) {
stopifnot(is.numeric(x))
stopifnot(is.numeric(a))
stopifnot(is.numeric(init))
stopifnot(length(x) == length(a))
## skip over missing values (maintaining the state y[i-1])
bad <- !is.finite(x) | !is.finite(a)
x[bad] <- 0
a[bad] <- 1
if (hydromad.getOption("pure.R.code")) {
y <- x
y[1] <- x[1] + a[1] * init
for (i in 2:length(x)) {
y[i] <- x[i] + a[i] * y[i - 1]
}
} else {
y <- x
y[] <- .C(ar1_tv,
as.double(x),
as.double(a),
as.integer(length(x)),
as.double(init),
out = double(length(x)),
PACKAGE = "hydromad"
)$out
}
## re-insert missing values
y[bad] <- NA
y
}
## recursive filter skimming over NAs (treated as zeros)
## TODO: or could maintain state using na.exclude(), naresid()
filter_ok <-
function(x, filter, method = "recursive", ...) {
bad <- !is.finite(x)
x[bad] <- 0
y <- filter(x, filter = filter, method = method, ...)
## re-insert missing values
y[bad] <- NA
y
}