Okay, I am trying to understand the statistics a bit. If I calculate detection limits and sensitivity, I get a listing of "percent analytical relative error at 1-sigma. This calculation is based on the standard error of the net peak as developed by Scott and Love. What I would like to assess is the uncertainty in the estimate of composition, generally estimated using something like the Ziebold-Lifshin approach to obtaining sigma - concentration from sigma-k. (Goldstein et al. 3rd ed. eq. 9.20). Seems like the percent analytical relative error when applied to the obtained concentration should give a value similar to the sigma-concentration. I am probably not thinking this through properly (missing a step somewhere?), but I don't get comparable values. Any insight would be helpful!
Mike J.
Hi Mike,
Not sure, but one thing you can do is turn on "debug mode" in the Output menu and then you can see the intermediate calculations that go into the calculation as seen here:
Line: 271 Intermediate Analytical Sensitivity Calculations (nominal beam = 1):
Element/Xray ti ka ti ka ti ka ti ka ti ka
Bgd Count/Sec 1.0 2.6 3.4 .8 1.4
Bgd CountTime 1920.00 1920.00 1920.00 1920.00 1920.00
Bgd Raw Count 381085.1010769.1315427. 302595. 529365.
Peak Cnt/Sec 1.0 2.6 3.4 .8 1.4
Peak Cnt Time 1920.00 1920.00 1920.00 1920.00 1920.00
Peak Raw Count 380952.1014290.1315704. 302399. 531793.
And in case it helps, here is the code used for the calculation:
Function ConvertAnalyticalSensitivity2(datarow As Integer, chan As Integer, sample() As TypeSample) As Single
' Calculate percent error for a single element
ierror = False
On Error GoTo ConvertAnalyticalSensitivity2Error
Dim temp1 As Single, temp2 As Single
Dim temp3 As Single, temp4 As Single
ConvertAnalyticalSensitivity2! = 0#
' Init debug variables
bgdtime! = 0#
bgdcount! = 0#
peakcount! = 0#
' Calculate
If sample(1).BgdData(datarow%, chan%) < 0# Then Exit Function
If sample(1).OnTimeData!(datarow%, chan%) <= 0# Then Exit Function
' Determine background count time for unknown
If sample(1).BackgroundTypes%(chan%) <> 1 Then ' 0=off-peak, 1=MAN, 2=multipoint
' 0=linear, 1=average, 2=high only, 3=low only, 4=exponential, 5=slope hi, 6=slope lo, 7=polynomial, 8=multi-point
If sample(1).OffPeakCorrectionTypes%(chan%) = 2 Then
bgdtime! = sample(1).HiTimeData!(datarow%, chan%) ' high only
ElseIf sample(1).OffPeakCorrectionTypes%(chan%) = 3 Then
bgdtime! = sample(1).LoTimeData!(datarow%, chan%) ' low only
Else
bgdtime! = sample(1).HiTimeData!(datarow%, chan%) + sample(1).LoTimeData!(datarow%, chan%) ' all other off peak types
End If
Else
bgdtime! = sample(1).OnTimeData!(datarow%, chan%) ' use on-peak time for MAN
End If
If bgdtime! = 0# Then Exit Function
' De-normalize unknown peak counts for time and beam (use corrected peak intensity + background for greater accuracy)
peakcount! = (sample(1).CorData!(datarow%, chan%) + sample(1).BgdData!(datarow%, chan%)) * sample(1).OnTimeData!(datarow%, chan%)
If peakcount! = 0# Then Exit Function
If Not sample(1).CombinedConditionsFlag% Then
Call DataCorrectDataBeamDrift2(peakcount!, sample(1).OnBeamData!(datarow%, chan%)) ' use OnBeamData in case of aggregate intensity calculation (average aggregate beam)
If ierror Then Exit Function
Else
Call DataCorrectDataBeamDrift2(peakcount!, sample(1).OnBeamDataArray!(datarow%, chan%)) ' use OnBeamDataArray in case of aggregate intensity calculation (average aggregate beam)
If ierror Then Exit Function
End If
' De-normalize unknown background counts for time and beam
bgdcount! = sample(1).BgdData(datarow%, chan%) * bgdtime!
If bgdcount! = 0# Then Exit Function
If Not sample(1).CombinedConditionsFlag% Then
Call DataCorrectDataBeamDrift2(bgdcount!, sample(1).OnBeamData(datarow%, chan%)) ' use OnBeamData in case of aggregate intensity calculation (use average aggregate beam)
If ierror Then Exit Function
Else
Call DataCorrectDataBeamDrift2(bgdcount!, sample(1).OnBeamDataArray!(datarow%, chan%)) ' use OnBeamDataArray in case of aggregate intensity calculation (use average aggregate beam)
If ierror Then Exit Function
End If
' Check for anomalies
If sample(1).OnTimeData!(datarow%, chan%) <= 0# Then Exit Function
If bgdtime! <= 0# Then Exit Function
temp1! = peakcount! / sample(1).OnTimeData!(datarow%, chan%) ^ 2
temp2! = bgdcount! / bgdtime! ^ 2
temp3! = peakcount! / sample(1).OnTimeData!(datarow%, chan%)
temp4! = bgdcount! / bgdtime!
If temp1! + temp2! < 0# Then Exit Function
If temp3! - temp4 = 0# Then Exit Function
ConvertAnalyticalSensitivity2! = 100# * Sqr(temp1! + temp2!) / (temp3! - temp4)
Exit Function
' Errors
ConvertAnalyticalSensitivity2Error:
MsgBox Error$, vbOKOnly + vbCritical, "ConvertAnalyticalSensitivity2"
ierror = True
Exit Function
End Function
Are you asking about trace elements because my take is that the analytical sensitivity calculation from Love-Scott is only useful for minor and major element concentrations?
Mainly I am trying to come up with a quick way to evaluate the standard deviation in wt.% (or ppm) for a single point in PfE. I can work out a spreadsheet calculation with the standard and unknown info using the Ziebold-Lifshin formula, which seems to agree quite well with the Cameca formulation of StdDev. wt%. Of course, this has to be all trace element business!
Hi Mike,
I understand. There's many ways to approach this for sure.
My preference is to utilize the t-test detection limit calculation from Goldstein et al. because it utilizes the actual measured variance and weights it for the number of points acquired. But that doesn't help you for evaluation of the single point detection limit. On the other hand one can compare the t-test (on a presumably homogeneous material) and compare that with the single point detection limit as shown here in bold:
Un 31 1920 sec on SiO2, Results in Elemental Weight Percents
ELEM: Ti Ti Ti Ti Ti Si O
TYPE: ANAL ANAL ANAL ANAL ANAL SPEC CALC
BGDS: LIN LIN LIN LIN LIN
TIME: 1920.00 1920.00 1920.00 1920.00 1920.00 --- ---
BEAM: 200.76 200.76 200.76 200.76 200.76 --- ---
ELEM: Ti Ti Ti Ti Ti Si O SUM
XRAY: (ka) (ka) (ka) (ka) (ka) () ()
271 -.00003 .00039 .00003 -.00006 .00051 46.7430 53.2576 100.001
272 .00010 .00039 .00022 -.00036 -.00030 46.7430 53.2570 100.000
273 .00003 .00037 .00008 .00007 .00048 46.7430 53.2577 100.002
274 .00002 .00016 .00015 -.00005 .00009 46.7430 53.2572 100.001
275 -.00010 .00019 -.00002 .00016 .00009 46.7430 53.2572 100.001
AVER: .00000 .00030 .00009 -.00005 .00017 46.743 53.257 100.001
SDEV: .00007 .00011 .00010 .00020 .00034 .000 .000 .00067
SERR: .00003 .00005 .00004 .00009 .00015 .00000 .00012
%RSD: 4057.70 37.3350 103.073 -404.32 193.525 .00000 .00050
STDS: 922 922 922 922 922 --- ---
STKF: .5621 .5621 .5621 .5621 .5621 --- ---
STCT: 667.34 1600.07 1901.70 531.93 828.32 --- ---
UNKF: .0000 .0000 .0000 .0000 .0000 --- ---
UNCT: .00 .01 .00 .00 .00 --- ---
UNBG: .99 2.63 3.41 .79 1.38 --- ---
ZCOR: 1.1969 1.1969 1.1969 1.1969 1.1969 --- ---
KRAW: .00000 .00000 .00000 .00000 .00000 --- ---
PKBG: 1.00002 1.00271 1.00077 .99951 1.00155 --- ---
BLNK#: 27 27 27 27 27 --- ---
BLNKL: .000142 .000142 .000142 .000142 .000142 --- ---
BLNKV: .000000 -.00125 -.00272 .000689 -.00040 --- ---
Detection limit at 99 % Confidence in Elemental Weight Percent (Single Line):
ELEM: Ti Ti Ti Ti Ti
271 .00049 .00033 .00032 .00054 .00046
272 .00048 .00033 .00032 .00054 .00046
273 .00049 .00033 .00032 .00054 .00046
274 .00049 .00033 .00032 .00054 .00046
275 .00049 .00033 .00031 .00054 .00046
AVER: .00049 .00033 .00032 .00054 .00046
SDEV: .00000 .00000 .00000 .00000 .00000
SERR: .00000 .00000 .00000 .00000 .00000
Percent Analytical Relative Error (One Sigma, Single Line):
ELEM: Ti Ti Ti Ti Ti
271 -655.0 40.4 585.3 -396.9 42.4
272 238.0 40.3 66.2 -70.9 -72.1
273 874.2 41.8 179.3 347.3 45.2
274 1001.7 95.3 102.3 -547.3 250.4
275 -226.3 80.7 -965.6 164.0 248.4
AVER: 246.5 59.7 -6.5 -100.8 102.9
SDEV: 707.2 26.4 574.8 373.8 141.9
SERR: 316.3 11.8 257.1 167.2 63.5
Detection Limit (t-test) in Elemental Weight Percent (Average of Sample):
ELEM: Ti Ti Ti Ti Ti
60ci .00008 .00004 .00019 .00014 .00009
80ci .00013 .00007 .00032 .00022 .00015
90ci .00018 .00009 .00044 .00031 .00021
95ci .00024 .00012 .00057 .00040 .00028
99ci .00039 .00020 .00095 .00066 .00046
Analytical Sensitivity (t-test) in Elemental Weight Percent (Average of Sample):
ELEM: Ti Ti Ti Ti Ti
60ci --- --- --- --- ---
80ci --- --- --- --- ---
90ci --- --- --- --- ---
95ci --- --- --- --- ---
99ci --- --- --- --- ---
So what I do is run a few test points on a homogeneous standard material and then hopefully that provides me with the confidence I need.
Right, that all is making good sense, but what is being asked by one of my users is not quite that. If, you have a concentration of say 10ppm, and a detection limit of 1ppm, it is in principal detectable, but what is the std. dev. of the concentration? So 10ppm +/- 4ppm? or is it 10ppm +/1 30ppm? (at some specified precision, 1-sigma, 2-sigma, etc.) makes a difference when comparing point to point along a line where you would like to apply some sort of error envelope.
Quote from: Mike Jercinovic on July 20, 2020, 12:25:21 PM
Right, that all is making good sense, but what is being asked by one of my users is not quite that. If, you have a concentration of say 10ppm, and a detection limit of 1ppm, it is in principal detectable, but what is the std. dev. of the concentration? So 10ppm +/- 4ppm? or is it 10ppm +/1 30ppm? (at some specified precision, 1-sigma, 2-sigma, etc.) makes a difference when comparing point to point along a line where you would like to apply some sort of error envelope.
Yeah the detection limit is not really what you want for an uncertainty "envelope" I agree.
But let me just say something about your example above for others reading this that might be confused: if I have a 10 PPM concentration for a single line and a reported 3 sigma detection limit (which is what we report) of 10 PPM, then that 10 PPM concentration is 99% confidently detected, not merely "in principal detectable". And of course concentrations less than 10 PPM are less than 99% confidently detected, and concentrations over 10 PPM are more than 99% confidently detected.
But what would be wrong in applying the analytical sensitivity % to the concentration? So if the analytical sensitivity is 100% on a 10 PPM concentration, then wouldn't the "envelope" of uncertainty be +/- 10 PPM for 1 sigma confidence or +/- 30 PPM for 3 sigma confidence?
Am I missing something?
It absolutely seems like applying the % analytical sensitivity to the concentration should be fine. However, it seems like it should roughly correspond to the concentration SD calculated through the Ziebold-Lifshin relationship, and this is where I am stuck at the moment. I need to check my calculations again.
Quote from: Mike Jercinovic on July 20, 2020, 03:21:01 PM
It absolutely seems like applying the % analytical sensitivity to the concentration should be fine. However, it seems like it should roughly correspond to the concentration SD calculated through the Ziebold-Lifshin relationship, and this is where I am stuck at the moment. I need to check my calculations again.
Hi Mike,
I'm not sure if the analytical sensitivity and standard deviation calculation results should be similar or not when dealing with trace elements.
However, if I examine statistics for some major elements, for example Si and Ca in my wollastonite standard, I see that the analytical sensitivity calculations agree pretty well with the relative standard deviations:
Un 6 Wollastonsite (Willsboro,NY) majors, random gr1, Results in Elemental Weight Percents
ELEM: Ca Si O
TYPE: ANAL ANAL CALC
BGDS: LIN LIN
TIME: 60.00 60.00 ---
BEAM: 20.01 20.01 ---
ELEM: Ca Si O SUM
193 34.354 24.581 41.721 100.656
194 34.352 24.536 41.669 100.558
195 34.219 24.548 41.629 100.396
196 34.013 24.561 41.562 100.136
197 34.352 24.481 41.606 100.439
198 34.390 24.488 41.629 100.507
AVER: 34.280 24.533 41.636 100.449
SDEV: .143 .040 .054 .178
SERR: .059 .016 .022
%RSD: .42 .16 .13
STDS: 358 14 ---
STKF: .1693 .4101 ---
STCT: 2291.6 23654.2 ---
UNKF: .3192 .2098 ---
UNCT: 4319.7 12104.0 ---
UNBG: 130.4 45.1 ---
ZCOR: 1.0740 1.1691 ---
KRAW: 1.8850 .5117 ---
PKBG: 34.14 269.68 ---
Percent Analytical Relative Error (One Sigma, Single Line):
ELEM: Ca Si
193 .3 .1
194 .3 .1
195 .3 .1
196 .3 .1
197 .3 .1
198 .3 .1
AVER: .3 .1
SDEV: .0 .0
SERR: .0 .0
Here is the new analytical sensitivity code for the Scott and Love (1983) calculation:
Function ConvertAnalyticalSensitivity3(datarow As Integer, chan As Integer, sample() As TypeSample) As Single
' Calculate percent error for a single element using raw intensity arrays (to better handle aggregate data statistics)
ierror = False
On Error GoTo ConvertAnalyticalSensitivity3Error
Dim m As Integer
Dim temp1 As Single, temp2 As Single
Dim temp3 As Single, temp4 As Single
ConvertAnalyticalSensitivity3! = 0#
' Init debug variables
bgdtime! = 0#
bgdcount! = 0#
peaktime! = 0#
peakcount! = 0#
' Sanity checks
If sample(1).OnPeakCounts_Raw_Cps!(datarow%, chan%) < 0# Then Exit Function
If sample(1).OnTimeData!(datarow%, chan%) <= 0# Then Exit Function
' Determine peak time for unknown
peaktime! = sample(1).OnTimeData!(datarow%, chan%)
' Determine background count time for unknown
If sample(1).CrystalNames$(chan%) <> EDS_CRYSTAL$ Then
' Check if off peak element
If sample(1).BackgroundTypes%(chan%) = 0 Then ' 0=off-peak, 1=MAN, 2=multipoint
' 0=linear, 1=average, 2=high only, 3=low only, 4=exponential, 5=slope hi, 6=slope lo, 7=polynomial, 8=multi-point
If sample(1).OffPeakCorrectionTypes%(chan%) = 2 Or sample(1).OffPeakCorrectionTypes%(chan%) = 5 Then
bgdtime! = sample(1).HiTimeData!(datarow%, chan%) ' high only
ElseIf sample(1).OffPeakCorrectionTypes%(chan%) = 3 Or sample(1).OffPeakCorrectionTypes%(chan%) = 6 Then
bgdtime! = sample(1).LoTimeData(datarow%, chan%) ' low only
Else
bgdtime! = sample(1).HiTimeData!(datarow%, chan%) + sample(1).LoTimeData!(datarow%, chan%) ' all other off peak types
End If
' MAN element
ElseIf sample(1).BackgroundTypes%(chan%) = 1 Then ' 0=off-peak, 1=MAN, 2=multipoint
bgdtime! = sample(1).OnTimeData!(datarow%, chan%) ' use on-peak time for MAN
' MPB element
Else
For m% = 1 To sample(1).MultiPointNumberofPointsAcquireHi%(chan%)
bgdtime! = bgdtime! + sample(1).MultiPointAcquireCountTimesHi!(datarow%, chan%, m%)
Next m%
For m% = 1 To sample(1).MultiPointNumberofPointsAcquireLo%(chan%)
bgdtime! = bgdtime! + sample(1).MultiPointAcquireCountTimesLo!(datarow%, chan%, m%)
Next m%
End If
' EDS element
Else
bgdtime! = sample(1).OnTimeData!(datarow%, chan%) ' use on-peak time for EDS
End If
If bgdtime! = 0# Then Exit Function
' Load raw peak cps for unknown using raw data array
peakcount! = sample(1).OnPeakCounts_Raw_Cps!(datarow%, chan%)
' Load raw bgd cps for unknown using calculated peak to background ratio (peak to bgd are calculated on the fly so aggregate intensities are handled properly)
bgdcount! = peakcount! / tRowUnkPeakToBgds!(datarow%, chan%)
' Calculate actual raw counts
peakcount! = peakcount! * peaktime!
bgdcount! = bgdcount! * bgdtime!
' Check for anomalies
If peakcount! = 0# Then Exit Function
If bgdcount! = 0# Then Exit Function
If peaktime! <= 0# Then Exit Function
If bgdtime! <= 0# Then Exit Function
' Calculate analytical sensitivity from Scott and Love 1983
temp1! = peakcount! / peaktime! ^ 2
temp2! = bgdcount! / bgdtime! ^ 2
temp3! = peakcount! / peaktime!
temp4! = bgdcount! / bgdtime!
If temp1! + temp2! < 0# Then Exit Function
If temp3! - temp4 = 0# Then Exit Function
'ConvertAnalyticalSensitivity3! = 100# * Sqr(temp1! + temp2!) / (temp3! - temp4)
ConvertAnalyticalSensitivity3! = Abs(100# * Sqr(temp1! + temp2!) / (temp3! - temp4)) ' assume absolute value
Exit Function
' Errors
ConvertAnalyticalSensitivity3Error:
MsgBox Error$, vbOKOnly + vbCritical, "ConvertAnalyticalSensitivity3"
ierror = True
Exit Function
End Function
This code is now utilized in the v. 13.6.1 of Probe for EPMA.