На днях должны подвезти спирт, и я смогу наконец-то подготовить криостат к тестовой откачке и, если течей не будет, испытанию холодом в наших условиях. А для этого нужно иметь надежную систему сбора температур. Я уже писал о тестировании системы в жидком азоте. Теперь же решил откалибровать при помощи точного омметра и посмотреть, как датчики себя в комнатной температуре будут вести. Для калибровки я просто повесил вместо терморезисторов один переменный резистор на 1.5кОм и, изменяя его сопротивление, проводил по нескольку замеров. Калибровочные данные получил простым скриптом (по сути, из него нужна только часть внутри if(MF)):
function data_stat(filename, msrd)
% prints some statistics
% also plot graphs
MF = 0;
if(nargin == 0) filename = 'tempout'; endif;
if(nargin == 2) MF = 1; endif;
D = dlmread(filename);
if(isempty(D)) return; endif;
printf("Some statistics:\n\n\trelative error for inner ADC:\n");
Time = (D(:,1)*2^24+D(:,2))/1000;
T = []; Rr = [];
x = rel_error(D(:,[3 4 6:10]));
printf("%f ", x);
avrg = mean(x);
printf("\t(aver: %f)\n", avrg);
printf("\n\trelative error for outern ADC:\n\n");
plot(Time, D(:,[3 4 6:10]));
if(MF)
R = dlmread(msrd);
Rr = R(:,2);
T = R(:,1)/1000;
addlabels(Time, D(:,[3 4 6:10]), T, Rr);
endif;
Tit = sprintf("Internal 12-bit ADC, err=%f%%", avrg);
xlabel("Time, s"); ylabel("R, ADU"); title(Tit);
print -dpng -color int.png;
close;
x = rel_error(D(:,[11:18]));
avrg = mean(x);
printf("%f ", x);
printf("\t(aver: %f)\n", avrg);
printf("\n");
plot(Time, D(:,[11:18]));
if(MF)
addlabels(Time, D(:,[11:18]), T, Rr);
endif;
Tit = sprintf("External 24-bit ADC, err=%f%%", avrg);
xlabel("Time, s"); ylabel("R, ADU"); title(Tit);
print -dpng -color ext.png;
close
meanline = mean(D(:,[11:18])')';
diffs = mean(D(:,[11:18]) - meanline) % average difference between mean line
newD = D(:,[11:18]) - diffs;
plot(Time, newD);
if(MF)
addlabels(Time, newD, T, Rr);
endif;
Tit = sprintf("External 24-bit ADC, corrected");
xlabel("Time, s"); ylabel("R, ADU"); title(Tit);
print -dpng -color ext_corr.png;
close
if(MF)
% R = K*ADU -> K = ADU \ R
Kmul = []; Kadd = []; Kmul2 = [];
for i = 11:18
dat = interp1(Time, D(:,i), T);
N = [ ones(size(dat)) dat dat.^2];
K = N \ Rr;
Kadd = [Kadd K(1)];
Kmul = [Kmul K(2)];
Kmul2= [Kmul2 K(3)];
endfor
%Kmul = median(Kmul);
%Kadd = median(Rr - dat*Kmul);
printf("coefficients:\n\tKadd = %s\n\tKmul = %s\n\tKmul2 = %s\n", num2str(Kadd), ...
num2str(Kmul), num2str(Kmul2));
printf("stat:\n\t = %g, sigma = %g\n\t = %g, sigma = %g\n", ...
median(Kmul), std(Kmul), median(Kmul2), std(Kmul2));
dd = D(:,[11:18]);
newR = dd.^2 .* Kmul2 + dd .* Kmul + Kadd;
plot(Time, newR);
addlabels(Time, newR, T, Rr);
Tit = sprintf("External 24-bit ADC, corrected");
xlabel("Time, s"); ylabel("R, Ohm"); title(Tit);
print -dpng -color ext_corr_Ohm.png;
endif
endfunction
function addlabels(Time, data, T, Rr)
%
% plot circles with R label
% - Time - original time labels
% - data - original data
% - T - time labels for Rr
% - Rr - measured resistance
%
meanline = mean(data')';
newDr = interp1(Time, meanline, T);
%N = [ ones(size(Rr)) Rr Rr.^2];
N = [ ones(size(Rr)) Rr ];
K = N \ newDr
%Y = Rr.^2 * K(3) + Rr * K(2) + K(1);
Y = Rr * K(2) + K(1);
hold on; plot(T, Y, '.');
text(T+10, Y, num2str(Rr));
%plot(Time, meanline, 'o');
hold off;
endfunction
Сначала я пробовал линейную аппроксимацию, но получилось плохо. А вот квадратичная вполне хорошо легла. Вот что получилось:
Калибровка восьми каналов АЦП. Горизонтальные участки сплошной линии — показания АЦП; точки — измерение омметром.
Так как прецизионного термометра и термостата у меня нет, то, не мудрствуя лукаво, я решил "в лоб" воспользоваться формулой для преобразования сопротивления ТРД HEL-705 в температуру:
function Tout = H705(Rin)
% Converts resistance of TRD into T (degrC)
_alpha = 0.00375;
_beta = 0.16;
_delta = 1.605;
T = [-300:0.1:300];
_A = _alpha + _alpha*_delta/100.;
_B = -_alpha*_delta/1e4;
_C = zeros(size(T));
_C(find(T<0.)) = -_alpha*_beta/1e8;
rT = 1000.*(1 + _A*T + _B*T.^2 - _C.*T.^3*100. + _C.*T.^4);
Tout = interp1(rT, T, Rin, 'spline');
endfunction
Теперь нужно лишь накопить результаты и преобразовать отчеты в температуру:
function [Time T Tfxd] = get_T(filename, filter_treshold)
% convert ADU into T in Kelvins
% filename - name of file with temperature data
% filter_treshold - treshold level
D = dlmread(filename);
if(isempty(D)) return; endif;
Time = (D(:,1)*2^24+D(:,2))/1000;
% measured coefficients
Kadd = [35.628 34.595 35.088 34.754 33.936 33.604 33.966 34.816];
Kmul = [0.00014524 0.00014577 0.0001462 0.00014628 0.00014577 0.00014545 0.00014558 0.00014523];
Kmul2 = [3.6789e-11 3.688e-11 3.6878e-11 3.6894e-11 3.6923e-11 3.6929e-11 3.6914e-11 3.6841e-11];
Readed = D(:,[11:18]);
nstr = [size(Readed, 1) 1];
Kadd = repmat(Kadd, nstr);
Kmul = repmat(Kmul, nstr);
Kmul2 = repmat(Kmul2, nstr);
R = Readed.^2 .* Kmul2 + Readed .* Kmul + Kadd;
T = H705(R);
% filtering
if(nargin == 2)
for i = 1:2
DT = diff(T);
[r c] = ind2sub(size(DT), find(DT < -filter_treshold));
T(r+1, :) = [];
R(r+1, :) = [];
Time(r+1, :) = [];
endfor
endif
plot(Time, R);
Tit = sprintf("Resistance, \\Omega");
xlabel("Time, s"); ylabel("R, \\Omega"); title(Tit);
print -dpng -color resistance.png;
close
plot(Time, T);
Tit = sprintf("Temperature, ^\\circ{}C");
xlabel("Time, s"); ylabel("T, ^\\circ{}C"); title(Tit);
print -dpng -color temperatures.png;
close
% calculate difference between thermometers
Tavr = mean(T, 2);
Tadd = mean(T - repmat(Tavr, [1 8]));
Tfxd = T - repmat(Tadd,[size(T,1) 1]);
plot(Time, Tfxd);
Tit = sprintf("Temperature fixed to average value, ^\\circ{}C");
xlabel("Time, s"); ylabel("T, ^\\circ{}C"); title(Tit);
print -dpng -color temperatures_fixed.png;
close
printf("differences:\n"); printf("%g\n", -Tadd);
endfunction
Блок, помеченный как filtering нужен был, пока у меня в "показометре" был баг: периодически терялся 64-байтный буфер, передаваемый по USB. Баг этот я починил (я забыл проверять, ушли ли уже предыдущие данные, прежде чем посылать следующую порцию).
Вот что получается, когда снимаются показания при комнатной температуре:
Не скорректированные на общее среднее показания.
Заметно, что ведут себя эти температуры очень скоррелированно, различаясь лишь аддитивно. Поэтому последняя часть предыдущей функции заодно выравнивает данные на общее среднее:
Скорректированные на "общее среднее" температуры.
В пределах пяти сотых получается примерно одно и то же.
Ну и напоследок еще картинка. Я нагрел руками дюралевый стаканчик, в котором находились ТРД: