function [struct_irf_record, D_record, gamma_record]=irfsignrespanel(beta_gibbs,sigma_gibbs,It,Bu,IRFperiods,n,p,m,k,signrestable,signresperiods)

% function [struct_irf_record D_record gamma_record]=irfsignrespanel(sigma_gibbs,irf_record,It,Bu,IRFperiods,n,signrestable,signresperiods,checkalgo,checkiter)
% runs the gibbs sampler to obtain draws from the posterior distribution of
% IRFs, orthogonalised with sign restrictions
% inputs:  - matrix'sigma_gibbs': record of the gibbs sampler draws for the sigma matrix (vectorised)
%          - cell 'irf_record': record of the gibbs sampler draws for the IRFs
%          - integer 'It': total number of iterations of the Gibbs sampler (defined p 28 of technical guide)
%          - integer 'Bu': number of burn-in iterations of the Gibbs sampler (defined p 28 of technical guide)
%          - integer 'IRFperiods': number of periods for IRFs
%          - integer 'n': number of endogenous variables in the BVAR model (defined p 7 of technical guide)
% outputs: - cell 'struct_irf_record': record of the gibbs sampler draws for the orthogonalised IRFs
%          - matrix 'D_record': record of the gibbs sampler draws for the structural matrix D
%          - matrix 'gamma_record': record of the gibbs sampler draws for the structural disturbances variance-covariance matrix gamma

% this function implements the sign restrictions approach for the panel

% preliminary tasks
% create first the cell that will store the results from the simulations
struct_irf_record=cell(n,n);
% storage cell
storage1=cell(It-Bu,1);
storage2=cell(It-Bu,1);

% now identify all the periods concerned with restrictions
% first expand the non-empty entries in signresperiods since they are only expressed in intervals: transform into list
% for instance, translate [1 4] into [1 2 3 4]; I don't think this can done without a loop
temp=cell2mat(signresperiods(~cellfun(@isempty,signresperiods)));
periods=[];
for ii=1:size(temp,1)
    periods=[periods temp(ii,1):temp(ii,2)];
end
% suppress duplicates and sort
periods=sort(unique(periods))';
% count the total number of restriction periods (required for IRF matrix)
nperiods=size(periods,1);

% Identify the restriction matrices
% create five cells, corresponding to the three possible restrictions:
% one cell for sign restrictions, three cells for magnitude restrictions, one cell for zero restrictions
Scell=cell(1,n);
Mcell=cell(1,n);
Mlcell=cell(1,n);
Mucell=cell(1,n);
Zcell=cell(1,n);

% loop over rows and columns of the period matrix
for ii=1:n
    for jj=1:n
        % if entry (ii,jj) of the period matrix is not empty...
        if ~isempty(signresperiods{ii,jj})
            % ... then there is a restriction over one (or several) periods
            % loop overt those periods
            for kk=signresperiods{ii,jj}(1,1):signresperiods{ii,jj}(1,2)
                % identify the position of the considered period within the list of all periods (required to build the matrix)
                position=find(periods==kk);
                % now create the restriction matrix: this will depend on the type of restriction
                % if it is a positive sign restriction...
                if strcmp(signrestable{ii,jj},'+')
                    % ... then input a 1 entry in the corresponding S matrix
                    Scell{1,jj}=[Scell{1,jj};zeros(1,n*nperiods)];
                    Scell{1,jj}(end,(position-1)*n+ii)=1;
                    % if it is a negative sign restriction...
                elseif strcmp(signrestable{ii,jj},'-')
                    % ... then input a -1 entry in the corresponding S matrix
                    Scell{1,jj}=[Scell{1,jj};zeros(1,n*nperiods)];
                    Scell{1,jj}(end,(position-1)*n+ii)=-1;
                    % if it is a zero restriction...
                elseif strcmp(signrestable{ii,jj},'0')
                    % ... then input a 1 entry in the corresponding Z matrix
                    Zcell{1,jj}=[Zcell{1,jj};zeros(1,n*nperiods)];
                    Zcell{1,jj}(end,(position-1)*n+ii)=1;
                    % else, a non-empty entry being neither a sign nor a zero restriction has to be a magnitude restriction
                else
                    % fill the corresponding M matrices:
                    % input a 1 in M
                    Mcell{1,jj}=[Mcell{1,jj};zeros(1,n*nperiods)];
                    Mcell{1,jj}(end,(position-1)*n+ii)=1;
                    % input the lower value of the interval in Ml
                    temp=str2num(signrestable{ii,jj});
                    Mlcell{1,jj}=[Mlcell{1,jj};temp(1,1)];
                    % input the upper value of the interval in Mu
                    Mucell{1,jj}=[Mucell{1,jj};temp(1,2)];
                end
            end
        end
    end
end

% now check what kind of restrictions apply among sign, zero and magnitude restrictions
% check for sign restrictions: if there are any, at least one entry in the cell Scell is non-empty
if sum(~cellfun(@isempty,Scell))~=0
    signres=1;
else
    signres=0;
end
% similarly check for zero restrictions
if sum(~cellfun(@isempty,Zcell))~=0
    zerores=1;
else
    zerores=0;
end
% and finally, check for magnitude restrictions
if sum(~cellfun(@isempty,Mcell))~=0
    magnres=1;
else
    magnres=0;
end

hbar = bear.parfor_progressbar(It-Bu,'Progress');  %create the progress bar

% step 1: repeat simulations a number of times equal to the number of simulations retained from Gibbs sampling
parfor ii=1:It-Bu
    % initiate the variable 'success'; this variable will be used to check whether the restrictions are satisfied
    % if there are only zero restrictions, they will be satisfied by construction, and 'success' will simply be ignored
    success=0;
    % how the algorithm will be conducted will depend on the types of restrictions implemented

    % if there are only zero restrictions, the algorithm is simple as no checking is required: the conditions are satisfied by construction
    if zerores==1 && signres==0 && magnres==0
        % draw beta and sigma
        beta=beta_gibbs(:,ii);
        sigma=reshape(sigma_gibbs(:,ii),n,n);
        hsigma=chol(bear.nspd(sigma),'lower');
        % obtain orthogonalised IRFs
        [irfmatrix, ortirfmatrix]=bear.irfsim(beta,hsigma,n,m,p,k,max(IRFperiods,max(periods)));
        % generate the stacked IRF matrix
        stackedirfmat=[];
        for jj=1:numel(periods)
            stackedirfmat=[stackedirfmat;ortirfmatrix(:,:,periods(jj,1)+1)];
        end
        % draw an entire random matrix Q satisfying the zero restrictions
        [Q]=bear.qzerores(n,Zcell,stackedirfmat);
        % there is no need to verify the restrictions: there are satisfied by construction

        % if there are sign/magnitude restrictions, possibly associated with zero restrictions
    else
        % the algorithm becomes a bit more complicated as conditions now need to be checked
        % to maintain efficiency, the algorithm proceeds recursively shock by shock, and stops as soon as a condition on the considered shock fails
        % repeat algorithm for the iteration as long as not all conditions are satisfied
        while success==0
            % switch 'success' to 1; it will be turned back to zero if at any time Q is detected as a candidate not satisfying the restrictions
            success=1;
            % draw randomly the vector of VAR coefficients: draw a random index
            index=floor(rand*(It-Bu))+1;
            % then draw a random set of beta and sigma corresponding to this index (this is done to make it possible to draw, if required, an infinite number of values from the gibbs sampler record, with equal probability on each value)
            beta=beta_gibbs(:,index);
            sigma=reshape(sigma_gibbs(:,index),n,n);
            hsigma=chol(bear.nspd(sigma),'lower');
            % obtain orthogonalised IRFs
            [irfmatrix, ortirfmatrix]=bear.irfsim(beta,hsigma,n,m,p,k,max(IRFperiods,max(periods)));
            % generate the stacked IRF matrix
            stackedirfmat=[];
            for jj=1:numel(periods)
                stackedirfmat=[stackedirfmat;ortirfmatrix(:,:,periods(jj,1)+1)];
            end
            % initiate Qj
            Qj=[];
            % now start looping over the shocks and checking sequentially whether conditions on these shocks hold
            % stop as soon as one restriction fails
            kk=1;
            while success==1 && kk<=n
                % build column j of the random matrix Q
                [qj]=bear.qrandj(n,Zcell{1,kk},stackedirfmat,Qj);
                % obtain the candidate column fj
                fj=stackedirfmat*qj;
                % check restrictions: first sign restrictions
                [success qj]=bear.checksignres(Scell{1,kk},qj,fj);
                % if 'success' is still equal to 1, also check for magnitude restrictions
                if success==1
                    [success]=bear.checkmagres(Mcell{1,kk},Mlcell{1,kk},Mucell{1,kk},fj);
                end
                % also, if 'success' is still equal to 1, update Qj by concatenating qj
                if success==1
                    Qj=[Qj qj];
                end
                kk=kk+1;
            end
            % repeat this loop until a succesful draw is obtained
        end
        % with succesful Qj at hand, eventually set Q as Qj
        Q=Qj;
    end

    % store
    for jj=1:IRFperiods
        storage1{ii,1}(:,:,jj)=ortirfmatrix(:,:,jj)*Q;
    end
    storage2{ii,1}=hsigma*Q;

    hbar.iterate(1);   % update progress by one iteration

end

close(hbar);   %close progress bar

% reorganise storage
% loop over iterations
for ii=1:It-Bu
    % loop over IRF periods
    for jj=1:IRFperiods
        % loop over variables
        for kk=1:n
            % loop over shocks
            for ll=1:n
                struct_irf_record{kk,ll}(ii,jj)=storage1{ii,1}(kk,ll,jj);
            end
        end
    end
    D_record(:,ii)=storage2{ii,1}(:);
    gamma_record(:,ii)=bear.vec(eye(n));
end


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% To run:  Edit user options in mtfcalc.m and execute the code.
%
% This code is intended to accompany the paper:
%
% S. N. Friedman, G. S. K. Fung, J. H. Siewerdsen, and B. M. W. Tsui.  "A
% simple approach to measure computed tomography (CT) modulation transfer
% function (MTF) and noise-power spectrum (NPS) using the American College
% of Radiology (ACR) accreditation phantom," Med. Phys. 40, 051907-1 -
% 051907-9 (2013).
% http://dx.doi.org/10.1118/1.4800795
%
% This code is free to distribute (see below).
%
% This program requires the following 2 files:
%   mtfcalc.m
%   license.txt
%
% Purpose:  To calculate the 1D radial (axial) MTF using CT data of the
%           American College of Radiology (ACR) accreditation phantom.
%
% Input:    Two consecutive scans of the phantom are needed.  The program
%           requires a data directory to be selected in which there are
%           only two subdirectories containing only CT slices corresponding
%           to the third module of the phantom.  Be careful of partial
%           volume effects with surrounding modules.
%
%           i.e.,  datadir
%                      |-> scan 1 dir
%                      |           | -> only module 3 slices
%                      |
%                      |-> scan 2 dir
%                                  |-> only module 3 slices
%
% Copyright 2012 Saul N. Friedman
%   Distributed under the terms of the "New BSD License."  Please see
%   license.txt.
%
% N.B.:  This code assumed the data are already organized such that only
%        relevant axial slices are contained within the data directory.
%        ESF = edge spread function
%        LSF = line spread function
%        MTF = modulation transfer function
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

close all;
clear all;
clc;

fprintf('****************************************************************************\n');
fprintf('CT MTF Calculation\n\n')
fprintf('This code is intended to accompany the paper:\n');
fprintf('S. N. Friedman, G. S. K. Fung, J. H. Siewerdsen, and B. M. W. Tsui.  "A\n')
fprintf('simple approach to measure computed tomography (CT) modulation transfer \n')
fprintf('function (MTF) and noise-power spectrum (NPS) using the American College \n')
fprintf('of Radiology (ACR) accreditation phantom," Med. Phys. 40, 051907-1 - \n')
fprintf('051907-9 (2013).\n')
fprintf('http://dx.doi.org/10.1118/1.4800795\n\n')
fprintf('This code can be freely distributed.  Please see license.txt for details.\n');
fprintf('****************************************************************************\n\n');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% User selected options
%

selectdir = 1;   % 1 = prompt for directly locations via dialogue box, 0 = hardcode locations below
    datadir = fullfile('data');
    resultsdir = fullfile('results',datadir);

saveresults = 1;  % Choose whether to save the calculated MTF to disk in text files

showfig = 3;  % decide how important a figure should be in order to be plotted, 1 = no figures, 4 = all figures

rstep = 0.1; %  Choose bin size in mm (i.e., effective pixel size) for oversampled edge spread function (ESF)

window = 1;  % Decide whether to apply a Hann window to the LSF before calculating the MTF (typically applied)

% Background and foreground values:  1 = prompted to draw rectangle to select ROI, 0 = use values below
manualROI = 1;
   % box border for background ROI in pixels
   BGxROI1 = 1;
   BGxROI2 = 100;
   BGyROI1 = 1;
   BGyROI2 = 100;

   % box border for foreground ROI in pixels
   FGxROI1 = 205;
   FGxROI2 = 305;
   FGyROI1 = 208;
   FGyROI2 = 308;

% 2D map of good pixels (1) and bad pixels (0) to use in calculation
% 1 = prompted to draw rectangle(s) to select ROI(s), 0 = use values below
manualmask = 1;
selectmask = 1; %prompt for image to use when creating data mask (only applicable if manualmask = 1)
    mask = ones(512,512);
    mask(450:512,1:125) = 0;
    mask(450:512,400:512) = 0;
    mask(400:425,84:105) = 0;
    mask(410:430,400:420) = 0;
    mask(220:230,279:288) = 0;
    mask(371:381,138:147) = 0;

% Determine which angles of data to use in radians (-pi to pi to use all)
thlim1 = -pi;
thlim2 = pi;

%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Start of analysis code
%

homedr = cd;

if selectdir ==1
    fprintf('Select the data directory.\n\n');
    datadir = uigetdir(homedr,'Pick data directory');
    if saveresults == 1
        fprintf('Select the results directory.\n\n');
        resultsdir = uigetdir(homedr,'Pick results directory');
    end
else
    datadir = fullfile(homedr,datadir);
    resultsdir = fullfile(homedr,resultsdir);
end

if saveresults == 1
    mkdir(resultsdir)
end

cd(datadir)

scandir = dir;

cd(homedr)

while or(strcmp(scandir(1).name,'.'),strcmp(scandir(1).name,'..'))
    scandir = scandir(2:end);
end

Nscan = size(scandir,1);
Nscan = 1;

nfilescheck = 0;

for i = 1:Nscan
    cd(fullfile(datadir,scandir(i).name))

    % get list of filenames

    ffiles = dir;

    cd(homedr)

    while or(strcmp(ffiles(1).name,'.'),strcmp(ffiles(1).name,'..'))
        ffiles = ffiles(2:end);
    end

    Nz = size(ffiles,1);

     if nfilescheck ~= Nz && nfilescheck ~=0
        fprintf('Error.  Scan directories do not contain the same number of slices.\n')
        return
    end

    nfilescheck = Nz;

    if i == 1

        % Read DICOM header info and determine correct mapping function to get HU
        % values as well as voxel sizes.

        im = single(dicomread(fullfile(datadir,scandir(i).name,ffiles(1).name)));

        imheader = dicominfo(fullfile(datadir,scandir(i).name,ffiles(1).name));

        b = imheader.RescaleIntercept;
        m = imheader.RescaleSlope;

        im = im.* m + b;

        pixelx = imheader.PixelSpacing(1);
        pixely = imheader.PixelSpacing(2);
        pixelz = imheader.SliceThickness;

        if showfig > 2
            figure
            imagesc(im)
            colormap gray
            hold on
            axis image;
            impixelinfo;
        end

        Nx = size(im,2);
        Ny = size(im,1);

        imaxisx = [1:Nx] .* pixelx;
        imaxisy = [1:Ny] .* pixely;

        imavg = zeros(Ny,Nx);
        im3D = zeros(Ny,Nx,Nz);
    end

    % Load data into memory and calculate an average 2D image to later
    % determine phantom location

    for z = 1:Nz
        im = single(dicomread(fullfile(datadir,scandir(i).name,ffiles(z).name)));
        im = im.* m + b;
        im3D(:,:,z,i) = im;
        imavg = imavg + im;
    end

end

imavg = imavg ./(Nz*Nscan);

if selectmask == 1 && manualmask == 1
    fprintf('Select the DICOM image to use for mask creation.\n\n');
    [imfile impath] = uigetfile('*','Pick a DICOM image to use for mask creation',datadir);
    if isequal(imfile,0) || isequal(impath,0)
        im = imavg;
    else
        im = single(dicomread(fullfile(impath,imfile)));
        im = im.* m + b;
    end
else
    im = imavg;
end

% Plot sample slice.  Use to create mask image if set to manual selection.

imaxisx = [1:size(im,2)] .* pixelx;
imaxisy = [1:size(im,1)] .* pixely;

if showfig > 3 || manualmask == 1
    figure
    imagesc(im)
    xlabel('pixel')
    ylabel('pixel')
    colormap gray
    hold on
    axis image;
    impixelinfo;
end

if manualmask ==1

    mask = ones(size(im));

    selectROI = 1;

    fprintf('Select the ROIs corresponding to bad data.\n\n');

    while selectROI == 1
        choice = menu('Select additional ROI of bad data?','Yes','No');

        if choice == 2
            selectROI = 0;
            hold off
        else
            h = imrect;
            ptmask = wait(h);

            maskx1 = round(ptmask(1));
            maskx2 = maskx1 + round(ptmask(3));
            masky1 = round(ptmask(2));
            masky2 = masky1 + round(ptmask(4));

            % force selected ROI to be within the bounds of the image
            maskx1 = min(maskx1,size(im,2));
            maskx2 = min(maskx2,size(im,2));
            masky1 = min(masky1,size(im,1));
            masky2 = min(masky2,size(im,1));
            maskx1 = max(maskx1,1);
            maskx2 = max(maskx2,1);
            masky1 = max(masky1,1);
            masky2 = max(masky2,1);

            mask(masky1:masky2,maskx1:maskx2) = 0;

            plot([maskx1,maskx2,maskx2,maskx1,maskx1],[masky1,masky1,masky2,masky2,masky1],'r-')
        end
    end
end

% Plot mask image overlying sample image to verify mask

if showfig > 3
    figure
    imagesc([imaxisy(1) imaxisy(end)],[imaxisx(1) imaxisx(end)],(im+100).*mask)
    xlabel('mm')
    ylabel('mm')
    colormap gray
    hold on
    axis image;
    impixelinfo;
end

% Show averaged image if desired or needed

if showfig > 2 || manualROI == 1
    figure
    imagesc(imavg)
    xlabel('pixel')
    ylabel('pixel')
    colormap gray
    hold on
    axis image;
    impixelinfo;
end

% Determine background and foreground values to properly normalized the
% data to range [0,1]

if manualROI == 1
    fprintf('Click and drag to create a rectangular ROI representing the background.  Double click the ROI when finished.\n\n');

    h = imrect;
    ptROI = wait(h);

    BGxROI1 = round(ptROI(1));
    BGxROI2 = BGxROI1 + round(ptROI(3));
    BGyROI1 = round(ptROI(2));
    BGyROI2 = BGyROI1 + round(ptROI(4));

    % force selected ROI to be within the bounds of the image
    BGxROI1 = min(BGxROI1,size(im,2));
    BGxROI2 = min(BGxROI2,size(im,2));
    BGyROI1 = min(BGyROI1,size(im,1));
    BGyROI2 = min(BGyROI2,size(im,1));
    BGxROI1 = max(BGxROI1,1);
    BGxROI2 = max(BGxROI2,1);
    BGyROI1 = max(BGyROI1,1);
    BGyROI2 = max(BGyROI2,1);
end

BGvalue = mean(mean(imavg(BGyROI1:BGyROI2,BGxROI1:BGxROI2)));

if manualROI == 1
    fprintf('Click and drag to create a rectangular ROI representing the foreground.  Double click the ROI when finished.\n\n');

    h = imrect;
    ptROI = wait(h);

    FGxROI1 = round(ptROI(1));
    FGxROI2 = FGxROI1 + round(ptROI(3));
    FGyROI1 = round(ptROI(2));
    FGyROI2 = FGyROI1 + round(ptROI(4));

    % force selected ROI to be within the bounds of the image
    FGxROI1 = min(FGxROI1,size(im,2));
    FGxROI2 = min(FGxROI2,size(im,2));
    FGyROI1 = min(FGyROI1,size(im,1));
    FGyROI2 = min(FGyROI2,size(im,1));
    FGxROI1 = max(FGxROI1,1);
    FGxROI2 = max(FGxROI2,1);
    FGyROI1 = max(FGyROI1,1);
    FGyROI2 = max(FGyROI2,1);
end

FGvalue = mean(mean(imavg(FGyROI1:FGyROI2,FGxROI1:FGxROI2)));

if or(showfig > 2,manualROI ==1)
    plot([BGxROI1,BGxROI2,BGxROI2,BGxROI1,BGxROI1],[BGyROI1,BGyROI1,BGyROI2,BGyROI2,BGyROI1],'r-')
    plot([FGxROI1,FGxROI2,FGxROI2,FGxROI1,FGxROI1],[FGyROI1,FGyROI1,FGyROI2,FGyROI2,FGyROI1],'r-')
    hold off
end

% Normalize averaged image such that values are [0,1]

imavg = (imavg - BGvalue) ./ (FGvalue - BGvalue);

if showfig > 2
    figure
    imagesc([imaxisy(1) imaxisy(end)],[imaxisx(1) imaxisx(end)],imavg)
    xlabel('mm')
    ylabel('mm')
    title('averaged and normalized image')
    colormap gray
    hold on
    axis image;
    impixelinfo;
end

% Determine which pixels correspond to the phantom cylinder

imlog = zeros(size(imavg));

level = graythresh(imavg);
imlog = im2bw(imavg,level);

% Calculate the center of the cylinder

fprintf('Calculating the center of the phantom and determining phantom-pixel locations.\n\n');

if exist('bwconncomp')==2
    CC = bwconncomp(imlog,26);
    for i = 1:CC.NumObjects;
        Lobj(i) =  length(CC.PixelIdxList{1,i}) ;
    end
else
    [CC CCn] = bwlabel(imlog,8);
    for i = 1:CCn
        Lobj(i) = length(find(CC == i));
    end
end

L = find(Lobj == max(Lobj));

S = regionprops(CC,'Centroid');

c.y = S(L).Centroid(2);
c.x = S(L).Centroid(1);

if showfig>2
    figure
    imagesc([imaxisy(1) imaxisy(end)],[imaxisx(1) imaxisx(end)],imlog)
    xlabel('mm')
    ylabel('mm')
    title('Cylinder with center marked')
    colormap gray
    hold on
    axis image;
    impixelinfo;
    if exist('bwconncomp')==2
        [I J] = ind2sub(size(imavg),CC.PixelIdxList{1,L});
    else
        [I,J] = find(CC == L);
    end
    plot(J*pixely,I.*pixelx,'.r')
    plot(c.x*pixelx,c.y*pixely,'*y')
    hold off
end

xaxis = ([1:size(imavg,2)] - c.x) .* pixelx;
yaxis = ([1:size(imavg,1)] - c.y) .* pixely;

% Convert all image coords to polar coords with origin at center of the
% cylinder

r = zeros(size(imavg));
th = zeros(size(imavg));

for i = 1 :size(imavg,2)
    for j = 1 : size(imavg,1)
        %         r(j,i) = sqrt(xaxis(i).^2 + yaxis(j).^2);
        %         th(j,i) = atan2(yaxis(j),xaxis(i));
        [th(j,i) r(j,i)] = cart2pol(xaxis(i),yaxis(j));
    end
end

% Create oversampled ESF excluding data specified in mask

rmax = max(max(r));

esf = zeros(ceil(rmax/rstep)+1,1);
nsamp = zeros(length(esf),1);

rbin = 0:rstep:rmax+rstep;

if showfig > 3
    figure
    imagesc((imavg+1).*mask)
    colormap gray
    hold all
    axis image;
    impixelinfo;
end

% data with radius falling within a given bin are averaged together for a
% low noise approximation of the ESF at the given radius

fprintf('Calculating the MTF.\n');
fprintf('The may take several minutes. \n');
fprintf('Please be patient.\n\n');

thlim1 = min(thlim1,thlim2);
thlim2 = max(thlim1,thlim2);

for i = 1:length(rbin)
    R1 = find(r >= rbin(i));
    R2 = find(r < rbin(i) + rstep);
    R3 = intersect(R1,R2);
    R4 = find(th >= thlim1);
    R5 = find(th < thlim2);
    R6 = intersect(R5,R4);
    R7 = intersect(R3,R6);
    R8 = R7.*mask(R7);
    R=R8(R8~=0);
    if showfig > 3
        [X Y] = ind2sub(size(imavg),R);
        plot(Y,X,'.')
        hold all
    end
    esf(i) = sum(imavg(R));
    nsamp(i) = length(R);
end

i1 = find(nsamp,1,'first');
i2 = find(nsamp,1,'last');
nsamp = nsamp(i1:i2);
esf = esf(i1:i2);
rbin = rbin(i1:i2);

