Initial Guess for GAUSSFIT Causes Problem
Name: William Thompson
E-mail Address: thompson@orpheus.nascom.nasa.gov
IDL version: 5.5
Platform and OS: All
Description of Behavior: The following is from a November 16th, 2001
article in the IDL newsgroup by William Thompson describing the problem
and how to solve it.
Subject: Problem with gaussfit in IDL/v5.5
From: thompson@orpheus.nascom.nasa.gov (William Thompson)
Date: 16 Nov 2001 17:14:12 GMT
We found a problem with the procedure gaussfit which is supplied with IDL/v5.5.
It appears that somebody at RSI tried to improve the algorithm for generating
the initial guess, but didn't quite complete the job. I've informed RSI, and
decided to also inform the newsgroup. The simple fix is to change the line
if nt gt 5 then a = [a, 0.]
to instead read
if nt gt 5 then a = [a, c[2]]
The complete routine with the fix is below.
Example Code: See fix below.
Know Workarounds or Fixes:
; NAME:
; GAUSS_FUNCT
;
; PURPOSE:
; EVALUATE THE SUM OF A GAUSSIAN AND A 2ND ORDER POLYNOMIAL
; AND OPTIONALLY RETURN THE VALUE OF IT'S PARTIAL DERIVATIVES.
; NORMALLY, THIS FUNCTION IS USED BY CURVEFIT TO FIT THE
; SUM OF A LINE AND A VARYING BACKGROUND TO ACTUAL DATA.
;
; CATEGORY:
; E2 - CURVE AND SURFACE FITTING.
; CALLING SEQUENCE:
; FUNCT,X,A,F,PDER
; INPUTS:
; X = VALUES OF INDEPENDENT VARIABLE.
; A = PARAMETERS OF EQUATION DESCRIBED BELOW.
; OUTPUTS:
; F = VALUE OF FUNCTION AT EACH X(I).
;
; OPTIONAL OUTPUT PARAMETERS:
; PDER = (N_ELEMENTS(X),6) ARRAY CONTAINING THE
; PARTIAL DERIVATIVES. P(I,J) = DERIVATIVE
; AT ITH POINT W/RESPECT TO JTH PARAMETER.
; COMMON BLOCKS:
; NONE.
; SIDE EFFECTS:
; NONE.
; RESTRICTIONS:
; NONE.
; PROCEDURE:
; F = A(0)*EXP(-Z^2/2) + A(3) + A(4)*X + A(5)*X^2
; Z = (X-A(1))/A(2)
; Elements beyond A(2) are optional.
; MODIFICATION HISTORY:
; WRITTEN, DMS, RSI, SEPT, 1982.
; Modified, DMS, Oct 1990. Avoids divide by 0 if A(2) is 0.
; Added to Gauss_fit, when the variable function name to
; Curve_fit was implemented. DMS, Nov, 1990.
;
PRO GAUSS_FUNCT,X,A,F,PDER
COMPILE_OPT idl2, hidden
ON_ERROR,2 ;Return to caller if an error occurs
n = n_elements(a)
if a[2] ne 0.0 then begin
Z = (X-A[1])/A[2] ;GET Z
EZ = EXP(-Z^2/2.) ;GAUSSIAN PART
endif else begin
z = 100.
ez = 0.0
endelse
case n of
3: F = A[0]*EZ
4: F = A[0]*EZ + A[3]
5: F = A[0]*EZ + A[3] + A[4]*X
6: F = A[0]*EZ + A[3] + A[4]*X + A[5]*X^2 ;FUNCTIONS.
ENDCASE
IF N_PARAMS(0) LE 3 THEN RETURN ;NEED PARTIAL?
;
PDER = FLTARR(N_ELEMENTS(X),n) ;YES, MAKE ARRAY.
PDER[*,0] = EZ ;COMPUTE PARTIALS
if a[2] ne 0. then PDER[*,1] = A[0] * EZ * Z/A[2]
PDER[*,2] = PDER[*,1] * Z
if n gt 3 then PDER[*,3] = 1.
if n gt 4 then PDER[*,4] = X
if n gt 5 then PDER[*,5] = X^2
RETURN
END
;+
; NAME:
; GAUSSFIT
;
; PURPOSE:
; Fit the equation y=f(x) where:
;
; F(x) = A0*EXP(-z^2/2) + A3 + A4*x + A5*x^2
; and
; z=(x-A1)/A2
;
; A0 = height of exp, A1 = center of exp, A2 = sigma (the width).
; A3 = constant term, A4 = linear term, A5 = quadratic term.
; Terms A3, A4, and A5 are optional.
; The parameters A0, A1, A2, A3 are estimated and then CURVEFIT is
; called.
;
; CATEGORY:
; ?? - fitting
;
; CALLING SEQUENCE:
; Result = GAUSSFIT(X, Y [, A])
;
; INPUTS:
; X: The independent variable. X must be a vector.
; Y: The dependent variable. Y must have the same number of points
; as X.
; KEYWORD INPUTS:
; KEYWORD INPUTS:
; ESTIMATES = optional starting estimates for the parameters of the
; equation. Should contain NTERMS (6 if NTERMS is not
; provided) elements.
; NTERMS = Set NTERMS to 3 to compute the fit: F(x) = A0*EXP(-z^2/2).
; Set it to 4 to fit: F(x) = A0*EXP(-z^2/2) + A3
; Set it to 5 to fit: F(x) = A0*EXP(-z^2/2) + A3 + A4*x
;
; OUTPUTS:
; The fitted function is returned.
;
; OPTIONAL OUTPUT PARAMETERS:
; A: The coefficients of the fit. A is a three to six
; element vector as described under PURPOSE.
;
; COMMON BLOCKS:
; None.
;
; SIDE EFFECTS:
; None.
;
; RESTRICTIONS:
; The peak or minimum of the Gaussian must be the largest
; or smallest point in the Y vector.
;
; PROCEDURE:
; The initial estimates are either calculated by the below procedure
; or passed in by the caller. Then the function CURVEFIT is called
; to find the least-square fit of the gaussian to the data.
;
; Initial estimate calculation:
; If the (MAX-AVG) of Y is larger than (AVG-MIN) then it is assumed
; that the line is an emission line, otherwise it is assumed there
; is an absorbtion line. The estimated center is the MAX or MIN
; element. The height is (MAX-AVG) or (AVG-MIN) respectively.
; The width is found by searching out from the extrema until
; a point is found less than the 1/e value.
;
; MODIFICATION HISTORY:
; DMS, RSI, Dec, 1983.
; DMS, RSI, Jun, 1995, Added NTERMS keyword. Result is now float if
; Y is not double.
; DMS, RSI, Added ESTIMATES keyword.
;-
;
Function Gaussfit, x, y, a, NTERMS=nt, ESTIMATES = est
COMPILE_OPT idl2
on_error,2 ;Return to caller if an error occurs
if n_elements(nt) eq 0 then nt = 6
if nt lt 3 or nt gt 6 then $
message,'NTERMS must have values from 3 to 6.'
n = n_elements(y) ;# of points.
s = size(y)
if n_elements(est) eq 0 then begin ;Compute estimates?
if (nt gt 3) then begin
; For a Gaussian + polynomial, we need to subtract off the polynomial
; in order to get good estimates.
degree = nt - 4 ; Fit a constant, straight line, or a quadratic
c = poly_fit(x,y,degree,yf)
yd = y - yf
endif else begin
; Just fitting a Gaussian. Don't need to subtract off anything.
yd = y
c = 0d
endelse
if s[s[0]+1] ne 5 then begin ;If Y is not double, use float
yd = float(yd)
c = float(c)
endif
;x,y and subscript of extrema
ymax=max(yd, imax)
xmax=x[imax]
ymin=min(yd, imin)
xmin=x[imin]
if abs(ymax) gt abs(ymin) then i0=imax else i0=imin ;emiss or absorp?
i0 = i0 > 1 < (n-2) ;never take edges
dy=yd[i0] ;diff between extreme and mean
del = dy/exp(1.) ;1/e value
i=0
while ((i0+i+1) lt n) and $ ;guess at 1/2 width.
((i0-i) gt 0) and $
(abs(yd[i0+i]) gt abs(del)) and $
(abs(yd[i0-i]) gt abs(del)) do i=i+1
a = [yd[i0], x[i0], abs(x[i0]-x[i0+i])]
if nt gt 3 then a = [a, c[0]] ;estimates
if nt gt 4 then a = [a, c[1]]
if nt gt 5 then a = [a, c[2]]
endif else begin
if nt ne n_elements(est) then message, 'ESTIMATES must have NTERM elements'
a = est
endelse
return,curvefit(x,y,replicate(1.,n),a,sigmaa, $
function_name = "GAUSS_FUNCT") ;call curvefit
end
RSI Technical Support Response: Notified. No response as yet.
[Return to Table of Contents]
Last Updated 17 November 2001