Calibration using a least squares fit

This is best done if you have a spectrum which goes over a rather large spectral range. Let's say you've run sgm_scan to obtain a particular .csv file of signal versus energy. Read the file into IDL with something like

IDL> read_csv,'/mnt/x1a/x1a_16jan2005_0019.csv',items
IDL> svec = size(items)
IDL> n = svec[2]
IDL> ev = reform(items[0,*],n)
IDL> signal = reform(items[1,*],n)
You can now do the following:
  IDL> plot,ev,signal
  IDL> plotpeak,ev,signal,ev1,sigma1
You can repeat the plotpeak command as many times as you want to get different peaks nailed down. I would suggest you write the peak positions down on a paper copy of the plot. You can then do
  IDL> ev_measured = [ev1,ev2,ev3]
Now you need to get the values for zero_order_steps and steps_per_angstrom from the file /mnt/x1a/sgm_i.dat or /mnt/x1a/sgm_o.dat. Let's call these previous values zos and spa. You can now do
  IDL> angstroms_measured = 12398.52/ev_measured
  IDL> steps_measured = zos+spa*angstroms_measured
Then make a list of ev_acutal with the same number of entries and order of entries as ev_measured:
  IDL> ev_actual = [290.74,292.74,296.38]
  IDL> angstroms_actual = 12398.52/ev_actual
Now you can do
  IDL> fit_coeff = poly_fit(steps_measured, angstrom_actual, 1)
  IDL> fit_spa = 1./fit_coeff(1)
  IDL> fit_zos = -fit_coeff(0)*fit_spa
  IDL> print,'New zos, spa: ',fit_zos,fit_spa
You can now find out where your measured peaks would be on the new calibration with
  IDL> angstroms_fit = (steps_measured-fit_zos)/float(fit_spa)
  IDL> ev_fit = 12398.52/angstroms_fit
  IDL> print,'Peak positions using fit: ',ev_fit
If you were to incorporate something like this in an IDL procedure, you could then add:
print,'ZOS: was '+strtrim(string(zos,format='(f10.1)'),2)+', fit '+$
  strtrim(string(fit_zos,format='(f10.1)'),2)
print,'SPA: was '+strtrim(string(spa,format='(f10.3)'),2)+', fit '+$
  strtrim(string(fit_spa,format='(f10.3)'),2)
n_points = n_elements(ev_actual)
print,'Step     True    Original    New fit  Fit-true'
print,'pos.     eV      claimed eV  eV       eV'
FOR i=0,(n_points-1) DO BEGIN
    print,string(steps_measured(i),format='(f7.1)')+'  '+$
      string(ev_actual(i),format='(f6.2)')+'  '+$
      string(ev_measured(i),format='(f6.2)')+'      '+$
      string(ev_fit(i),format='(f6.2)')+'   '+$
      string(ev_fit(i)-ev_actual(i),format='(f6.2)')
ENDFOR
to get something like:
ZOS: was 355.6, fit 648.8
SPA: was 510.695, fit 504.267
Step     True    Original    New fit  Fit-true
pos.     eV      claimed eV  eV       eV
22152.7  290.74  290.49      290.75     0.01
22004.4  292.76  292.48      292.76     0.00
21845.0  294.98  294.65      294.97    -0.01
16230.9  401.10  398.85      401.24     0.14
16047.9  406.10  403.50      406.01    -0.09
16008.3  407.10  404.52      407.05    -0.05

As far as sgm_cal.pro is concerned, it wants two step positions and two eV positions to do the calibration of both zos and spa. If you've done a least squares fit, you can generate these two values as follows:

  IDL> ev_cal = [300.,400.]
  IDL> angstroms_cal = 12398.52/ev_cal
  IDL> steps_cal = fit_zos+fit_spa*angstroms_cal
  IDL> print,'Use step positions ',steps_cal,' for eneriges ',ev_cal

Holger Fleckenstein 2008-07-08