Calibration of a thermometer (GUM H3)

An example from Appendix H3 of the GUM [1].

Code

from __future__ import print_function
from GTC import *

print("""
-------------------------------
Example from Appendix H3 of GUM
-------------------------------
""")
# Thermometer readings (degrees C)
t = (21.521,22.012,22.512,23.003,23.507,23.999,24.513,25.002,25.503,26.010,26.511)

# Observed differences with calibration standard (degrees C)
b = (-0.171,-0.169,-0.166,-0.159,-0.164,-0.165,-0.156,-0.157,-0.159,-0.161,-0.160)

# Arbitrary offset temperature (degrees C)
t_0 = 20.0

# Calculate the temperature relative to t_0
t_rel = [ t_k - t_0 for t_k in t ]

# Least-squares regression
cal = type_a.line_fit(t_rel,b)
print( cal )
print

# Apply correction at 30 C
b_30 = cal.intercept + cal.slope*(30.0 - t_0)

print("Correction at 30 C: {}".format(b_30))

Explanation

A thermometer is calibrated by comparing 11 readings \(t_k\) with corresponding values of a temperature reference standard \(t_{\mathrm{R}\cdot k}\).

The readings and the differences \(b_k = t_{\mathrm{R}\cdot k} - t_k\) are used to calculate the slope and intercept of a calibration line, which can be used to estimate a temperature correction for a thermometer reading, including the uncertainty.

A linear model of the thermometer is assumed,

\[B_k = Y_1 + Y_2(t_k - t_0) + E_k \;\]

An arbitrary fixed temperature \(t_0\) is chosen for convenience, \(t_k\) is the temperature indicated by the thermometer and \(B_k\) is the correction that should be applied to a reading. The constants \(Y_1\) and \(Y_2\) define a linear relationship between the indicated temperature and the correction \(B_k\) (\(Y_1\) and \(Y_2\) correspond to the intercept and slope).

The accuracy of the temperature standard is high, so values of \(t_{\mathrm{R}\cdot k}\) have no significant error. However, the estimates obtained for the difference between the actual temperature and the indicated temperature are \(b_k\) are subject to error.

Estimates of the intercept and slope are obtained by least-squares regression on \(b_k\) and \(t_k\). The uncertainty in these estimates is due to random fluctuations in the measurement system (represented by \(E_k\)) .

In the GTC calculation, data are contained in a pair of sequences. The function type_a.line_fit() performs the regression.

# Thermometer readings (degrees C)
t = (21.521,22.012,22.512,23.003,23.507,23.999,24.513,25.002,25.503,26.010,26.511)

# Observed differences with calibration standard (degrees C)
b = (-0.171,-0.169,-0.166,-0.159,-0.164,-0.165,-0.156,-0.157,-0.159,-0.161,-0.160)

# Arbitrary offset temperature (degrees C)
t_0 = 20.0

# Calculate the temperature relative to t_0
t_rel = [ t_k - t_0 for t_k in t ]

# Least-squares regression
cal = type_a.line_fit(t_rel,b)
print cal
print

The fitted calibration line can be used to calculate a correction for a reading of 30 C

# Apply correction at 30 C
b_30 = cal.intercept + cal.slope*(30.0 - t_0)

print("Correction at 30 C: {}".format(b_30))

The results agree with the numbers reported in the GUM

-------------------------------
Example from Appendix H3 of GUM
-------------------------------

Ordinary Least-Squares Results:

  Intercept: -0.1712(29)
  Slope: 0.00218(67)
  Correlation: -0.93
  Sum of the squared residuals: 0.000110096583109
  Number of points: 11

Correction at 30 C: -0.1494(41)

Other error models

In GUM appendix H.3.6, two alternative scenarios are considered for the thermometer calibration.

Known variance

In the first, the variance of the b_k data is assumed known from prior calibrations.

There are two ways to do this regression problem with GTC.

One way is to define a sequence with the uncertainties of the respective b_k observations. This sequence can be used with type_a.line_fit_wls() to obtain the slope and intercept. The other way is to define a sequence of uncertain real numbers representing the b_k data and use the function type_b.line_fit()

u_b = 0.001 # an arbitrary value, just as an example
cal = type_b.line_fit(t_rel,[ureal(b_i,u_b) for b_i in b])

in either case, the results obtained can be used as above to evaluate corrections.

Systematic error in the standard temperature

The other scenario considers a systematic error that causes all b_k values to have some constant offset error. A type-A analysis can still be used on the data to evaluate the contribution to uncertainty due to system instability. However, the systematic error cannot be evaluated by a statistical analysis (it is constant).

This can be handled by combining the results from both type-A and type-B regression analyses.

First, we define a sequence of uncertain real numbers for the b_k data, in which a term representing the systematic error is included

E_sys = ureal(0,0.005)
b_sys = [b_i + E_sys for b_i in b]
cal_b = type_b.line_fit(t_rel,b_sys)
print cal_b

Note that E_sys, which represents the systematic error, is defined outside the list and then added to each list element. The results are

Ordinary Least-Squares Results:

  Intercept: -0.1712(50)
  Slope: 0.00218269773988727725(16)
  Correlation: -1
  Sum of the squared residuals: 0.000110096583109
  Number of points: 11

The standard uncertainty in the slope is effectively zero (the small non-zero value can be attributed to numerical round-off error), as expected: an error in the temperature standard shifts all values of b_k by the same amount, so the slope does not change.

Second, a type-A regression analysis is done on the same b_k data sequence (this processes the uncertain-number values, but ignores the uncertainies)

cal_a = ta.line_fit(t_rel,b_sys)
print cal_a

The results are

Ordinary Least-Squares Results:

  Intercept: -0.1712(29)
  Slope: 0.00218(67)
  Correlation: -0.93
  Sum of the squared residuals: 0.000110096583109
  Number of points: 11

Notice that the slope and intercept are the same, but not the uncertainties or the correlation coefficient.

In a final step, the results are combined

intercept = ta.merge(cal_a.intercept,cal_b.intercept)
slope = ta.merge(cal_a.slope,cal_b.slope)

print( repr(intercept) )
print( repr(slope) )

which displays

ureal(-0.17120379013135004,0.00576893138292676,145.37964721007157)
ureal(0.0021826977398872894,0.0006679387732278323,9.0)

Notice that neither of the estimates, or the standard uncertainty in the slope, change as a result of merging. However, the standard uncertainty of the intercept does increase, due to uncertainty about the systematic error, as described in H.3.6 in the GUM.

Footnotes