I = find(nsamp > 0);
esf(I) = esf(I)./nsamp(I);

% Plot oversampled ESF
if showfig > 2
    figure
    plot(rbin,esf)
    xlabel('radius (mm)')
    ylabel('normalized + oversampled ESF')
    grid on
    axis([rbin(1) rbin(end) -1.2*min(esf) 1.1*max(esf)])
end

% Calculated the LSF from the ESF
lsf = diff(esf);

% artifacts caused by empty bins likely have a value of -/+ 1, so try to
% remove them.
I = find(abs(lsf)> 0.9);
lsf(I) = 0;

if max(lsf) < max(abs(lsf))
    lsf = -lsf;
end

maxlsf = max(lsf);

rcent = find(lsf == maxlsf);
lsfaxis = rbin(1:end-1) - rbin(rcent);

% Center edge location in LSF and keep surrounding data range specified by
% pad.  N.B. data from regions greater than the FOV is removed in
% this manner.
pad = round(length(lsfaxis)/5);
lsfaxis = lsfaxis(rcent-pad:rcent+pad);
lsf = lsf(rcent-pad:rcent+pad);

nlsf = length(lsf);

%calculate Hann window and apply to data if specified.
if window == 1
    w = 0.5 .* (1 - cos(2*pi*[1:length(lsfaxis)]./length(lsfaxis)));
    w = w';
else
    w = ones(length(lsfaxis),1);
end
lsfw = lsf .* w;

% Plot windowed LSF and scaled window together
if showfig > 1
    figure
    plot(lsfaxis,lsfw)
    hold on
    plot(lsfaxis,w.*max(lsfw),'r--')
    hold off
    legend('oversampled + normalized LSF','scaled Hann window')
    xlabel('radius (mm)')
    ylabel('signal')
    axis([lsfaxis(1) lsfaxis(end) 1.1*min(lsfw) 1.1*max(lsfw)])
    grid on
end

% Calculate the MTF from the LSF

T = fftshift(fft(lsfw));
faxis = ([1:nlsf]./nlsf - 0.5) ./ rstep;

MTF = abs(T);

%Plot the MTF
if showfig > 1
    figure
    plot(faxis,MTF,'.-')
    xlabel('spatial frequency (mm^{-1})');
    ylabel('MTF_r')
    axis([0 max(faxis) 0 1.1*max(MTF)])
    grid on
end

fprintf('MTF calculated.\n\n');

% Save MTF results if indicated
if saveresults == 1
    save(fullfile(resultsdir,'axisvalues.txt'),'faxis','-ASCII')
    save(fullfile(resultsdir,'MTFvalues.txt'),'MTF','-ASCII')
    fprintf('Results saved.\n\n');
end

return;
%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


classdef VehicleArticulatedNonlinear < VehicleDynamicsLateral.VehicleArticulated
    % VehicleArticulatedNonlinear Nonlinear articulated vehicle model.
    %
    % It inherits properties from VehicleArticulated.

    methods
        % Constructor
        function self = VehicleArticulatedNonlinear()
            self.mF0    = 5200;    % Mass at front axle of the tractor without semi-trailer [kg]
            self.mR0    = 2400;    % Mass at rear axle of the tractor without semi-trailer [kg]
            self.mF     = 6000;    % Mass at front axle of the tractor with semi-trailer [kg]
            self.mR     = 10000;   % Mass at rear axle of the tractor with semi-trailer [kg]
            self.mM     = 17000;   % Mass at the axle of the semi-trailer [kg]
            self.IT     = 46000;   % Moment of inertia of the tractor [kg.m2]
            self.IS     = 450000;  % Moment of inertia of the semi-trailer [kg.m2]
            self.lT     = 3.5;     % Wheelbase of the tractor [m]
            self.lS     = 7.7;     % Distance from articulation (fifth wheel) to semi-trailer axle [m]
            self.c      = -0.3;    % Position of articulation (fifth wheel) to semi-trailer axle [m]
            self.nF     = 2;       % Number of wheels at front axle
            self.nR     = 4;       % Number of wheels at rear axle
            self.nM     = 8;       % Number of wheels at semi-trailer axle
            self.wT     = 2.6;     % Tractor width [m]
            self.wS     = 2.4;     % Semi-trailer width [m]
            self.muy    = 0.3;     % Friction
            self.deltaf = 0;       % Steering angle front [rad]
            self.deltar = 0;       % Steering angle rear [rad]
            self.deltam = 0;       % Steering angle semi-trailer [rad]
            self.Fxf    = 0;       % Longitudinal force at front axle [N]
            self.Fxr    = 0;       % Longitudinal force at rear axle [N]
            self.Fxm    = 0;       % Longitudinal force at semi-trailer axle [N]
        end

        function dx = Model(self,t, states,tspan)
            % dx = VehicleModel.Model(t,states,tspan)
            % dx = VehicleModel.MassMatrix(t,states,tspan)
            %
            % Sintax
            % |dx = _VehicleModel_.Model(t,states,tspan)|
            %
            % |dx = _VehicleModel_.MassMatrix(t,states,tspan)|
            %
            % Arguments
            % The following table describes the input arguments:
            %
            % t - Time
            % states - Model state variables: [XT YT PSI PHI VT ALPHAT dPSI dPHI]
            % tspan - Time span

            % Vehicle parameters
            mT  = self.mT;
            mS  = self.mS;
            % IT = self.IT;
            % IS = self.IS;
            a   = self.a;
            b   = self.b;
            c   = self.c;
            d   = self.d;
            e   = self.e;
            nF  = self.nF;
            nR  = self.nR;
            nM  = self.nM;

            g = 9.81;

            FzF = self.mF * g;
            FzR = self.mR * g;
            FzM = self.mM * g;
            muy = self.muy;

            % States
            X       = states(1,1);
            Y       = states(2,1);
            PSI     = states(3,1);
            PHI     = states(4,1);
            VT      = states(5,1);
            ALPHAT  = states(6,1);
            dPSI    = states(7,1);
            dPHI    = states(8,1);

            if isa(self.deltaf,'function_handle')
                % Closed loop steering
                deltaf = self.deltaf([X;Y;PSI;PHI;VT;ALPHAT;dPSI;dPHI],t);
            elseif length(self.deltaf)>1
                % Open loop variable steering
                deltaf = interp1(tspan,self.deltaf,t);
            else
                % Open loop single value steering
                deltaf = self.deltaf;
            end

            if isa(self.deltar,'function_handle')
                % Closed loop steering
                deltar = self.deltar([X;Y;PSI;PHI;VT;ALPHAT;dPSI;dPHI],t);
            elseif length(self.deltar)>1
                % Open loop variable steering
                deltar = interp1(tspan,self.deltar,t);
            else
                % Open loop single value steering
                deltar = self.deltar;
            end

            if isa(self.deltam,'function_handle')
                % Closed loop steering
                deltam = self.deltam([X;Y;PSI;PHI;VT;ALPHAT;dPSI;dPHI],t);
            elseif length(self.deltam)>1
                % Open loop variable steering
                deltam = interp1(tspan,self.deltam,t);
            else
                % Open loop single value steering
                deltam = self.deltam;
            end

            % Slip angles
            ALPHAF = - deltaf + atan2(a*dPSI + VT*sin(ALPHAT), VT*cos(ALPHAT));
            ALPHAR = - deltar + atan2(VT*sin(ALPHAT) - b*dPSI, VT*cos(ALPHAT));
%           ALPHAM = atan2(((d + e)*(dPHI - dPSI) + VT * sin(ALPHAT + PHI) - b * dPSI * cos(PHI) - c * dPSI * cos(PHI)),(VT * cos(ALPHAT + PHI) + b * dPSI * sin(PHI) + c * dPSI * sin(PHI)));
            ALPHAM = - deltam + atan2((d + e)*(dPHI - dPSI) + VT*sin(ALPHAT + PHI) - dPSI*cos(PHI)*(b + c), VT*cos(ALPHAT + PHI) + dPSI*sin(PHI)*(b + c));
            % Longitudinal forces
            % Front
            if isa(self.Fxf,'function_handle')
                FxF = self.Fxf([X;Y;PSI;PHI;VT;ALPHAT;dPSI;dPHI],t);
            elseif length(self.Fxf)>1
                FxF = interp1(tspan,self.Fxf,t);
            else
                FxF = self.Fxf;
            end
            % Rear
            if isa(self.Fxr,'function_handle')
                FxR = self.Fxr([X;Y;PSI;PHI;VT;ALPHAT;dPSI;dPHI],t);
            elseif length(self.Fxr)>1
                FxR = interp1(tspan,self.Fxr,t);
            else
                FxR = self.Fxr;
            end
            % Semitrailer
            if isa(self.Fxm,'function_handle')
                FxM = self.Fxm([X;Y;PSI;PHI;VT;ALPHAT;dPSI;dPHI],t);
            elseif length(self.Fxm)>1
                FxM = interp1(tspan,self.Fxm,t);
            else
                FxM = self.Fxm;
            end

            % Lateral forces
            FyF = nF * self.tire.Characteristic(ALPHAF, FzF/nF, muy);
            FyR = nR * self.tire.Characteristic(ALPHAR, FzR/nR, muy);
            FyM = nM * self.tire.Characteristic(ALPHAM, FzM/nM, muy);

            t2 = cos(ALPHAT);
            t3 = cos(PSI);
            t4 = sin(PHI);
            t5 = sin(PSI);
            t6 = cos(deltam);
            t7 = sin(deltam);
            t8 = PSI+deltaf;
            t9 = PSI+deltar;
            t10 = dPHI.^2;
            t11 = dPSI.^2;
            t12 = ALPHAT+PHI;
            t13 = ALPHAT+PSI;
            t21 = -PHI;
            t22 = -PSI;
            t23 = -deltam;
            t14 = cos(t12);
            t15 = cos(t13);
            t16 = sin(t13);
            t17 = cos(t8);
            t18 = cos(t9);
            t19 = sin(t8);
            t20 = sin(t9);
            t24 = FyM.*d.*t6;
            t25 = FyM.*e.*t6;
            t26 = FxM.*d.*t7;
            t27 = FxM.*e.*t7;
            t28 = PHI+t22;
            t29 = PHI+t23;
            t31 = PSI+deltam+t21;
            t30 = cos(t28);
            t32 = sin(t28);
            t33 = cos(t29);
            t34 = sin(t29);
            t35 = cos(t31);
            t36 = sin(t31);
            t37 = VT.*d.*dPSI.*mS.*t14;
            f = [VT.*t15;VT.*t16;dPSI;dPHI;FxF.*t17+FxM.*t35+FxR.*t18-FyF.*t19-FyM.*t36-FyR.*t20-b.*mS.*t3.*t11-c.*mS.*t3.*t11-d.*mS.*t10.*t30-d.*mS.*t11.*t30+VT.*dPSI.*mS.*t16+VT.*dPSI.*mT.*t16+d.*dPHI.*dPSI.*mS.*t30.*2.0;FxF.*t19+FxM.*t36+FxR.*t20+FyF.*t17+FyM.*t35+FyR.*t18-b.*mS.*t5.*t11-c.*mS.*t5.*t11+d.*mS.*t10.*t32+d.*mS.*t11.*t32-VT.*dPSI.*mS.*t15-VT.*dPSI.*mT.*t15-d.*dPHI.*dPSI.*mS.*t32.*2.0;-t24-t25-t26-t27+t37+FxM.*b.*t34-FyM.*b.*t33+FxM.*c.*t34-FyM.*c.*t33+FyF.*a.*cos(deltaf)-FyR.*b.*cos(deltar)+FxF.*a.*sin(deltaf)-FxR.*b.*sin(deltar)+VT.*b.*dPSI.*mS.*t2+VT.*c.*dPSI.*mS.*t2-b.*d.*mS.*t4.*t10-c.*d.*mS.*t4.*t10+b.*d.*dPHI.*dPSI.*mS.*t4.*2.0+c.*d.*dPHI.*dPSI.*mS.*t4.*2.0;t24+t25+t26+t27-t37-b.*d.*mS.*t4.*t11-c.*d.*mS.*t4.*t11];

            dx = f;
        end

        function [value,isterminal,direction] = velocity(~,~,states)
            % If the velocity is less than 0.1m/s the integrator stops.
            % The MassMatrix is singular when the velocity is 0 m/s.
            value = states(5,1) - 0.1;
            isterminal = 1;
            direction = -1;
        end

        function M = MassMatrix(self,~,states)
            % Vehicle Parameters
            mT = self.mT;
            mS = self.mS;
            IT = self.IT;
            IS = self.IS;
            % a = self.a;
            b = self.b;
            c = self.c;
            d = self.d;
            % e = self.e;
            % deltaf = self.deltaf;
            % nF = self.nF;
            % nR = self.nR;
            % nM = self.nM;

            % g = 9.81;

            % FzF = self.mF * g;
            % FzR = self.mR * g;
            % FzM = self.mM * g;
            % muy = self.muy;

            % States
            PSI = states(3,1);
            PHI = states(4,1);
            VT = states(5,1);
            ALPHAT = states(6,1);
            % dPSI = states(7,1);
            % dPHI = states(8,1);

            t2 = cos(ALPHAT);
            t3 = cos(PHI);
            t4 = sin(ALPHAT);
            t5 = b+c;
            t6 = mS+mT;
            t7 = d.^2;
            t8 = ALPHAT+PHI;
            t9 = ALPHAT+PSI;
            t14 = -IS;
            t15 = -PSI;
            t10 = cos(t8);
            t11 = cos(t9);
            t12 = sin(t8);
            t13 = sin(t9);
            t16 = mS.*t7;
            t17 = b.*d.*mS.*t3;
            t18 = c.*d.*mS.*t3;
            t19 = PHI+t15;
            t20 = -t16;
            t21 = cos(t19);
            t22 = sin(t19);
            t23 = -t17;
            t24 = -t18;
            t25 = t14+t20+t23+t24;
            M = reshape([1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,t6.*t11,t6.*t13,-mS.*(b.*t4+c.*t4+d.*t12),d.*mS.*t12,0.0,0.0,0.0,0.0,-VT.*t6.*t13,VT.*t6.*t11,-VT.*mS.*(b.*t2+c.*t2+d.*t10),VT.*d.*mS.*t10,0.0,0.0,0.0,0.0,mS.*(d.*t22.*2.0-t5.*sin(PSI).*2.0).*(-1.0./2.0),mS.*(d.*t21.*2.0+t5.*cos(PSI).*2.0).*(-1.0./2.0),IS+IT+t16+t17.*2.0+t18.*2.0+b.^2.*mS+c.^2.*mS+b.*c.*mS.*2.0,t25,0.0,0.0,0.0,0.0,d.*mS.*t22,d.*mS.*t21,t25,IS+t16],[8,8]);
        end
    end

