├── .gitignore ├── README.md ├── doc └── karedal.pdf ├── res └── antenna │ └── Eaz.mat ├── .gitattributes └── src ├── CreateProgressBar.m ├── plotTheoTimeDelay.m ├── V2V_antresp.m ├── V2V_plot_geometry.m ├── V2V_model_params.m ├── V2V_gen_LS_fading.m ├── V2V_model.m └── ConsoleProgressBar.m /.gitignore: -------------------------------------------------------------------------------- 1 | *.asv 2 | V2V_model_output.mat -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # v2v 2 | Vehicle-to-Vehicle Comm. 3 | -------------------------------------------------------------------------------- /doc/karedal.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimme/v2v-model/HEAD/doc/karedal.pdf -------------------------------------------------------------------------------- /res/antenna/Eaz.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimme/v2v-model/HEAD/res/antenna/Eaz.mat -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.mat -crlf -diff -merge 2 | *.p -crlf -diff -merge 3 | *.slx -crlf -diff -merge 4 | *.mdl -crlf -diff -merge 5 | 6 | *.mdlp -crlf -diff -merge 7 | *.slxp -crlf -diff -merge 8 | *.sldd -crlf -diff -merge 9 | *.mexa64 -crlf -diff -merge 10 | *.mexw64 -crlf -diff -merge 11 | *.mexmaci64 -crlf -diff -merge 12 | *.xlsx -crlf -diff -merge 13 | *.docx -crlf -diff -merge 14 | *.pdf -crlf -diff -merge 15 | *.jpg -crlf -diff -merge 16 | *.png -crlf -diff -merge -------------------------------------------------------------------------------- /src/CreateProgressBar.m: -------------------------------------------------------------------------------- 1 | function cpb = CreateProgressBar(maxVal) 2 | 3 | % Create Instance 4 | cpb = ConsoleProgressBar(); 5 | 6 | % Set progress bar parameters 7 | cpb.setLeftMargin(3); % progress bar left margin 8 | cpb.setTopMargin(0); % rows margin 9 | 10 | cpb.setLength(30); % progress bar length: [.....] 11 | cpb.setMinimum(0); % minimum value of progress range [min max] 12 | cpb.setMaximum(maxVal); % maximum value of progress range [min max] 13 | 14 | cpb.setElapsedTimeVisible(1); 15 | cpb.setRemainedTimeVisible(1); 16 | 17 | cpb.setElapsedTimePosition('left'); 18 | cpb.setRemainedTimePosition('right'); -------------------------------------------------------------------------------- /src/plotTheoTimeDelay.m: -------------------------------------------------------------------------------- 1 | function plotTheoTimeDelay(p, d_LOS, d_MD, d_SD) 2 | 3 | figure; hold on 4 | % Easy solution to get the legend right 5 | plot(squeeze(d_MD(1,1,:))/300, p.T, 'b--', 'LineWidth', 1.5) 6 | plot(squeeze(d_SD(1,1,:))/300, p.T, 'm-.', 'LineWidth', 1.5) 7 | plot(d_LOS/300, p.T, 'r-','linewidth',1.5) 8 | 9 | % Plot the rest 10 | plot(squeeze(d_MD(1,2:end,:))/300, p.T, 'b--', 'LineWidth', 1.5) 11 | plot(squeeze(d_SD(1,2:end,:))/300, p.T, 'm-.', 'LineWidth', 1.5) 12 | 13 | % Set some axes settings 14 | set(gca, ... 15 | 'FontSize', 14, ... 16 | 'FontName', 'Times', ... 17 | 'LineWidth', 1 ... 18 | ) 19 | xlabel('Delay [\mu s]') 20 | ylabel('Time [s]') 21 | grid on 22 | title('Theoretic time-delay plot') 23 | legend('MD', 'SD', 'LOS') 24 | axis([0 10 0 0.2338]) 25 | 26 | drawnow -------------------------------------------------------------------------------- /src/V2V_antresp.m: -------------------------------------------------------------------------------- 1 | function G = V2V_antresp( p, channel, angleTx, angleRx ) 2 | % V2V_antresp ... returns the antenna respose for a certain Tx AND Rx angle 3 | % 4 | % Parameters: 5 | % p V2V parameter structure containing the antenna response and the 6 | % antenna rotations 7 | % channel containing the channel number (1...N_Tx*N_Rx) 8 | % angleTx contains a vector of Tx angles 9 | % angleRx contains a vector of corresponding Rx angles 10 | % 11 | % Returns: 12 | % Antenna gain vector for the combined Tx/Rx angles 13 | % 14 | % History: 15 | % 2008-03-13 NCZ: created 16 | 17 | % Select the angular indices; 18 | switch channel 19 | case 1, phiTx = p.phi(1,:); phiRx = p.phi(1,:); 20 | 21 | case 2, phiTx = p.phi(2,:); phiRx = p.phi(1,:); 22 | 23 | case 3, phiTx = p.phi(1,:); phiRx = p.phi(2,:); 24 | 25 | case 4, phiTx = p.phi(2,:); phiRx = p.phi(2,:); 26 | end 27 | 28 | [~,idxTx] = min(abs(repmat(angleTx.'/pi*180,1,length(phiTx)) - repmat(phiTx,length(angleTx),1)),[],2); 29 | [~,idxRx] = min(abs(repmat(angleRx.'/pi*180,1,length(phiRx)) - repmat(phiRx,length(angleRx),1)),[],2); 30 | 31 | G = p.G_ant(idxTx) .* p.G_ant(idxRx); 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/V2V_plot_geometry.m: -------------------------------------------------------------------------------- 1 | function V2V_plot_geometry(p) 2 | % V2V_plot_geometry Plots the inital geometry being simulated. 3 | % 4 | % Input parameters: 5 | % p V2V parameter structure 6 | % 7 | % Output: 8 | % A new figure containing the geometry 9 | % 10 | 11 | tailLength = 50; 12 | 13 | xRx0 = p.xRx0(1,:); 14 | xTx0 = p.xTx0(1,:); 15 | 16 | figure; hold on 17 | 18 | plot(p.xD(:,1), p.xD(:,2), 'k.', 'MarkerSize', 8, 'LineWidth', 1.5) 19 | plot(p.xMD0(:,1), p.xMD0(:,2), 'b*', 'MarkerSize', 8, 'LineWidth', 1.5) 20 | plot(p.xSD(:,1), p.xSD(:,2), 'ms', 'MarkerSize', 8, 'LineWidth', 1.5) 21 | 22 | plot(xTx0(1), xTx0(2), 'rv', 'MarkerSize', 8, 'LineWidth', 1.5) 23 | plot(xRx0(1), xRx0(2), 'rd', 'MarkerSize', 8, 'LineWidth', 1.5) 24 | 25 | plot([xTx0(1) xTx0(1)+sign(p.vTx(1))*tailLength], [xTx0(2) xTx0(2)], 'r-', 'LineWidth', 1.5) 26 | plot([xRx0(1) xRx0(1)+sign(p.vRx(1))*tailLength], [xRx0(2) xRx0(2)], 'r-', 'LineWidth', 1.5) 27 | 28 | plot([p.xMD0(:,1) p.xMD0(:,1)+sign(p.vMD(:,1))*tailLength]',[p.xMD0(:,2) p.xMD0(:,2)]', 'b-', 'LineWidth', 1.5) 29 | 30 | set(gca, ... 31 | 'FontSize', 14, ... 32 | 'FontName', 'Times', ... 33 | 'LineWidth', 1 ... 34 | ) 35 | xlabel('x [m]') 36 | xlabel('y [m]') 37 | grid on 38 | title('Initial geometry') 39 | 40 | drawnow 41 | -------------------------------------------------------------------------------- /src/V2V_model_params.m: -------------------------------------------------------------------------------- 1 | function p = V2V_model_params( dir ) 2 | % V2V_model_params 3 | % generates a parameter set for the optimised V2V model 4 | % 5 | % Input parameters: 6 | % dir ... When empty, or 'OD', a highway, opposite-direction scenario is parametrised 7 | % When 'SD', a highway, same-direction scenario is parametrised 8 | % 9 | % Output parameters: 10 | % params .. V2V model parameters 11 | % NOTE: Set params.filename to the output file path! 12 | % 13 | % Prerequisites: 14 | % Make sure that Eaz.mat is in the current directory or in the MATLAB 15 | % path 16 | 17 | % History: 18 | % 2008-03-13 NCZ: created 19 | 20 | rootDir = fullfile(fileparts(fileparts(which(mfilename)))); 21 | 22 | p.filename = fullfile(rootDir,'V2V_model_output.mat'); 23 | p.chunksize = 10; 24 | 25 | if nargin == 1, 26 | if strcmp( dir,'SD') 27 | p.di = 'SD'; 28 | else 29 | p.di = 'OD'; 30 | end 31 | else 32 | p.di = 'OD'; 33 | end 34 | 35 | 36 | %% Radio parameters 37 | % dt Measured value 0.3072e-3; 38 | % Tmax Measured value 10 s250 39 | p.dt = 0.3072e-3; %.01; 40 | p.Tmax = 0.5; 41 | p.T = 0:p.dt:p.Tmax; 42 | p.F = (5.08:0.01/32:5.32)*1e9; 43 | 44 | %% Geometry limits - geometric coordinates organized as matrices "x" with {x_coord ycoord} as rows 45 | p.xmin = [-250 0]; 46 | p.xmax = [250 250]; 47 | p.w_road = 17; % Width of road 48 | p.NbrLanes = 4; % Number of lanes, must be even 49 | p.y_m_SD = 14; % Distance from center of road to mean value of SD positions 50 | p.y_sigma_SD = 3; % Standard deviation of SD position y-coordinates 51 | p.y_m_D = 11; % Distance from center of road to first value of diffuse scattering positions 52 | p.w_D = 5; % Width of diffuse scattering band 53 | 54 | %% Statistics 55 | % Scatterer densities 56 | p.chi_SD = 0.005; 57 | p.chi_MD = 0.005; 58 | p.chi_D = 1; 59 | 60 | % Distribution parameters for model parameters 61 | p.mu_sigma2_LOS = 6.8; 62 | p.mu_sigma2_MD = 9.4; 63 | p.mu_sigma2_SD = 6.3; 64 | 65 | p.mu_d50_LOS = 7.2; 66 | p.mu_d50_MD = 5.4; 67 | p.mu_d50_SD = 4.9; 68 | 69 | p.d50_min_LOS = 4.4; 70 | p.d50_min_MD = 1.1; 71 | p.d50_min_SD = 1.0; 72 | 73 | p.n_PL_LOS = 1.6; 74 | p.n_PL_D = 8; 75 | 76 | p.m_n_MD = 1.9; 77 | p.m_n_SD = 1.0; 78 | 79 | p.sigma_n_MD = 2.5; 80 | p.sigma_n_SD = 3.1; 81 | 82 | p.n_min_MD = 0; 83 | p.n_min_SD = 0; 84 | p.n_max_MD = 3.5; 85 | p.n_max_SD = 3.5; 86 | 87 | p.m_v_MD = 90; 88 | p.sigma_v_MD = 2; 89 | 90 | p.G0_LOS = -30; 91 | p.G0_D = 100; 92 | 93 | % Implementation parameters 94 | p.L_filter = 500; 95 | 96 | % Time, frequency vectors etc. 97 | p.c = 3e8; 98 | p.NbrFreq = length(p.F); 99 | p.BW = p.F(end)-p.F(1); 100 | p.tau = (0:p.NbrFreq-1)/p.BW; 101 | p.nu = ((0:length(p.T)-1)/p.dt/(length(p.T))); p.nu = p.nu-p.nu(end)/2; 102 | 103 | 104 | % Antenna patterns 105 | Eaz = []; 106 | load(fullfile(rootDir,'res','antenna','Eaz.mat')); 107 | [~,ind_max] = max(abs(Eaz)); 108 | p.G_ant = single([Eaz(ind_max:end) Eaz(1:ind_max-1)]); 109 | p.phi(1,:) = [224:2:358 0:2:222]; 110 | p.phi(2,:) = [314:2:358 0:2:312]; 111 | p.phi(3,:) = [44:2:358 0:2:42]; 112 | p.phi(4,:) = [134:2:358 0:2:132]; 113 | 114 | p.xTx0 = [ 0.00 0.00 % Tx initial position vector [xcoord,ycoord], el 1 115 | 0.09 0.00]; % el 2 116 | p.xRx0 = [20.00 0.00 % Rx " " " " 117 | 20.09 0.00]; 118 | p.N_Tx = 2; 119 | p.N_Rx = 2; 120 | p.vTx = repmat([90 0],p.N_Tx,1)/3.6; % Tx velocity vector [xcoord,ycoord] 121 | p.vRx = repmat([91 0],p.N_Rx,1)/3.6; % Rx " " " 122 | if strcmp(p.di,'OD') 123 | p.xRx0(:,2) = p.w_road - p.w_road/p.NbrLanes; 124 | p.vRx = -p.vRx; 125 | else 126 | p.xRx0(:,2) = 0; 127 | end 128 | 129 | %%% Generate a random environment 130 | fprintf( 'Generating random environment ...\r\n'); 131 | 132 | p.N_SD = ceil(p.chi_SD*(p.xmax(1)-p.xmin(1))/2)*2; 133 | p.N_MD = round(randn + p.chi_MD*(p.xmax(1)-p.xmin(1))); if p.N_MD < 0, p.N_MD = 0; end; 134 | p.N_D = p.chi_D*(p.xmax(1)-p.xmin(1)); 135 | 136 | p.xMD0 = [(p.xmax(1)-p.xmin(1))*rand(p.N_MD,1)+p.xmin(1) p.w_road/p.NbrLanes*(ceil(p.NbrLanes*rand(p.N_MD,1))-1)]; 137 | p.vMD = [p.sigma_v_MD*randn(p.N_MD,1)+p.m_v_MD zeros(p.N_MD,1)]/3.6; 138 | p.vMD(p.xMD0(:,2)/p.w_road >= .5, 1) = - p.vMD(p.xMD0(:,2)/p.w_road >= .5,1); 139 | 140 | p.xSD = [(p.xmax(1)-p.xmin(1))*rand(p.N_SD/2,1)+p.xmin(1) p.y_sigma_SD*randn(p.N_SD/2,1)+(p.w_road*(p.NbrLanes-1)/2/p.NbrLanes)+p.y_m_SD 141 | (p.xmax(1)-p.xmin(1))*rand(p.N_SD/2,1)+p.xmin(1) p.y_sigma_SD*randn(p.N_SD/2,1)+(p.w_road*(p.NbrLanes-1)/2/p.NbrLanes)-p.y_m_SD]; 142 | p.xD = [ (p.xmax(1)-p.xmin(1))*rand(p.N_D/2, 1)+p.xmin(1) p.w_D * rand(p.N_D/2,1)+ (p.w_road*(p.NbrLanes-1)/2/p.NbrLanes)+p.y_m_D 143 | (p.xmax(1)-p.xmin(1))*rand(p.N_D/2, 1)+p.xmin(1) -p.w_D * rand(p.N_D/2,1)+ (p.w_road*(p.NbrLanes-1)/2/p.NbrLanes)-p.y_m_D]; 144 | 145 | % LOS 146 | p.sigma_LS_LOS = abs(sqrt(p.mu_sigma2_LOS/2)*(randn+1j*randn)).^2; 147 | p.d05_LOS = p.d50_min_LOS + abs(sqrt(p.mu_d50_LOS/2)*(randn+1j*randn)).^2; 148 | 149 | % Mobile Discrete 150 | p.sigma_LS_MD = abs(sqrt(p.mu_sigma2_MD/2).*(randn(p.N_MD,1)+1j*randn(p.N_MD,1))).^2; 151 | p.d05_MD = p.d50_min_MD + abs(sqrt(p.mu_d50_MD/2).*(randn(p.N_MD,1)+1j*randn(p.N_MD,1))).^2; 152 | p.n_PL_MD = p.sigma_n_MD*randn(p.N_MD,1) + p.m_n_MD; p.n_PL_MD(p.n_PL_MD < p.n_min_MD) = p.n_min_MD; p.n_PL_MD(p.n_PL_MD > p.n_max_MD) = p.n_max_MD; 153 | p.G0_MD = -100+24*p.n_PL_MD; 154 | p.phi_MD = 2*pi*rand(p.N_MD,1); 155 | 156 | % Static Discrete 157 | p.sigma_LS_SD = abs(sqrt(p.mu_sigma2_SD/2).*(randn(p.N_SD,1)+1j*randn(p.N_SD,1))).^2; 158 | p.d05_SD = p.d50_min_SD + abs(sqrt(p.mu_d50_SD/2).*(randn(p.N_SD,1)+1j*randn(p.N_SD,1))).^2; 159 | p.n_PL_SD = p.sigma_n_SD*randn(p.N_SD,1) + p.m_n_SD; p.n_PL_SD(p.n_PL_SD < p.n_min_SD) = p.n_min_SD; p.n_PL_SD(p.n_PL_SD > p.n_max_SD) = p.n_max_SD; 160 | p.G0_SD = -100+24*p.n_PL_SD; 161 | p.phi_SD = 2*pi*rand(p.N_SD,1); 162 | 163 | -------------------------------------------------------------------------------- /src/V2V_gen_LS_fading.m: -------------------------------------------------------------------------------- 1 | function [G_LS_LOS, G_LS_MD, G_LS_SD] = V2V_gen_LS_fading( p, d_LOS, d_MD, d_SD ) 2 | % V2V_gen_LS_fading 3 | % 4 | % Subroutine for V2V model, generates the LS fading. 5 | % Speed improvement by using SVDS function (evaluates only the first 6 6 | % singular values, which is much faster and - in this application - equally accurate. 7 | % 8 | % First, samples are generated with equidistant spacing, then the samples 9 | % are linearly interpolated for the (non-equidistant) path lengths 10 | % 11 | % Parameters: 12 | % p V2V parameter structure 13 | % d_LOS LOS distances 14 | % d_MD MD path distances (for all N_MD paths) 15 | % d_SM SD path distances (for all N_SD paths) 16 | % 17 | % Output: 18 | % G_LS_LOS, G_LS_MD, G_LS_SD large-scale fading factors (log-scale!) 19 | 20 | % History: 21 | % 2008-03-13 NCZ: created 22 | 23 | disp('Generate LS fading') 24 | 25 | disp(' ...for LOS...') 26 | d_sim_LOS = [0 cumsum(abs(diff(d_LOS(1,:))))]; % Correlated data sampled at d_samp_LOS, resample to d_sim_LOS 27 | d_samp_LOS = (0:p.L_filter-1)/(p.L_filter-1)*ceil(d_sim_LOS(end)); 28 | G_LS_LOS_uncorr = randn(length(d_samp_LOS),1); 29 | R_LOS_row = p.sigma_LS_LOS^2*exp(-log(2)/p.d05_LOS^2*(d_samp_LOS).^2); 30 | R_LOS = toeplitz(R_LOS_row); [U_LOS,S_LOS,V_LOS] = svds(double(R_LOS)); 31 | G_LS_LOS_eqd = ((U_LOS*sqrt(S_LOS)*V_LOS'*G_LS_LOS_uncorr).'); 32 | 33 | disp(' ...for mobile discrete scatterers...') 34 | d_MD_mean = squeeze(d_MD(1,:,:)); 35 | for ctr_MD = 1:p.N_MD 36 | d_diff_MD = [0 d_MD_mean(ctr_MD,:)]-[d_MD_mean(ctr_MD,:) 0]; d_diff_MD = d_diff_MD(2:end-1); 37 | d_sim_MD_temp = [0 cumsum(abs(d_diff_MD))]; % Correlated data sampled at d_samp_MD, resample to d_sim_MD 38 | d_sim_MD_max(ctr_MD) = d_sim_MD_temp(end); 39 | end 40 | d_samp_MD = (0:p.L_filter-1)/(p.L_filter-1)*ceil(max(d_sim_MD_max)); 41 | for ctr_MD = 1:p.N_MD 42 | G_LS_MD_uncorr = randn(length(d_samp_MD),1); 43 | R_MD_row = p.sigma_LS_MD(ctr_MD)^2*exp(-log(2)/p.d05_MD(ctr_MD)^2*(d_samp_MD).^2); 44 | R_MD = toeplitz(R_MD_row); [U_MD,S_MD,V_MD] = svds(double(R_MD)); 45 | G_LS_MD_eqd(ctr_MD,:) = ((U_MD*sqrt(S_MD)*V_MD'*G_LS_MD_uncorr).'); 46 | end 47 | 48 | disp(' ...for stationary discrete scatterers...') 49 | d_SD_mean = squeeze(d_SD(1,:,:)); 50 | for ctr_SD = 1:p.N_SD 51 | d_diff_SD = [0 d_SD_mean(ctr_SD,:)]-[d_SD_mean(ctr_SD,:) 0]; d_diff_SD = d_diff_SD(2:end-1); 52 | d_sim_SD_temp = [0 cumsum(abs(d_diff_SD))]; % Correlated data sampled at d_samp_SD, resample to d_sim_SD 53 | d_sim_SD_max(ctr_SD) = d_sim_SD_temp(end); 54 | end 55 | d_samp_SD = (0:p.L_filter-1)/(p.L_filter-1)*ceil(max(d_sim_SD_max)); 56 | for ctr_SD = 1:p.N_SD 57 | G_LS_SD_uncorr = randn(length(d_samp_SD),1); 58 | R_SD_row = p.sigma_LS_SD(ctr_SD)^2*exp(-log(2)/p.d05_SD(ctr_SD)^2*(d_samp_SD).^2); 59 | R_SD = toeplitz(R_SD_row); [U_SD,S_SD,V_SD] = svds(double(R_SD)); 60 | G_LS_SD_eqd(ctr_SD,:) = ((U_SD*sqrt(S_SD)*V_SD'*G_LS_SD_uncorr).'); 61 | end 62 | 63 | 64 | disp(' Resampling large-scale data...') 65 | disp(' ...for LOS...') 66 | G_LS_LOS(1) = G_LS_LOS_eqd(1); 67 | for ctr_LOS = 2:length(d_sim_LOS) 68 | xtemp = d_samp_LOS(abs(d_sim_LOS(ctr_LOS)-d_samp_LOS)==min(abs(d_sim_LOS(ctr_LOS)-d_samp_LOS))); 69 | if length(xtemp) == 2 70 | x1 = min(xtemp); 71 | x2 = max(xtemp); 72 | y1 = G_LS_LOS_eqd(abs(d_samp_LOS-x1)<1e-6); 73 | y2 = G_LS_LOS_eqd(abs(d_samp_LOS-x2)<1e-6); 74 | elseif d_sim_LOS(ctr_LOS) < xtemp 75 | x2 = xtemp; 76 | y2 = G_LS_LOS_eqd(abs(d_samp_LOS-x2)<1e-6); 77 | x1 = xtemp - (d_samp_LOS(2) - d_samp_LOS(1)); 78 | y1 = G_LS_LOS_eqd(abs(d_samp_LOS-x1)<1e-6); 79 | else 80 | x1 = xtemp; 81 | y1 = G_LS_LOS_eqd(abs(d_samp_LOS-x1)<1e-6); 82 | x2 = xtemp + (d_samp_LOS(2) - d_samp_LOS(1)); 83 | y2 = G_LS_LOS_eqd(abs(d_samp_LOS-x2)<1e-6); 84 | end 85 | G_LS_LOS(ctr_LOS) = interp1([x1 x2], [y1 y2], d_sim_LOS(ctr_LOS), 'linear', 'extrap'); 86 | end 87 | 88 | disp(' ...mobile discrete scatterers...') 89 | for ctr_MD = 1:p.N_MD 90 | d_diff_MD = [0 d_MD_mean(ctr_MD,:)]-[d_MD_mean(ctr_MD,:) 0]; d_diff_MD = d_diff_MD(2:end-1); 91 | d_sim_MD = [0 cumsum(abs(d_diff_MD))]; % Correlated data sampled at d_samp_MD, resample to d_sim_MD 92 | G_LS_MD(ctr_MD,1) = G_LS_MD_eqd(ctr_MD,1); 93 | for ctr_d = 2:length(d_sim_MD) 94 | xtemp = d_samp_MD(abs(d_sim_MD(ctr_d)-d_samp_MD)==min(abs(d_sim_MD(ctr_d)-d_samp_MD))); 95 | if d_sim_MD(ctr_d) < xtemp 96 | x2 = xtemp; 97 | y2 = G_LS_MD_eqd(ctr_MD,abs(d_samp_MD-x2)<1e-6); 98 | x1 = xtemp - (d_samp_MD(2) - d_samp_MD(1)); 99 | y1 = G_LS_MD_eqd(ctr_MD,abs(d_samp_MD-x1)<1e-6); 100 | else 101 | x1 = xtemp; 102 | y1 = G_LS_MD_eqd(ctr_MD,abs(d_samp_MD-x1)<1e-6); 103 | x2 = xtemp + (d_samp_MD(2) - d_samp_MD(1)); 104 | y2 = G_LS_MD_eqd(ctr_MD,abs(d_samp_MD-x2)<1e-6); 105 | end 106 | G_LS_MD(ctr_MD,ctr_d) = interp1([x1 x2], [y1 y2], d_sim_MD(ctr_d), 'linear', 'extrap'); 107 | end 108 | end 109 | 110 | disp(' ...stationary discrete scatterers...') 111 | for ctr_SD = 1:p.N_SD 112 | d_diff_SD = [0 d_SD_mean(ctr_SD,:)]-[d_SD_mean(ctr_SD,:) 0]; d_diff_SD = d_diff_SD(2:end-1); 113 | d_sim_SD = [0 cumsum(abs(d_diff_SD))]; % Correlated data sampled at d_samp_SD, resample to d_sim_SD 114 | G_LS_SD(ctr_SD,1) = G_LS_SD_eqd(ctr_SD,1); 115 | for ctr_d = 2:length(d_sim_SD) 116 | xtemp = d_samp_SD(abs(d_sim_SD(ctr_d)-d_samp_SD)==min(abs(d_sim_SD(ctr_d)-d_samp_SD))); 117 | if d_sim_SD(ctr_d) < xtemp 118 | x2 = xtemp; 119 | y2 = G_LS_SD_eqd(ctr_SD,abs(d_samp_SD-x2)<1e-6); 120 | x1 = xtemp - (d_samp_SD(2) - d_samp_SD(1)); 121 | y1 = G_LS_SD_eqd(ctr_SD,abs(d_samp_SD-x1)<1e-6); 122 | else 123 | x1 = xtemp; 124 | y1 = G_LS_SD_eqd(ctr_SD,abs(d_samp_SD-x1)<1e-6); 125 | x2 = xtemp + (d_samp_SD(2) - d_samp_SD(1)); 126 | y2 = G_LS_SD_eqd(ctr_SD,abs(d_samp_SD-x2)<1e-6); 127 | end 128 | G_LS_SD(ctr_SD,ctr_d) = interp1([x1 x2], [y1 y2],d_sim_SD(ctr_d), 'linear', 'extrap'); 129 | end 130 | end -------------------------------------------------------------------------------- /src/V2V_model.m: -------------------------------------------------------------------------------- 1 | function V2V_model( p ) 2 | % V2V_model --- Optimised Vehicle-to-Vehicle model 3 | % 4 | % Based on the C2C model of Johan Karedal, Lund University, Sweden 5 | % Optimised by Nicolai Czink, FTW, Vienna, Austria 6 | % 7 | % Input paramters: 8 | % params ... V2V parameter structure 9 | % OR 10 | % filename containing the parameters (NOT in a structure) 11 | % (save a params structure with "save -struct ") 12 | % 13 | % Output: 14 | % This function writes a file containing the modelled snapshots of the 15 | % channel and the scenario parameters (filename specified in the params 16 | % structure) 17 | % 18 | % Quick-Start-Guide: 19 | % Call 20 | % V2V_model_opt( ) 21 | % for opposite direction highway scenario @ 90 km/h 22 | % 23 | % OR 24 | % 25 | % V2V_model_opt( V2V_model_params('SD') ) 26 | % for same direction highway scenario @ 90 km/h 27 | % 28 | % History: 29 | % 2008-03-13 NCZ: created 30 | 31 | if nargin == 0, 32 | p = V2V_model_params; 33 | end 34 | 35 | if ischar(p), 36 | p = load(p); 37 | end 38 | 39 | save(p.filename,'p'); 40 | 41 | %% Determine distance vectors and angle vectors 42 | % New implementation: all time instants are calculated at the same time 43 | % while the loops are over the antenna elements and the scatterers 44 | % -> speed increases by a factor of ~60. 45 | 46 | fprintf('Determining distance vectors ... \r\n'); 47 | 48 | n_T = length(p.T); 49 | 50 | % Preliminary matrix/vector stacking 51 | d_LOS = zeros(p.N_Tx*p.N_Rx, n_T); 52 | d_MD = zeros(p.N_Tx*p.N_Rx, p.N_MD, n_T); 53 | d_SD = zeros(p.N_Tx*p.N_Rx, p.N_SD, n_T); 54 | d_D = zeros(p.N_Tx*p.N_Rx, p.N_D, n_T); 55 | thTxRx = zeros(p.N_Tx*p.N_Rx, n_T, 'single'); 56 | thTxMD = zeros(p.N_Tx*p.N_Rx, p.N_MD, n_T, 'single'); 57 | thTxSD = zeros(p.N_Tx*p.N_Rx, p.N_SD, n_T, 'single'); 58 | thTxD = zeros(p.N_Tx*p.N_Rx, p.N_D, n_T, 'single'); 59 | 60 | thRxMD = zeros(p.N_Tx*p.N_Rx, p.N_MD, n_T, 'single'); 61 | thRxSD = zeros(p.N_Tx*p.N_Rx, p.N_SD, n_T, 'single'); 62 | thRxD = zeros(p.N_Tx*p.N_Rx, p.N_D, n_T, 'single'); 63 | 64 | xTx = repmat(p.xTx0(:), 1, n_T) + p.vTx(:)*p.T; 65 | xRx = repmat(p.xRx0(:), 1, n_T) + p.vRx(:)*p.T; 66 | xMD = repmat(p.xMD0(:), 1, n_T) + p.vMD(:)*p.T; 67 | xSD = repmat(p.xSD(:), 1, n_T); 68 | xD = repmat(p.xD(:), 1, n_T); 69 | 70 | % Determining distances and angles 71 | ctr_ch = 0; 72 | for ch2 = 1:p.N_Rx % for all channels 73 | for ch1 = 1:p.N_Tx 74 | ctr_ch = ctr_ch + 1; 75 | 76 | % Determine Tx and Rx channel 77 | xTx_ch = xTx([ch1; ch1 + p.N_Tx],:); 78 | xRx_ch = xRx([ch2; ch2 + p.N_Rx],:); 79 | 80 | % Determine LOS distance and angle 81 | d_LOS(ctr_ch,:) = sqrt( sum((xTx_ch - xRx_ch).^2,1) ); 82 | thTxRx(ctr_ch,:) = acos((xRx_ch(1,:)-xTx_ch(1,:))./d_LOS(ctr_ch,:)); 83 | 84 | % Determine SD distances and angles 85 | for ctr_SD = 1:p.N_SD 86 | xSD_this = xSD([ctr_SD; ctr_SD + p.N_SD],:); 87 | toSD = sqrt( sum((xTx_ch - xSD_this).^2,1) ); 88 | fromSD = sqrt( sum((xSD_this - xRx_ch).^2,1)); 89 | d_SD(ctr_ch,ctr_SD,:) = toSD + fromSD; 90 | 91 | thTxSD(ctr_ch,ctr_SD,:) = acos((xSD_this(1,:)-xTx_ch(1,:))./toSD); 92 | thRxSD(ctr_ch,ctr_SD,:) = acos((xSD_this(1,:)-xRx_ch(1,:))./fromSD); 93 | end 94 | 95 | % Determine MD distances and angles 96 | for ctr_MD = 1:p.N_MD 97 | xMD_this = xMD([ctr_MD; ctr_MD + p.N_MD],:); 98 | toMD = sqrt( sum((xTx_ch - xMD_this).^2,1) ); 99 | fromMD = sqrt( sum((xMD_this - xRx_ch).^2,1)); 100 | d_MD(ctr_ch,ctr_MD,:) = toMD + fromMD; 101 | 102 | thTxMD(ctr_ch,ctr_MD,:) = acos((xMD_this(1,:)-xTx_ch(1,:))./toMD); 103 | thRxMD(ctr_ch,ctr_MD,:) = acos((xMD_this(1,:)-xRx_ch(1,:))./fromMD); 104 | end 105 | 106 | % Determine diffuse distances and angels 107 | for ctr_D = 1:p.N_D 108 | xD_this = xD([ctr_D; ctr_D + p.N_D],:); 109 | toD = sqrt( sum((xTx_ch - xD_this).^2,1) ); 110 | fromD = sqrt( sum((xD_this - xRx_ch).^2,1)); 111 | d_D(ctr_ch,ctr_D,:) = toD + fromD; 112 | 113 | thTxD(ctr_ch,ctr_D,:) = acos((xD_this(1,:)-xTx_ch(1,:))./toD); 114 | thRxD(ctr_ch,ctr_D,:) = acos((xD_this(1,:)-xRx_ch(1,:))./fromD); 115 | end 116 | end 117 | end 118 | 119 | if 0; plotTheoTimeDelay(p, d_LOS, d_MD, d_SD); end 120 | 121 | %% Generate LS fading 122 | 123 | [G_LS_LOS, G_LS_MD, G_LS_SD] = V2V_gen_LS_fading( p, d_LOS, d_MD, d_SD ); 124 | 125 | %% Generate channel matrix 126 | fprintf('\nGenerate channel matrix ...\n') 127 | ctr_t = 0; 128 | H = zeros(p.chunksize,p.N_Rx*p.N_Tx,length(p.F)); 129 | chunk = 0; 130 | save_cell = cell(floor(length(p.T)/p.chunksize), 2); 131 | 132 | cpb = CreateProgressBar(length(p.T)); 133 | cpb.start(); 134 | for t = p.T 135 | ctr_t = ctr_t + 1; 136 | idx_t = mod(ctr_t,p.chunksize); 137 | 138 | userText = sprintf('Progress: [%d/%d]', ctr_t, length(p.T)); 139 | cpb.setValue(ctr_t); % update progress value 140 | cpb.setText(userText) % update user text 141 | 142 | % overcome the MATLAB non-zero indexing 143 | if idx_t == 0; idx_t = p.chunksize; end; 144 | 145 | % Add LOS component 146 | for ctr_ch = 1:p.N_Rx*p.N_Tx; 147 | 148 | % LOS path 149 | H(idx_t,ctr_ch, :) = H(idx_t, ctr_ch, :) + ... 150 | shiftdim((V2V_antresp(p, ctr_ch, thTxRx(ctr_ch,ctr_t), thTxRx(ctr_ch,ctr_t)+pi).* ... 151 | 10.^(p.G0_LOS/20) .* 10.^(G_LS_LOS(ctr_t)/20) .* exp(-1j*2*pi*p.F/p.c*d_LOS(ctr_ch,ctr_t)) ./ ... 152 | (d_LOS(ctr_ch,ctr_t)^(p.n_PL_LOS/2))),-1); 153 | % MD paths 154 | H(idx_t, ctr_ch, :) = H(idx_t, ctr_ch, :) + ... 155 | shiftdim((V2V_antresp(p, ctr_ch,thTxSD(ctr_ch, :, ctr_t),thRxSD(ctr_ch, :, ctr_t)).* ... % SD 156 | 10.^(p.G0_SD.'/20) .* 10.^(G_LS_SD(:,ctr_t).'/20) ./ ((d_SD(ctr_ch,:,ctr_t).^(p.n_PL_SD(:).'/2)))) ... 157 | * exp(-1j*2*pi/p.c*d_SD(ctr_ch,:,ctr_t).'*p.F),-1); 158 | % SD paths 159 | H(idx_t, ctr_ch, :) = H(idx_t, ctr_ch, :) + ... 160 | shiftdim((V2V_antresp(p, ctr_ch,thTxMD(ctr_ch, :, ctr_t),thRxMD(ctr_ch, :, ctr_t)).* ... % MD 161 | 10.^(p.G0_MD.'/20) .* 10.^(G_LS_MD(:,ctr_t).'/20) ./ ((d_MD(ctr_ch,:,ctr_t).^(p.n_PL_MD(:).'/2))) ) ... 162 | * exp(-1j*2*pi/p.c*d_MD(ctr_ch,:,ctr_t).'*p.F),-1); 163 | % Diffuse paths 164 | H(idx_t, ctr_ch, :) = H(idx_t, ctr_ch, :) + ... 165 | shiftdim( ( V2V_antresp(p, ctr_ch, thTxD(ctr_ch, :, ctr_t),thRxD(ctr_ch, :, ctr_t)).* ... % D 166 | 10.^(p.G0_D/20) * (1/sqrt(p.N_D)) ./d_D(ctr_ch,:,ctr_t).^(p.n_PL_D/2) ) ... 167 | * exp(-1j*2*pi/p.c* d_D(ctr_ch,:,ctr_t).'*p.F), -1); 168 | end 169 | 170 | 171 | % Store a chunk when it is ready 172 | if idx_t == p.chunksize, 173 | chunk = chunk + 1; 174 | eval( sprintf( 'fr%09d.H = H;', floor(ctr_t/p.chunksize)) ); 175 | eval( sprintf( 'fr%09d.t = p.T(ctr_t-p.chunksize+1);', floor(ctr_t/p.chunksize)) ); 176 | save_cell{chunk, 1} = sprintf( 'fr%09d', floor(ctr_t/p.chunksize) ); 177 | save_cell{chunk, 2} = eval(sprintf( 'fr%09d', floor(ctr_t/p.chunksize) )); 178 | eval( sprintf( 'clear(''fr%09d'')', floor(ctr_t/p.chunksize)) ); 179 | H = zeros(p.chunksize,p.N_Rx*p.N_Tx,length(p.F)); 180 | end 181 | 182 | end 183 | cpb.stop(); 184 | 185 | c = cell2struct(save_cell(:,2), save_cell(:,1)); 186 | 187 | hSize = whos('c'); 188 | 189 | fprintf('\n ... saving channel matrix (compressing %4.2f MB) ...', hSize.bytes*1e-6); 190 | save('-append', p.filename, '-struct', 'c'); 191 | 192 | % do the last write if it hasn't been done before. 193 | if idx_t ~= p.chunksize, 194 | H = H(1:idx_t,:,:); 195 | eval( sprintf( 'fr%09d.H = H;', ceil(ctr_t/p.chunksize)) ); 196 | eval( sprintf( 'fr%09d.t = p.T(ctr_t-p.chunksize+1);', ceil(ctr_t/p.chunksize)) ); 197 | save( '-append', p.filename, sprintf( 'fr%09d', ceil(ctr_t/p.chunksize) ) ); 198 | eval( sprintf( 'clear(''fr%09d'')', ceil(ctr_t/p.chunksize)) ); 199 | end 200 | 201 | MyFileInfo = dir(p.filename); 202 | fprintf('\nFinished! Output saved to:\n\t%s (%4.2f MB)\n', p.filename, MyFileInfo.bytes*1e-6) 203 | 204 | -------------------------------------------------------------------------------- /src/ConsoleProgressBar.m: -------------------------------------------------------------------------------- 1 | classdef ConsoleProgressBar < handle 2 | %ConsoleProgressBar Console progress bar for long-running operations 3 | % 4 | % Description: 5 | % This class creates a console progress bar (status bar) 6 | % for long-running operations. 7 | % 8 | % It is possible to measure the elapsed and remained time of progress. 9 | % 10 | % 11 | % Usage: 12 | % cpb = ConsoleProgressBar(); 13 | % 14 | % 15 | % Example: 16 | % % Create Instance 17 | % cpb = ConsoleProgressBar(); 18 | % 19 | % % Set progress bar parameters 20 | % cpb.setLeftMargin(1); % progress bar left margin 21 | % cpb.setTopMargin(1); % rows margin 22 | % 23 | % cpb.setLength(40); % progress bar length: [.....] 24 | % cpb.setMinimum(0); % minimum value of progress range [min max] 25 | % cpb.setMaximum(100); % maximum value of progress range [min max] 26 | % 27 | % cpb.start(); 28 | % 29 | % for k = 0:100 30 | % userText = sprintf('Progress: [%d/%d]', k, 100); 31 | % 32 | % cpb.setValue(k); % update progress value 33 | % cpb.setText(userText) % update user text 34 | % 35 | % pause(0.025) 36 | % end 37 | % 38 | % cpb.stop(); 39 | % 40 | % 41 | % See also WAITBAR 42 | % 43 | 44 | % --------------------------------------------------------------------- 45 | % Version : 0.3 46 | % Author : Evgeny Prilepin aka iroln 47 | % Created : 03.02.11 48 | % Updated : 05.02.11 49 | % 50 | % Copyright : (C) 2011 Evgeny Prilepin 51 | % --------------------------------------------------------------------- 52 | 53 | 54 | properties (GetAccess = public, SetAccess = private) 55 | % GetAccess public properties 56 | 57 | leftMargin = 1 % Left margin in characters 58 | topMargin = 0 % Top margin in rows 59 | progressLength = 50 % Length of progress bar in characters 60 | minimum = 0 % Minimum progress value 61 | maximum = 100 % Maximum progress value 62 | value = 0 % Current progress value 63 | 64 | text = '' % User text 65 | isTextVisible = true % User text visible flag 66 | textPosition = 'right' % User text position 'left' or 'right' 67 | 68 | isPercentVisible = true % Percent text visible flag 69 | percentPosition = 'left' % Percent text position 'left' or 'right' 70 | 71 | isElapsedTimeVisible = false % Elapsed time text visible flag 72 | elapsedTimePosition = 'right' % Elapsed time text position 73 | 74 | isRemainedTimeVisible = false % Remained time text visible flag 75 | remainedTimePosition = 'right' % Remained time text position 76 | 77 | progressPercent = 0 % Percent of progress 78 | elapsedSeconds = 0 % Elapsed time from start in seconds 79 | remainedSeconds = Inf % Remained time (prediction) 80 | 81 | end % GetAccess public properties 82 | 83 | 84 | properties (Access = private) 85 | % Private Properties 86 | 87 | isStarted = false 88 | 89 | progressBuffer = '' 90 | progressString = '' 91 | prevProgressStringLength = 0 92 | 93 | timeStart = 0 94 | timeStamp = [] 95 | pctStamp = [] 96 | 97 | end % Private Properties 98 | 99 | 100 | %====================================================================== 101 | methods (Access = public) 102 | % Public Methods 103 | 104 | %------------------------------------------------------------------ 105 | function obj = ConsoleProgressBar() 106 | %ConsoleProgressBar Constructor 107 | % 108 | % Description: 109 | % Creates an instance of ConsoleProgressBar 110 | % 111 | % Usage: 112 | % obj = ConsoleProgressBar() 113 | % 114 | 115 | error(nargchk(0, 0, nargin)); 116 | end 117 | 118 | %------------------------------------------------------------------ 119 | function start(obj) 120 | %start Start progress bar 121 | % 122 | % Description: 123 | % Initialize and start new progress bar 124 | % 125 | % Usage: 126 | % obj.start() 127 | % start(obj) 128 | % 129 | 130 | error(nargchk(1, 1, nargin)); 131 | 132 | obj.stop(); 133 | 134 | obj.isStarted = true; 135 | obj.update(); 136 | obj.resetTime(); 137 | end 138 | 139 | %------------------------------------------------------------------ 140 | function stop(obj) 141 | %start Stop progress bar 142 | % 143 | % Description: 144 | % Stop the current progress bar 145 | % 146 | % Usage: 147 | % obj.stop() 148 | % stop(obj) 149 | % 150 | 151 | error(nargchk(1, 1, nargin)); 152 | 153 | obj.progressString = ''; 154 | obj.prevProgressStringLength = 0; 155 | 156 | obj.isStarted = false; 157 | obj.shiftToNewLine(); 158 | end 159 | 160 | %------------------------------------------------------------------ 161 | function reset(obj) 162 | %reset Reset progress bar 163 | % 164 | % Description: 165 | % Reset progress bar to the minimum value. 166 | % 167 | % Usage: 168 | % obj.reset() 169 | % reset(obj) 170 | % 171 | 172 | error(nargchk(1, 1, nargin)); 173 | 174 | obj.setValue(obj.minimum); 175 | obj.resetTime(); 176 | end 177 | 178 | %------------------------------------------------------------------ 179 | function setLength(obj, len) 180 | %setLength Set progress bar length 181 | % 182 | % Description: 183 | % Sets the length of progress bar 184 | % 185 | % Usage: 186 | % obj.setLength(len) 187 | % setLength(obj, len) 188 | % 189 | % Inputs: 190 | % len -- length in characters 191 | % 192 | 193 | error(nargchk(2, 2, nargin)); 194 | 195 | validateattributes(len, {'numeric'}, ... 196 | {'scalar', '>=', 10, '<=', 500}, ... 197 | mfilename('fullpath'), 'Progress Bar Length'); 198 | 199 | obj.progressLength = len; 200 | obj.update(); 201 | end 202 | 203 | %------------------------------------------------------------------ 204 | function setLeftMargin(obj, margin) 205 | %setLeftMargin Set progress bar left margin 206 | % 207 | % Description: 208 | % Sets margin of the left edge of the command window 209 | % 210 | % Usage: 211 | % obj.setLeftMargin(margin) 212 | % setLeftMargin(obj, margin) 213 | % 214 | % Inputs: 215 | % margin -- margin in characters 216 | % 217 | 218 | error(nargchk(2, 2, nargin)); 219 | 220 | validateattributes(margin, {'numeric'}, ... 221 | {'scalar', '>=', 0, '<=', 100}, ... 222 | mfilename('fullpath'), 'Left Margin'); 223 | 224 | obj.leftMargin = margin; 225 | obj.update(); 226 | end 227 | 228 | %------------------------------------------------------------------ 229 | function setTopMargin(obj, margin) 230 | %setTopMargin Set progress bar top margin 231 | % 232 | % Description: 233 | % Sets the number of lines shift progress bar down 234 | % 235 | % Usage: 236 | % obj.setTopMargin(margin) 237 | % setTopMargin(obj, margin) 238 | % 239 | % Inputs: 240 | % margin -- margin in rows 241 | % 242 | 243 | error(nargchk(2, 2, nargin)); 244 | 245 | validateattributes(margin, {'numeric'}, ... 246 | {'scalar', '>=', 0, '<=', 10}, ... 247 | mfilename('fullpath'), 'Top Margin'); 248 | 249 | obj.topMargin = margin; 250 | end 251 | 252 | %------------------------------------------------------------------ 253 | function setValue(obj, val) 254 | %setValue Set current progress value 255 | % 256 | % Description: 257 | % Sets current progress value 258 | % 259 | % Usage: 260 | % obj.setValue(val) 261 | % setValue(obj, val) 262 | % 263 | % Inputs: 264 | % val -- progres value in range [min max] 265 | % 266 | 267 | error(nargchk(2, 2, nargin)); 268 | 269 | validateattributes(val, {'numeric'}, ... 270 | {'scalar', '>=', obj.minimum, '<=', obj.maximum}, ... 271 | mfilename('fullpath'), 'Progress Value'); 272 | 273 | obj.value = val; 274 | obj.update(); 275 | obj.measureTime() 276 | end 277 | 278 | %------------------------------------------------------------------ 279 | function setMinimum(obj, minVal) 280 | %setMinimum Set minimum progress range value 281 | % 282 | % Description: 283 | % Sets minimum value of progress range 284 | % 285 | % Usage: 286 | % obj.setMinimum(minVal) 287 | % setMinimum(obj, minVal) 288 | % 289 | % Inputs: 290 | % minVal -- minimum value of progress range [min max] 291 | % 292 | 293 | error(nargchk(2, 2, nargin)); 294 | 295 | validateattributes(minVal, {'numeric'}, ... 296 | {'scalar', '<', obj.maximum}, ... 297 | mfilename('fullpath'), 'Minimum Value'); 298 | 299 | obj.minimum = minVal; 300 | 301 | if (obj.value < obj.minimum) 302 | obj.value = obj.minimum; 303 | end 304 | 305 | obj.update(); 306 | end 307 | 308 | %------------------------------------------------------------------ 309 | function setMaximum(obj, maxVal) 310 | %setMaximum Set maximum progress range value 311 | % 312 | % Description: 313 | % Sets maximum value of progress range 314 | % 315 | % Usage: 316 | % obj.setMaximum(maxVal) 317 | % setMaximum(obj, maxVal) 318 | % 319 | % Inputs: 320 | % maxVal -- maximum value of progress range [min max] 321 | % 322 | 323 | error(nargchk(2, 2, nargin)); 324 | 325 | validateattributes(maxVal, {'numeric'}, ... 326 | {'scalar', '>', obj.minimum}, ... 327 | mfilename('fullpath'), 'Maximum Value'); 328 | 329 | obj.maximum = maxVal; 330 | 331 | if (obj.value > obj.maximum) 332 | obj.value = obj.maximum; 333 | end 334 | 335 | obj.update(); 336 | end 337 | 338 | %------------------------------------------------------------------ 339 | function setText(obj, userText) 340 | %setText Set user text 341 | % 342 | % Description: 343 | % Sets any text, which will be displayed 344 | % 345 | % Usage: 346 | % obj.setText(text) 347 | % setText(obj, text) 348 | % 349 | % Inputs: 350 | % text -- text string 351 | % 352 | 353 | error(nargchk(2, 2, nargin)); 354 | 355 | validateattributes(userText, {'char'}, {'row'}, ... 356 | mfilename('fullpath'), 'Text'); 357 | 358 | % Remove \n and \r characters 359 | userText = regexprep(userText, sprintf('(\n|\r)'), ''); 360 | obj.text = userText; 361 | 362 | obj.update(); 363 | end 364 | 365 | %------------------------------------------------------------------ 366 | function setTextVisible(obj, flag) 367 | %setTextVisible Set user text visible 368 | % 369 | % Description: 370 | % Sets visible flag of user text 371 | % 372 | % Usage: 373 | % obj.setTextVisible(flag) 374 | % setTextVisible(obj, flag) 375 | % 376 | % Inputs: 377 | % flag -- true - visible, false - invisible 378 | % 379 | 380 | error(nargchk(2, 2, nargin)); 381 | 382 | validateattributes(flag, {'numeric', 'logical'}, ... 383 | {'scalar', '>=', 0, '<=', 1}, ... 384 | mfilename('fullpath'), 'Text Visible'); 385 | 386 | obj.isTextVisible = flag; 387 | 388 | obj.update(); 389 | obj.showProgressBar(); 390 | end 391 | 392 | %------------------------------------------------------------------ 393 | function setTextPosition(obj, pos) 394 | %setTextPosition Set user text position 395 | % 396 | % Description: 397 | % Sets position of user text 398 | % 399 | % Usage: 400 | % obj.setTextPosition(pos) 401 | % setTextPosition(obj, pos) 402 | % 403 | % Inputs: 404 | % pos -- text position: 'left' or 'right' 405 | % 406 | 407 | error(nargchk(2, 2, nargin)); 408 | 409 | pos = validatestring(lower(pos), {'left', 'right'}, ... 410 | mfilename('fullpath'), 'Text Position'); 411 | 412 | obj.textPosition = pos; 413 | obj.update(); 414 | end 415 | 416 | %------------------------------------------------------------------ 417 | function setPercentVisible(obj, flag) 418 | %setPercentVisible Set percent text visible 419 | % 420 | % Description: 421 | % Sets visible flag of percent text 422 | % 423 | % Usage: 424 | % obj.setPercentVisible(flag) 425 | % setPercentVisible(obj, flag) 426 | % 427 | % Inputs: 428 | % flag -- true - text visible, false - text invisible 429 | % 430 | 431 | error(nargchk(2, 2, nargin)); 432 | 433 | validateattributes(flag, {'numeric', 'logical'}, ... 434 | {'scalar', '>=', 0, '<=', 1}, ... 435 | mfilename('fullpath'), 'Percent Text Visible'); 436 | 437 | obj.isPercentVisible = flag; 438 | obj.update(); 439 | end 440 | 441 | %------------------------------------------------------------------ 442 | function setPercentPosition(obj, pos) 443 | %setPercentPosition Set percent text position 444 | % 445 | % Description: 446 | % Sets position of percent text 447 | % 448 | % Usage: 449 | % obj.setPercentPosition(pos) 450 | % setPercentPosition(obj, pos) 451 | % 452 | % Inputs: 453 | % pos -- text position: 'left' or 'right' 454 | % 455 | 456 | error(nargchk(2, 2, nargin)); 457 | 458 | pos = validatestring(lower(pos), {'left', 'right'}, ... 459 | mfilename('fullpath'), 'Percent Text Position'); 460 | 461 | obj.percentPosition = pos; 462 | obj.update(); 463 | end 464 | 465 | %------------------------------------------------------------------ 466 | function setElapsedTimeVisible(obj, flag) 467 | %setElapsedTimeVisible Set elapsed time text visible 468 | % 469 | % Description: 470 | % Sets visible flag of elapsed time text 471 | % 472 | % Usage: 473 | % obj.setElapsedTimeVisible(flag) 474 | % setElapsedTimeVisible(obj, flag) 475 | % 476 | % Inputs: 477 | % flag -- true - text visible, false - text invisible 478 | % 479 | 480 | error(nargchk(2, 2, nargin)); 481 | 482 | validateattributes(flag, {'numeric', 'logical'}, ... 483 | {'scalar', '>=', 0, '<=', 1}, ... 484 | mfilename('fullpath'), 'Elapsed Time Text Visible'); 485 | 486 | obj.isElapsedTimeVisible = flag; 487 | obj.update(); 488 | end 489 | 490 | %------------------------------------------------------------------ 491 | function setElapsedTimePosition(obj, pos) 492 | %setElapsedTimePosition Set elapsed time text position 493 | % 494 | % Description: 495 | % Sets position of elapsed time text 496 | % 497 | % Usage: 498 | % obj.setElapsedTimePosition(pos) 499 | % setElapsedTimePosition(obj, pos) 500 | % 501 | % Inputs: 502 | % pos -- text position: 'left' or 'right' 503 | % 504 | 505 | error(nargchk(2, 2, nargin)); 506 | 507 | pos = validatestring(lower(pos), {'left', 'right'}, ... 508 | mfilename('fullpath'), 'Elapsed Time Text Position'); 509 | 510 | obj.elapsedTimePosition = pos; 511 | obj.update(); 512 | end 513 | 514 | %------------------------------------------------------------------ 515 | function setRemainedTimeVisible(obj, flag) 516 | %setRemainedTimeVisible Set elapsed time text visible 517 | % 518 | % Description: 519 | % Sets visible flag of remained time text 520 | % 521 | % Usage: 522 | % obj.setRemainedTimeVisible(flag) 523 | % setRemainedTimeVisible(obj, flag) 524 | % 525 | % Inputs: 526 | % flag -- true - text visible, false - text invisible 527 | % 528 | 529 | error(nargchk(2, 2, nargin)); 530 | 531 | validateattributes(flag, {'numeric', 'logical'}, ... 532 | {'scalar', '>=', 0, '<=', 1}, ... 533 | mfilename('fullpath'), 'Elapsed Time Text Visible'); 534 | 535 | obj.isRemainedTimeVisible = flag; 536 | obj.update(); 537 | end 538 | 539 | %------------------------------------------------------------------ 540 | function setRemainedTimePosition(obj, pos) 541 | %setRemainedTimePosition Set remained time text position 542 | % 543 | % Description: 544 | % Sets position of remained time text 545 | % 546 | % Usage: 547 | % obj.setRemainedTimePosition(pos) 548 | % setRemainedTimePosition(obj, pos) 549 | % 550 | % Inputs: 551 | % pos -- text position: 'left' or 'right' 552 | % 553 | 554 | error(nargchk(2, 2, nargin)); 555 | 556 | pos = validatestring(lower(pos), {'left', 'right'}, ... 557 | mfilename('fullpath'), 'Remained Time Position'); 558 | 559 | obj.remainedTimePosition = pos; 560 | obj.update(); 561 | end 562 | 563 | %------------------------------------------------------------------ 564 | function str = getElapsedTimeStr(obj, format) 565 | %getElapsedTimeStr Get elapsed time formated string 566 | % 567 | % Description: 568 | % Gets formated string of elapsed time from start progress 569 | % 570 | % Note: 571 | % This method is slow. 572 | % 573 | % Usage: 574 | % obj.getElapsedTimeStr(format) 575 | % getElapsedTimeStr(obj, format) 576 | % 577 | % Inputs: 578 | % format -- DATESTR supported format 579 | % 580 | % Example: 581 | % str = obj.getElapsedTimeStr('HH:MM:SS.FFF') 582 | % 583 | 584 | error(nargchk(2, 2, nargin)); 585 | 586 | elapsedTimeNum = datenum([0 0 0 0 0 obj.elapsedSeconds]); 587 | str = datestr(elapsedTimeNum, format); 588 | end 589 | 590 | %------------------------------------------------------------------ 591 | function str = getRemainedTimeStr(obj, format) 592 | %getRemainedTimeStr Get remained time formated string 593 | % 594 | % Description: 595 | % Gets formated string of remained time from progress 596 | % 597 | % Usage: 598 | % obj.getRemainedTimeStr(format) 599 | % getRemainedTimeStr(obj, format) 600 | % 601 | % Inputs: 602 | % format -- DATESTR supported format 603 | % 604 | % Example: 605 | % str = obj.getRemainedTimeStr('HH:MM:SS.FFF') 606 | % 607 | 608 | error(nargchk(2, 2, nargin)); 609 | 610 | if ~isinf(obj.remainedSeconds) 611 | remainedTimeNum = datenum([0 0 0 0 0 obj.remainedSeconds]); 612 | str = datestr(remainedTimeNum, format); 613 | else 614 | str = '--/--'; 615 | end 616 | end 617 | 618 | end % Public Methods 619 | 620 | 621 | %====================================================================== 622 | methods (Access = private) 623 | % Private Methods 624 | 625 | %------------------------------------------------------------------ 626 | function update(obj) 627 | %update 628 | 629 | if obj.isStarted 630 | obj.calculatePercent(); 631 | obj.fillProgressBuffer(); 632 | obj.updateProgressString(); 633 | obj.showProgressBar(); 634 | end 635 | end 636 | 637 | %------------------------------------------------------------------ 638 | function calculatePercent(obj) 639 | %calculatePercent 640 | 641 | obj.progressPercent = ... 642 | ((obj.value - obj.minimum) / (obj.maximum - obj.minimum)) * 100; 643 | end 644 | 645 | %------------------------------------------------------------------ 646 | function fillProgressBuffer(obj) 647 | %fillProgressBuffer 648 | 649 | obj.progressBuffer = repmat('.', [1 obj.progressLength]); 650 | 651 | filledPart = round(... 652 | obj.progressLength * obj.progressPercent / 100); 653 | 654 | if (filledPart > 0) 655 | obj.progressBuffer(1:filledPart-1) = '='; 656 | obj.progressBuffer(filledPart) = '>'; 657 | end 658 | 659 | obj.progressBuffer = ['[', obj.progressBuffer, ']']; 660 | end 661 | 662 | %------------------------------------------------------------------ 663 | function updateProgressString(obj) 664 | %updateProgressString 665 | 666 | obj.prevProgressStringLength = length(obj.progressString); 667 | obj.progressString = obj.progressBuffer; 668 | 669 | obj.addPercentString(); 670 | obj.addTimeString(); 671 | obj.addTextString(); 672 | 673 | obj.progressString = [blanks(obj.leftMargin), obj.progressString]; 674 | end 675 | 676 | %------------------------------------------------------------------ 677 | function addPercentString(obj) 678 | %addPercentString 679 | 680 | if obj.isPercentVisible 681 | percentText = sprintf('%d%%', fix(obj.progressPercent)); 682 | marginBlanks = blanks(4 - length(percentText)); 683 | 684 | switch obj.percentPosition 685 | case 'left', obj.progressString = [marginBlanks, percentText, ' ', obj.progressString]; 686 | case 'right', obj.progressString = [obj.progressString, ' ', marginBlanks, percentText]; 687 | end 688 | end 689 | end 690 | 691 | %------------------------------------------------------------------ 692 | function addTimeString(obj) 693 | %addTimeString 694 | 695 | if all(strcmpi('left', {obj.elapsedTimePosition, obj.remainedTimePosition})) 696 | % 697 | cat_fun = @(e,r,es,rs) [e, es, r, rs, obj.progressString]; 698 | 699 | elseif all(strcmpi('right', {obj.elapsedTimePosition, obj.remainedTimePosition})) 700 | % 701 | cat_fun = @(e,r,es,rs) [obj.progressString, es, e, rs, r]; 702 | 703 | elseif all(strcmpi({'left', 'right'}, {obj.elapsedTimePosition, obj.remainedTimePosition})) 704 | % 705 | cat_fun = @(e,r,es,rs) [e, es, obj.progressString, rs, r]; 706 | 707 | elseif all(strcmpi({'right', 'left'}, {obj.elapsedTimePosition, obj.remainedTimePosition})) 708 | % 709 | cat_fun = @(e,r,es,rs) [r, rs, obj.progressString, es, e]; 710 | 711 | end 712 | 713 | %FIXME: slow 714 | 715 | elapsedTimeStr = ''; 716 | remainedTimeStr = ''; 717 | es = ''; 718 | rs = ''; 719 | 720 | to_vec = @(s) datevec(datenum([0 0 0 0 0 round(s)])); 721 | to_str = @(h,m,s) sprintf('%02d:%02d:%02d', h, m, s); 722 | 723 | if obj.isElapsedTimeVisible 724 | dv = to_vec(obj.elapsedSeconds); 725 | elapsedTimeStr = ['E ', to_str(dv(4), dv(5), dv(6))]; 726 | es = ' '; 727 | end 728 | 729 | if obj.isRemainedTimeVisible 730 | if ~isinf(obj.remainedSeconds) 731 | dv = to_vec(obj.remainedSeconds); 732 | remainedTimeStr = ['R ', to_str(dv(4), dv(5), dv(6))]; 733 | else 734 | remainedTimeStr = 'R --/--'; 735 | end 736 | rs = ' '; 737 | end 738 | 739 | obj.progressString = cat_fun(elapsedTimeStr, remainedTimeStr, es, rs); 740 | end 741 | 742 | %------------------------------------------------------------------ 743 | function addTextString(obj) 744 | %addTextString 745 | 746 | if obj.isTextVisible 747 | switch obj.textPosition 748 | case 'left', obj.progressString = [obj.text, ' ', obj.progressString]; 749 | case 'right', obj.progressString = [obj.progressString, ' ', obj.text]; 750 | end 751 | end 752 | end 753 | 754 | %------------------------------------------------------------------ 755 | function showProgressBar(obj) 756 | %showProgressBar 757 | 758 | backspaceStr = sprintf('\b'); 759 | backspaceStr = backspaceStr(ones(1, obj.prevProgressStringLength)); 760 | 761 | fprintf('%s%s', backspaceStr, obj.progressString); 762 | end 763 | 764 | %------------------------------------------------------------------ 765 | function shiftToNewLine(obj) 766 | %switchNewLine 767 | 768 | newLines = sprintf('\n'); 769 | newLines = newLines(ones(1, obj.topMargin)); 770 | 771 | fprintf(newLines); 772 | end 773 | 774 | %------------------------------------------------------------------ 775 | function resetTime(obj) 776 | %resetTime 777 | 778 | obj.timeStart = tic; 779 | 780 | obj.elapsedSeconds = 0; 781 | obj.remainedSeconds = Inf; 782 | obj.timeStamp = []; 783 | obj.pctStamp = []; 784 | end 785 | 786 | %------------------------------------------------------------------ 787 | function measureTime(obj) 788 | %measureTime 789 | 790 | obj.elapsedSeconds = toc(obj.timeStart); 791 | 792 | % Accumulation time and percent values (timespent) 793 | obj.timeStamp = horzcat(obj.timeStamp, obj.elapsedSeconds); 794 | obj.pctStamp = horzcat(obj.pctStamp, obj.progressPercent); 795 | 796 | % Prediction remained time (simple linear least square estimate method) 797 | if (length(obj.timeStamp) > 1) 798 | % y = k*x + b, b == 0 799 | xy = sum(obj.timeStamp .* obj.pctStamp); 800 | x2 = sum(obj.pctStamp .* obj.pctStamp); 801 | predictionSeconds = (xy / x2) * 100; 802 | 803 | obj.remainedSeconds = abs(predictionSeconds - obj.elapsedSeconds); 804 | end 805 | end 806 | 807 | end % Private Methods 808 | 809 | end % ConsoleProgressBar 810 | 811 | --------------------------------------------------------------------------------