📄 robust_poly_fit.pro
字号:
FUNCTION ROBUST_POLY_FIT,X,Y,NDEG,YFIT,SIG, NUMIT=THIS_MANY, DOUBLE=DOUBLE;+; NAME:; ROBUST_POLY_FIT;; PURPOSE:; An outlier-resistant polynomial fit.;; CALLING SEQUENCE:; COEFF = ROBUST_POLY_FIT(X,Y,NDEGREE ,[ YFIT,SIG, /DOULBE, NUMIT=] );; INPUTS:; X = Independent variable vector, floating-point or double-precision; Y = Dependent variable vector; NDEGREE - integer giving degree of polynomial to fit, maximum = 6; 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;; OPTIONAL INPUT KEYWORD:; /DOUBLE - If set, then force all computations to double precision.; NUMIT - Maximum number of iterations to perform, default = 25; 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)).;; PROCEDURES CALLED:; POLY(), POLY_FIT(); ROB_CHECKFIT(); REVISION HISTORY; Written, H. Freudenreich, STX, 8/90. Revised 4/91.; 2/94 -- changed convergence criterion; Added /DOUBLE keyword, remove POLYFITW call W. Landsman Jan 2009;-ON_ERROR,2COMPILE_OPT IDL2EPS = 1.0E-20DEL = 5.0E-07DEGMAX= 6IF N_ELEMENTS(THIS_MANY) GT 0 THEN ITMAX=THIS_MANY ELSE ITMAX=25BADFIT=0NPTS = N_ELEMENTS(X)MINPTS=NDEG+1IF (NPTS/4*4) EQ NPTS THEN NEED2 = 1 ELSE NEED2 = 0N3 = 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-Y0ENDIF ELSE BEGIN U=X & V=YENDELSE; The initial estimate.; Choose an odd number of segments:NUM_SEG = NDEG+2IF (NUM_SEG/2*2) EQ NUM_SEG THEN NUM_SEG =NUM_SEG+1MIN_PTS = NUM_SEG*3IF NPTS LT 10000 THEN BEGIN ;MIN_PTS THEN BEGIN; Settle for least-squares: LSQFIT = 1 CC = POLY_FIT( U, V, NDEG, YFIT , DOUBLE=DOUBLE)ENDIF ELSE BEGIN; Break up the data into segments: LSQFIT = 0 Q = SORT(U) U = U[Q] & V = V[Q] N_PER_SEG = REPLICATE( NPTS/NUM_SEG, 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 = DBLARR(NUM_SEG) & S = DBLARR(NUM_SEG) R[0]=MEDIAN( U[0:N_PER_SEG[0]-1],/EVEN ) S[0]=MEDIAN( V[0:N_PER_SEG[0]-1],/EVEN ) 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] = MEDIAN( U[I1:I2], /EVEN) & S[I] = MEDIAN( V[I1:I2],/EVEN ) ENDFOR; Now fit: CC = POLY_FIT( R,S, NDEG, DOUBLE=DOUBLE ) YFIT = POLY(U,CC) ENDELSEISTAT = ROB_CHECKFIT(V,YFIT,EPS,DEL, SIG,FRACDEV,NGOOD,W,S)IF ISTAT EQ 0 THEN GOTO,AFTERFITIF NGOOD LT MINPTS THEN BEGIN IF LSQFIT EQ 0 THEN BEGIN ; Try a least-squares: CC = POLY_FIT( U, V, NDEG, YFIT, DOUBLE=DOUBLE ) 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. ENDIFENDIF; Now iterate until the solution converges:CLOSE_ENOUGH = .03*SQRT(.5/(NPTS-1)) > DEL DIFF= 1.0E10SIG_1= (100.*SIG) < 1.0E20NIT = 0WHILE( (DIFF GT CLOSE_ENOUGH) AND (NIT LT ITMAX) ) DO BEGIN NIT=NIT+1 SIG_2=SIG_1 SIG_1=SIG; We use the "obsolete" POLYFITW routine because it allows us to input weights; rather than measure errors g = where(W gt 0, Ng) if Ng LT N_elements(w) then begin ;Throw out points with zero weight u = u[g] v = v[g] w = w[g] endif CC = POLY_FIT( U, V, NDEG, YFIT, MEASURE_ERRORS = 1/W^2, DOUBLE=DOUBLE ) 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 BEGINCASE 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 ENDCASEENDIF; 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,CCEND
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -