Mercurial > hg > ltpda
diff m-toolbox/classes/+utils/@math/linfitsvd.m @ 0:f0afece42f48
Import.
author | Daniele Nicolodi <nicolodi@science.unitn.it> |
---|---|
date | Wed, 23 Nov 2011 19:22:13 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/m-toolbox/classes/+utils/@math/linfitsvd.m Wed Nov 23 19:22:13 2011 +0100 @@ -0,0 +1,213 @@ +% Linear fit with singular value decomposition +% +% INPUT: +% - exps: is a N dimensional struct whose fields are fitdata +% (experimental data), fitbasis (basis for the fit) and params (cell +% array with the names of the parameters used in the experiment). +% - groundexps: a M dim struct containing results from on ground experiments. +% Fuields are: pos (parameter position number), value (on ground measurement +% result) and err (experimental error on the on ground measurement). +% - sThreshold it's a threshold for singular values. It is a +% number, typically 1. It will remove singular values larger +% than sThreshold which corresponds to removing svd parameters estimated +% with an error larger than sThreshold. +% +% OUTPUT: +% a: params values +% Ca: fit covariance matrix for A +% Corra: fit correlation matrix for A +% Vu: is the complete conversion matrix +% Cbu: is the new variables covariance matrix +% Fbu: is the information matrix for the new variable +% mse: is the fit Mean Square Error +% dof: degrees of freedom for the global estimation +% ppm: number of svd parameters per measurements, provides also the +% number of independent combinations of parameters per each singular +% measurement. The coefficients of the combinations are then stored in Vu +% +% 21-07-2009 L Ferraioli +% CREATION +% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% $Id: linfitsvd.m,v 1.8 2010/10/29 12:40:47 ingo Exp $ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [a,Ca,Corra,Vu,bu,Cbu,Fbu,mse,dof,ppm] = linfitsvd(varargin) + + % get inputs + if nargin == 1 % no ground experiment + exps = varargin{1}; + groundexps = []; + remerr = false; + elseif nargin == 2 + exps = varargin{1}; + if isnumeric(varargin{2}) + sThreshold = varargin{2}; + remerr = true; + groundexps = []; + else + groundexps = varargin{2}; + remerr = false; + end + elseif nargin == 3 + exps = varargin{1}; + groundexps = varargin{2}; + sThreshold = varargin{3}; % admitted threshold for singular values + remerr = true; + if ~isnumeric(sThreshold) + sThreshold = inf; + end + end + + % init collect results struct + + % init union matrices + Vu = []; + Fbu = []; + wFbu = []; + bu = []; +% eCbu = []; + Cbu = []; + ppm = []; % number of svd parameters per measurements + + N = numel(exps); + % run over input experiments + for ii=1:N + % get data of the experiments out of the input struct + y = exps(ii).fitdata; + X = exps(ii).fitbasis; + + % willing to work with columns + if size(y,1)<size(y,2) + y = y.'; + end + if size(X,1)<size(X,2) + X = X.'; + end + + % get svd of X + [U,W,V] = svd(X,0); + + % removing zero singular values + svals = diag(W); + idx = svals==0; + svals(idx) = []; + + % removing columns of U and V corresponding to zero svalues + U(:,idx) = []; + V(:,idx) = []; + + if remerr + % Find params combinations with error larger than 1 + idx = svals<sThreshold; + svals(idx) = []; + + % removing columns of U and V corresponding to params combinations with + % error larger than 1 + U(:,idx) = []; + V(:,idx) = []; + end + + % Sanity check + % if svals is empty you are going to gain no information from the + % current data series + if ~isempty(svals) % go with the fit + % rebuild W + W = diag(svals); + + % update ppm with the number of parameters for the given experiment + ppm = [ppm; numel(svals)]; + + % get new basis for the fit + K = U*W; + + % get expected covariance matrix for b, assuming white noise + Fb = W*W; % information matrix for parameters b + + % get b params with errors, mse is the mean square error, Cb is the + % covariance matrix of fitted b. It should be equal to eCb.*mse + [b,stdxb,mseb,Cb] = lscov(K,y); + + % information matrix weighted for fit results Cb = inv(wFb) + wFb = Fb./mseb; + + % add params from present experiment + % get union matrices + Vu = [Vu;V.']; + Fbu = blkdiag(Fbu,Fb); + wFbu = blkdiag(wFbu,wFb); + Cbu = blkdiag(Cbu,Cb); + bu = [bu;b]; + + else % no information, no fit + % update ppm with the number of parameters for the given experiment + ppm = [ppm; 0]; + end + + + + end + + % insert values from on-ground measured parameters if applicable + if nargin == 2 + + for jj = 1:numel(groundexps) + + % get values + pos = groundexps(jj).pos; + val = groundexps(jj).value; + err = groundexps(jj).err; + + tV = zeros(1,size(Vu,2)); + tV(1,pos) = 1; + Vu = [Vu;tV]; + bu = [bu;val]; + Cbu = blkdiag(Cbu,err^2); + Fbu = blkdiag(Fbu,1/(err^2)); + wFbu = blkdiag(wFbu,1/(err^2)); + ppm = [ppm; 1]; + + end + + end + + % get results on physical parameters, solve the system with proper weights + a = lscov(Vu,bu,1./diag(Cbu)); + + % get params covariance + Ca = inv(Vu'*wFbu*Vu); + + % get params correlation matrix + Corra = Ca; + for tt=1:size(Corra,1) + for hh=1:size(Corra,2) + Corra(tt,hh) = Ca(tt,hh)/(sqrt(Ca(tt,tt))*sqrt(Ca(hh,hh))); + end + end + + % get chi square assuming unitary variance white noise + N = numel(exps); + mse = 0; + tL = 0; + % run over input experiments + for ii=1:N + % get data of the experiments out of the input struct + y = exps(ii).fitdata; + X = exps(ii).fitbasis; + + mse = mse + sum((y - X*a).^2); + tL = tL + numel(y); + end + dof = tL-numel(a); + mse = mse./dof; + +end + + + + + + + + +