| c |
| c from netlib/a/stl: no authorship nor copyright claim in the source; |
| c presumably by the authors of |
| c |
| c R.B. Cleveland, W.S.Cleveland, J.E. McRae, and I. Terpenning, |
| c STL: A Seasonal-Trend Decomposition Procedure Based on Loess, |
| c Statistics Research Report, AT&T Bell Laboratories. |
| c |
| c Converted to double precision by B.D. Ripley 1999. |
| c Indented, goto labels renamed, many goto's replaced by `if then {else}' |
| c (using Emacs), many more comments; by M.Maechler 2001-02. |
| c |
| subroutine stl(y,n,np,ns,nt,nl, isdeg,itdeg,ildeg, |
| & nsjump,ntjump,nljump, ni,no, rw,season,trend,work) |
| |
| c implicit none |
| c Arg |
| integer n, np, ns,nt,nl, isdeg,itdeg,ildeg, nsjump,ntjump,nljump, |
| & ni, no |
| c n : length(y) |
| c ns, nt, nl : spans for `s', `t' and `l' smoother |
| c isdeg, itdeg, ildeg : local degree for `s', `t' and `l' smoother |
| c nsjump,ntjump,nljump: ........ for `s', `t' and `l' smoother |
| c ni, no : number of inner and outer (robust) iterations |
| |
| double precision y(n), rw(n), season(n), trend(n), |
| & work(n+2*np,5) |
| c Var |
| integer i,k, newns, newnt, newnl, newnp |
| logical userw |
| |
| userw = .false. |
| do 1 i = 1,n |
| trend(i) = 0.d0 |
| 1 continue |
| c the three spans must be at least three and odd: |
| newns = max0(3,ns) |
| newnt = max0(3,nt) |
| newnl = max0(3,nl) |
| if(mod(newns,2) .eq. 0) newns = newns + 1 |
| if(mod(newnt,2) .eq. 0) newnt = newnt + 1 |
| if(mod(newnl,2) .eq. 0) newnl = newnl + 1 |
| c periodicity at least 2: |
| newnp = max0(2,np) |
| |
| k = 0 |
| c --- outer loop -- robustnes iterations |
| 100 continue |
| call stlstp(y,n, newnp,newns,newnt,newnl, isdeg,itdeg,ildeg, |
| & nsjump,ntjump,nljump, ni,userw,rw,season, trend, work) |
| k = k+1 |
| if(k .gt. no) goto 10 |
| |
| do 3 i = 1,n |
| work(i,1) = trend(i)+season(i) |
| 3 continue |
| call stlrwt(y,n,work(1,1),rw) |
| userw = .true. |
| goto 100 |
| c --- end Loop |
| 10 continue |
| |
| c robustness weights when there were no robustness iterations: |
| if(no .le. 0) then |
| do 15 i = 1,n |
| rw(i) = 1.d0 |
| 15 continue |
| endif |
| return |
| end |
| |
| subroutine stless(y,n,len,ideg,njump,userw,rw,ys,res) |
| |
| c implicit none |
| c Arg |
| integer n, len, ideg, njump |
| double precision y(n), rw(n), ys(n), res(n) |
| c Var |
| integer newnj, nleft, nright, nsh, k, i, j |
| double precision delta |
| logical ok, userw |
| |
| if(n .lt. 2) then |
| ys(1) = y(1) |
| return |
| endif |
| |
| newnj = min0(njump, n-1) |
| if(len .ge. n) then |
| nleft = 1 |
| nright = n |
| do 20 i = 1,n,newnj |
| call stlest(y,n,len,ideg,dble(i),ys(i),nleft,nright,res, |
| & userw,rw,ok) |
| if(.not. ok) ys(i) = y(i) |
| 20 continue |
| |
| else |
| |
| if(newnj .eq. 1) then |
| nsh = (len+1)/2 |
| nleft = 1 |
| nright = len |
| do 30 i = 1,n |
| if(i .gt. nsh .and. nright .ne. n) then |
| nleft = nleft+1 |
| nright = nright+1 |
| endif |
| call stlest(y,n,len,ideg,dble(i),ys(i),nleft,nright,res, |
| & userw,rw,ok) |
| if(.not. ok) ys(i) = y(i) |
| 30 continue |
| else |
| nsh = (len+1)/2 |
| do 40 i = 1,n,newnj |
| if(i .lt. nsh) then |
| nleft = 1 |
| nright = len |
| else if(i .ge. n-nsh+1) then |
| nleft = n-len+1 |
| nright = n |
| else |
| nleft = i-nsh+1 |
| nright = len+i-nsh |
| endif |
| |
| call stlest(y,n,len,ideg,dble(i),ys(i),nleft,nright,res, |
| & userw,rw,ok) |
| if(.not. ok) ys(i) = y(i) |
| 40 continue |
| |
| endif |
| |
| endif |
| |
| if(newnj .ne. 1) then |
| do 45 i = 1,n-newnj,newnj |
| delta = (ys(i+newnj)-ys(i))/dble(newnj) |
| do 47 j = i+1,i+newnj-1 |
| ys(j) = ys(i)+delta*dble(j-i) |
| 47 continue |
| 45 continue |
| k = ((n-1)/newnj)*newnj+1 |
| |
| if(k .ne. n) then |
| call stlest(y,n,len,ideg,dble(n),ys(n),nleft,nright,res, |
| & userw,rw,ok) |
| if(.not. ok) ys(n) = y(n) |
| |
| if(k .ne. n-1) then |
| delta = (ys(n)-ys(k))/dble(n-k) |
| do 55 j = k+1,n-1 |
| ys(j) = ys(k)+delta*dble(j-k) |
| 55 continue |
| endif |
| endif |
| endif |
| return |
| end |
| |
| subroutine stlest(y,n,len,ideg,xs,ys,nleft,nright,w, |
| & userw,rw,ok) |
| |
| c implicit none |
| c Arg |
| integer n, len, ideg, nleft, nright |
| double precision y(n), w(n), rw(n), xs, ys |
| logical userw,ok |
| c Var |
| double precision range, h, h1, h9, a, b, c, r |
| integer j |
| |
| range = dble(n)-dble(1) |
| h = max(xs - dble(nleft), dble(nright) - xs) |
| if(len .gt. n) h = h + dble((len-n)/2) |
| h9 = 0.999d0*h |
| h1 = 0.001d0*h |
| a = 0.d0 |
| do 60 j = nleft,nright |
| r = abs(dble(j)-xs) |
| if(r .le. h9) then |
| if(r .le. h1) then |
| w(j) = 1.d0 |
| else |
| w(j) = (1.d0 - (r/h)**3)**3 |
| endif |
| if(userw) w(j) = rw(j)*w(j) |
| a = a+w(j) |
| else |
| w(j) = 0.d0 |
| endif |
| 60 continue |
| |
| if(a .le. 0.d0) then |
| ok = .false. |
| else |
| ok = .true. |
| do 69 j = nleft,nright |
| w(j) = w(j)/a |
| 69 continue |
| if((h .gt. 0.d0) .and. (ideg .gt. 0)) then |
| a = 0.d0 |
| do 73 j = nleft,nright |
| a = a+w(j)*dble(j) |
| 73 continue |
| b = xs-a |
| c = 0.d0 |
| do 75 j = nleft,nright |
| c = c+w(j)*(dble(j)-a)**2 |
| 75 continue |
| if(sqrt(c) .gt. 0.001d0*range) then |
| b = b/c |
| do 79 j = nleft,nright |
| w(j) = w(j)*(b*(dble(j)-a)+1.0d0) |
| 79 continue |
| endif |
| endif |
| ys = 0.d0 |
| do 81 j = nleft,nright |
| ys = ys+w(j)*y(j) |
| 81 continue |
| endif |
| |
| return |
| end |
| |
| subroutine stlfts(x,n,np,trend,work) |
| integer n, np |
| double precision x(n), trend(n), work(n) |
| |
| call stlma(x, n, np, trend) |
| call stlma(trend,n-np+1, np, work) |
| call stlma(work, n-2*np+2,3, trend) |
| return |
| end |
| |
| |
| subroutine stlma(x, n, len, ave) |
| |
| c Moving Average (aka "running mean") |
| c ave(i) := mean(x{j}, j = max(1,i-k),..., min(n, i+k)) |
| c for i = 1,2,..,n |
| |
| c implicit none |
| c Arg |
| integer n, len |
| double precision x(n), ave(n) |
| c Var |
| double precision flen, v |
| integer i, j, k, m, newn |
| newn = n-len+1 |
| flen = dble(len) |
| v = 0.d0 |
| do 3 i = 1,len |
| v = v+x(i) |
| 3 continue |
| ave(1) = v/flen |
| if(newn .gt. 1) then |
| k = len |
| m = 0 |
| do 7 j = 2, newn |
| k = k+1 |
| m = m+1 |
| v = v-x(m)+x(k) |
| ave(j) = v/flen |
| 7 continue |
| endif |
| return |
| end |
| |
| |
| subroutine stlstp(y,n,np,ns,nt,nl,isdeg,itdeg,ildeg,nsjump, |
| & ntjump,nljump,ni,userw,rw,season,trend,work) |
| |
| c implicit none |
| c Arg |
| integer n,np,ns,nt,nl,isdeg,itdeg,ildeg,nsjump,ntjump,nljump,ni |
| logical userw |
| double precision y(n),rw(n),season(n),trend(n),work(n+2*np,5) |
| c Var |
| integer i,j |
| |
| do 80 j = 1,ni |
| do 1 i = 1,n |
| work(i,1) = y(i)-trend(i) |
| 1 continue |
| call stlss(work(1,1),n,np,ns,isdeg,nsjump,userw,rw,work(1,2), |
| & work(1,3),work(1,4),work(1,5),season) |
| call stlfts(work(1,2),n+2*np,np,work(1,3),work(1,1)) |
| call stless(work(1,3),n,nl,ildeg,nljump,.false.,work(1,4), |
| & work(1,1),work(1,5)) |
| do 3 i = 1,n |
| season(i) = work(np+i,2)-work(i,1) |
| 3 continue |
| do 5 i = 1,n |
| work(i,1) = y(i)-season(i) |
| 5 continue |
| call stless(work(1,1),n,nt,itdeg,ntjump,userw,rw,trend, |
| & work(1,3)) |
| 80 continue |
| return |
| end |
| |
| subroutine stlrwt(y,n,fit,rw) |
| c Robustness Weights |
| c rw_i := B( |y_i - fit_i| / (6 M) ), i = 1,2,...,n |
| c where B(u) = (1 - u^2)^2 * 1[|u| < 1] {Tukey's biweight} |
| c and M := median{ |y_i - fit_i| } |
| c implicit none |
| c Arg |
| integer n |
| double precision y(n), fit(n), rw(n) |
| c Var |
| integer mid(2), i |
| double precision cmad, c9, c1, r |
| |
| do 7 i = 1,n |
| rw(i) = abs(y(i)-fit(i)) |
| 7 continue |
| mid(1) = n/2+1 |
| mid(2) = n-mid(1)+1 |
| call psort(rw,n,mid,2) |
| cmad = 3.0d0*(rw(mid(1))+rw(mid(2))) |
| c = 6 * MAD |
| c9 = 0.999d0*cmad |
| c1 = 0.001d0*cmad |
| do 10 i = 1,n |
| r = abs(y(i)-fit(i)) |
| if(r .le. c1) then |
| rw(i) = 1.d0 |
| else if(r .le. c9) then |
| rw(i) = (1.d0 - (r/cmad)**2)**2 |
| else |
| rw(i) = 0.d0 |
| endif |
| 10 continue |
| return |
| end |
| |
| subroutine stlss(y,n,np,ns,isdeg,nsjump,userw,rw,season, |
| & work1,work2,work3,work4) |
| c |
| c called by stlstp() at the beginning of each (inner) iteration |
| c |
| c implicit none |
| c Arg |
| integer n, np, ns, isdeg, nsjump |
| double precision y(n), rw(n), season(n+2*np), |
| & work1(n), work2(n), work3(n), work4(n) |
| logical userw |
| c Var |
| integer nright, nleft, i, j, k, m |
| logical ok |
| double precision xs |
| |
| if(np .lt. 1) return |
| |
| do 200 j = 1, np |
| k = (n-j)/np+1 |
| do 10 i = 1,k |
| work1(i) = y((i-1)*np+j) |
| 10 continue |
| if(userw) then |
| do 12 i = 1,k |
| work3(i) = rw((i-1)*np+j) |
| 12 continue |
| endif |
| call stless(work1,k,ns,isdeg,nsjump,userw,work3,work2(2),work4) |
| xs = 0 |
| nright = min0(ns,k) |
| call stlest(work1,k,ns,isdeg,xs,work2(1),1,nright,work4, |
| & userw,work3,ok) |
| if(.not. ok) work2(1) = work2(2) |
| xs = k+1 |
| nleft = max0(1,k-ns+1) |
| call stlest(work1,k,ns,isdeg,xs,work2(k+2),nleft,k,work4, |
| & userw,work3,ok) |
| if(.not. ok) work2(k+2) = work2(k+1) |
| do 18 m = 1,k+2 |
| season((m-1)*np+j) = work2(m) |
| 18 continue |
| |
| 200 continue |
| |
| return |
| end |
| |
| |
| c STL E_Z_ : "Easy" user interface -- not called from R |
| |
| subroutine stlez(y, n, np, ns, isdeg, itdeg, robust, no, rw, |
| & season, trend, work) |
| |
| c implicit none |
| c Arg |
| integer n, np, ns, isdeg, itdeg, no |
| logical robust |
| double precision y(n), rw(n), season(n), trend(n), work(n+2*np,7) |
| c Var |
| integer i, j, ildeg, nt, nl, ni, nsjump, ntjump, nljump, |
| & newns, newnp |
| double precision maxs, mins, maxt, mint, maxds, maxdt, difs, dift |
| |
| ildeg = itdeg |
| newns = max0(3,ns) |
| if(mod(newns,2) .eq. 0) newns = newns+1 |
| newnp = max0(2,np) |
| nt = int((1.5d0*newnp)/(1.d0 - 1.5d0/newns) + 0.5d0) |
| nt = max0(3,nt) |
| if(mod(nt,2) .eq. 0) nt = nt+1 |
| nl = newnp |
| if(mod(nl,2) .eq. 0) nl = nl+1 |
| |
| if(robust) then |
| ni = 1 |
| else |
| ni = 2 |
| endif |
| |
| nsjump = max0(1,int(float(newns)/10 + 0.9)) |
| ntjump = max0(1,int(float(nt)/10 + 0.9)) |
| nljump = max0(1,int(float(nl)/10 + 0.9)) |
| do 2 i = 1,n |
| trend(i) = 0.d0 |
| 2 continue |
| call stlstp(y,n,newnp,newns,nt,nl,isdeg,itdeg,ildeg,nsjump, |
| & ntjump,nljump,ni,.false.,rw,season,trend,work) |
| |
| no = 0 |
| if(robust) then |
| j=1 |
| C Loop --- 15 robustness iterations |
| 100 if(j .le. 15) then |
| do 35 i = 1,n |
| work(i,6) = season(i) |
| work(i,7) = trend(i) |
| work(i,1) = trend(i)+season(i) |
| 35 continue |
| call stlrwt(y,n,work(1,1),rw) |
| call stlstp(y, n, newnp, newns, nt,nl, isdeg,itdeg,ildeg, |
| & nsjump,ntjump,nljump, ni, .true., |
| & rw, season, trend, work) |
| no = no+1 |
| maxs = work(1,6) |
| mins = work(1,6) |
| maxt = work(1,7) |
| mint = work(1,7) |
| maxds = abs(work(1,6) - season(1)) |
| maxdt = abs(work(1,7) - trend(1)) |
| do 137 i = 2,n |
| if(maxs .lt. work(i,6)) maxs = work(i,6) |
| if(maxt .lt. work(i,7)) maxt = work(i,7) |
| if(mins .gt. work(i,6)) mins = work(i,6) |
| if(mint .gt. work(i,7)) mint = work(i,7) |
| difs = abs(work(i,6) - season(i)) |
| dift = abs(work(i,7) - trend(i)) |
| if(maxds .lt. difs) maxds = difs |
| if(maxdt .lt. dift) maxdt = dift |
| 137 continue |
| if((maxds/(maxs-mins) .lt. 0.01d0) .and. |
| & (maxdt/(maxt-mint) .lt. 0.01d0)) goto 300 |
| continue |
| j=j+1 |
| goto 100 |
| endif |
| C end Loop |
| 300 continue |
| |
| else |
| c .not. robust |
| |
| do 150 i = 1,n |
| rw(i) = 1.0d0 |
| 150 continue |
| endif |
| |
| return |
| end |
| |
| subroutine psort(a,n,ind,ni) |
| c |
| c Partial Sorting ; used for Median (MAD) computation only |
| c |
| c implicit none |
| c Arg |
| integer n,ni |
| double precision a(n) |
| integer ind(ni) |
| c Var |
| integer indu(16),indl(16),iu(16),il(16),p,jl,ju,i,j,m,k,ij,l |
| double precision t,tt |
| |
| if(n .lt. 0 .or. ni .lt. 0) return |
| |
| if(n .lt. 2 .or. ni .eq. 0) return |
| |
| jl = 1 |
| ju = ni |
| indl(1) = 1 |
| indu(1) = ni |
| i = 1 |
| j = n |
| m = 1 |
| |
| c Outer Loop |
| 161 continue |
| if(i .lt. j) go to 10 |
| |
| c _Loop_ |
| 166 continue |
| m = m-1 |
| if(m .eq. 0) return |
| i = il(m) |
| j = iu(m) |
| jl = indl(m) |
| ju = indu(m) |
| if(.not.(jl .le. ju)) goto 166 |
| |
| c while (j - i > 10) |
| 173 if(.not.(j-i .gt. 10)) goto 174 |
| |
| 10 k = i |
| ij = (i+j)/2 |
| t = a(ij) |
| if(a(i) .gt. t) then |
| a(ij) = a(i) |
| a(i) = t |
| t = a(ij) |
| endif |
| l = j |
| if(a(j) .lt. t) then |
| a(ij) = a(j) |
| a(j) = t |
| t = a(ij) |
| if(a(i) .gt. t) then |
| a(ij) = a(i) |
| a(i) = t |
| t = a(ij) |
| endif |
| endif |
| |
| 181 continue |
| l = l-1 |
| if(a(l) .le. t)then |
| tt = a(l) |
| 186 continue |
| k = k+1 |
| if(.not.(a(k) .ge. t)) goto 186 |
| |
| if(k .gt. l) goto 183 |
| |
| a(l) = a(k) |
| a(k) = tt |
| endif |
| goto 181 |
| |
| 183 continue |
| indl(m) = jl |
| indu(m) = ju |
| p = m |
| m = m+1 |
| if(l-i .le. j-k) then |
| il(p) = k |
| iu(p) = j |
| j = l |
| |
| 193 continue |
| if(jl .gt. ju) goto 166 |
| if(ind(ju) .gt. j) then |
| ju = ju-1 |
| goto 193 |
| endif |
| indl(p) = ju+1 |
| else |
| il(p) = i |
| iu(p) = l |
| i = k |
| |
| 200 continue |
| if(jl .gt. ju) goto 166 |
| if(ind(jl) .lt. i) then |
| jl = jl+1 |
| goto 200 |
| endif |
| indu(p) = jl-1 |
| endif |
| |
| goto 173 |
| c end while |
| 174 continue |
| |
| if(i .ne. 1) then |
| i = i-1 |
| 209 continue |
| i = i+1 |
| if(i .eq. j) goto 166 |
| t = a(i+1) |
| if(a(i) .gt. t) then |
| k = i |
| c repeat |
| 216 continue |
| a(k+1) = a(k) |
| k = k-1 |
| if(.not.(t .ge. a(k))) goto 216 |
| c until t >= a(k) |
| a(k+1) = t |
| endif |
| goto 209 |
| |
| endif |
| |
| goto 161 |
| c End Outer Loop |
| |
| end |