end


function f = plotkf(kf, plotDir);
%-------------------------------------------------------------------------------
% f = plotkf(kf, isPrintToFile);
% generate plots for Kalman filter estimates
% input:
% 1) kf is the data loaded into memory
% => use kf = readdata(solFileName, 1+9+9) to load binary file format
% => use kf = load(solFileName) to load text file format
% 2) plotDir => to control where to print a tiff file for each plot or not,
% use empty [] to turn off print
% output:
% f => figure handles
% by Dr. Yudan Yi
% modified date on: 04/08/2013
%-------------------------------------------------------------------------------
if (nargin<1) return; end;
[nn,mm] = size(kf);
if (nn<1) return; end;
isPrintToFile = false;
if nargin<2 plotDir = []; end;
if ~isempty(plotDir)
    isPrintToFile = true;
    n = length(plotDir);
    if (plotDir(n)~='\')
        plotDir = [plotDir '\'];
    end
    if ~isdir(plotDir)
        mkdir(plotDir);
    end
end
%-------------------------------------------------------------------------------
max_x = max(abs(kf(:,3)));
max_y = max(abs(kf(:,2)));
isNED = false;
if (max_y>pi||max_x>(2.0*pi))
    isNED = true;
end
f(1) = figure;
plot(kf(:,3),kf(:,2),'marker','.')
grid
axis equal
if (isNED)
    xlabel('East [m]')
    ylabel('North[m]')
else
    xlabel('Lontitude [radian]')
    ylabel('Latitude [radian]')
end
title('Ground Track');
if isPrintToFile
    print(f(1), '-dtiff', [plotDir 'ground_track']);
end
%close all
f(2) = figure;
plot(kf(:,1)-kf(1,1),kf(:,4),'marker','.')
grid
xlabel('Time [s]')
ylabel('m')
title('Height Profile');
if isPrintToFile
    print(f(2), '-dtiff', [plotDir 'ht']);
end
%close all
f(3) = figure;
plot(kf(:,1)-kf(1,1),kf(:,5:7),'marker','.')
grid
xlabel('Time [s]')
ylabel('m/s')
legend('Vx','Vy','Vz')
title('Velocity');
if isPrintToFile
    print(f(3), '-dtiff', [plotDir 'vel']);
end
%close all
% % note: roll is around pi, make to around 0
% kf(:,8) = kf(:,8);
% loc = find(kf(:,8)>pi);
% kf(loc,8) = kf(loc,8);
f(4) = figure;
plot(kf(:,1)-kf(1,1),kf(:,8:10),'marker','.')
grid
xlabel('Time [s]')
ylabel('degree')
legend('Roll','Pitch','Yaw/Heading')
title('Orientation');
if isPrintToFile
    print(f(4), '-dtiff', [plotDir 'att']);
end
%close all
if mm==19
f(5) = figure;
plot(kf(:,1)-kf(1,1),kf(:,11:13),'marker','.')
grid
xlabel('Time [s]')
ylabel('m')
legend('X','Y','Z')
title('Position RMS in ECEF XYZ');
if isPrintToFile
    print(f(5), '-dtiff', [plotDir 'rms_pos']);
end
%close all
f(6) = figure;
plot(kf(:,1)-kf(1,1),kf(:,14:16),'marker','.')
grid
xlabel('Time [s]')
ylabel('m/s')
legend('Vn','Ve','Vd')
title('Velocity RMS in NED');
if isPrintToFile
    print(f(6), '-dtiff', [plotDir 'rms_vel']);
end
%close all
f(7) = figure;
plot(kf(:,1)-kf(1,1),kf(:,17:19)*180/pi,'marker','.')
grid
xlabel('Time [s]')
ylabel('radian')
legend('Roll','Pitch','Yaw/Heading')
title('Orientation RMS in RPY');
if isPrintToFile
    print(f(7), '-dtiff', [plotDir 'rms_att']);
end
end
%close all


function ff = ifft(data)
% ff = ifft(data) does the inverse fourier transform of the data (power of 2 only)

% This m-file implementation of the fft is meant solely for use with adiff
% objects; it's far too inefficient for general use.

ff = fft(conj(data))/length(data);


%CHEBFUN3V   Class constructor for CHEBFUN3V objects.
%
%   CHEBFUN3V(F, G) constructs a CHEBFUN3V with two components from the
%   function handles F and G. F and G can also be CHEBFUN3 objects or any
%   other object that the CHEBFUN3 constructor accepts. Each component is
%   represented as a CHEBFUN3.
%
%   CHEBFUN3V(F, G, H) constructs a CHEBFUN3V with three components from
%   the function handles F, G, and H.  F, G, and H can also be CHEBFUN3
%   objects or any other objects that the CHEBFUN3 constructor accepts.
%
%   CHEBFUN3V(F, G, [A B C D E K]) constructs a CHEBFUN3V object from F and
%   G on the domain [A B] x [C D] x [E K].
%
%   CHEBFUN3V(F, G, H, [A B C D E K]) constructs a CHEBFUN3V object from F,
%   G, and H on the domain [A B] x [C D] x [E K].
%
% See also CHEBFUN3.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

classdef chebfun3v

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %% CLASS PROPERTIES:
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    properties ( Access = public )
        components   % Array of CHEBFUN3 objects.
        nComponents  % Number of components
        isTransposed % transposed?
    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %% CLASS CONSTRUCTOR:
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    methods ( Access = public, Static = false )

        function F = chebfun3v(varargin)
            % The main CHEBFUN3V constructor!

            % Return an empty CHEBFUN3V:
            if ( (nargin == 0) || isempty(varargin) )
                return
            end

            % This function calls the CHEBFUN3 constructor once for each
            % non-zero component because a CHEBFUN3V is just vector of
            % CHEBFUN3 objects.

            % If argument is a CHEBFUN3V, nothing to do:
            if ( isa(varargin{1}, 'chebfun3v') )
                F = varargin{1};
                return
            end

            % Find the domain:
            domain = [-1 1 -1 1 -1 1];
            for jj = 1:numel(varargin)
               if ( isa(varargin{jj}, 'double') && numel(varargin{jj}) == 6 )
                   domain = varargin{jj};
                   varargin(jj) = [];
               elseif ( isa( varargin{jj}, 'chebfun3') )
                   domain = varargin{jj}.domain;
               end
            end

            % Pick up vectorize flag:
            vectorize = 0;
            for jj = 1:numel(varargin)
                if ( strcmpi( varargin{jj}, 'vectorize' ) )
                    vectorize = 1;
                    varargin(jj) = [];
                end
            end

            % Unwrap input arguments;
            component = 1;
            for jj = 1:numel(varargin)
                if ( iscell(varargin{jj}) )
                    for kk = 1:numel(varargin{jj})
                        fh{component} = varargin{jj}{kk};
                        component = component + 1;
                    end
                else
                    fh{component} = varargin{jj};
                    component = component + 1;
                end
            end
            varargin = fh;

            % Convert all function handles to chebfun3 objects:
            for jj = 1:numel(varargin)
                if ( isa( varargin{jj}, 'function_handle') )
                    if ( ~vectorize )
                        newcheb = chebfun3(varargin{jj}, domain);
                    else
                        newcheb = chebfun3(varargin{jj}, domain, 'vectorize');
                    end
                    fh{jj} = newcheb;
                elseif ( isa(varargin{jj}, 'chebfun3') )
                    fh{jj} = varargin{jj};
                elseif ( isa(varargin{jj}, 'double') )
                    fh{jj} = chebfun3(varargin{jj}, domain);
                end
            end

            % Stop if there are too many components
            if ( numel( fh ) > 3 )
                error('CHEBFUN:CHEBFUN3V:arrayValued', ...
                          'More than three components is not supported.')
            end

            % Stop if there are no components:
            if ( numel(fh) == 0 )
                error('CHEBFUN:CHEBFUN3V:empty', ...
                ['The Chebfun3 constructor needs to be given function ' ...
                     'handles or chebfun3 objects.'])
            end

            % Check the domains of all the chebfun3 objects are the same:
            pass = zeros(numel(fh)-1, 1);
            for jj = 2:numel(fh)
               pass(jj-1) = domainCheck(fh{1}, fh{jj});
            end

            if ( ~all(pass) )
                error('CHEBFUN:CHEBFUN3V:domainCheck', ...
                    'All chebfun3 objects need to have the same domain.');
            end

            % Assign to the Chebfun3v object:
            F.components = fh;
            F.nComponents = numel(fh);
            F.isTransposed = 0;

        end
    end

end


function varargout = Sim_MonteCarlo_Diffusion_GUI(varargin)
% ## Purpose
% This Monte Carlo simulator for 2D diffusion is able to generate synthetic diffusion signal from any 2D axon packing.
%
% ## Approach
% First, the [axonpacking](https://github.com/neuropoly/axonpacking) software is used to generate dense packing of circles.
% Then, the Monte Carlo simulator moves water molecules around in the packing and apply the phase shift induced by the diffusion gradients.
%
% ## Interface
% First step is to generate an axon packing. Pre-packed examples are
% proposed.
%
% Then, when clicking on `Update` button, the Monte Carlo simulation runs in this packing.
% _Note: blues dots correspond to extra-axonal water molecules and red dots to intra-axonal water_
% _Note: The `MPG strength` and `Signal Strength` plots correspond to the last bvalue in the protocol. But Signal Strength is computed for all bvalues from the protocol._
%
% Once the simulation is finished, synthetic data are plotted and fitted by the charmed model.
% The user is able to save this synthetic signal in a `.mat` file.
%
% Authors: Yasuhiko Tachibana, Tanguy Duval, Tom Mingasson, 2019

% Edit the above text to modify the response to help Sim_SimMCdiff

% Last Modified by GUIDE v2.5 26-Aug-2019 15:37:40

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
    'gui_Singleton',  gui_Singleton, ...
    'gui_OpeningFcn', @Sim_SimMCdiff_OpeningFcn, ...
    'gui_OutputFcn',  @Sim_SimMCdiff_OutputFcn, ...
    'gui_LayoutFcn',  [] , ...
    'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

% --- Executes just before Sim_SimMCdiff is made visible.
function Sim_SimMCdiff_OpeningFcn(hObject, eventdata, handles, varargin)
handles.output = hObject;
handles.Model = varargin{1};
setappdata(0,'Model',handles.Model);

if ~isfield(handles,'opened')
    if ~ismac
        set(findobj(hObject,'Type','uicontrol'),'FontSize',7);
    end % everything is bigger on windows or linux

    savedPacks = dir(fullfile(fileparts(which('Sim_MonteCarlo_Diffusion_GUI.m')),'savedPacks','*.mat'));
    set(handles.preset_packing,'String',{savedPacks.name});
    [axons, packing] = loadPreset(handles);
    handles.axonpacking.axons = axons;
    handles.axonpacking.packing = packing;

    % Statistics from the packing
    k=1;
    [FVF, FR, MVF, AVF] = compute_statistics(axons.d{k}/2, axons.Delta{k}, packing.final_positions{k}, [], axons.g_ratio{k});
    set(handles.tableVolumes,'Data',[FVF; FR; MVF; AVF])

    % set values
    slider_Naxons_Callback(handles.slider_Naxons, [], handles)
    slider_dvar_Callback(handles.slider_dvar, [], handles)
    slider_dmean_Callback(handles.slider_dmean, [], handles)
    slider_gap_Callback(handles.slider_gap, [], handles)
    slider_trans_Callback(handles.slider_trans, [], handles)
    slider_numelparticle_Callback(handles.slider_numelparticle, [], handles)
    slider_Dcoef_Callback(handles.slider_Dcoef, [], handles)

    % clear axe
    handles.opened = 1;
end
% Update handles structure
guidata(hObject, handles);

% UIWAIT makes Sim_SimMCdiff wait for user response (see UIRESUME)
% uiwait(handles.Simu);

% --- Outputs from this function are returned to the command line.
function varargout = Sim_SimMCdiff_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure

% Get default command line output from handles structure
varargout{1} = handles.output;

% --- Executes on button press in SimMCdiffUpdate.
function SimMCdiffUpdate_Callback(hObject, eventdata, handles)
set(findobj('Name','SimMCdiff'),'pointer', 'watch'); drawnow;
MonteCarloSim(handles, handles.axonpacking.axons, handles.axonpacking.packing)
set(findobj('Name','SimMCdiff'),'pointer', 'arrow'); drawnow;

% GETAPPDATA
function varargout = GetAppData(varargin)
for k=1:nargin; varargout{k} = getappdata(0, varargin{k}); end

%SETAPPDATA
function SetAppData(varargin)
for k=1:nargin; setappdata(0, inputname(k), varargin{k}); end

% RMAPPDATA
function RmAppData(varargin)
for k=1:nargin; rmappdata(0, varargin{k}); end

% --------------------------------------------------------------------
function helpbutton_ClickedCallback(hObject, eventdata, handles)
doc Sim_MonteCarlo_Diffusion_GUI

function slider_gap_Callback(hObject, eventdata, handles)
%update_axonSetup(handles);
set(handles.text_gap,'String', ['Gap between axons: ' num2str(get(hObject,'Value')) 'um'])
function slider_dvar_Callback(hObject, eventdata, handles)
update_axonSetup(handles);
set(handles.text_dvar,'String', ['Diameter variance: ' num2str(get(hObject,'Value')) 'um'])
function slider_dmean_Callback(hObject, eventdata, handles)
update_axonSetup(handles);
set(handles.text_dmean,'String', ['mean diameter: ' num2str(get(hObject,'Value')) 'um'])
function slider_Naxons_Callback(hObject, eventdata, handles)
update_axonSetup(handles);
set(handles.text_Naxons,'String', ['# axons: ' num2str(round(get(hObject,'Value')))])

function [d, x0, side, axons] = update_axonSetup(handles)
k=1;
axons.N{k}      = round(get(handles.slider_Naxons,'Value'));
axons.d_mean{k} = round(get(handles.slider_dmean,'Value')*10)/10;
set(handles.slider_dmean,'Value',axons.d_mean{k})
axons.d_var{k}  = round(get(handles.slider_dvar,'Value')*10)/10;
set(handles.slider_dvar,'Value',axons.d_var{k});
axons.Delta{k}  = get(handles.slider_gap,'Value');
axons.threshold_high{k} = 20;
axons.threshold_low{k}  = .1;
axons
[d, x0, side] = axons_setup(axons,'gamma', k, handles.axes_axonDist);
if ~ismac, set(handles.axes_axonDist,'FontSize',7); end

function run_pack_Callback(hObject, eventdata, handles)
k=1;
[d, x0, side, axons] = update_axonSetup(handles);

axons.d{k} = d;
axons.g_ratio{k} = compute_gratio(d);

% packing process of the axons
iter_max = 10000;
iter_fvf = iter_max/10;
[final_positions, final_overlap, fvf_historic] = process_packing(x0, d/2, axons.Delta{k}, side, iter_max, iter_fvf);

% store packing results
% main results
packing.initial_positions{k}    = reshape(x0,2,length(x0)/2);
packing.final_positions{k}      = final_positions;
% secondary results
packing.final_overlap{k}        = final_overlap;
packing.FVF_historic{k}         = fvf_historic;
packing.iter_max{k}             = iter_max;

% Statistics from the packing
[FVF, FR, MVF, AVF] = compute_statistics(axons.d{k}/2, axons.Delta{k}, packing.final_positions{k}, side, axons.g_ratio{k});
set(handles.tableVolumes,'Data',[FVF; FR; MVF; AVF])

if ishandle(201), close(201); end
plotPacking(handles,axons,packing)
handles.axonpacking.axons = axons;
handles.axonpacking.packing = packing;

guidata(hObject, handles);

function save_pack_Callback(hObject, eventdata, handles)
axons   = handles.axonpacking.axons;
packing = handles.axonpacking.packing;
fname = sprintf('pack_d%.1fvar%.1fgap%.1f.mat',axons.d_mean{1},axons.d_var{1},axons.Delta{1});
fname = fullfile(fileparts(which('Sim_MonteCarlo_Diffusion_GUI.m')),'savedPacks',fname);
[fname, path] = uiputfile('*.mat','Save Packing as...',fname);
if fname
    save(fullfile(path,fname),'axons','packing')
    savedPacks = get(handles.preset_packing,'String');
    set(handles.preset_packing,'String',unique([savedPacks; {fname}]));
    savedPacks = get(handles.preset_packing,'String');
    set(handles.preset_packing,'Value',length(savedPacks));
end

function preset_packing_Callback(hObject, eventdata, handles)
[axons, packing] = loadPreset(handles);
handles.axonpacking.axons = axons;
handles.axonpacking.packing = packing;
k=1;
[FVF, FR, MVF, AVF] = compute_statistics(axons.d{k}/2, axons.Delta{k}, packing.final_positions{k}, [], axons.g_ratio{k});
set(handles.tableVolumes,'Data',[FVF; FR; MVF; AVF])

guidata(hObject, handles);

function     [axons, packing] = loadPreset(handles)
file = get(handles.preset_packing,'String');
load(file{get(handles.preset_packing,'Value')})
axons_setup(axons,'gamma', 1, handles.axes_axonDist);
if ~ismac, set(handles.axes_axonDist,'FontSize',7); end
plotPacking(handles,axons,packing)

function plotPacking(handles,axons,packing)
% plot disks
numelobj = size(packing.final_positions{1},2);
cen = packing.final_positions{1}'; cen=cen(:,[2 1]); cen=cen-repmat([mean(cen(:,1)) mean(cen(:,2))],[size(cen,1) 1]); % center position of the cells
cen = [cen, zeros(numelobj,1)];

% Radius of the "cells"
R = [axons.d{1}.*axons.g_ratio{1} axons.d{1}]/2; % internal / external diameter in um
R = R(:,2); %use external radius only.

t = linspace(0,2*pi);

axes(handles.axes_axonPack)
hold off
for k =1:size(R,1)
    plot(R(k,1)*cos(t)+cen(k,1), R(k)*sin(t)+cen(k,2),'b','linewidth',1);
    hold on
end
hold off
axis equal tight
xlabel x(\mum)
ylabel y(\mum)

if ~ismac, set(handles.axes_axonPack,'FontSize',7); end

function MonteCarloSim(handles, axons, packing)

% Read updated Model
Model_new = getappdata(0,'Model');
if ~isempty(Model_new) && strcmp(class(Model_new),class(handles.Model))
    handles.Model = Model_new;
end

axes(handles.uipanel12);

% Read parameters
numelparticle = round(get(handles.slider_numelparticle,'Value'));

trans_mean = get(handles.slider_trans,'Value'); % mean probability of penetrating the cell walls [0-1]

D = get(handles.slider_Dcoef,'Value'); % Diffusion coefficient

handles.Model.Sim_MonteCarlo_Diffusion(numelparticle, trans_mean, D, packing, axons);

function slider_trans_Callback(hObject, eventdata, handles)
set(handles.text_trans,'String', ['Permeability: ' num2str(get(hObject,'Value'))])
function slider_numelparticle_Callback(hObject, eventdata, handles)
set(hObject,'Value',round(get(hObject,'Value')))
set(handles.text_numelparticle,'String', ['Number of particles: ' num2str(get(hObject,'Value'))])
function slider_bv_Callback(hObject, eventdata, handles)
set(handles.text_bv,'String', ['bvalue: ' num2str(get(hObject,'Value')) 'sec/mm2'])
function slider_Dcoef_Callback(hObject, eventdata, handles)
D = get(hObject,'Value');
set(handles.text_Dcoef,'String', sprintf('Diffusion coefficient: \n\tD = %.2gx 10-3 mm2/sec',D))
set(handles.text_Step,'String', sprintf('steptime = %.1g [ms]\nstepflight = %.1g [um]\n(stepflight^2 = 4*D*steptime)',0.5,sqrt(4*D*.5)))

function preset_packing_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
function slider_gap_CreateFcn(hObject, eventdata, handles)
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end
function slider_dvar_CreateFcn(hObject, eventdata, handles)
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end
function slider_dmean_CreateFcn(hObject, eventdata, handles)
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end
function slider_Naxons_CreateFcn(hObject, eventdata, handles)
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end
function slider_trans_CreateFcn(hObject, eventdata, handles)
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end
function slider_numelparticle_CreateFcn(hObject, eventdata, handles)
function slider_bv_CreateFcn(hObject, eventdata, handles)
function slider9_CreateFcn(hObject, eventdata, handles)
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end
function slider_Dcoef_CreateFcn(hObject, eventdata, handles)
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end


function outstr = midrad(c,name,restricted)
%MIDRAD       Display of intervals by midpoint/radius (rigorous)
%
%The call
%
%  midrad(c)        displays interval c in < mid , rad > representation
%  str = midrad(c)  puts output into string str
%
%Output in string str columnwise; can be used for input by intval(str).
%

%for internal use:
%  name                name of output variable
%  restricted == 1     no header, no extra lines output
%
%Call only with 1 or 3 input arguments
%
%Special call:  outstr = midrad(x,[],[])
%  for column vector x output in outstr.exp and outstr.str
%

% written  11/30/98     S.M. Rump
% modified 06/10/98     S.M. Rump  multi-dimensional arrays, exceptions
% modified 06/23/99     S.M. Rump  dble2str -> dble2str_rnd in \private,
%                                  sparse arrays
% modified 08/29/00     S.M. Rump  special output in outstr.exp and .str added
%                                  rounding unchanged after use
% modified 10/03/02     S.M. Rump  improved for Matlab 6.1f and sparse output
% modified 04/04/04     S.M. Rump  set round to nearest for safety
%                                    take care of Matlab sparse Inf/NaN bug
% modified 04/06/05     S.M. Rump  rounding unchanged
% modified 11/20/05     S.M. Rump  fast check for rounding to nearest
% modified 02/11/06     S.M. Rump  SparseInfNanFlag removed
%                                    linear indices for huge matrices
% modified 08/25/07     S.M. Rump  huge indices for sparse matrices
% modified 10/14/08     S.M. Rump  huge indices for sparse matrices
% modified 08/26/12     S.M. Rump  global variables removed
% modified 10/04/12     S.M. Rump  take care of sparse input
%

  e = 1e-30;
  if 1+e==1-e                           % fast check for rounding to nearest
    rndold = 0;
  else
    rndold = getround;
    setround(0)
  end

  if nargin<=2
    name = inputname(1);
    restricted = 0;
  end

  loose = strcmp(get(0,'FormatSpacing'),'loose');

  siz = size(c);
  if ~restricted & ~nargout & ( length(siz)<3 )
    if loose, disp(' '); end
    disp([ 'intval ' name ' = ' ])
    if loose, disp(' '); end
  end

  if isempty(c)          % empty interval
    if c.complex
      c.mid
    else
      c.inf
    end
    if loose & ~restricted & ~nargout
      disp(' ')
    end
    setround(rndold)
    return
  end

  if length(siz)>2 & ~nargout
    siz = siz(3:end);
    len = length(siz);
    prodsiz = cumprod([1 siz(1:len-1)]);

    for k=0:prod(siz)-1
      y = mod(floor(k./prodsiz),siz);
      str = sprintf(',%d',y+1);
%VVVV eval(['cs = c(:,:' str ');']);
      s.type = '()';
      eval(['s.subs = {'':'','':''' str '};']);
      cs = subsref(c,s);
%AAAA Matlab V5.2 bug fix
      midrad(cs,[name '(:,:' str ')'],0);
    end
    setround(rndold)
    return
  end

  cmid = mid(c);
  crad = rad(c);
  [m n] = size(cmid);

  format = get(0,'format');
  if ~isequal(format,'short') & ~isequal(format,'long') & ...
     ~isequal(format,'shortE') & ~isequal(format,'longE')
    format = 'short';
  end

  INTLAB_INTVAL_POWER10 = getappdata(0,'INTLAB_INTVAL_POWER10');
  commonexp = 0;
  if ~isequal(format(end),'E')
    % calculate exponent range and common factor
    if c.complex
      cre = abs(real(cmid));
      cim = abs(imag(cmid));
      cre = nonzeros(cre);
      cim = nonzeros(cim);
      if isempty(cre)                   % careful: max(1,[]) = []
        cre = 0;
      end
      if isempty(cim)
        cim = 0;
      end
      cre(isinf(cre)) = 0;
      cim(isinf(cim)) = 0;
      cremax = max(cre(:));
      cimmax = max(cim(:));
      cmax = max(cremax,cimmax);
    else
      cmid_ = abs(cmid);
      cmid_ = nonzeros(cmid_);
      if isempty(cmid_)                 % careful: max(1,[]) = []
        cmid_ = 0;
      end
      cmid_(isinf(cmid_)) = 0;
      cmax = max(cmid_);
      cmax = max(cmax(:));
    end
    crad_ = abs(crad);
    crad_ = nonzeros(crad_);
      if isempty(crad_)                 % careful: max(1,[]) = []
        crad_ = 0;
      end
    crad_(isinf(crad_)) = 0;
    cmax = max( cmax , max(crad_(:)) );
    % care for sparse matrices
    cmax = full(cmax);
    if isempty(cmax)
      cmax = 0;
    end

    emax = floor(log10( cmax + (cmax==0) ));
    if c.complex
      if emax >= 2
        commonexp = emax;
      end
      if emax <= -3
        commonexp = emax+1;
      end
    else
      if isequal(format,'short') & emax >= 3
        commonexp = emax;
      elseif isequal(format,'long') & emax >= 2
        commonexp = emax;
      end
      if emax <= -4
        commonexp = emax+1;
      end
    end
  end
  factor = INTLAB_INTVAL_POWER10.sup(1,commonexp+341);    % 10^commonexp

  if commonexp~=0                      % common factor
    if nargout                         % output to str: be sure with exponent
      if ~( isempty(name) & isempty(restricted) )   % if not special output
        commonexp = 0;
        if ~isequal(format(end),'E')
          format = [ format 'E' ];
        end
      end
    else
      strexp = sprintf('%04d',commonexp);
      if commonexp >= 0
        strexp(1) = '+';
      end
      disp([ '  1.0e' strexp ' *' ])
      if loose, disp(' '); end
    end
  end

  if c.complex
    switch format
      case 'short',  len = 9;  prec = 4;  expon = 0;
      case 'long',   len = 19; prec = 14; expon = 0;
      case 'shortE', len = 13; prec = 4;  expon = 1;
      case 'longE',  len = 24; prec = 15; expon = 1;
    end
    len1 = 3*len+5;    % length of one element in current format
  else
    switch format
      case 'short',  len = 10; prec = 4;  expon = 0;
      case 'long',   len = 19; prec = 14; expon = 0;
      case 'shortE', len = 13; prec = 4;  expon = 1;
      case 'longE',  len = 24; prec = 15; expon = 1;
    end
    len1 = 2*len+2;    % length of one element in current format
  end
  INTLAB_DISPLAY_WIDTH = getappdata(0,'INTLAB_DISPLAY_WIDTH');    % minimum 110, so columns>=1
  columns = floor((INTLAB_DISPLAY_WIDTH+1)/(len1+1));

  formatstr = [ '%' int2str(len) '.' int2str(prec) 'f' ];
  if expon
    formatstr(end) = 'e';
  end

  if nargout & isempty(name) & isempty(restricted)
    % special case: input c column vector, output in outstr.exp and outstr.str

    if commonexp~=0                      % common factor
      strexp = sprintf('%04d',commonexp);
      if commonexp >= 0
        strexp(1) = '+';
      end
      outstr.exp = [ '  1.0e' strexp ' *' ];
    else
      outstr.exp = '';
    end

    if c.complex           % complex intervals
      outstr.str = char(zeros(m,3*len+5));
      for i=1:m
        s = '';
        cmidi = full(cmid(i));
        strrealmid = sprintf(formatstr,real(cmidi)/factor);
        signimagmid = sign(imag(cmidi));
        strimagmid = sprintf(formatstr,abs(imag(cmidi))/factor);
        strimagmid = strimagmid(2:end);     % omit leading space
        [cmidrealinf,cmidrealsup] = str2intval(strrealmid,commonexp);
        if signimagmid==1
          [cmidimaginf,cmidimagsup] = str2intval(strimagmid,commonexp);
        else
          [cmidimagsup,cmidimaginf] = str2intval(strimagmid,commonexp);
          cmidimagsup = - cmidimagsup ;
          cmidimaginf = - cmidimaginf ;
        end
        setround(1)
        re = max( real(cmidi)-cmidrealinf,cmidrealsup-real(cmidi) );
        im = max( imag(cmidi)-cmidimaginf,cmidimagsup-imag(cmidi) );
        if isequal(crad,0)
          cradij = abs( re + sqrt(-1)*im );
        else
          cradij = crad(i) + abs( re + sqrt(-1)*im );
        end
        cradij = full(cradij);
        chsign = '+';
        if signimagmid==-1
          chsign = '-';
        end
        strrad = dble2str_rnd(cradij,commonexp,len-1,prec,expon,+1);
        s = [ s '<' strrealmid ' ' chsign strimagmid 'i,' ...
              strrad '> ' ];
        outstr.str(i,:) = s;
      end
    else                   % real intervals
      outstr.str = char(zeros(m,2*len+3));
      for i=1:m
        s = '';
        cmidi = full(cmid(i));
        strmid = sprintf(formatstr,cmidi/factor);
        [cmidinf,cmidsup] = str2intval(strmid,commonexp);
        setround(1)
        cradij = full( crad(i) + max(cmidi-cmidinf,cmidsup-cmidi) );
        s = [ s '<' strmid ',' ...
              dble2str_rnd(cradij,commonexp,len-1,prec,expon,+1) '> ' ];
        outstr.str(i,:) = s;
      end
    end
    setround(rndold)
    return
  end

  if nargout
    outstr = [];
    if c.complex
      for i=1:prod(size(cmid))
        cmidi = full(cmid(i));
        strrealmid = sprintf(formatstr,real(cmidi));
        strimagmid = sprintf(formatstr,imag(cmidi));
        strimagmid(isspace(strimagmid)) = '';
        if strimagmid(1)~='-'
          strimagmid = [ '+' strimagmid ];
        end
        [cmidrealinf,cmidrealsup] = str2intval(strrealmid,0);
        [cmidimaginf,cmidimagsup] = str2intval(strimagmid,0);
        setround(1)
        re = max( real(cmidi)-cmidrealinf,cmidrealsup-real(cmidi) );
        im = max( imag(cmidi)-cmidimaginf,cmidimagsup-imag(cmidi) );
        if isequal(crad,0)
          cradi = abs( re + sqrt(-1)*im );
        else
          cradi = crad(i) + abs( re + sqrt(-1)*im );
        end
        cradi = full(cradi);
        strrad = dble2str_rnd(cradi,commonexp,len-1,prec,expon,+1);
        outstr = [ outstr '<' strrealmid strimagmid 'i,' strrad '> ' ];
      end
    else
      for i=1:prod(size(cmid))
        cmidi = full(cmid(i));
        strmid = sprintf(formatstr,cmidi);
        [cmidinf,cmidsup] = str2intval(strmid,0);
        setround(1)
        cradi = full( crad(i) + max(cmidi-cmidinf,cmidsup-cmidi) );
        outstr = [ outstr '<' strmid ',' ...
              dble2str_rnd(cradi,commonexp,len-1,prec,expon,+1) '> ' ];
      end
    end
    setround(rndold)
    return
  end

  if issparse(c)
    if isequal(crad,0)                            % mid or rad maybe zero
      [I,J] = find(spones(cmid));
    else
      [I,J] = find(spones(cmid)+spones(crad));
    end
    if length(I)==0
      mid(c)
      setround(rndold)
      return
    end
    if c.complex
      for i=1:length(I)
        str = sprintf('  (%d,%d)',I(i),J(i));
        str = [ str blanks(20-length(str)) ];
        cmidij = full(cmid(I(i),J(i)));
        strrealmid = sprintf(formatstr,real(cmidij)/factor);
        signimagmid = sign(imag(cmidij));
        strimagmid = sprintf(formatstr,abs(imag(cmidij))/factor);
        strimagmid = strimagmid(2:end);     % omit leading space
        [cmidrealinf,cmidrealsup] = str2intval(strrealmid,commonexp);
        if signimagmid==1
          [cmidimaginf,cmidimagsup] = str2intval(strimagmid,commonexp);
        else
          [cmidimagsup,cmidimaginf] = str2intval(strimagmid,commonexp);
          cmidimagsup = - cmidimagsup ;
          cmidimaginf = - cmidimaginf ;
        end
        setround(1)
        re = max( real(cmidij)-cmidrealinf,cmidrealsup-real(cmidij) );
        im = max( imag(cmidij)-cmidimaginf,cmidimagsup-imag(cmidij) );
        if isequal(crad,0)
          cradij = abs( re + sqrt(-1)*im );
        else
          cradij = crad(I(i),J(i)) + abs( re + sqrt(-1)*im );
        end
        cradij = full(cradij);
        chsign = '+';
        if signimagmid==-1
          chsign = '-';
        end
        strrad = dble2str_rnd(cradij,commonexp,len-1,prec,expon,+1);
        str = [ str '<' strrealmid ' ' chsign strimagmid 'i,' ...
                strrad '> ' ];
        disp( str )
      end
    else
      for i=1:length(I)
        str = sprintf('  (%d,%d)',I(i),J(i));
        str = [ str blanks(20-length(str)) ];
        cmidij = full(cmid(I(i),J(i)));
        strmid = sprintf(formatstr,cmidij/factor);
        [cmidinf,cmidsup] = str2intval(strmid,commonexp);
        setround(1)
        cradij = full(crad(I(i),J(i)) + max(cmidij-cmidinf,cmidsup-cmidij));
        str = [ str '<' strmid ',' ...
                dble2str_rnd(cradij,commonexp,len-1,prec,expon,+1) '> ' ];
        disp( str )
      end
    end
    setround(rndold)
    return
  end

  for jj=1:ceil(n/columns)
    j1 = (jj-1)*columns+1;
    if jj*columns<n
      j2 = jj*columns;
    else
      j2 = n;
    end
    if n>columns
      if j1~=j2
        disp(['  Columns ' sprintf('%d',j1) ' through ' sprintf('%d',j2)]);
      else
        disp(['  Column ' sprintf('%d',j1)]);
      end
      if loose, disp(' '); end
    end
    if c.complex           % complex intervals
      for i=1:m
        s = '';
        for j = j1:j2
          cmidij = full(cmid(i,j));
          strrealmid = sprintf(formatstr,real(cmidij)/factor);
          signimagmid = sign(imag(cmidij));
          strimagmid = sprintf(formatstr,abs(imag(cmidij))/factor);
          strimagmid = strimagmid(2:end);     % omit leading space
          [cmidrealinf,cmidrealsup] = str2intval(strrealmid,commonexp);
          if signimagmid==1
            [cmidimaginf,cmidimagsup] = str2intval(strimagmid,commonexp);
          else
            [cmidimagsup,cmidimaginf] = str2intval(strimagmid,commonexp);
            cmidimagsup = - cmidimagsup ;
            cmidimaginf = - cmidimaginf ;
          end
          setround(1)
          re = max( real(cmidij)-cmidrealinf,cmidrealsup-real(cmidij) );
          im = max( imag(cmidij)-cmidimaginf,cmidimagsup-imag(cmidij) );
          if isequal(crad,0)
            cradij = abs( re + sqrt(-1)*im );
          else
            cradij = crad(i,j) + abs( re + sqrt(-1)*im );
          end
          cradij = full(cradij);
          chsign = '+';
          if signimagmid==-1
            chsign = '-';
          end
          strrad = dble2str_rnd(cradij,commonexp,len-1,prec,expon,+1);
          s = [ s '<' strrealmid ' ' chsign strimagmid 'i,' ...
                strrad '> ' ];
        end
        disp(s)
      end
    else                   % real intervals
      for i=1:m
        s = '';
        for j = j1:j2
          cmidij = full(cmid(i,j));
          strmid = sprintf(formatstr,cmidij/factor);
          [cmidinf,cmidsup] = str2intval(strmid,commonexp);
          setround(1)
          cradij = full( crad(i,j) + max(cmidij-cmidinf,cmidsup-cmidij) );
          s = [ s '<' strmid ',' ...
                dble2str_rnd(cradij,commonexp,len-1,prec,expon,+1) '> ' ];
        end
        disp(s)
      end
    end
    if loose & ~restricted, disp(' '); end
  end

  setround(rndold)

function [xinf,xsup] = str2intval(str,commonexp)
%STR2INTVAL   internal routine for output routines midrad
%

%Rigorous conversion of string to lower/upper bound with directed rounding
%  and common exponent; only for one real input.
%Input string in e- or f-format, possibly with exponent
%Input number is assumed to be correct.
%

  % exception handling
  if any( str=='a' ) | any( str=='f' )    % NaN or Inf
    xinf = NaN;
    xsup = NaN;
    return
  end

  INTLAB_INTVAL_POWER10 = getappdata(0,'INTLAB_INTVAL_POWER10');
  [m i] = max(str~=' ');
  str(1:i-1) = '';             % omit leading blanks

  sign = 1;                    % calculate sign
  if str(1)=='+'
    str = str(2:end);
  elseif str(1)=='-'
    sign = -1;
    str = str(2:end);
  end

  indexdp = find(str=='.');    % index of decimal point
  str(indexdp) = '';

  indexexp = find(str=='e');   % check exponent
  if ~isempty(indexexp)
    Exp = ( 2*(str(indexexp+1)=='+') - 1 ) * ...
          (str(indexexp+2:end)-'0')*(10.^((length(str)-indexexp-2):-1:0)');
    indexend = indexexp-1;
  else
    Exp = 0;
    indexend = length(str);
  end

  m = str(indexend:-1:1) - '0';

  % convert back to double
  offset = 9*(indexdp-2+Exp+commonexp+341);
  mant = 9*(indexend:-1:1);
  index = (m~=0).*(offset - mant + m) + (m==0);
  if sign==1
    setround(-1)
    xinf = sum( INTLAB_INTVAL_POWER10.inf(index) );
    setround(1)
    xsup = sum( INTLAB_INTVAL_POWER10.sup(index) );
  else
    setround(1)
    xinf = - sum( INTLAB_INTVAL_POWER10.sup(index) );
    setround(-1)
    xsup = - sum( INTLAB_INTVAL_POWER10.inf(index) );
  end
  setround(0)


%% Analyzing Neural Time Series Data
% Matlab code for Chapter 9
% Mike X Cohen
%
% This code accompanies the book, titled "Analyzing Neural Time Series Data"
% (MIT Press). Using the code without following the book may lead to confusion,
% incorrect data analyses, and misinterpretations of results.
% Mike X Cohen assumes no responsibility for inappropriate or incorrect use of this code.

%% Figure 9.1a

% load EEG data
load sampleEEGdata.mat

% plot a few trials from one channel...

% specify the label of the channel to plot
which_channel_to_plot = 'fcz';
% and find the index (channel number) of that label
channel_index = strcmpi(which_channel_to_plot,{EEG.chanlocs.labels});

x_axis_limit = [-200 1000]; % in ms

num_trials2plot = 12;

figure
set(gcf,'Name',[ num2str(num_trials2plot) ' random trials from channel ' which_channel_to_plot ],'Number','off')
for i=1:num_trials2plot

    % figure out how many subplots we need
    subplot(ceil(num_trials2plot/ceil(sqrt(num_trials2plot))),ceil(sqrt(num_trials2plot)),i)

    % pick a random trial (using randsample, which is in the stats toolbox)
    random_trial_to_plot = randsample(EEG.trials,1);
    % if you don't have the stats toolbox, use the following two lines:
    %random_trial_to_plot = randperm(EEG.trials);
    %random_trial_to_plot = random_trial_to_plot(1);

    % plot trial and specify x-axis and title
    plot(EEG.times,squeeze(EEG.data(channel_index,:,random_trial_to_plot)));
    set(gca,'xlim',x_axis_limit,'ytick',[])
    title([ 'Trial ' num2str(random_trial_to_plot) ])
end

%% Figure 9.1b

figure
% plot all trials
plot(EEG.times,squeeze(EEG.data(channel_index,:,:)),'y')

hold on
% plot ERP (simply the average time-domain signal)
plot(EEG.times,squeeze(mean(EEG.data(channel_index,:,:),3)),'k','linew',2)
set(gca,'xlim',[-300 1000],'ylim',[-60 60],'ydir','reverse')

% now plot only the ERP
figure
plot(EEG.times,squeeze(mean(EEG.data(channel_index,:,:),3))) % Note the "3" as second input to "mean"; this takes the average of the 3rd dimension.

% plot lines indicating baseline activity and stim onset
hold on
plot(get(gca,'xlim'),[0 0],'k')
plot([0 0],get(gca,'ylim'),'k:')

% add axis labels and title
xlabel('Time (ms)')
ylabel('\muV') % note that matlab interprets "\mu" as the Greek character for micro
title([ 'ERP (average of ' num2str(EEG.trials) ' trials) from electrode ' EEG.chanlocs(channel_index).labels ])

% plot upside down, following ERP convention
set(gca,'ydir','reverse')
% axis ij % this does the same as the previous trial

% below is some advanced but flexible code to change the x-axis label
set(gca,'xlim',[-300 1000])
xticklabel=cellstr(get(gca,'xticklabel'));
xticklabel{str2double(xticklabel)==0}='stim';
set(gca,'xticklabel',xticklabel)

%% Figure 9.2

% pick a channel
chan2plot = 'p7';

% compute ERP
erp = double(squeeze(mean(EEG.data(strcmpi(chan2plot,{EEG.chanlocs.labels}),:,:),3)));

% low-pass filter data (requires signal processing toolbox)
% you'll learn about how filtering works, and what this code means, in chapter 14.
nyquist          = EEG.srate/2;
transition_width = 0.15; % percent

% first, filter from 0-40
filter_cutoff = 40; % Hz
ffrequencies  = [ 0 filter_cutoff filter_cutoff*(1+transition_width) nyquist ]/nyquist;
idealresponse = [ 1 1 0 0 ];
filterweights = firls(100,ffrequencies,idealresponse);
erp_0to40     = filtfilt(filterweights,1,double(erp));

% next, filter from 0-10
filter_cutoff = 10; % Hz
ffrequencies  = [ 0 filter_cutoff filter_cutoff*(1+transition_width) nyquist ]/nyquist;
idealresponse = [ 1 1 0 0 ];
filterweights = firls(100,ffrequencies,idealresponse);
erp_0to10     = filtfilt(filterweights,1,double(erp));

% finally, filter from 5-15
filter_low    =  5; % Hz
filter_high   = 15; % Hz
ffrequencies  = [ 0 filter_low*(1-transition_width) filter_low filter_high filter_high*(1+transition_width) nyquist ]/nyquist;
idealresponse = [ 0 0 1 1 0 0 ];
filterweights = firls(round(3*(EEG.srate/filter_low)),ffrequencies,idealresponse);
erp_5to15     = filtfilt(filterweights,1,double(erp));

% now plot all filtered ERPs
figure
plot(EEG.times,erp,'k')
hold on
plot(EEG.times,erp_0to40,'b','linew',2)
plot(EEG.times,erp_0to10,'r')
plot(EEG.times,erp_5to15,'m')

set(gca,'xlim',[-200 1200],'ydir','r')
xlabel('Time (ms)'), ylabel('Voltage (\muV)')
title([ 'ERP from electrode ' chan2plot ])
legend({'None';'0-40';'0-10';'5-15'})

%% Figure 9.3

figure

% Butterfly plot
subplot(211)
plot(EEG.times,squeeze(mean(EEG.data,3)))
set(gca,'xlim',[-200 1000],'ydir','reverse')
xlabel('Time (ms)'), ylabel('\muV')
title('ERP from all sensors')

% topographical variance plot
subplot(212)
plot(EEG.times,squeeze(var( mean(EEG.data,3) ))) % note: change var to std for global field power
set(gca,'xlim',[-200 1000])
xlabel('Time (ms)'), ylabel('var(\muV)')
title('Topographical variance')

%% figure 9.4

% topoplot with colored dots vs. interpolated surface
% topoplot is a function in the eeglab toolbox, which you can download for
% free from the internet.

figure
subplot(121)
% To get the following line to work, you need to modify the eeglab function 'topoplot'
% Replace the first line of code (the function definition) with:
% function [handle,Zi,grid,Xi,Yi,x,y,pltchans] = topoplot(Values,loc_file,varargin)
[~,~,~,~,~,xi,yi,pltchans] = topoplot(zeros(64,1),EEG.chanlocs,'electrodes','off','plotrad',.53);

hold on
c = -squeeze(mean(EEG.data(:,300,:),3));
c = c-min(c); % these lines scale the variable c
c = c./max(c);
c = repmat(c,1,3);
for i=1:length(xi)
    hold on
    plot3(yi(i),xi(i),.1,'o','markerfacecolor',c(i,:),'markersize',5,'markeredge','none');
    % here, plot3 is used to plot the electrode on top of the topomap
    % (compare with the plot function) (a trick I learned from topoplot.m)
end

subplot(122)
c = -squeeze(mean(EEG.data(:,300,:),3));
c = c-min(c);
c = c./max(c);
c = repmat(c,1,3);
topoplot(double(c(:,1)),EEG.chanlocs,'plotrad',.53,'electrodes','off','numcontour',0);

colormap gray

%% introduction to topographical plotting

timepoint2plot = 100; % in ms
trial2plot = randsample(EEG.trials,1);

color_limit = 20; % more-or-less arbitrary, but this is a good value

% convert time point from ms to index
[junk,timepointidx] = min(abs(EEG.times-timepoint2plot));

% First step is to get X and Y coordinates of electrodes
% These must be converted to polar coordinates
th=pi/180*[EEG.chanlocs.theta];
[electrode_locs_X,electrode_locs_Y] = pol2cart(th,[EEG.chanlocs.radius]);

% interpolate to get nice surface
interpolation_level = 100; % you can try changing this number, but 100 is probably good
interpX = linspace(min(electrode_locs_X),max(electrode_locs_X),interpolation_level);
interpY = linspace(min(electrode_locs_Y),max(electrode_locs_Y),interpolation_level);

% meshgrid is a function that creates 2D grid locations based on 1D inputs
[gridX,gridY] = meshgrid(interpX,interpY);

% let's look at these matrices
figure
subplot(121)
imagesc(gridX)

subplot(122)
imagesc(gridY)

% now interpolate the data on a 2D grid
interpolated_EEG_data = griddata(electrode_locs_Y,electrode_locs_X,double(squeeze(EEG.data(:,timepointidx,trial2plot))),gridX,gridY);

figure
set(gcf,'number','off','name',[ 'Topographical data from trial ' num2str(trial2plot) ', time=' num2str(round(EEG.times(timepointidx))) ]);
subplot(121)
contourf(interpY,interpX,interpolated_EEG_data,100,'linecolor','none');
axis square
set(gca,'clim',[-color_limit color_limit],'xlim',[min(interpY) max(interpY)]*1.1,'ylim',[min(interpX) max(interpX)]*1.1)
title('Interpolated data in matlab')

subplot(122)
topoplot(double(squeeze(EEG.data(:,timepointidx,trial2plot))),EEG.chanlocs,'maplimits',[-color_limit color_limit]); % eeglab's topoplot function
title('eeglab ''topoplot'' function')

figure
set(gcf,'name','a landscape of cortical electrophysiological dynamics')
surf(interpY,interpX,interpolated_EEG_data);
xlabel('left-right of scalp'), ylabel('anterior-posterior of scalp'), zlabel('\muV')
shading interp, axis tight
set(gca,'clim',[-color_limit color_limit],'xlim',[min(interpY) max(interpY)]*1.1,'ylim',[min(interpX) max(interpX)]*1.1)
rotate3d on, view(0,90)

%% Figure 9.5

% find indices for requested plot times
times2plot = dsearchn(EEG.times',(-100:50:600)');

figure
for i=1:length(times2plot)
    subplot(3,5,i)

    % extract EEG data and replace FC4 data with noise
    eegdata2plot = double(squeeze(mean(EEG.data(:,times2plot(i),:),3)));
    eegdata2plot(strcmpi('fc4',{EEG.chanlocs.labels})) = randn*10;

    topoplot(eegdata2plot,EEG.chanlocs,'maplimits',[-8 8]);
    title([ num2str(round(EEG.times(times2plot(i)))) ' ms' ])
end

%% Figure 9.6

useRTs = true; % or false

% get RTs from each trial, to use for sorting trials. In this experiment,
% the RT was always the first event after the stimulus (the time=0 event).
% Normally, you should build in exceptions in case there was no response or
% another event occured between the stimulus and response. This was already
% done for the current dataset.

rts = zeros(size(EEG.epoch));
for ei=1:length(EEG.epoch)

    % first, find the index at which the time=0 event occurs
    time0event = find(cell2mat(EEG.epoch(ei).eventlatency)==0);

    % then get reaction time
    rts(ei) = EEG.epoch(ei).eventlatency{time0event+1};
end

% now find the sorting indices for RTs
if useRTs
    [dontneed,rts_idx] = sort(rts);
else
    [dontneed,rts_idx] = sort(squeeze(EEG.data(47,334,:)));
end

% now plot
figure
imagesc(EEG.times,1:EEG.trials,squeeze(EEG.data(47,:,rts_idx))');
set(gca,'clim',[-30 30],'xlim',[-200 1200],'ydir','n')

% also plot the RTs on each trial
if useRTs
    hold on
    plot(rts(rts_idx),1:EEG.trials,'k','linew',3)
end

%% end.


function bnet = mk_alarm_bnet()

% Written by Qian Diao <qian.diao@intel.com> on 11 Dec 01

N = 37;
dag = zeros(N,N);
dag(21,23) = 1 ;
dag(21,24) = 1 ;
dag(1,24) = 1 ;
dag(1,23) = 1 ;
dag(2,26) = 1 ;
dag(2,25) = 1 ;
dag(2,24) = 1 ;
dag(2,13) = 1 ;
dag(2,23) = 1 ;
dag(13,30) = 1 ;
dag(30,31) = 1 ;
dag(3,14) = 1 ;
dag(3,19) = 1 ;
dag(4,36) = 1 ;
dag(14,35) = 1 ;
dag(32,33) = 1 ;
dag(32,35) = 1 ;
dag(32,34) = 1 ;
dag(32,36) = 1 ;
dag(15,21) = 1 ;
dag(5,31) = 1 ;
dag(27,30) = 1 ;
dag(28,31) = 1 ;
dag(28,29) = 1 ;
dag(26,28) = 1 ;
dag(26,27) = 1 ;
dag(16,31) = 1 ;
dag(16,37) = 1 ;
dag(23,26) = 1 ;
dag(23,29) = 1 ;
dag(23,25) = 1 ;
dag(6,15) = 1 ;
dag(7,27) = 1 ;
dag(8,21) = 1 ;
dag(19,20) = 1 ;
dag(19,22) = 1 ;
dag(31,32) = 1 ;
dag(9,14) = 1 ;
dag(9,17) = 1 ;
dag(9,19) = 1 ;
dag(10,33) = 1 ;
dag(10,34) = 1 ;
dag(11,16) = 1 ;
dag(12,13) = 1 ;
dag(12,18) = 1 ;
dag(35,37) = 1 ;

node_sizes = 2*ones(1,N);
node_sizes(2) = 3;
node_sizes(6) = 3;
node_sizes(14) = 3;
node_sizes(15) = 4;
node_sizes(16) = 3;
node_sizes(18) = 3;
node_sizes(19) = 3;
node_sizes(20) = 3;
node_sizes(21) = 4;
node_sizes(22) = 3;
node_sizes(23) = 4;
node_sizes(24) = 4;
node_sizes(25) = 4;
node_sizes(26) = 4;
node_sizes(27) = 3;
node_sizes(28) = 3;
node_sizes(29) = 4;
node_sizes(30) = 3;
node_sizes(32) = 3;
node_sizes(33) = 3;
node_sizes(34) = 3;
node_sizes(35) = 3;
node_sizes(36) = 3;
node_sizes(37) = 3;

bnet = mk_bnet(dag, node_sizes);

bnet.CPD{1} = tabular_CPD(bnet, 1,[0.96 0.04 ]);
bnet.CPD{2} = tabular_CPD(bnet, 2,[0.92 0.03 0.05 ]);
bnet.CPD{3} = tabular_CPD(bnet, 3,[0.8 0.2 ]);
bnet.CPD{4} = tabular_CPD(bnet, 4,[0.95 0.05 ]);
bnet.CPD{5} = tabular_CPD(bnet, 5,[0.8 0.2 ]);
bnet.CPD{6} = tabular_CPD(bnet, 6,[0.01 0.98 0.01 ]);
bnet.CPD{7} = tabular_CPD(bnet, 7,[0.01 0.99 ]);
bnet.CPD{8} = tabular_CPD(bnet, 8,[0.95 0.05 ]);
bnet.CPD{9} = tabular_CPD(bnet, 9,[0.95 0.05 ]);
bnet.CPD{10} = tabular_CPD(bnet, 10,[0.9 0.1 ]);
bnet.CPD{11} = tabular_CPD(bnet, 11,[0.99 0.01 ]);
bnet.CPD{12} = tabular_CPD(bnet, 12,[0.99 0.01 ]);
bnet.CPD{13} = tabular_CPD(bnet, 13,[0.95 0.95 0.05 0.1 0.1 0.01 0.05 0.05 0.95 0.9 0.9 0.99 ]);
bnet.CPD{14} = tabular_CPD(bnet, 14,[0.05 0.95 0.5 0.98 0.9 0.04 0.49 0.01 0.05 0.01 0.01 0.01 ]);
bnet.CPD{15} = tabular_CPD(bnet, 15,[0.01 0.01 0.01 0.97 0.01 0.01 0.01 0.97 0.01 0.01 0.01 0.97 ]);
bnet.CPD{16} = tabular_CPD(bnet, 16,[0.3 0.98 0.4 0.01 0.3 0.01 ]);
bnet.CPD{17} = tabular_CPD(bnet, 17,[0.99 0.1 0.01 0.9 ]);
bnet.CPD{18} = tabular_CPD(bnet, 18,[0.05 0.01 0.9 0.19 0.05 0.8 ]);
bnet.CPD{19} = tabular_CPD(bnet, 19,[0.05 0.98 0.01 0.95 0.9 0.01 0.09 0.04 0.05 0.01 0.9 0.01 ]);
bnet.CPD{20} = tabular_CPD(bnet, 20,[0.95 0.04 0.01 0.04 0.95 0.29 0.01 0.01 0.7 ]);
bnet.CPD{21} = tabular_CPD(bnet, 21,[0.97 0.97 0.01 0.97 0.01 0.97 0.01 0.97 0.01 0.01 0.97 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.97 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.97 0.01 ]);
bnet.CPD{22} = tabular_CPD(bnet, 22,[0.95 0.04 0.01 0.04 0.95 0.04 0.01 0.01 0.95 ]);
bnet.CPD{23} = tabular_CPD(bnet, 23,[0.97 0.97 0.97 0.97 0.97 0.97 0.01 0.95 0.97 0.97 0.01 0.95 0.01 0.4 0.97 0.97 0.01 0.5 0.01 0.3 0.97 0.97 0.01 0.3 0.01 0.01 0.01 0.01 0.01 0.01 0.97 0.03 0.01 0.01 0.97 0.03 0.01 0.58 0.01 0.01 0.01 0.48 0.01 0.68 0.01 0.01 0.01 0.68 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.97 0.01 0.01 0.01 0.97 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.97 0.01 0.01 0.01 0.97 0.01 ]);
bnet.CPD{24} = tabular_CPD(bnet, 24,[0.97 0.97 0.97 0.97 0.97 0.97 0.01 0.01 0.4 0.1 0.01 0.01 0.01 0.01 0.2 0.05 0.01 0.01 0.01 0.01 0.2 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.97 0.49 0.58 0.84 0.9 0.29 0.01 0.01 0.75 0.25 0.01 0.01 0.01 0.01 0.7 0.15 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.3 0.01 0.05 0.08 0.3 0.97 0.08 0.04 0.25 0.38 0.08 0.01 0.01 0.09 0.25 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.2 0.01 0.01 0.01 0.4 0.01 0.9 0.01 0.45 0.6 0.9 0.97 0.97 0.01 0.59 0.97 0.97 ]);
bnet.CPD{25} = tabular_CPD(bnet, 25,[0.97 0.97 0.97 0.01 0.6 0.01 0.01 0.5 0.01 0.01 0.5 0.01 0.01 0.01 0.01 0.97 0.38 0.97 0.01 0.48 0.01 0.01 0.48 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.97 0.01 0.97 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.97 0.01 0.97 ]);
bnet.CPD{26} = tabular_CPD(bnet, 26,[0.97 0.97 0.97 0.01 0.01 0.03 0.01 0.01 0.01 0.97 0.01 0.01 0.01 0.01 0.01 0.97 0.97 0.95 0.01 0.01 0.94 0.01 0.01 0.88 0.01 0.01 0.01 0.01 0.01 0.01 0.97 0.97 0.04 0.01 0.01 0.1 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.97 0.97 0.01 ]);
bnet.CPD{27} = tabular_CPD(bnet, 27,[0.98 0.98 0.98 0.98 0.95 0.01 0.95 0.01 0.01 0.01 0.01 0.01 0.04 0.95 0.04 0.01 0.01 0.01 0.01 0.01 0.01 0.04 0.01 0.98 ]);
bnet.CPD{28} = tabular_CPD(bnet, 28,[0.01 0.01 0.04 0.9 0.01 0.01 0.92 0.09 0.98 0.98 0.04 0.01 ]);
bnet.CPD{29} = tabular_CPD(bnet, 29,[0.97 0.01 0.01 0.01 0.97 0.01 0.01 0.01 0.97 0.01 0.01 0.01 0.01 0.97 0.97 0.97 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.97 0.97 0.97 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.97 0.97 0.43 ]);
bnet.CPD{30} = tabular_CPD(bnet, 30,[0.98 0.98 0.01 0.98 0.01 0.69 0.01 0.01 0.98 0.01 0.01 0.3 0.01 0.01 0.01 0.01 0.98 0.01 ]);
bnet.CPD{31} = tabular_CPD(bnet, 31,[0.05 0.01 0.05 0.01 0.05 0.01 0.05 0.01 0.05 0.01 0.05 0.01 0.01 0.01 0.01 0.01 0.01 0.01 0.1 0.01 0.95 0.01 0.95 0.05 0.1 0.01 0.95 0.01 0.95 0.05 0.1 0.01 0.3 0.01 0.3 0.01 0.95 0.01 0.99 0.05 0.95 0.05 0.95 0.01 0.99 0.05 0.99 0.05 0.3 0.01 0.99 0.01 0.3 0.01 0.95 0.99 0.95 0.99 0.95 0.99 0.95 0.99 0.95 0.99 0.95 0.99 0.99 0.99 0.99 0.99 0.99 0.99 0.9 0.99 0.05 0.99 0.05 0.95 0.9 0.99 0.05 0.99 0.05 0.95 0.9 0.99 0.7 0.99 0.7 0.99 0.05 0.99 0.00999999 0.95 0.05 0.95 0.05 0.99 0.01 0.95 0.01 0.95 0.7 0.99 0.01 0.99 0.7 0.99 ]);
bnet.CPD{32} = tabular_CPD(bnet, 32,[0.1 0.01 0.89 0.09 0.01 0.9 ]);
bnet.CPD{33} = tabular_CPD(bnet, 33,[0.98 0.33333334 0.01 0.33333334 0.01 0.33333334 0.01 0.33333334 0.98 0.33333334 0.01 0.33333334 0.01 0.33333334 0.01 0.33333334 0.98 0.33333334 ]);
bnet.CPD{34} = tabular_CPD(bnet, 34,[0.98 0.33333334 0.01 0.33333334 0.01 0.33333334 0.01 0.33333334 0.98 0.33333334 0.01 0.33333334 0.01 0.33333334 0.01 0.33333334 0.98 0.33333334 ]);
bnet.CPD{35} = tabular_CPD(bnet, 35,[0.98 0.95 0.3 0.95 0.04 0.01 0.8 0.01 0.01 0.01 0.04 0.69 0.04 0.95 0.3 0.19 0.04 0.01 0.01 0.01 0.01 0.01 0.01 0.69 0.01 0.95 0.98 ]);
bnet.CPD{36} = tabular_CPD(bnet, 36,[0.98 0.98 0.01 0.4 0.01 0.3 0.01 0.01 0.98 0.59 0.01 0.4 0.01 0.01 0.01 0.01 0.98 0.3 ]);
bnet.CPD{37} = tabular_CPD(bnet, 37,[0.98 0.98 0.3 0.98 0.1 0.05 0.9 0.05 0.01 0.01 0.01 0.6 0.01 0.85 0.4 0.09 0.2 0.09 0.01 0.01 0.1 0.01 0.05 0.55 0.01 0.75 0.9 ]);