/usr/share/psychtoolbox-3/PsychGamma/FitGamma.m is in psychtoolbox-3-common 3.0.14.20170103+git6-g605ff5c.dfsg1-1build1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | function [fit_out,x,fitComment] = ...
FitGamma(values_in,measurements,values_out,fitType)
% [fit_out,x,fitComment] = ...
% FitGamma(values_in,measurements,values_out,[fitType])
%
% Fit a gamma function. This essentially a driver function.
% It has two main purposes.
%
% First it tries several different
% underlying parametric forms for the fit and chooses the best
% for a particular data set.
%
% Second, it does the bookkeeping for fitting each column of
% input measurements. (Each of the underlying fit functions expects
% only vector input.)
%
% To a large extent, the interface to the underlying fit functions
% (e.g. FitGammaPow, FitGammaSig, ...) is uniform. However, this routine
% does have to know a little bit about initial value dimension and choice.
% We have tried to localize this information in the initialization routines
% (e.g. InitialXPow, InitialXSig, ...) as much as possible, but some
% caution is advised.
%
% Optional argument fitType allows you to force the return of a particular
% paramtetric form. Currently:
% fitType == 1: Power function
% fitType == 2: Extended power function
% fitType == 3: Sigmoid
% fitType == 4: Weibull
% fitType == 5: Modified polynomial
% fitType == 6: Linear interpolation
% fitType == 7: Cubic spline
%
% All fit types are in a form such that the fit is forced through the
% origin for 0 input. This is because our convention is that gamma
% correction happens after subtraction of the ambient light.
%
% NOTE: FitGammaPow (and perhaps other subroutines) uses CONSTR, which is part of the
% Mathworks Optimization Toolbox.
%
% Also see FitGammaDemo.
% 10/3/93 dhb Removed polynomial fit from list tried with fitType == 0.
% Added Weibull function fit
% 3/15/94 dhb, jms Added linear interpolation.
% 7/18/94 dhb Added cubic spline interpolation.
% 8/7/00 dhb Fix bug. Spline was calling linear interpolation. Thanks to
% Chien-Chung Chen for notifying us of this bug.
% 11/14/06 dhb Modify how default type is set. Handle passed empty matrix.
% 3/07/10 dhb Cosmetic to make m-lint happier, including some "|" -> "||"
% 5/26/10 dhb Allow values_in to be either a single column or a matrix with same number of columns as values_out.
% 6/5/10 dhb Fix a lot of MATLAB lint warnings.
% dhb Fix error reporting to actually take mean across devices.
% dhb Rewrite how mean is taken for evaluation of best fit. I think this was done right.
% 11/07/10 dhb Print out fit exponents when gamma fit by a simple power function.
% Get sizes
[nDevices] = size(measurements,2);
[nOut] = size(values_out,1);
% If input comes as a single column, then replicate it to
% match number of devices
if (size(values_in,2) == 1)
values_in = repmat(values_in,1,nDevices);
end
% Set up number of fit types
nFitTypes = 5;
error = zeros(nFitTypes,nDevices);
% Handle force fittting
if (nargin < 4 || isempty(fitType))
fitType = 0;
end
% Fit with simple power function through origin
if (fitType == 0 || fitType == 1 || fitType == 2)
disp('Fitting with simple power function');
fit_out1 = zeros(nOut,nDevices);
[nParams] = size(InitialXPow,1);
x1 = zeros(nParams,nDevices);
for i = 1:nDevices
x0 = InitialXPow;
[fit_out1(:,i),x1(:,i),error(1,i)] = ...
FitGammaPow(values_in(:,i),measurements(:,i),values_out,x0);
fprintf('Exponent for device %d is %g\n',i,x1(:,i));
end
fprintf('Simple power function fit, RMSE: %g\n',mean(error(1,i)));
end
% Fit with extended power function. Use power function
% fit to drive parameters. InitialXExtP can take a two
% vector as input. This defines the parameters of a good fitting
% simple power function.
if (fitType == 0 || fitType == 2)
disp('Fitting with extended power function');
fit_out2 = zeros(nOut,nDevices);
[nParams] = size(InitialXExtP,1);
x2 = zeros(nParams,nDevices);
for i = 1:nDevices
x0 = InitialXExtP(x1(:,i));
[fit_out2(:,i),x2(:,i),error(2,i)] = ...
FitGammaExtP(values_in(:,i),measurements(:,i),values_out,x0);
end
fprintf('Extended power function fit, RMSE: %g\n',mean(error(2,i)));
end
% Fit with a sigmoidal shape. This works well for
% the dimmer packs controlling lights. InitialXSig can take
% a two vector as input. This defines roughly the input for
% half maximum and the maximum output value.
if (fitType == 0 || fitType == 3)
disp('Fitting with sigmoidal function');
fit_out3 = zeros(nOut,nDevices);
[nParams] = size(InitialXSig,1);
x3 = zeros(nParams,nDevices);
for i = 1:nDevices
maxVals = max(values_in(:,i));
x0 = InitialXSig(maxVals'/2);
[fit_out3(:,i),x3(:,i),error(3,i)] = ...
FitGammaSig(values_in(:,i),measurements(:,i),values_out,x0);
end
fprintf('Sigmoidal fit, RMSE: %g\n',mean(error(3,i)));
end
% Fit with Weibull
if (fitType == 0 || fitType == 4)
disp('Fitting with Weibull function');
fit_out4 = zeros(nOut,nDevices);
[nParams] = size(InitialXWeib(values_in(:,1),measurements(:,1)),1);
x4 = zeros(nParams,nDevices);
for i = 1:nDevices
x0 = InitialXWeib(values_in(:,i),measurements(:,i));
[fit_out4(:,i),x4(:,i),error(4,i)] = ...
FitGammaWeib(values_in(:,i),measurements(:,i),values_out,x0);
end
fprintf('Weibull function fit, RMSE: %g\n',mean(error(4,i)));
end
% Fit with polynomial. InitalXPoly is used mostly for consistency
% with other calling forms, since FitGammaPoly computes an analytic
% fit to start the search. But it serves to implicitly defines the
% order of the polynomial.
if (fitType == 0 || fitType == 5)
disp('Fitting with polynomial');
fit_out5 = zeros(nOut,nDevices);
[order5] = size(InitialXPoly,1);
x5 = zeros(order5,nDevices);
for i = 1:nDevices
[fit_out5(:,i),x5(:,i),error(5,i)] = ...
FitGammaPoly(values_in(:,i),measurements(:,i),values_out);
end
fprintf('Polynomial fit, order %g, RMSE: %g\n',order5,mean(error(5,i)));
end
% Linear interpolation. Variable x is bogus here, but
% we fill it in to keep the accountants upstream happy.
if (fitType == 6)
disp('Fitting with linear interpolation');
fit_out6 = zeros(nOut,nDevices);
for i = 1:nDevices
[fit_out6(:,i)] = ...
FitGammaLin(values_in(:,i),measurements(:,i),values_out);
end
x6 = [];
end
% Cubic spline. Variable x is bogus here, but
% we fill it in to keep the accountants upstream happy.
if (fitType == 7)
disp('Fitting with cubic spline');
fit_out7 = zeros(nOut,nDevices);
for i = 1:nDevices
[fit_out7(:,i)] = ...
FitGammaSpline(values_in(:,i),measurements(:,i),values_out);
end
x7 = [];
end
% If we are not forcing a fit type, find best fit.
% Don't check linear interpolation, as it has zero error always.
% Currently we take the minimum mean error over all devices.
% In principle, could use best fit type for each device. But
% that would make the interface tricky.
if (fitType == 0)
meanErr = mean(error,2);
[minErr,bestFit] = min(meanErr);
fitType = bestFit;
end
if (fitType == 1)
fit_out = fit_out1;
x = x1;
fitComment = (sprintf('Simple power function fit, RMSE: %g',...
mean(error(1,:))));
elseif (fitType == 2)
fit_out = fit_out2;
x = x2;
fitComment = (sprintf('Extended power function fit, RMSE: %g',...
mean(error(2,:))));
elseif (fitType == 3)
fit_out = fit_out3;
x = x3;
fitComment = (sprintf('Sigmoidal fit, RMSE: %g',...
mean(error(3,:))));
elseif (fitType == 4)
fit_out = fit_out4;
x = x4;
fitComment = (sprintf('Weibull fit, RMSE: %g',...
mean(error(4,:))));
elseif (fitType == 5)
fit_out = fit_out5;
x = x5;
fitComment = (sprintf('Polynomial fit, RMSE: %g',...
mean(error(5,:))));
elseif (fitType == 6)
fit_out = fit_out6;
x = x6;
fitComment = (sprintf('Linear interpolation fit'));
elseif (fitType == 7)
fit_out = fit_out7;
x = x7;
fitComment = (sprintf('Cubic spline fit'));
end
% Check that fit is non-decreasing
if (CheckMonotonic(fit_out) == 0)
disp('Warning, fit is not non-decreasing');
end
|