Viewing contents of file '../idllib/astron/contrib/freudenreich/robust_poly_fit.pro'
FUNCTION ROBUST_POLY_FIT,X,Y,NDEG,YFIT,SIG, NUMIT=THIS_MANY
;+
; NAME:
; ROBUST_POLY_FIT
;
; PURPOSE:
; An outlier-resistant polynomial fit.
;
; CALLING SEQUENCE:
; COEFF = ROBUST_POLY_FIT(X,Y,NDEGREE ,[ YFIT,SIG, NUMIT =] )
;
; INPUTS:
; X = Independent variable vector, floating-point or double-precision
; Y = Dependent variable vector
;
; OUTPUTS:
; Function result = coefficient vector, length NDEGREE+1.
; IF COEFF=0.0, NO FIT! If N_ELEMENTS(COEFF) > degree+1, the fit is poor
; (in this case the last element of COEFF=0.)
; Either floating point or double precision.
;
; OPTIONAL OUTPUT PARAMETERS:
; YFIT = Vector of calculated y's
; SIG = the "standard deviation" of the residuals
;
; RESTRICTIONS:
; Large values of NDEGREE should be avoided. This routine works best
; when the number of points >> NDEGREE.
;
; PROCEDURE:
; For the initial estimate, the data is sorted by X and broken into
; NDEGREE+2 sets. The X,Y medians of each set are fitted to a polynomial
; via POLY_FIT. Bisquare ("Tukey's Biweight") weights are then
; calculated, using a limit of 6 outlier-resistant standard deviations.
; The fit is repeated iteratively until the robust standard deviation of
; the residuals changes by less than .03xSQRT(.5/(N-1)).
;
; REVISION HISTORY
; Written, H. Freudenreich, STX, 8/90. Revised 4/91.
; 2/94 -- changed convergence criterion
;-
ON_ERROR,2
EPS = 1.0E-20
DEL = 5.0E-07
DEGMAX= 6
IF N_ELEMENTS(THIS_MANY) GT 0 THEN ITMAX=THIS_MANY ELSE ITMAX=25
BADFIT=0
NPTS = N_ELEMENTS(X)
MINPTS=NDEG+1
IF (NPTS/4*4) EQ NPTS THEN NEED2 = 1 ELSE NEED2 = 0
N3 = 3*NPTS/4 & N1 = NPTS/4
; If convenient, move X and Y to their centers of gravity:
IF NDEG LT DEGMAX THEN BEGIN
X0=TOTAL(X)/NPTS & Y0=TOTAL(Y)/NPTS
U=X-X0 & V=Y-Y0
ENDIF ELSE BEGIN
U=X & V=Y
ENDELSE
; The initial estimate.
; Choose an odd number of segments:
NUM_SEG = NDEG+2
IF (NUM_SEG/2*2) EQ NUM_SEG THEN NUM_SEG =NUM_SEG+1
MIN_PTS = NUM_SEG*3
IF NPTS LT 10000 THEN BEGIN ;MIN_PTS THEN BEGIN
; Settle for least-squares:
LSQFIT = 1
CC = POLY_FIT( U, V, NDEG, YFIT )
ENDIF ELSE BEGIN
; Break up the data into segments:
LSQFIT = 0
Q = SORT(U)
U = U(Q) & V = V(Q)
N_PER_SEG = INTARR(NUM_SEG)
N_PER_SEG(*) = NPTS/NUM_SEG
; Put the leftover points in the middle segment:
N_LEFT = NPTS - N_PER_SEG(0)*NUM_SEG
N_PER_SEG(NUM_SEG/2) = N_PER_SEG(NUM_SEG/2) + N_LEFT
R = FLTARR(NUM_SEG) & S = FLTARR(NUM_SEG)
R(0)=MED( U(0:N_PER_SEG(0)-1) ) & S(0)=MED( V(0:N_PER_SEG(0)-1) )
I2 = N_PER_SEG(0)-1
FOR I=1,NUM_SEG-1 DO BEGIN
I1 = I2 + 1
I2 = I1 + N_PER_SEG(I) - 1
R(I) = MED( U(I1:I2) ) & S(I) = MED( V(I1:I2) )
ENDFOR
; Now fit:
CC = POLY_FIT( R,S, NDEG )
YFIT = POLY(U,CC)
ENDELSE
ISTAT=ROB_CHECKFIT(V,YFIT,EPS,DEL, SIG,FRACDEV,NGOOD,W,S)
IF ISTAT EQ 0 THEN GOTO,AFTERFIT
IF NGOOD LT MINPTS THEN BEGIN
IF LSQFIT EQ 0 THEN BEGIN
; Try a least-squares:
CC = POLY_FIT( U, V, NDEG, YFIT )
ISTAT=ROB_CHECKFIT(V,YFIT,EPS,DEL, SIG,FRACDEV,NGOOD,W,S)
IF ISTAT EQ 0 THEN GOTO,AFTERFIT
NGOOD = NPTS-COUNT
ENDIF
IF NGOOD LT MINPTS THEN BEGIN
PRINT,'ROBUST_POLY_FIT: No Fit Possible!'
RETURN,0.
ENDIF
ENDIF
; Now iterate until the solution converges:
CLOSE_ENOUGH = .03*SQRT(.5/(NPTS-1)) > DEL
DIFF= 1.0E10
SIG_1= (100.*SIG) < 1.0E20
NIT = 0
WHILE( (DIFF GT CLOSE_ENOUGH) AND (NIT LT ITMAX) ) DO BEGIN
NIT=NIT+1
SIG_2=SIG_1
SIG_1=SIG
CC= POLYFITW( U, V, W, NDEG, YFIT )
ISTAT=ROB_CHECKFIT(V,YFIT,EPS,DEL, SIG,FRACDEV,NGOOD,W,S)
IF ISTAT EQ 0 THEN GOTO,AFTERFIT
IF NGOOD LT MINPTS THEN BEGIN
PRINT,'ROBUST_POLY_FIT: Questionable Fit!'
BADFIT=1
GOTO,AFTERFIT
ENDIF
DIFF = (ABS(SIG_1-SIG)/SIG) < (ABS(SIG_2-SIG)/SIG)
ENDWHILE
;IF NIT GE ITMAX THEN PRINT,'ROBUST_POLY_FIT: Did not converge in',ITMAX,$
;' iterations!'
AFTERFIT:
CC=REFORM(CC)
IF NDEG LT DEGMAX THEN BEGIN
CASE NDEG OF
1: CC(0) = CC(0)-CC(1)*X0 + Y0
2: BEGIN
CC(0) = CC(0)-CC(1)*X0+CC(2)*X0^2 + Y0
CC(1) = CC(1)-2.*CC(2)*X0
END
3: BEGIN
CC(0) = CC(0)-CC(1)*X0+CC(2)*X0^2-CC(3)*X0^3 + Y0
CC(1) = CC(1)-2.*CC(2)*X0+3.*CC(3)*X0^2
CC(2) = CC(2)-3.*CC(3)*X0
END
4: BEGIN
CC(0) = CC(0)- CC(1)*X0+CC(2)*X0^2-CC(3)*X0^3+CC(4)*X0^4+ Y0
CC(1) = CC(1)-2.*CC(2)*X0+3.*CC(3)*X0^2-4.*CC(4)*X0^3
CC(2) = CC(2)-3.*CC(3)*X0+6.*CC(4)*X0^2
CC(3) = CC(3)-4.*CC(4)*X0
END
5: BEGIN
CC(0) = CC(0)- CC(1)*X0+CC(2)*X0^2-CC(3)*X0^3+CC(4)*X0^4-CC(5)*X0^5+ Y0
CC(1) = CC(1)-2.*CC(2)*X0+ 3.*CC(3)*X0^2- 4.*CC(4)*X0^3+5.*CC(5)*X0^4
CC(2) = CC(2)-3.*CC(3)*X0+ 6.*CC(4)*X0^2-10.*CC(5)*X0^3
CC(3) = CC(3)-4.*CC(4)*X0+10.*CC(5)*X0^2
CC(4) = CC(4)-5.*CC(5)*X0
END
ENDCASE
ENDIF
; Calculate the fit at points X:
IF( N_PARAMS(0) GT 3 )THEN YFIT=POLY(X,CC)
IF BADFIT EQ 1 THEN CC=[CC,0.]
RETURN,CC
END