The ErrorNum class (advanced)

A Japanese version is here.

In the last post, I explained the basic usage of the ErrorNum class. In this post, I will explain a little more advanced usage of the class, including the following topics.

  • How to use covariance for error calculation
  • Significance test of the value
  • Conversion of a value using a function and its derivative

How to use covariance for error calculation

Sometimes, two variables have errors that do not independently vary. An example case is like this.

>> x = 4 + randn(100, 1);
>> y = x + 0.5 * randn(100, 1);
>> figure;plot(x, y, '.');
>> axis([0, 8, 0, 8]);

The resulting plot is,

Fig. 1: Two variables with correlated errors (covariance)

In this case, the error of x and y covary positively. Namely, when x is high, y also tends to be high and vice versa. In this case, x + y will have a larger error than x – y as illustrated in the next image.

Fig. 2: The variance of x + y should be larger than that of x – y

If two values have finite covariance, a naive addition or subtraction in the ErrorNum class will give an incorrect error estimation.

>> x_en = ErrorNum.create(x, 1);
>> y_en = ErrorNum.create(y, 1);

>> x_en + y_en % error is simple square root addition of individual error
ans = 
ErrorNum:
8.3 ± 1.5

>> x_en - y_en % this error should be smaller
ans = 
ErrorNum:
0.0 ± 1.5

In the ErrorNum class, you can aid this by giving covariance of these two variables. There are methods to invoke covariance-enable calculation.

% calculate covariance and feed it into addition.
>> cov_xy = cov(x, y); % note, cov gives a covariance 'matrix', so pick up (1, 2) or (2, 1) element.

>> x_en.covadd(y_en, cov_xy(1, 2))
ans = 
ErrorNum:
8 ± 2

>> x_en.covsub(y_en, cov_xy(1, 2))
ans = 
ErrorNum:
0.0 ± 0.4

Now the covariance for the subtraction is reduced to 0.4 from 1.5. By construction, y is based on x plus additional noise with 0.5 * randn, so getting a value close to 0.5 makes sense.

Significance test for the value

Once you calculate a value, you often want to do a significance test. The ErrorNum class can give you a simple estimate of the error based on ANOVA (analysis of variance).

%% ANOVA significance test
>> a = ErrorNum(3, 1);
>> b = ErrorNum(2, 1);

>> a.sig % this works
ans =
    0.0027

>> sig(a) % this also works
ans =
    0.0027

>> sig(a - b) % this also works
ans =
    0.4795

>> (a - b).sig % this doesn't work.
Error: File: ErrorNum_demo_advanced.m Line: 34 Column: 8
Invalid use of operator.

Note that there are two ways to invoke a class method. One with dot-notation, another with function-notation. Beware with the dot notation as it does not work unless an ErrorNum instance is already created before invoking the command.

Conversion of a value using a function and its derivative

Another case where the error calculation is complicated is when you convert a number with a certain function. Let’s see the following example.

>> x = ErrorNum([1, 2, 3], 0.1 * ones(1, 3))
ErrorNum:
1.00 ± 0.10,  2.00 ± 0.10,  3.00 ± 0.10

>> y = x.convert(@log, @(t) 1./t)
ErrorNum:
0.00 ± 0.10,  0.69 ± 0.05,  1.10 ± 0.03

In general, normal built-in functions do not work for ErrorNum (e.g. log(x) gives you an error), but by using this convert function and giving its derivative directly, you can let it apply function with appropriate (linear) errors calculation. Note that the same error in x is correctly shrunk in y, depending on the value of x.