0001 function [NF,SE] = calc_noise_figure( inv_model, hp, iterations, extraparam)
0002 
0003 
0004 
0005 
0006 
0007 
0008 
0009 
0010 
0011 
0012 
0013 
0014 
0015 
0016 
0017 
0018 
0019 
0020 
0021 
0022 
0023 
0024 
0025 
0026 
0027 
0028 
0029 
0030 
0031 
0032 
0033 
0034 
0035 
0036 
0037 
0038 
0039 
0040 
0041 
0042 
0043 
0044 
0045 
0046 
0047 
0048 
0049 
0050 
0051 
0052 if ischar(inv_model) && strcmp(inv_model,'UNIT_TEST'), do_unit_test, return, end
0053 
0054 if nargin == 3 && numel(hp) > 1
0055     h_data = hp;
0056     c_data = iterations;
0057     if isstruct(c_data) && strcmp(c_data.type,'data'); 
0058        c_data = c_data.meas;
0059     end
0060 elseif nargin == 3 && isstruct(hp);
0061     if strcmp(hp.type,'data'); 
0062        h_data = hp.meas;
0063     else
0064        error('expecting object of type "data"')
0065     end
0066     c_data = iterations;
0067     if isstruct(c_data) && strcmp(c_data.type,'data'); 
0068        c_data = c_data.meas;
0069     end
0070 elseif nargin == 4
0071 
0072    h_data = hp;
0073    c_data = iterations;
0074    inv_model.hyperparameter.value= extraparam;
0075 elseif nargin>=2 && numel(hp) == 1
0076    inv_model.hyperparameter.value= hp;
0077 
0078    try; inv_model.hyperparameter = rmfield(inv_model.hyperparameter,'func'); end
0079    [inv_model, h_data, c_data] = process_parameters( inv_model );
0080 else
0081    [inv_model, h_data, c_data] = process_parameters( inv_model );
0082 end
0083 
0084 
0085 inv_model.inv_solve.calc_solution_error = false;
0086 
0087 
0088 
0089 if nargin<3; iterations= 10; end
0090 solver = inv_model.solve;
0091 if ischar(solver) && strcmp(solver, 'eidors_default')
0092     solver = eidors_default('get','inv_solve');
0093 end
0094 if isa(solver,'function_handle')
0095     solver = func2str(solver);
0096 end
0097 switch solver
0098     case {'inv_solve_backproj'
0099             'inv_solve_conj_grad'
0100             'inv_solve_diff_GN_one_step'
0101             'inv_solve_trunc_iterative'
0102             'inv_solve_TSVD'
0103             'solve_use_matrix'}
0104         NF = nf_calc_linear( inv_model, h_data, c_data);
0105         SE = 0;
0106     otherwise
0107         [NF,SE]= nf_calc_random( inv_model, h_data, c_data, iterations);
0108 end
0109 eidors_msg('@@ NF= %f', NF, 3);
0110 
0111 function [inv_model, h_data, c_data] = process_parameters( inv_model );
0112 
0113    if     isfield(inv_model.hyperparameter,'tgt_elems')
0114       [h_data, c_data]= simulate_targets( inv_model.fwd_model, ...
0115            inv_model.hyperparameter.tgt_elems);
0116    elseif isfield(inv_model.hyperparameter,'tgt_data')
0117       tgt_data= inv_model.hyperparameter.tgt_data;
0118       h_data= tgt_data.meas_t1;
0119       c_data= tgt_data.meas_t2;
0120    else
0121       error('unsure how to get data to measure signal');
0122    end
0123 
0124    
0125 
0126    if isfield(inv_model.hyperparameter,'func')
0127       funcname= inv_model.hyperparameter.func;
0128       if strcmp( class(funcname), 'function_handle')
0129          funcname= func2str(funcname);
0130       end
0131 
0132       if strcmp(funcname, 'choose_noise_figure')
0133          error('specifying inv_model.hp.func = choose_noise_figure will recurse');
0134       end
0135    end
0136 
0137 function params = nf_calc_linear(imdl, vh, vi )
0138 
0139 
0140 
0141 
0142 
0143 
0144 
0145 
0146 
0147 
0148 if 0 
0149      
0150    Nnoise = 1000;
0151    noise = 0.01*std(vh)*randn(size(vh,1),Nnoise);
0152    vhn= vh*ones(1,Nnoise) + noise;
0153 else 
0154    if isstruct(vh)
0155       vhm = vh.meas;
0156    else
0157       vhm = vh;
0158    end 
0159    noise = 0.01*std(vhm)*speye(size(vhm,1));
0160    vhn= vhm*ones(1,size(vhm,1)) + noise;
0161 end
0162 
0163 signal_y = calc_difference_data( vh, vi,  imdl.fwd_model);
0164 noise_y  = calc_difference_data( vh, vhn, imdl.fwd_model);
0165 
0166 signal_x = inv_solve(imdl, vh, vi);  
0167 signal_x = data_mapper(signal_x); signal_x = signal_x.elem_data;
0168 noise_x  = inv_solve(imdl, vh, vhn); 
0169 noise_x  = data_mapper(noise_x);  noise_x  = noise_x.elem_data;
0170 
0171 use_rec = 1;
0172 try 
0173    use_rec = ~imdl.prior_use_fwd_not_rec;
0174 end
0175 if use_rec
0176    try
0177       VOL = get_elem_volume(imdl.rec_model);
0178    catch
0179       VOL = get_elem_volume(imdl.fwd_model);
0180    end
0181 else
0182    VOL = get_elem_volume(imdl.fwd_model);
0183 end
0184 VOL = spdiags(VOL,0, length(VOL), length(VOL));
0185 
0186 signal_x = VOL*signal_x;
0187 noise_x = VOL*noise_x;
0188 
0189 signal_x = mean(abs(signal_x),1);
0190 noise_x  = mean(std(noise_x));
0191 snr_x = signal_x / noise_x;
0192 
0193 signal_y = mean(abs(signal_y),1);
0194 noise_y  = mean(std(noise_y)); 
0195 snr_y = signal_y / noise_y;
0196 
0197 params= [snr_y(:)./snr_x(:)]';
0198 
0199 try
0200 eidors_msg('@@ NF= %f (hp=%e)', NF, imdl.hyperparameter.value, 2);
0201 end
0202 
0203 
0204 
0205 
0206 
0207 
0208 
0209 
0210 
0211 
0212 
0213 
0214 
0215 
0216 
0217 
0218 
0219    
0220    
0221 function NF= nf_calc_use_matrix( inv_model, h_data, c_data)
0222 
0223 
0224 
0225 
0226 
0227 
0228 
0229 
0230 
0231 
0232 
0233 
0234 
0235 
0236 
0237 
0238 
0239    try 
0240        VOL = get_elem_volume(inv_model.rec_model)';
0241    catch
0242        VOL = get_elem_volume(inv_model.fwd_model)';
0243    end
0244 
0245    
0246    d_len   = size(h_data,1);
0247    delta   = 1e-2* mean(h_data);
0248    c_noise = c_data*ones(1,d_len) + eye(d_len);
0249    h_full  = h_data*ones(1,d_len);
0250 
0251    sig_data = mean(abs( ...
0252          calc_difference_data( h_data, c_data , inv_model.fwd_model ) ...
0253                        ));
0254    var_data = mean(sum( ...
0255          calc_difference_data( h_full, c_noise, inv_model.fwd_model ) ...
0256                        .^2, 2)); 
0257                       
0258 
0259    
0260    
0261    [img0, img0n] = get_images( inv_model, h_data, c_data, ...
0262                                h_full, c_noise);
0263 
0264    i_len = length(img0);
0265    sig_img= VOL*abs(img0) / i_len;;
0266    var_img= VOL.^2*sum(img0n.^2 ,2) / i_len;
0267    
0268    NF = ( sig_data/ sqrt(var_data) ) / ( sig_img / sqrt(var_img)  );
0269 
0270    
0271    
0272    
0273    
0274    
0275    
0276 
0277    
0278 
0279 function [h_data, c_data]= simulate_targets( fwd_model, ctr_elems)
0280 
0281    homg= 1; 
0282 
0283    
0284    sigma= homg*ones( size(fwd_model.elems,1) ,1);
0285 
0286    img= eidors_obj('image', 'homogeneous image', ...
0287                    'elem_data', sigma, ...
0288                    'fwd_model', fwd_model );
0289    h_data=fwd_solve( img );
0290    h_data= h_data.meas;
0291 
0292    
0293    delta = 1e-2;
0294    sigma(ctr_elems) = homg*(1 + delta);
0295    img.elem_data = sigma;
0296    c_data=fwd_solve( img );
0297    c_data= c_data.meas;
0298 
0299 function [img0, img0n] = get_images( inv_model, h_data, c_data, ...
0300                                h_full, c_noise);
0301    if isa(inv_model.solve,'function_handle')
0302       solve= func2str(inv_model.solve);
0303    else
0304       solve= inv_model.solve;
0305    end
0306 
0307 
0308    switch solve
0309    case 'ab_tv_diff_solve'
0310       error('Dont know how to calculate TV noise figure')
0311 
0312    case 'inv_solve_diff_kalman'
0313       inv_model.inv_solve_diff_kalman.keep_K_k1= 1;
0314       stablize = 6;
0315       img0 = inv_solve( inv_model, h_data, ...
0316                                    c_data*ones(1,stablize) );
0317       K= img0.inv_solve_diff_kalman.K_k1;
0318       img0.elem_data = K*calc_difference_data( h_data , c_data , inv_model.fwd_model);
0319       img0n.elem_data= K*calc_difference_data( h_full , c_noise, inv_model.fwd_model);
0320 
0321    otherwise
0322       img0 = inv_solve( inv_model, h_data, c_data);
0323       if nargin>4
0324       img0n= inv_solve( inv_model, h_full, c_noise);
0325       end
0326    end
0327 
0328    
0329    if isfield(img0,'node_data');
0330       img0 = img0.node_data;
0331    else
0332       img0 = img0.elem_data;
0333    end
0334 
0335    if isfield(img0n,'node_data');
0336       img0n = img0n.node_data;
0337    else
0338       img0n = img0n.elem_data;
0339    end
0340 
0341 
0342 function NF= nf_calc_iterate( inv_model, h_data, c_data);
0343    try 
0344        VOL = get_elem_volume(inv_model.rec_model)';
0345    catch
0346        VOL = get_elem_volume(inv_model.fwd_model)';
0347    end
0348    
0349    d_len   = size(h_data,1);
0350    delta   = 1e-2* mean(h_data);
0351    sig_data = mean(abs( ...
0352          calc_difference_data( h_data, c_data , inv_model.fwd_model ) ...
0353                        ));
0354    
0355    
0356 
0357    [img0] = get_images( inv_model, h_data, c_data);
0358 
0359    sig_img= VOL*abs(img0) / length(img0);
0360 
0361    
0362    var_data= 0;
0363    var_img = 0;
0364    for i=1:d_len
0365       this_noise = -ones(d_len, size(c_data,2))/(d_len-1);
0366       this_noise(i,:) = 1;
0367       c_noise = c_data + this_noise;
0368       [imgn] = get_images( inv_model, h_data, c_noise);
0369       if 1
0370          var_data = var_data + mean(sum( ...
0371             calc_difference_data( h_data, c_noise, inv_model.fwd_model ) ...
0372                           .^2, 2)); 
0373 
0374          var_img= var_img +  (VOL.^2)*sum(imgn.elem_data.^2,2 ) / length(imgn.elem_data); 
0375       else
0376          
0377          var_data = var_data + var( ...
0378             calc_difference_data( h_data, c_noise, inv_model.fwd_model ) ...
0379                                  ); 
0380          var_img= var_img + var( VOL'.*imgn.elem_data ); 
0381       end
0382    end
0383    var_data = var_data / d_len;
0384    var_img  = var_img  / d_len;
0385    NF = ( sig_data/ sqrt(var_data) ) / ( sig_img / sqrt(var_img)  );
0386 
0387 function [NF,SE]= nf_calc_random( rec, vh, vi, N_RUNS);
0388    eidors_cache('boost_priority',-2); 
0389 
0390    imgr= inv_solve(rec, vh, vi);
0391 
0392    if isfield(imgr,'node_data');
0393       img0 = imgr.node_data;
0394       try
0395           VOL = get_elem_volume(rec.rec_model, 1);
0396       catch
0397           VOL = get_elem_volume(rec.fwd_model, 1);
0398       end
0399    else
0400       n_els = length(rec.fwd_model);
0401       img0 = imgr.elem_data(1:n_els); 
0402       try
0403           VOL = get_elem_volume(rec.rec_model, 0);
0404       catch
0405           VOL = get_elem_volume(rec.fwd_model, 0);
0406       end
0407    end
0408 
0409    sig_ampl = mean( abs( VOL .* img0 )) / ...
0410               mean( abs( calc_difference_data( vh, vi, rec.fwd_model )));
0411 
0412 
0413    for i=1:N_RUNS
0414       vn= addnoise(vh, vi, 1.0);
0415 
0416       imgr= inv_solve(rec, vh, vn);
0417 
0418       if isfield(imgr,'node_data'); img0 = imgr.node_data;
0419       else;                         img0 = imgr.elem_data(1:n_els);
0420       end
0421 
0422       noi_imag(i) = std( VOL .* img0 );
0423       noi_sgnl(i) = std( calc_difference_data( vh, vn, rec.fwd_model ));
0424    end
0425 
0426    noi_ampl = noi_imag./noi_sgnl;
0427    NF =  mean(noi_ampl/sig_ampl);
0428    SE =  std(noi_ampl/sig_ampl)/sqrt(N_RUNS);
0429    eidors_msg('NF= %f+/-%f', NF, SE, 3);
0430 
0431    eidors_cache('boost_priority',2);
0432 
0433 function noise= addnoise( vh, vi, SNR);
0434       if isstruct(vh); vh= vh.meas; end
0435       if isstruct(vi); vi= vi.meas; end
0436       noise = randn(size(vh));
0437       noise = noise*std(vh-vi)/std(noise);
0438       noise = vh + SNR*noise;
0439 
0440 function do_unit_test
0441     ll = eidors_msg('log_level',1);
0442     test1; 
0443     imdl = mk_common_model('a2t2',16); test2(imdl);
0444     imdl = mk_common_model('d2t2',16); test2(imdl);
0445     imdl = mk_common_model('a2c2',16); test2(imdl);
0446     imdl = mk_common_model('d2c2',16); test2(imdl);
0447     ll = eidors_msg('log_level',ll);
0448 
0449     imdl = mk_common_model('a2c2',16);
0450     img = mk_image(imdl,1); vh=fwd_solve(img);
0451     img.elem_data(1:4)=1.1; vi=fwd_solve(img);
0452     NFREQ = 0.5;
0453     [hpx] = fminbnd(@(hpx) abs(NFREQ -  ...
0454               calc_noise_figure(imdl,vh,vi,10^hpx)), -5,0);
0455     eidors_msg('log_level',ll);
0456 
0457 
0458 function test0
0459     imdl = mk_common_model('a2c2',16);
0460     img = mk_image(imdl,1); vh=fwd_solve(img);
0461     img.elem_data(1:4)=1.1; vi=fwd_solve(img);
0462     NF=calc_noise_figure(imdl,vh,vi);
0463 
0464 function test1
0465     
0466     fmdl = mk_library_model('pig_23kg_16el');
0467     [fmdl.stimulation fmdl.meas_select] = mk_stim_patterns(16,1,'{ad}','{ad}');
0468     fmdl = mdl_normalize(fmdl, 1);  
0469     opt.noise_figure = 0.5; opt.imgsz = [64 64];
0470     imdl = mk_GREIT_model(fmdl, 0.25, [], opt);
0471     
0472     img = mk_image(fmdl,1);
0473     vh = fwd_solve(img);
0474     
0475     select_fcn = inline('(x-0).^2+(y-0).^2+(z-0.5).^2<0.1^2','x','y','z');
0476     mfrac = elem_select(fmdl, select_fcn);
0477     img.elem_data = img.elem_data + mfrac*0.1;
0478     vi = fwd_solve(img);
0479     
0480     nf1 = calc_noise_params(imdl, vh.meas, vi.meas);
0481     
0482     
0483     imdl.hyperparameter.tgt_data.meas_t1 = vh.meas;
0484     imdl.hyperparameter.tgt_data.meas_t2 = vi.meas;
0485     try
0486         
0487         nf2 = calc_noise_figure(imdl);
0488     catch
0489         nf2 = 0;
0490     end
0491     unit_test_cmp('Noise fig implementations',nf1, nf2, 1e-2);
0492 
0493 function test2(imdl)
0494     fmdl = imdl.fwd_model;
0495     
0496     img = mk_image(fmdl,1);
0497     vh = fwd_solve(img);
0498     
0499     select_fcn = inline('(x-0).^2+(y-0).^2.^2<15^2','x','y','z');
0500     mfrac = elem_select(fmdl, select_fcn);
0501     img.elem_data = img.elem_data + mfrac*0.1;
0502     vi = fwd_solve(img);
0503 
0504     nf1 = calc_noise_params(imdl, vh.meas, vi.meas);
0505     eidors_msg(nf1,0);
0506 
0507 imdl.hyperparameter.tgt_data.meas_t1 = vh.meas;
0508 imdl.hyperparameter.tgt_data.meas_t2 = vi.meas;
0509 
0510 nf2 = calc_noise_figure(imdl,[],1000);
0511 unit_test_cmp('Noise fig implementations',nf1, nf2, 1e-2);
0512