; $Id: svdfit.pro,v 1.22 2004/01/26 21:33:03 chris Exp $ ;+ ; NAME: ; SVDFIT ; ; PURPOSE: ; Perform a general least squares fit with optional error estimates. ; ; This version uses the Numerical Recipies (2nd Edition) function ; SVDFIT. A user-supplied function or a built-in polynomial or ; legendre polynomial is fit to the data. ; ; CATEGORY: ; Curve fitting. ; ; CALLING SEQUENCE: ; Result = SVDFIT(X, Y, [M]) ; ; INPUTS: ; X: A vector representing the independent variable. ; ; Y: Dependent variable vector. This vector must be same length ; as X. ; ; OPTIONAL INPUTS: ; ; M: The number of coefficients in the fitting function. For ; polynomials, M is equal to the degree of the polynomial + 1. ; If not specified and the keyword A is set, then ; M = N_ELEMENTS(A). ; ; INPUT KEYWORDS: ; ; A: The inital estimates of the desired coefficients. If M ; is specified, then A must be a vector of M elements. ; If A is specified, then the input M can be omitted and ; M=N_ELEMENTS(A). If not specified, the initial value ; of each coefficient is taken to be 1.0. If both M and A are ; specified, them must agree as to the number of paramaters. ; ; DOUBLE: Set this keyword to force double precision computations. This ; is helpful in reducing roundoff errors and improves the chances ; of function convergence. ; ; MEASURE_ERRORS: Set this keyword to a vector containing standard ; measurement errors for each point Y[i]. This vector must be the same ; length as X and Y. ; ; Note - For Gaussian errors (e.g. instrumental uncertainties), ; MEASURE_ERRORS should be set to the standard ; deviations of each point in Y. For Poisson or statistical weighting ; MEASURE_ERRORS should be set to sqrt(Y). ; ; TOL: Set this keyword to the tolerance used when removing singular ; values. The default is 1e-5 for single precision, and 2d-12 ; for double precision (these defaults are approximately 100 ; and 10000 times the machine precisions for single and ; double precision, respectively). Setting TOL to a larger value ; may remove coefficients that do not contribute to the solution, ; which may reduce the errors on the remaining coefficients. ; ; Note - The WEIGHTS keyword is obsolete. New code should use MEASURE_ERRORS. ; WEIGHTS: A vector of weights for Y[i]. This vector must be the same ; length as X and Y. If this parameter is ommitted, 1's ; (No weighting) are assumed. ; The error for each term is weighted by Weight[i] when computing the ; fit. Gaussian or instrumental uncertianties should be weighted as ; Weight = 1/Sigma where Sigma is the measurement error or standard ; deviations of Y. For Poisson or statistical weighting use ; Weight=1/sqrt(Y), since Sigma=sqrt(Y). ; ; FUNCTION_NAME: ; A string that contains the name of an optional user-supplied ; basis function with M coefficients. If omitted, polynomials ; are used. ; ; The function is called: R=SVDFUNCT(X,M) ; ; where X and M are scalar values, and the function value is an ; M element vector evaluated at X with the M basis functions. ; M is the degree of the polynomial +1 if the basis functions are ; polynomials. For example, see the function SVDFUNCT or SVDLEG, ; in the IDL User Library: ; ; For more examples, see Numerical Recipes in C, second Edition, ; page 676-681. ; ; The basis function for polynomials, is R[j] = x)^j. ; ; The function must be able to return R as a FLOAT vector or ; a DOUBLE vector depending on the input type of X. ; ; LEGENDRE: Set this keyword to use the IDL function SVDLEG in the lib ; directory to fit the data to an M element legendre polynomial. ; This keyword overrides the FUNCTION_NAME keyword. ; ; OUTPUTS: ; SVDFIT returns a vector of the M coefficients fitted to the ; supplied function. ; ; OPTIONAL OUTPUT PARAMETERS: ; ; CHISQ: Sum of squared errors divided by MEASURE_ERRORS if specified. ; ; COVAR: Covariance matrix of the coefficients. ; ; VARIANCE: Sigma squared in estimate of each coeff(M). ; That is sqrt(VARIANCE) equals the 1 sigma deviations ; of the returned coefficients. ; ; SIGMA: The 1-sigma error estimates of the returned parameters, ; SIGMA=SQRT(VARIANCE). ; ; Note: if MEASURE_ERRORS is omitted, then you are assuming that ; your model is correct. In this case, ; SIGMA is multiplied by SQRT(CHISQ/(N-M)), where N is the ; number of points in X. See section 15.2 of Numerical Recipes ; in C (Second Edition) for details. ; ; SINGULAR: The number of singular values returned. This value should ; be 0. If not, the basis functions do not accurately ; characterize the data. ; ; SING_VALUES: Set this keyword to a named variable in which to return the ; singular values from the SVD. Singular values which have been removed ; will be set to zero. ; ; STATUS: Set this keyword to a named variable that will contain the status ; of the computation. Possible values are: ; STATUS = 0: The computation was successful. ; STATUS > 0: Singular values were found and were removed. ; STATUS contains the number of singular values. ; Note: If STATUS is not specified, any error messages will be output ; to the screen. ; ; YFIT: Vector of calculated Y's. ; ; COMMON BLOCKS: ; None. ; ; SIDE EFFECTS: ; None. ; ; MODIFICATION HISTORY: ; Adapted from SVDFIT, from the book Numerical Recipes, Press, ; et. al., Page 518. ; minor error corrected April, 1992 (J.Murthy) ; ; Completely rewritten to use the actual Numerical Recipes routines ; of the 2nd Edition (V.2.06). Added the DOUBLE, SIGMA, A, and ; LEGENDRE keywords. Also changed Weight to Weights to match the ; other fitting routines. ; ; CT, RSI, March 2000: Fixed DOUBLE keyword; fixed SIGMA if ; WEIGHTS is omitted. ; CT, RSI, August 2000: Added MEASURE_ERRORS. ; CT, RSI, September 2002: Add SING_VALUES, STATUS, TOL keywords. Change ; default tolerance from 1e-9 to 1e-5 (single) or 2d-12 (double). ; Variance values are now removed using the SING_VALUES vector. ; ;- FUNCTION SVDFIT,X,Y,M, YFIT = yfit, CHISQ = chisq, $ SINGULAR = sing, VARIANCE = variance, COVAR = covar, SIGMA=sigma, $ Function_name = function_name, A=A, $ LEGENDRE=legendre, DOUBLE=double, MEASURE_ERRORS=measure_errors, $ TOL=tolIn, $ SING_VALUES=singular, $ STATUS=status, $ WEIGHTS=weights ; obsolete keyword COMPILE_OPT idl2 ON_ERROR,2 ;RETURN TO CALLER IF ERROR ; ; Ensure that the proper number/type of parameters are used ; np=N_PARAMS() HAVE_IN_A=KEYWORD_SET(A) IF HAVE_IN_A THEN IN_A=A IF NOT KEYWORD_SET(LEGENDRE) THEN use_legendre=0 ELSE use_legendre=1 ; ; Either two or three parameters must be supplied ; IF np NE 2 and np NE 3 THEN $ MESSAGE,'Incorrect number of arguments for SVDFIT,x,y,[m]' ; ; If 2 paramaters are supplied, then A must be supplied ; IF np EQ 2 THEN $ IF N_ELEMENTS(A) eq 0 THEN $ MESSAGE,'The keyword A must be set to call SVDFIT as SVDFIT,x,y' $ ELSE M=N_ELEMENTS(A) ; ; IF np EQ 3 THEN BEGIN IF (SIZE(M))[0] NE 0 THEN $ MESSAGE,'The input M must be a scalar.' IF not KEYWORD_SET(A) THEN A=REPLICATE(1.0,M) ELSE $ IF N_ELEMENTS(A) NE M or (SIZE(A))[0] NE 1 THEN $ MESSAGE,'The keyword A must be an M element vector.' ENDIF IF (SIZE(X))[0] NE 1 THEN $ MESSAGE,'The input X must be a vector.' IF (SIZE(Y))[0] NE 1 THEN $ MESSAGE,'The input Y must be a vector.' ; ; Evaluate/Set/Check a few essential paramaters ; ndata = N_ELEMENTS(x) ;SIZE of X IF ndata NE N_ELEMENTS(y) THEN $ message, 'Error: X and Y must have same # of elements.' isWeight = N_ELEMENTS(weights) GT 0 isMeasure = N_ELEMENTS(measure_errors) GT 0 IF isWeight OR isMeasure THEN BEGIN IF isWeight AND isMeasure THEN $ MESSAGE, 'Incompatible keywords MEASURE_ERRORS and WEIGHTS.' sig = isWeight ? 1.0/weights : measure_errors nsig = N_ELEMENTS(sig) IF nsig NE ndata THEN $ MESSAGE, 'MEASURE_ERRORS must have the number of elements as X and Y.' ENDIF ELSE BEGIN sig = REPLICATE(1.0, ndata) nsig = 0 ; no measure errors actually specified ENDELSE IF n_elements(FUNCTION_NAME) EQ 0 THEN FUNCTION_NAME='svdfunct' IF FUNCTION_NAME EQ '' THEN FUNCTION_NAME='svdfunct' IF use_legendre THEN FUNCTION_NAME='svdleg' ; ; If x or y or sig or a is double precision, set use_double to true ; IF (N_ELEMENTS(double) GT 0) then use_double = KEYWORD_SET(double) $ else use_double = (reverse(size(a)))[1] eq 5 or $ (reverse(size(x)))[1] eq 5 or $ (reverse(size(y)))[1] eq 5 or $ (reverse(size(sig)))[1] eq 5 IF use_double THEN begin chisq=0.0D xx=double(x) & yy=double(y) & a=double(a) ssig=abs(double(sig)) > 1d-300 ; Cannot have ssig=0 ENDIF ELSE BEGIN chisq=0.0 xx=float(x) & yy=float(y) & a=float(a) ssig=abs(float(sig)) > 1e-30 ; Cannot have ssig=0 ENDELSE ; Tolerance used in editing singular values. ; The defaults are approximately (100 or 10000)*machar.eps tol = (N_ELEMENTS(tolIn) eq 1) ? tolIn[0] : use_double ? 2d-12 : 1e-5 ; ; Call the actual NR routine. ; ; Warning, direct use of this function is not supported, as ; the calling sequence is scheduled to change in a future release ; of IDL. ; NR__SVDFIT,FUNCTION_NAME,xx,yy,ssig,ndata,A,M,COVAR,CHISQ,singular,tol, $ DOUBLE=use_double ; ; The variance is the diagonal elements of the covariance matrix ; variance=COVAR[lindgen(M)*(M+1)] IF (nsig EQ 0) THEN $ ; correction for no weighting variance = variance*chisq/(ndata-M) sigma=sqrt(abs(variance)) ; Find singular values that were removed, and set variance to zero. small = WHERE(singular eq 0, cc) IF cc GT 0 THEN variance[small]=0 sing = LONG(TOTAL(variance eq 0)) ;# of singular values status = sing if sing ne 0 then begin if (not ARG_PRESENT(status)) then $ message, 'Warning: ' + strcompress(sing, /REMOVE) + $ ' singular values found.',/INFORM endif ; ; calculate YFIT ; IF KEYWORD_SET(use_double) THEN BEGIN yfit=DBLARR(ndata) afunc=DBLARR(M) ENDIF ELSE BEGIN yfit=FLTARR(ndata) afunc=FLTARR(M) ENDELSE FOR i=0L,ndata-1 DO $ YFIT[i]=total(A * call_function(FUNCTION_NAME, xx[i], M)) ; ; Return the fitted parameters ; OUT_A=A IF HAVE_IN_A THEN A=IN_A RETURN,OUT_A end