Viewing contents of file '../idllib/astron/contrib/freudenreich/lowess.pro'
FUNCTION LOWESS,X,Y,WINDOW,NDEG, NOISE
;
;+
; NAME:
; LOWESS
;
; PURPOSE:
; Robust smoothing of 1D data. A non-parametric way of drawing a smooth
; curve to represent data. (For 2D (map) data, use LOESS.)
;
; CALLING SEQUENCE:
; YSmooth = LOWESS( X, Y, Window, NDeg, Noise )
;
; INPUT ARGUMENTS:
; X = X values
; Y = Y values, to be smoothed
; WINDOW = width of smoothing window
; NDEG = degree of polynomial to be used within the window (1 or 2
; recommended)
;
; OUTPUT:
; Ysmooth - LOWESS returns the vector of smoothed Y values
;
; OPTIONAL OUTPUT ARGUMENT:
; Noise = the robust std. deviation w.r.t. the fit, at each point
;
; NOTE:
; This routine uses a least-squares fit within a moving window. The fit
; is weighted by statistical weights and weights that are a function of
; distance from the center of the window. This is a "local weighted
; polynomial regression smoother" (Cleveland 1979, Journal of the Amer.
; Statistical Association, 74, 829-836).
; A polynomial of degree NDEG+1 is fitted directly to the first and last
; WINDOW/2 points.
;
; This routine is fairly slow.
;
; SUBROUTINES CALLED:
; ROBUST_LINEFIT
; ROBUST_POLY_FIT
; ROB_CHECKFIT
; ROBUST_SIGMA
; POLYFITW
; MED
;
; REVISION HISTORY:
; Written, H.T. Freudenreich, HSTX, 1/8/93
; H.T. Freudenreich, 2/94 Return sigma rather than slope
;-
ON_ERROR,2
EPS = 1.0E-20
ITMAX = 3
M=WINDOW/2
N=N_ELEMENTS(X)
IF N_PARAMS() GT 4 THEN BEGIN
WANT_NOISE=1
NOISE=FLTARR(N)
ENDIF ELSE WANT_NOISE=0
Z=Y
FOR I=M,N-M-1 DO BEGIN
WIDENED=0
FITIT:
U=X(I-M:I+M) - X(I)
V=Y(I-M:I+M)
; If V is constant, do nothing:
IF MAX(V) EQ MIN(V) THEN BEGIN
Z(I)=V(0)
IF WANT_NOISE EQ 1 THEN NOISE(I)=0.
GOTO,NEXT
ENDIF
; First, a robust fit. Allowing more than 3 iterations is usually a waste
; of time.
IF NDEG EQ 1 THEN CC=ROBUST_LINEFIT( U,V, YFIT, NUMIT=ITMAX ) ELSE $
CC=ROBUST_POLY_FIT( U,V,NDEG,YFIT, NUMIT=ITMAX )
; If no fit possible...
NCOEF=N_ELEMENTS(CC)
IF NCOEF NE (NDEG+1) THEN BEGIN
IF (I GT M) AND (I LT (N-M-1)) THEN BEGIN
; Widen the window temporarily and try again.
WINDOW=WINDOW+2 & M=M+1
PRINT,'LOWESS: Expanding window by 2 points to try again'
WIDENED = 1
GOTO,FITIT
ENDIF ELSE BEGIN
Z(I) = MED(V)
IF WANT_NOISE EQ 1 THEN NOISE(I)=ROBUST_SIGMA(V-Z(I),/ZERO)
PRINT,'LOWESS: Taking Y median instead of fit'
GOTO,NEXT
ENDELSE
ENDIF
; Now calculate the biweights from the residuals:
R = V-YFIT
SIG = ROBUST_SIGMA(R,/ZERO)
IF WANT_NOISE EQ 1 THEN NOISE(I)=SIG
IF SIG LT eps THEN SIG=TOTAL(ABS(R))/.8/N_ELEMENTS(R)
IF SIG LT eps THEN BEGIN
W=FLTARR(WINDOW)
W(*)=1.0 ; equal weights
ENDIF ELSE BEGIN
R = ( R/(6.*SIG) )^2
Q = WHERE(R GT 1.,COUNT) & IF COUNT GT 0 THEN R(Q)=1.
W =(1.-R)^2
ENDELSE
; Now multiply by the "distance" weights:
DEL = .5*( U(1)-U(0)+U(M)-U(M-1) )
D = DEL+MAX([U(WINDOW-1)-U(M),U(M)-U(0)]) ;=max distance of any point from Xi
WD= ( 1.- ( ABS( ( U-U(M) )/D ) )^3 )^3
W = W*WD
W = W/TOTAL(W)
; Now a weighted polynomial fit:
CC=POLYFITW(U,V,W,NDEG,YFIT)
Z(I) = CC(0)
IF WIDENED EQ 1 THEN BEGIN
WINDOW=WINDOW-2 & M=M-1
WIDENED=0
ENDIF
NEXT:
ENDFOR
; Now take care of the end points! Fit a polynomial of degree NDEG to them.
I1=WINDOW-1
FITSTART:
U=X(0:I1) & V=Z(0:I1)
CC=ROBUST_POLY_FIT( U,V,NDEG,YFIT,SIG )
IF N_ELEMENTS(CC) NE (NDEG+1) THEN BEGIN
I1=I1+1
GOTO,FITSTART
ENDIF
Z(0:M-1) = YFIT(0:M-1)
IF WANT_NOISE EQ 1 THEN NOISE(0:M-1)=SIG
I1=N-WINDOW
FITEND:
U=X(I1:N-1) & V=Z(I1:N-1)
CC=ROBUST_POLY_FIT( U,V,NDEG,YFIT,SIG )
IF N_ELEMENTS(CC) NE (NDEG+1) THEN BEGIN
I1=I1-1
GOTO,FITEND
ENDIF
IEND=N_ELEMENTS(YFIT)
Z(N-M:N-1)=YFIT(IEND-M:IEND-1)
IF WANT_NOISE EQ 1 THEN NOISE(N-M:N-1)=SIG
RETURN,Z
END