diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..09d3da4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +Raytracing_scenarios/* +Examples/dmv3_example_html/* \ No newline at end of file diff --git a/DeepMIMO_Dataset_Generator.m b/DeepMIMO_Dataset_Generator.m index 6da7d9e..6ec6b4c 100644 --- a/DeepMIMO_Dataset_Generator.m +++ b/DeepMIMO_Dataset_Generator.m @@ -1,11 +1,15 @@ % ----------------- Add the path of DeepMIMO function --------------------% -addpath('DeepMIMO_functions') +addpath(genpath('DeepMIMO_functions')) % -------------------- DeepMIMO Dataset Generation -----------------------% % Load Dataset Parameters dataset_params = read_params('parameters.m'); [DeepMIMO_dataset, dataset_params] = DeepMIMO_generator(dataset_params); +% To plot the LoS status of each user, provide the basestation data +% into plot_los_status function. +plot_los_status(DeepMIMO_dataset{1}); % Plots the LoS for the first basestation + % -------------------------- Output Examples -----------------------------% % DeepMIMO_dataset{i}.user{j}.channel % Channel between BS i - User j % % (# of User antennas) x (# of BS antennas) x (# of OFDM subcarriers) diff --git a/DeepMIMO_functions/DeepMIMO_generator.m b/DeepMIMO_functions/DeepMIMO_generator.m index 92d469f..a4a6c7a 100644 --- a/DeepMIMO_functions/DeepMIMO_generator.m +++ b/DeepMIMO_functions/DeepMIMO_generator.m @@ -15,34 +15,19 @@ if params_inner.dynamic_scenario for f = 1:length(params_inner.list_of_folders) fprintf('\nGenerating Scene %i/%i', f, length(params_inner.list_of_folders)) - params.scenario_files = fullfile(params_inner.list_of_folders{f}, params.scenario); % The initial of all the scenario files + params.scenario_files = params_inner.list_of_folders{f}; % The initial of all the scenario files DeepMIMO_scene{f} = generate_data(params, params_inner); param{f} = params; end DeepMIMO_dataset = DeepMIMO_scene; params = param; - saveDataset = params{1}.saveDataset; else - DeepMIMO_dataset = generate_data(params, params_inner); - saveDataset = params.saveDataset; - end - - % Saving the data - if saveDataset - fprintf('\n Saving the DeepMIMO Dataset ...') - - - fileidx = 1; - while isfile(sprintf('DeepMIMO_dataset/dataset_%i.mat', fileidx)) - fileidx = fileidx + 1; + if params_inner.dual_polar_available + DeepMIMO_dataset = generate_data_polar(params, params_inner); + else + DeepMIMO_dataset = generate_data(params, params_inner); end - sfile_DeepMIMO = sprintf('DeepMIMO_dataset/dataset_%i.mat', fileidx); - dataset_params = params; - save(sfile_DeepMIMO,'DeepMIMO_dataset', 'dataset_params', '-v7.3'); - - fprintf('\n The generated DeepMIMO dataset is saved into %s file.', sfile_DeepMIMO); - end fprintf('\n DeepMIMO Dataset Generation completed \n') @@ -55,62 +40,128 @@ for t=1:params.num_active_BS bs_ID = params.active_BS(t); fprintf('\n Basestation %i', bs_ID); - [TX{t}.channel_params, TX{t}.channel_params_BSBS, TX{t}.loc] = read_raytracing(bs_ID, params, params_inner.scenario_files); + [TX{t}.channel_params, TX{t}.channel_params_BSBS, TX{t}.loc] = feval(params_inner.raytracing_fn, bs_ID, params, params_inner); end % Constructing the channel matrices from ray-tracing for t = 1:params.num_active_BS fprintf('\n Constructing the DeepMIMO Dataset for BS %d', params.active_BS(t)) - c = progress_counter(params.num_user+params.enable_BS2BSchannels*params.num_active_BS); + c = progress_counter(length(TX{t}.channel_params)+params.num_active_BS); % BS transmitter location & rotation DeepMIMO_dataset{t}.loc = TX{t}.loc; DeepMIMO_dataset{t}.rotation = params_inner.array_rotation_BS(t,:); %----- BS-User Channels - for user=1:params.num_user + for user=1:length(TX{t}.channel_params) % Channel Construction if params.generate_OFDM_channels - [DeepMIMO_dataset{t}.user{user}.channel]=construct_DeepMIMO_channel(params_inner.num_ant_BS(t, :), params_inner.array_rotation_BS(t,:), params_inner.ant_spacing_BS(t), params.num_ant_UE, params_inner.array_rotation_UE(user, :), params.ant_spacing_UE, TX{t}.channel_params(user), params); + [DeepMIMO_dataset{t}.user{user}.channel, LOS, TX{t}.channel_params(user)] = construct_DeepMIMO_channel(params_inner.num_ant_BS(t, :), params_inner.array_rotation_BS(t,:), params_inner.ant_FoV_BS(t, :), params_inner.ant_spacing_BS(t), params.num_ant_UE, params_inner.array_rotation_UE(user, :), params_inner.ant_FoV_UE, params.ant_spacing_UE, TX{t}.channel_params(user), params, params_inner); else - [DeepMIMO_dataset{t}.user{user}.channel]=construct_DeepMIMO_channel_TD(params_inner.num_ant_BS(t, :), params_inner.array_rotation_BS(t,:), params_inner.ant_spacing_BS(t), params.num_ant_UE, params_inner.array_rotation_UE(user, :), params.ant_spacing_UE, TX{t}.channel_params(user), params); + [DeepMIMO_dataset{t}.user{user}.channel, LOS, TX{t}.channel_params(user)] = construct_DeepMIMO_channel_TD(params_inner.num_ant_BS(t, :), params_inner.array_rotation_BS(t,:), params_inner.ant_FoV_BS(t, :), params_inner.ant_spacing_BS(t), params.num_ant_UE, params_inner.array_rotation_UE(user, :), params_inner.ant_FoV_UE, params.ant_spacing_UE, TX{t}.channel_params(user), params, params_inner); DeepMIMO_dataset{t}.user{user}.ToA = TX{t}.channel_params(user).ToA; %Time of Arrival/Flight of each channel path (seconds) end DeepMIMO_dataset{t}.user{user}.rotation = params_inner.array_rotation_UE(user, :); % Location, LOS status, distance, pathloss, and channel path parameters DeepMIMO_dataset{t}.user{user}.loc=TX{t}.channel_params(user).loc; - DeepMIMO_dataset{t}.user{user}.LoS_status=TX{t}.channel_params(user).LoS_status; + DeepMIMO_dataset{t}.user{user}.LoS_status = LOS; DeepMIMO_dataset{t}.user{user}.distance=TX{t}.channel_params(user).distance; + %% TO BE UPDATED DeepMIMO_dataset{t}.user{user}.pathloss=TX{t}.channel_params(user).pathloss; + + %% DeepMIMO_dataset{t}.user{user}.path_params=rmfield(TX{t}.channel_params(user),{'loc','distance','pathloss'}); c.increment(); end %----- BS-BS Channels - if params.enable_BS2BSchannels - for BSreceiver=1:params.num_active_BS + for BSreceiver=1:params.num_active_BS + % Channel Construction + if params.generate_OFDM_channels + [DeepMIMO_dataset{t}.basestation{BSreceiver}.channel, LOS, TX{t}.channel_params_BSBS(BSreceiver)] = construct_DeepMIMO_channel(params_inner.num_ant_BS(t, :), params_inner.array_rotation_BS(t,:), params_inner.ant_FoV_BS(t, :), params_inner.ant_spacing_BS(t), params_inner.num_ant_BS(BSreceiver, :), params_inner.array_rotation_BS(BSreceiver,:), params_inner.ant_FoV_BS(BSreceiver, :), params_inner.ant_spacing_BS(BSreceiver), TX{t}.channel_params_BSBS(BSreceiver), params, params_inner); + else + [DeepMIMO_dataset{t}.basestation{BSreceiver}.channel, LOS, TX{t}.channel_params_BSBS(BSreceiver)]=construct_DeepMIMO_channel_TD(params_inner.num_ant_BS(t, :), params_inner.array_rotation_BS(t,:), params_inner.ant_FoV_BS(t, :), params_inner.ant_spacing_BS(t), params_inner.num_ant_BS(BSreceiver, :), params_inner.array_rotation_BS(BSreceiver,:), params_inner.ant_FoV_BS(BSreceiver, :), params_inner.ant_spacing_BS(BSreceiver), TX{t}.channel_params_BSBS(BSreceiver), params, params_inner); + DeepMIMO_dataset{t}.basestation{BSreceiver}.ToA=TX{t}.channel_params_BSBS(BSreceiver).ToA; %Time of Arrival/Flight of each channel path (seconds) + end + DeepMIMO_dataset{t}.basestation{BSreceiver}.rotation = params_inner.array_rotation_BS(BSreceiver, :); + + % Location, LOS status, distance, pathloss, and channel path parameters + DeepMIMO_dataset{t}.basestation{BSreceiver}.loc=TX{t}.channel_params_BSBS(BSreceiver).loc; + DeepMIMO_dataset{t}.basestation{BSreceiver}.LoS_status=LOS; + DeepMIMO_dataset{t}.basestation{BSreceiver}.distance=TX{t}.channel_params_BSBS(BSreceiver).distance; + + %% Update Path loss + DeepMIMO_dataset{t}.basestation{BSreceiver}.pathloss=TX{t}.channel_params_BSBS(BSreceiver).pathloss; + DeepMIMO_dataset{t}.basestation{BSreceiver}.path_params=rmfield(TX{t}.channel_params_BSBS(BSreceiver),{'loc','distance','pathloss'}); + + c.increment(); + end + end +end + +function DeepMIMO_dataset = generate_data_polar(params, params_inner) + % Reading ray tracing data + fprintf('\n Reading the channel parameters of the ray-tracing scenario %s', params.scenario) + for t=1:params.num_active_BS + bs_ID = params.active_BS(t); + for polarization = params_inner.polarization_list + fprintf('\n Basestation %i', bs_ID); + [TX{t}.channel_params, TX{t}.channel_params_BSBS, TX{t}.loc] = feval(params_inner.raytracing_fn, bs_ID, params, params_inner, polarization); + + fprintf('\n Constructing the DeepMIMO Dataset for BS %d', params.active_BS(t)) + c = progress_counter(params.num_user+params.num_active_BS); + + % BS transmitter location & rotation + DeepMIMO_dataset{t}.loc = TX{t}.loc; + DeepMIMO_dataset{t}.rotation = params_inner.array_rotation_BS(t,:); + + %----- BS-User Channels + for user=1:length(TX{t}.channel_params) % Channel Construction if params.generate_OFDM_channels - [DeepMIMO_dataset{t}.basestation{BSreceiver}.channel]=construct_DeepMIMO_channel(params_inner.num_ant_BS(t, :), params_inner.array_rotation_BS(t,:), params_inner.ant_spacing_BS(t), params_inner.num_ant_BS(BSreceiver, :), params_inner.array_rotation_BS(BSreceiver,:), params_inner.ant_spacing_BS(BSreceiver), TX{t}.channel_params_BSBS(BSreceiver), params); + [DeepMIMO_dataset{t}.user{user}.(strcat("channel", polarization)), LOS, TX{t}.channel_params(user)] = construct_DeepMIMO_channel(params_inner.num_ant_BS(t, :), params_inner.array_rotation_BS(t,:), params_inner.ant_FoV_BS(t, :), params_inner.ant_spacing_BS(t), params.num_ant_UE, params_inner.array_rotation_UE(user, :), params_inner.ant_FoV_UE, params.ant_spacing_UE, TX{t}.channel_params(user), params, params_inner); else - [DeepMIMO_dataset{t}.basestation{BSreceiver}.channel]=construct_DeepMIMO_channel_TD(params_inner.num_ant_BS(t, :), params_inner.array_rotation_BS(t,:), params_inner.ant_spacing_BS(t), params_inner.num_ant_BS(BSreceiver, :), params_inner.array_rotation_BS(BSreceiver,:), params_inner.ant_spacing_BS(BSreceiver), TX{t}.channel_params_BSBS(BSreceiver), params); - DeepMIMO_dataset{t}.basestation{BSreceiver}.ToA=TX{t}.channel_params_BSBS(BSreceiver).ToA; %Time of Arrival/Flight of each channel path (seconds) + [DeepMIMO_dataset{t}.user{user}.(strcat("channel", polarization)), LOS, TX{t}.channel_params(user)] = construct_DeepMIMO_channel_TD(params_inner.num_ant_BS(t, :), params_inner.array_rotation_BS(t,:), params_inner.ant_FoV_BS(t, :), params_inner.ant_spacing_BS(t), params.num_ant_UE, params_inner.array_rotation_UE(user, :), params_inner.ant_FoV_UE, params.ant_spacing_UE, TX{t}.channel_params(user), params, params_inner); + DeepMIMO_dataset{t}.user{user}.ToA = TX{t}.channel_params(user).ToA; %Time of Arrival/Flight of each channel path (seconds) end - DeepMIMO_dataset{t}.basestation{BSreceiver}.rotation = params_inner.array_rotation_BS(BSreceiver, :); + DeepMIMO_dataset{t}.user{user}.rotation = params_inner.array_rotation_UE(user, :); % Location, LOS status, distance, pathloss, and channel path parameters - DeepMIMO_dataset{t}.basestation{BSreceiver}.loc=TX{t}.channel_params_BSBS(BSreceiver).loc; - DeepMIMO_dataset{t}.basestation{BSreceiver}.LoS_status=TX{t}.channel_params_BSBS(BSreceiver).LoS_status; - DeepMIMO_dataset{t}.basestation{BSreceiver}.distance=TX{t}.channel_params_BSBS(BSreceiver).distance; - DeepMIMO_dataset{t}.basestation{BSreceiver}.pathloss=TX{t}.channel_params_BSBS(BSreceiver).pathloss; - DeepMIMO_dataset{t}.basestation{BSreceiver}.path_params=rmfield(TX{t}.channel_params_BSBS(BSreceiver),{'loc','distance','pathloss'}); + DeepMIMO_dataset{t}.user{user}.loc=TX{t}.channel_params(user).loc; + DeepMIMO_dataset{t}.user{user}.LoS_status = LOS; + DeepMIMO_dataset{t}.user{user}.distance=TX{t}.channel_params(user).distance; + %% TO BE UPDATED + DeepMIMO_dataset{t}.user{user}.pathloss=TX{t}.channel_params(user).pathloss; + DeepMIMO_dataset{t}.user{user}.path_params=rmfield(TX{t}.channel_params(user),{'loc','distance','pathloss'}); c.increment(); end + + if ~isempty(TX{t}.channel_params_BSBS) + %----- BS-BS Channels + for BSreceiver=1:params.num_active_BS + % Channel Construction + if params.generate_OFDM_channels + [DeepMIMO_dataset{t}.basestation{BSreceiver}.(strcat("channel", polarization)), LOS, TX{t}.channel_params_BSBS(BSreceiver)] = construct_DeepMIMO_channel(params_inner.num_ant_BS(t, :), params_inner.array_rotation_BS(t,:), params_inner.ant_FoV_BS(t, :), params_inner.ant_spacing_BS(t), params_inner.num_ant_BS(BSreceiver, :), params_inner.array_rotation_BS(BSreceiver,:), params_inner.ant_FoV_BS(BSreceiver, :), params_inner.ant_spacing_BS(BSreceiver), TX{t}.channel_params_BSBS(BSreceiver), params, params_inner); + else + [DeepMIMO_dataset{t}.basestation{BSreceiver}.(strcat("channel", polarization)), LOS, TX{t}.channel_params_BSBS(BSreceiver)]=construct_DeepMIMO_channel_TD(params_inner.num_ant_BS(t, :), params_inner.array_rotation_BS(t,:), params_inner.ant_FoV_BS(t, :), params_inner.ant_spacing_BS(t), params_inner.num_ant_BS(BSreceiver, :), params_inner.array_rotation_BS(BSreceiver,:), params_inner.ant_FoV_BS(BSreceiver, :), params_inner.ant_spacing_BS(BSreceiver), TX{t}.channel_params_BSBS(BSreceiver), params, params_inner); + DeepMIMO_dataset{t}.basestation{BSreceiver}.ToA=TX{t}.channel_params_BSBS(BSreceiver).ToA; %Time of Arrival/Flight of each channel path (seconds) + end + DeepMIMO_dataset{t}.basestation{BSreceiver}.rotation = params_inner.array_rotation_BS(BSreceiver, :); + + % Location, LOS status, distance, pathloss, and channel path parameters + DeepMIMO_dataset{t}.basestation{BSreceiver}.loc=TX{t}.channel_params_BSBS(BSreceiver).loc; + DeepMIMO_dataset{t}.basestation{BSreceiver}.LoS_status=LOS; + DeepMIMO_dataset{t}.basestation{BSreceiver}.distance=TX{t}.channel_params_BSBS(BSreceiver).distance; + DeepMIMO_dataset{t}.basestation{BSreceiver}.pathloss=TX{t}.channel_params_BSBS(BSreceiver).pathloss; + DeepMIMO_dataset{t}.basestation{BSreceiver}.path_params=rmfield(TX{t}.channel_params_BSBS(BSreceiver),{'loc','distance','pathloss'}); + + c.increment(); + end + end end end - end \ No newline at end of file diff --git a/DeepMIMO_functions/antenna/antenna_FoV.m b/DeepMIMO_functions/antenna/antenna_FoV.m new file mode 100644 index 0000000..9cc434e --- /dev/null +++ b/DeepMIMO_functions/antenna/antenna_FoV.m @@ -0,0 +1,14 @@ +% --------- DeepMIMO: A Generic Dataset for mmWave and massive MIMO ------% +% Authors: Ahmed Alkhateeb, Umut Demirhan, Abdelrahman Taha +% Date: March 17, 2022 +% Goal: Encouraging research on ML/DL for MIMO applications and +% providing a benchmarking tool for the developed algorithms +% ---------------------------------------------------------------------- % + +function path_inclusion = antenna_FoV(theta, phi, FoV_limits) + path_inclusion = ((phi <= 0+FoV_limits(1)/2) ... + | (phi >= 360-FoV_limits(1)/2)) ... + & ((theta <= 90+FoV_limits(2)/2) ... + & (theta >= 90-FoV_limits(2)/2)); +end + diff --git a/DeepMIMO_functions/antenna_channel_map.m b/DeepMIMO_functions/antenna/antenna_channel_map.m similarity index 100% rename from DeepMIMO_functions/antenna_channel_map.m rename to DeepMIMO_functions/antenna/antenna_channel_map.m diff --git a/DeepMIMO_functions/antenna_pattern_halfwavedipole.m b/DeepMIMO_functions/antenna/antenna_pattern_halfwavedipole.m similarity index 93% rename from DeepMIMO_functions/antenna_pattern_halfwavedipole.m rename to DeepMIMO_functions/antenna/antenna_pattern_halfwavedipole.m index 1a9f6c5..500b4ba 100644 --- a/DeepMIMO_functions/antenna_pattern_halfwavedipole.m +++ b/DeepMIMO_functions/antenna/antenna_pattern_halfwavedipole.m @@ -5,7 +5,7 @@ % providing a benchmarking tool for the developed algorithms % ---------------------------------------------------------------------- % -function Directivity = antenna_pattern_halfwavedipole(Theta,Phi) +function Directivity = antenna_pattern_halfwavedipole(Theta, Phi) %RADIATION PATTERN EFFECT on the receive power calculation % Calculate Half-wave dipole directivity in a given direction % It is an omni directional radiation pattern diff --git a/DeepMIMO_functions/axes_rotation.m b/DeepMIMO_functions/antenna/antenna_rotation.m similarity index 80% rename from DeepMIMO_functions/axes_rotation.m rename to DeepMIMO_functions/antenna/antenna_rotation.m index 904425e..ef041ec 100644 --- a/DeepMIMO_functions/axes_rotation.m +++ b/DeepMIMO_functions/antenna/antenna_rotation.m @@ -5,19 +5,19 @@ % providing a benchmarking tool for the developed algorithms % ---------------------------------------------------------------------- % -function [DoD_theta_LCS, DoD_phi_LCS, DoA_theta_LCS, DoA_phi_LCS] = axes_rotation(TX_rot, DoD_theta_GCS, DoD_phi_GCS, RX_rot, DoA_theta_GCS, DoA_phi_GCS) - %AXES ROTATION EFFECT on the DoDs and the DOAs +function [DoD_theta_LCS, DoD_phi_LCS, DoA_theta_LCS, DoA_phi_LCS] = antenna_rotation(TX_rot, DoD_theta_GCS, DoD_phi_GCS, RX_rot, DoA_theta_GCS, DoA_phi_GCS) + %AXES ROTATION EFFECT on the DoDs and the DOA % Arbitrary 3D axes rotation from the "global coordinate system" (x,y,z) of the % chose scenario to the "the local coordinate systems" (x',y',z') relative % to the new panel orientation - [DoD_theta_LCS,DoD_phi_LCS]= angle_transformation(TX_rot,DoD_theta_GCS,DoD_phi_GCS); - [DoA_theta_LCS,DoA_phi_LCS]= angle_transformation(RX_rot,DoA_theta_GCS,DoA_phi_GCS); + [DoD_theta_LCS,DoD_phi_LCS]= rotateAngles(TX_rot, DoD_theta_GCS, DoD_phi_GCS); + [DoA_theta_LCS,DoA_phi_LCS]= rotateAngles(RX_rot, DoA_theta_GCS, DoA_phi_GCS); end -function [Theta2, Phi2] = angle_transformation(Rot, Theta, Phi) +function [Theta2, Phi2] = rotateAngles(Rot, Theta, Phi) % Phi = wrapTo360(Phi); Alpha = Rot(3); diff --git a/DeepMIMO_functions/pulse_sinc.m b/DeepMIMO_functions/antenna/pulse_sinc.m similarity index 100% rename from DeepMIMO_functions/pulse_sinc.m rename to DeepMIMO_functions/antenna/pulse_sinc.m diff --git a/DeepMIMO_functions/channel/construct_DeepMIMO_channel.m b/DeepMIMO_functions/channel/construct_DeepMIMO_channel.m new file mode 100644 index 0000000..329e20b --- /dev/null +++ b/DeepMIMO_functions/channel/construct_DeepMIMO_channel.m @@ -0,0 +1,141 @@ +% --------- DeepMIMO: A Generic Dataset for mmWave and massive MIMO ------% +% Authors: Ahmed Alkhateeb, Umut Demirhan, Abdelrahman Taha +% Date: March 17, 2022 +% Goal: Encouraging research on ML/DL for MIMO applications and +% providing a benchmarking tool for the developed algorithms +% ---------------------------------------------------------------------- % + +function [channel, channel_LoS_status, path_params] = construct_DeepMIMO_channel(tx_ant_size, tx_rotation, tx_FoV, tx_ant_spacing, rx_ant_size, rx_rotation, rx_FoV, rx_ant_spacing, path_params, params, params_inner) + + BW = params.bandwidth*1e9; + deg_to_rad = pi/180; + Ts=1/BW; + k=(params.OFDM_sampling-1).'; + num_sampled_subcarriers=length(k); + + % TX antenna parameters for a UPA structure + M_TX_ind = antenna_channel_map(1, tx_ant_size(1), tx_ant_size(2), 0); + M_TX=prod(tx_ant_size); + kd_TX=2*pi*tx_ant_spacing; + + % RX antenna parameters for a UPA structure + M_RX_ind = antenna_channel_map(1, rx_ant_size(1), rx_ant_size(2), 0); + M_RX=prod(rx_ant_size); + kd_RX=2*pi*rx_ant_spacing; + + if path_params.num_paths == 0 + channel = complex(zeros(M_RX, M_TX, num_sampled_subcarriers)); + channel_LoS_status = -1; + return + end + + [DoD_theta, DoD_phi, DoA_theta, DoA_phi] = antenna_rotation(tx_rotation, path_params.DoD_theta, path_params.DoD_phi, rx_rotation, path_params.DoA_theta, path_params.DoA_phi); + + % Apply the radiation pattern of choice + if params.radiation_pattern % Half-wave dipole radiation pattern + power = path_params.power.* antenna_pattern_halfwavedipole(DoD_theta, DoD_phi) .* antenna_pattern_halfwavedipole(DoA_theta, DoA_phi); + else % Isotropic radiation pattern + power = path_params.power; + end + + % Apply the FoV + FoV_TX = antenna_FoV(DoD_theta, DoD_phi, tx_FoV); + FoV_RX = antenna_FoV(DoA_theta, DoA_phi, rx_FoV); + + %% LoS status computation + FoV = FoV_TX & FoV_RX; + if sum(FoV) > 0 + channel_LoS_status = sum(path_params.LoS_status & FoV)>0; + else + channel = complex(zeros(M_RX, M_TX, num_sampled_subcarriers)); + channel_LoS_status = -1; + end + + % Update the paths with FoV + DoD_theta = DoD_theta(FoV); + DoD_phi = DoD_phi(FoV); + DoA_theta = DoA_theta(FoV); + DoA_phi = DoA_phi(FoV); + power = power(FoV); + phase = path_params.phase(FoV); + if params_inner.doppler_available + Doppler_vel = path_params.Doppler_vel(FoV); + Doppler_acc = path_params.Doppler_acc(FoV); + end + + num_paths = sum(FoV); + LoS_status = path_params.LoS_status(FoV); + ToA = path_params.ToA(FoV); + + %% + % Update path parameters based on the computed values after + % the rotation/FoV/radiation pattern + path_params.phase = phase; + path_params.power = power; + path_params.DoD_theta = DoD_theta; + path_params.DoD_phi = DoD_phi; + path_params.DoA_theta = DoA_theta; + path_params.DoA_phi = DoA_phi; + if params_inner.doppler_available + path_params.Doppler_vel = Doppler_vel; + path_params.Doppler_acc = Doppler_acc; + end + path_params.num_paths = num_paths; + path_params.ToA = ToA; + path_params.LoS_status = LoS_status; + + if num_paths == 0 + channel = complex(zeros(M_RX, M_TX, num_sampled_subcarriers)); + channel_LoS_status = -1; + return + end + %% + % TX Array Response - BS + gamma_TX=+1j*kd_TX*[sind(DoD_theta).*cosd(DoD_phi); + sind(DoD_theta).*sind(DoD_phi); + cosd(DoD_theta)]; + array_response_TX = exp(M_TX_ind*gamma_TX); + + % RX Array Response - UE or BS + gamma_RX=+1j*kd_RX*[sind(DoA_theta).*cosd(DoA_phi); + sind(DoA_theta).*sind(DoA_phi); + cosd(DoA_theta)]; + array_response_RX = exp(M_RX_ind*gamma_RX); + + % Account only for the channel within the useful OFDM symbol duration + delay_normalized=path_params.ToA/Ts; + power(delay_normalized >= params.num_OFDM) = 0; + delay_normalized(delay_normalized>=params.num_OFDM) = params.num_OFDM; + + + + %Assuming the pulse shaping as a dirac delta function and no receive LPF + if ~params.activate_RX_filter + path_const=sqrt(power/params.num_OFDM).*exp(1j*path_params.phase*deg_to_rad).*exp(-1j*2*pi*(k/params.num_OFDM)*delay_normalized); + if params.enable_Doppler + delay = delay_normalized.*Ts; + Doppler_phase = exp(-1j*2*pi*params.carrier_freq*( ((path_params.Doppler_vel.*delay)./physconst('LightSpeed')) + ((path_params.Doppler_acc.*(delay.^2))./(2*physconst('LightSpeed'))) )); + path_const = path_const .* Doppler_phase; + end + + channel = sum(reshape(array_response_RX, M_RX, 1, 1, []) .* reshape(array_response_TX, 1, M_TX, 1, []) .* reshape(path_const, 1, 1, num_sampled_subcarriers, []), 4); + else + + d_ext = [0:(params.num_OFDM-1)]; %extended d domain + delay_d_conv = exp(-1j*(2*pi.*k/params.num_OFDM).*d_ext); + + % Generate the pulse function + LP_fn = pulse_sinc(d_ext.'-delay_normalized); + conv_vec = exp(1j*path_params.phase*deg_to_rad).*sqrt(power/params.num_OFDM) .* LP_fn; %Power of the paths and phase + + if params.enable_Doppler + d_time = Ts*(d_ext.'); + Doppler_phase = exp(-1j*2*pi*params.carrier_freq*( ((path_params.Doppler_vel.*d_time)./physconst('LightSpeed')) + ((path_params.Doppler_acc.*(d_time.^2))./(2*physconst('LightSpeed'))) )); + conv_vec = conv_vec .* Doppler_phase; %Power of the paths and phase + end + + channel = sum(reshape(array_response_RX, M_RX, 1, 1, []) .* reshape(array_response_TX, 1, M_TX, 1, []) .* reshape(conv_vec, 1, 1, [], path_params.num_paths), 4); + channel = sum(reshape(channel, M_RX, M_TX, 1, []) .* reshape(delay_d_conv, 1, 1, num_sampled_subcarriers, []), 4); + end + +end \ No newline at end of file diff --git a/DeepMIMO_functions/channel/construct_DeepMIMO_channel_TD.m b/DeepMIMO_functions/channel/construct_DeepMIMO_channel_TD.m new file mode 100644 index 0000000..716730c --- /dev/null +++ b/DeepMIMO_functions/channel/construct_DeepMIMO_channel_TD.m @@ -0,0 +1,106 @@ +% --------- DeepMIMO: A Generic Dataset for mmWave and massive MIMO ------% +% Authors: Ahmed Alkhateeb, Umut Demirhan, Abdelrahman Taha +% Date: March 17, 2022 +% Goal: Encouraging research on ML/DL for MIMO applications and +% providing a benchmarking tool for the developed algorithms +% ---------------------------------------------------------------------- % + +function [channel, channel_LoS_status, path_params] = construct_DeepMIMO_channel_TD(tx_ant_size, tx_rotation, tx_FoV, tx_ant_spacing, rx_ant_size, rx_rotation, rx_FoV, rx_ant_spacing, path_params, params, params_inner) + + deg_to_rad = pi/180; + + % TX antenna parameters for a UPA structure + M_TX_ind = antenna_channel_map(1, tx_ant_size(1), tx_ant_size(2), 0); + M_TX=prod(tx_ant_size); + kd_TX=2*pi*tx_ant_spacing; + + % RX antenna parameters for a UPA structure + M_RX_ind = antenna_channel_map(1, rx_ant_size(1), rx_ant_size(2), 0); + M_RX=prod(rx_ant_size); + kd_RX=2*pi*rx_ant_spacing; + + if path_params.num_paths == 0 + channel = complex(zeros(M_RX, M_TX, path_params.num_paths)); + channel_LoS_status = -1; + return + end + + + [DoD_theta, DoD_phi, DoA_theta, DoA_phi] = antenna_rotation(tx_rotation, path_params.DoD_theta, path_params.DoD_phi, rx_rotation, path_params.DoA_theta, path_params.DoA_phi); + + % Apply the radiation pattern of choice + if params.radiation_pattern % Half-wave dipole radiation pattern + power = path_params.power.* antenna_pattern_halfwavedipole(DoD_theta, DoD_phi) .* antenna_pattern_halfwavedipole(DoA_theta, DoA_phi); + else % Isotropic radiation pattern + power = path_params.power; + end + + % Apply the FoV + FoV_TX = antenna_FoV(DoD_theta, DoD_phi, tx_FoV); + FoV_RX = antenna_FoV(DoA_theta, DoA_phi, rx_FoV); + + %% LoS status computation + FoV = FoV_TX & FoV_RX; + if sum(FoV) > 0 + channel_LoS_status = sum(path_params.LoS_status & FoV)>0; + else + channel = complex(zeros(M_RX, M_TX, num_sampled_subcarriers)); + channel_LoS_status = -1; + end + + % Update the paths with FoV + DoD_theta = DoD_theta(FoV); + DoD_phi = DoD_phi(FoV); + DoA_theta = DoA_theta(FoV); + DoA_phi = DoA_phi(FoV); + power = power(FoV); + phase = path_params.phase(FoV); + if params_inner.doppler_available + Doppler_vel = path_params.Doppler_vel(FoV); + Doppler_acc = path_params.Doppler_acc(FoV); + end + + num_paths = sum(FoV); + LoS_status = path_params.LoS_status(FoV); + ToA = path_params.ToA(FoV); + + %% + % Update path parameters based on the computed values after + % the rotation/FoV/radiation pattern + path_params.phase = phase; + path_params.power = power; + path_params.DoD_theta = DoD_theta; + path_params.DoD_phi = DoD_phi; + path_params.DoA_theta = DoA_theta; + path_params.DoA_phi = DoA_phi; + if params_inner.doppler_available + path_params.Doppler_vel = Doppler_vel; + path_params.Doppler_acc = Doppler_acc; + end + path_params.num_paths = num_paths; + path_params.ToA = ToA; + path_params.LoS_status = LoS_status; + + if num_paths == 0 + channel = complex(zeros(M_RX, M_TX, num_sampled_subcarriers)); + channel_LoS_status = -1; + return + end + + + % TX Array Response - BS + gamma_TX=+1j*kd_TX*[sind(DoD_theta).*cosd(DoD_phi); + sind(DoD_theta).*sind(DoD_phi); + cosd(DoD_theta)]; + array_response_TX = exp(M_TX_ind*gamma_TX); + + % RX Array Response - UE or BS + gamma_RX=+1j*kd_RX*[sind(DoA_theta).*cosd(DoA_phi); + sind(DoA_theta).*sind(DoA_phi); + cosd(DoA_theta)]; + array_response_RX = exp(M_RX_ind*gamma_RX); + + %Generate the time domain (TD) impulse response where each 2D slice represents the TD channel matrix for one specific path delay + path_const=sqrt(power).*exp(1j*path_params.phase*deg_to_rad); + channel = reshape(array_response_RX, M_RX, 1, []) .* reshape(array_response_TX, 1, M_TX, []) .* reshape(path_const, 1, 1, path_params.num_paths); +end \ No newline at end of file diff --git a/DeepMIMO_functions/construct_DeepMIMO_channel.m b/DeepMIMO_functions/construct_DeepMIMO_channel.m deleted file mode 100644 index 0275da3..0000000 --- a/DeepMIMO_functions/construct_DeepMIMO_channel.m +++ /dev/null @@ -1,84 +0,0 @@ -% --------- DeepMIMO: A Generic Dataset for mmWave and massive MIMO ------% -% Authors: Ahmed Alkhateeb, Umut Demirhan, Abdelrahman Taha -% Date: March 17, 2022 -% Goal: Encouraging research on ML/DL for MIMO applications and -% providing a benchmarking tool for the developed algorithms -% ---------------------------------------------------------------------- % - -function [channel]=construct_DeepMIMO_channel(tx_ant_size, tx_rotation, tx_ant_spacing, rx_ant_size, rx_rotation, rx_ant_spacing, params_user, params) - -BW = params.bandwidth*1e9; -ang_conv=pi/180; -Ts=1/BW; -k=(0:params.OFDM_sampling_factor:params.OFDM_limit-1).'; -num_sampled_subcarriers=length(k); - -% TX antenna parameters for a UPA structure -M_TX_ind = antenna_channel_map(tx_ant_size(1), tx_ant_size(2), tx_ant_size(3), 0); -M_TX=prod(tx_ant_size); -kd_TX=2*pi*tx_ant_spacing; - -% RX antenna parameters for a UPA structure -M_RX_ind = antenna_channel_map(rx_ant_size(1), rx_ant_size(2), rx_ant_size(3), 0); -M_RX=prod(rx_ant_size); -kd_RX=2*pi*rx_ant_spacing; - -if params_user.num_paths == 0 - channel = complex(zeros(M_RX, M_TX, num_sampled_subcarriers)); - return -end - - -% Change the DoD and DoA angles based on the panel orientations -if params.activate_array_rotation - [DoD_theta, DoD_phi, DoA_theta, DoA_phi] = axes_rotation(tx_rotation, params_user.DoD_theta, params_user.DoD_phi, rx_rotation, params_user.DoA_theta, params_user.DoA_phi); -else - DoD_theta = params_user.DoD_theta; - DoD_phi = params_user.DoD_phi; - DoA_theta = params_user.DoA_theta; - DoA_phi = params_user.DoA_phi; -end - -% Apply the radiation pattern of choice -if params.radiation_pattern % Half-wave dipole radiation pattern - power = params_user.power.* antenna_pattern_halfwavedipole(DoD_theta, DoD_phi) .* antenna_pattern_halfwavedipole(DoA_theta, DoA_phi); -else % Isotropic radiation pattern - power = params_user.power; -end - -% TX Array Response - BS -gamma_TX=+1j*kd_TX*[sind(DoD_theta).*cosd(DoD_phi); - sind(DoD_theta).*sind(DoD_phi); - cosd(DoD_theta)]; -array_response_TX = exp(M_TX_ind*gamma_TX); - -% RX Array Response - UE or BS -gamma_RX=+1j*kd_RX*[sind(DoA_theta).*cosd(DoA_phi); - sind(DoA_theta).*sind(DoA_phi); - cosd(DoA_theta)]; -array_response_RX = exp(M_RX_ind*gamma_RX); - -% Account only for the channel within the useful OFDM symbol duration -delay_normalized=params_user.ToA/Ts; - -power(delay_normalized >= params.num_OFDM) = 0; -delay_normalized(delay_normalized>=params.num_OFDM) = params.num_OFDM; - -%Assuming the pulse shaping as a dirac delta function and no receive LPF -if ~params.activate_RX_filter - path_const=sqrt(power/params.num_OFDM).*exp(1j*params_user.phase*ang_conv).*exp(-1j*2*pi*(k/params.num_OFDM)*delay_normalized); - channel = sum(reshape(array_response_RX, M_RX, 1, 1, []) .* reshape(array_response_TX, 1, M_TX, 1, []) .* reshape(path_const, 1, 1, num_sampled_subcarriers, []), 4); -else - - d_ext = [0:(params.num_OFDM-1)]; %extended d domain - delay_d_conv = exp(-1j*(2*pi.*k/params.num_OFDM).*d_ext); - - % Generate the pulse function - LP_fn = pulse_sinc(d_ext.'-delay_normalized); - conv_vec = exp(1j*params_user.phase*ang_conv).*sqrt(power/params.num_OFDM) .* LP_fn; %Power of the paths and phase - - channel = sum(reshape(array_response_RX, M_RX, 1, 1, []) .* reshape(array_response_TX, 1, M_TX, 1, []) .* reshape(conv_vec, 1, 1, [], params_user.num_paths), 4); - channel = sum(reshape(channel, M_RX, M_TX, 1, []) .* reshape(delay_d_conv, 1, 1, num_sampled_subcarriers, []), 4); -end - -end \ No newline at end of file diff --git a/DeepMIMO_functions/construct_DeepMIMO_channel_TD.m b/DeepMIMO_functions/construct_DeepMIMO_channel_TD.m deleted file mode 100644 index 7142a24..0000000 --- a/DeepMIMO_functions/construct_DeepMIMO_channel_TD.m +++ /dev/null @@ -1,61 +0,0 @@ -% --------- DeepMIMO: A Generic Dataset for mmWave and massive MIMO ------% -% Authors: Ahmed Alkhateeb, Umut Demirhan, Abdelrahman Taha -% Date: March 17, 2022 -% Goal: Encouraging research on ML/DL for MIMO applications and -% providing a benchmarking tool for the developed algorithms -% ---------------------------------------------------------------------- % - -function [channel]=construct_DeepMIMO_channel_TD(tx_ant_size, tx_rotation, tx_ant_spacing, rx_ant_size, rx_rotation, rx_ant_spacing, params_user, params) - -ang_conv=pi/180; - -% TX antenna parameters for a UPA structure -M_TX_ind = antenna_channel_map(tx_ant_size(1), tx_ant_size(2), tx_ant_size(3), 0); -M_TX=prod(tx_ant_size); -kd_TX=2*pi*tx_ant_spacing; - -% RX antenna parameters for a UPA structure -M_RX_ind = antenna_channel_map(rx_ant_size(1), rx_ant_size(2), rx_ant_size(3), 0); -M_RX=prod(rx_ant_size); -kd_RX=2*pi*rx_ant_spacing; - -if params_user.num_paths == 0 - channel = complex(zeros(M_RX, M_TX, params_user.num_paths)); - return -end - -% Change the DoD and DoA angles based on the panel orientations -if params.activate_array_rotation - [DoD_theta, DoD_phi, DoA_theta, DoA_phi] = axes_rotation(tx_rotation, params_user.DoD_theta, params_user.DoD_phi, rx_rotation, params_user.DoA_theta, params_user.DoA_phi); -else - DoD_theta = params_user.DoD_theta; - DoD_phi = params_user.DoD_phi; - DoA_theta = params_user.DoA_theta; - DoA_phi = params_user.DoA_phi; -end - -% Apply the radiation pattern of choice -if params.radiation_pattern % Half-wave dipole radiation pattern - power = params_user.power.* antenna_pattern_halfwavedipole(DoD_theta, DoD_phi) .* antenna_pattern_halfwavedipole(DoA_theta, DoA_phi); -else % Isotropic radiation pattern - power = params_user.power; -end - - -% TX Array Response - BS -gamma_TX=+1j*kd_TX*[sind(DoD_theta).*cosd(DoD_phi); - sind(DoD_theta).*sind(DoD_phi); - cosd(DoD_theta)]; -array_response_TX = exp(M_TX_ind*gamma_TX); - -% RX Array Response - UE or BS -gamma_RX=+1j*kd_RX*[sind(DoA_theta).*cosd(DoA_phi); - sind(DoA_theta).*sind(DoA_phi); - cosd(DoA_theta)]; -array_response_RX = exp(M_RX_ind*gamma_RX); - -%Generate the time domain (TD) impulse response where each 2D slice represents the TD channel matrix for one specific path delay -path_const=sqrt(power).*exp(1j*params_user.phase*ang_conv); -channel = reshape(array_response_RX, M_RX, 1, []) .* reshape(array_response_TX, 1, M_TX, []) .* reshape(path_const, 1, 1, params_user.num_paths); - -end \ No newline at end of file diff --git a/DeepMIMO_functions/duration_check.m b/DeepMIMO_functions/misc/duration_check.m similarity index 100% rename from DeepMIMO_functions/duration_check.m rename to DeepMIMO_functions/misc/duration_check.m diff --git a/DeepMIMO_functions/find_users.m b/DeepMIMO_functions/misc/find_users.m similarity index 100% rename from DeepMIMO_functions/find_users.m rename to DeepMIMO_functions/misc/find_users.m diff --git a/DeepMIMO_functions/progress_counter.m b/DeepMIMO_functions/misc/progress_counter.m similarity index 100% rename from DeepMIMO_functions/progress_counter.m rename to DeepMIMO_functions/misc/progress_counter.m diff --git a/DeepMIMO_functions/default_parameters.m b/DeepMIMO_functions/parameters/default_parameters.m similarity index 83% rename from DeepMIMO_functions/default_parameters.m rename to DeepMIMO_functions/parameters/default_parameters.m index e7c327e..4a3a83a 100644 --- a/DeepMIMO_functions/default_parameters.m +++ b/DeepMIMO_functions/parameters/default_parameters.m @@ -20,18 +20,21 @@ params.row_subsampling = 1; % Randomly select round(row_subsampling*(active_user_last-params.active_user_first)) rows params.user_subsampling = 1; % Randomly select round(user_subsampling*number_of_users_in_row) users in each row +%% Antenna Parameters % Antenna array dimensions -params.num_ant_BS = [1, 8, 4]; % Number of antenna elements for the BS arrays in the x,y,z-axes +params.num_ant_BS = [8, 1]; % Number of antenna elements for the BS arrays in the x,y,z-axes % By defauly, all BSs will have the same array sizes % To define different array sizes for the selected active BSs, you can add multiple rows. % Example: For two active BSs with a 8x4 y-z UPA in the first BS and 4x4 % x-z UPA for the second BS, you write % params.num_ant_BS = [[1, 8, 4]; [1, 4, 4]]; -params.num_ant_UE = [1, 4, 2]; % Number of antenna elements for the user arrays in the x,y,z-axes +params.num_ant_UE = [4, 1]; % Number of antenna elements for the user arrays in the x,y,z-axes + +params.FoV_ant_BS = [180, 180]; % Degrees in horizontal-vertical +params.FoV_ant_UE = [360, 180]; % Degrees in horizontal-vertical % Antenna array orientations -params.activate_array_rotation = 0; % 0 -> no array rotation - 1 -> apply the array rotation defined in params.array_rotation_BS params.array_rotation_BS = [5, 10, 20]; % 3D rotation angles in degrees around the x,y,z axes respectively % The rotations around x,y,z are also called as slant, downtilt, and bearing angles (of an antenna towards +x) @@ -48,8 +51,6 @@ % set [[x_min, x_max]; [y_min, y_max]; [z_min, z_max]] % params.array_rotation_UE = [[0, 30]; [30, 60]; [60, 90]]; -params.enable_BS2BSchannels = 1; % Enable generating BS to BS channel (could be useful for IAB, RIS, repeaters, etc.) - % Antenna array spacing params.ant_spacing_BS = .5; % ratio of the wavelength; for half wavelength enter .5 params.ant_spacing_UE = .5; % ratio of the wavelength; for half wavelength enter .5 @@ -63,6 +64,7 @@ params.activate_RX_filter = 0; % 0 No RX filter % 1 Apply RX low-pass filter (ideal: Sinc in the time domain) + % Channel parameters # Activate OFDM params.generate_OFDM_channels = 1; % 1: activate frequency domain (FD) channel generation for OFDM systems % 0: activate instead time domain (TD) channel impulse response generation for non-OFDM systems @@ -70,7 +72,7 @@ % OFDM parameters params.num_OFDM = 512; % Number of OFDM subcarriers -params.OFDM_sampling_factor = 1; % The constructed channels will be calculated only at the sampled subcarriers (to reduce the size of the dataset) -params.OFDM_limit = 64; % Only the first params.OFDM_limit subcarriers will be considered +params.OFDM_sampling = [2:3]; % The constructed channels will be calculated only at the sampled subcarriers (to reduce the size of the dataset) -params.saveDataset = 0; % 0: Will return the dataset without saving it (highly recommended!) \ No newline at end of file +params.dual_polar = 0; +params.enable_Doppler = 0; % Enable Doppler shift (if available in the scenario) \ No newline at end of file diff --git a/DeepMIMO_functions/read_params.m b/DeepMIMO_functions/parameters/read_params.m similarity index 100% rename from DeepMIMO_functions/read_params.m rename to DeepMIMO_functions/parameters/read_params.m diff --git a/DeepMIMO_functions/parameters/validate_parameters.m b/DeepMIMO_functions/parameters/validate_parameters.m new file mode 100644 index 0000000..973629d --- /dev/null +++ b/DeepMIMO_functions/parameters/validate_parameters.m @@ -0,0 +1,317 @@ +% --------- DeepMIMO: A Generic Dataset for mmWave and massive MIMO ------% +% Authors: Ahmed Alkhateeb, Umut Demirhan, Abdelrahman Taha +% Date: March 17, 2022 +% Goal: Encouraging research on ML/DL for MIMO applications and +% providing a benchmarking tool for the developed algorithms +% ---------------------------------------------------------------------- % + +function [params, params_inner] = validate_parameters(params) + + [params] = compareWithDefaultParameters(params); + [params, params_inner] = additionalParameters(params); + [params_inner] = addPolarizationList(params, params_inner); + + params_inner = validateAntennaParameters(params, params_inner); + params = validateChannelParameters(params); +end + +function [params, params_inner] = additionalParameters(params) + + % Add dataset path + if ~isfield(params, 'dataset_folder') + current_folder = mfilename('fullpath'); + deepmimo_folder = fileparts(fileparts(fileparts(current_folder))); + params_inner.dataset_folder = fullfile(deepmimo_folder, '/Raytracing_scenarios/'); + + % Create folders if not exists + folder_one = fullfile(deepmimo_folder, '/Raytracing_scenarios/'); + folder_two = fullfile(deepmimo_folder, '/DeepMIMO_dataset/'); + if ~exist(folder_one, 'dir') + mkdir(folder_one); + end + if ~exist(folder_two, 'dir') + mkdir(folder_two) + end + else + params_inner.dataset_folder = fullfile(params.dataset_folder); + end + + scenario_folder = fullfile(params_inner.dataset_folder, params.scenario); + assert(logical(exist(scenario_folder, 'dir')), ['There is no scenario named "' params.scenario '" in the folder "' scenario_folder '/"' '. Please make sure the scenario name is correct and scenario files are downloaded and placed correctly.']); + + % Determine if the scenario is dynamic + params_inner.dynamic_scenario = 0; + if ~isempty(strfind(params.scenario, 'dyn')) + params_inner.dynamic_scenario = 1; + end + + % Check data version and load parameters of the scenario + params_inner.data_format_version = checkDataVersion(scenario_folder); + version = params_inner.data_format_version; + if version == 2 + version = 3; + end + version_postfix = strcat('v', num2str(version)); + + % Load Scenario Parameters (version specific) + load_scenario_params_fun = strcat('load_scenario_params_', version_postfix); + [params, params_inner] = feval(load_scenario_params_fun, params, params_inner); + + % Select raytracing function (version specific) + params_inner.raytracing_fn = strcat('read_raytracing_', version_postfix); + + + params.symbol_duration = (params.num_OFDM) / (params.bandwidth*1e9); + params.num_active_BS = length(params.active_BS); + + validateUserParameters(params); + [params.user_ids, params.num_user] = find_users(params); +end + +function version = checkDataVersion(scenario_folder) + new_params_file = fullfile(scenario_folder, 'params.mat'); + if exist(new_params_file, 'file') == 0 + version = 1; + else + load(new_params_file) + end +end + +function [params, params_inner] = load_scenario_params_v3(params, params_inner) + + if params_inner.dynamic_scenario == 1 + list_of_folders = strsplit(sprintf('scene_%i--', params.scene_first-1:params.scene_last-1),'--'); + list_of_folders(end) = []; + list_of_folders = fullfile(params_inner.dataset_folder, params.scenario, list_of_folders); + else + list_of_folders = {fullfile(params_inner.dataset_folder, params.scenario)}; + end + params_inner.list_of_folders = list_of_folders; + + % Read scenario parameters + params_inner.scenario_files=params_inner.list_of_folders{1}; % The initial of all the scenario files + params_file = fullfile(params_inner.dataset_folder, params.scenario, 'params.mat'); + + load(params_file) % Scenario parameter file + + params.carrier_freq = carrier_freq; % in Hz + params.transmit_power_raytracing = transmit_power; % in dB + params.user_grids = user_grids; + params.num_BS = num_BS; + if params.enable_Doppler && ~doppler_available + params.enable_Doppler = 0; + warning('There is no Doppler data in this scenario (it is not dynamic). The parameter enable_Doppler is set to 0.') + end + + if params.dual_polar && ~dual_polar_available + params.dual_polar = 0; + warning('There is no dual-polar data in this scenario. The parameter dual_polar is set to 0.') + end + %params.BS_grids = BS_grids; + %params.BS_ID_map = TX_ID_map; % New addition for the new data format + + params_inner = findUserFileSplit(params_inner); + params_inner.doppler_available = doppler_available; + params_inner.dual_polar_available = dual_polar_available; + +end + +function [params, params_inner] = load_scenario_params_v1(params, params_inner) + + if params_inner.dynamic_scenario == 1 + list_of_folders = strsplit(sprintf('/scene_%i/--', params.scene_first-1:params.scene_last-1),'--'); + list_of_folders(end) = []; + list_of_folders = fullfile(params_inner.dataset_folder, params.scenario, list_of_folders); + else + list_of_folders = {fullfile(params_inner.dataset_folder, params.scenario)}; + end + params_inner.list_of_folders = list_of_folders; + + % Read scenario parameters + params_inner.scenario_files=fullfile(list_of_folders{1}, params.scenario); % The initial of all the scenario files + load([params_inner.scenario_files, '.params.mat']) % Scenario parameter file + params.carrier_freq = carrier_freq; % in Hz + params.transmit_power_raytracing = transmit_power; % in dBm + params.user_grids = user_grids; + params.num_BS = num_BS; + + % BS-BS channel parameters + load([params_inner.scenario_files, '.BSBS.params.mat']) % BS2BS parameter file + params.BS_grids = BS_grids; + +end + +% Check the validity of the given parameters +% Add default parameters if they don't exist in the current file +function [params] = compareWithDefaultParameters(params) + default_params = read_params('default_parameters.m'); + default_fields = fieldnames(default_params); + fields = fieldnames(params); + default_fields_exist = zeros(1, length(default_fields)); + for i = 1:length(fields) + comp = strcmp(fields{i}, default_fields); + if sum(comp) == 1 + default_fields_exist(comp) = 1; + else + if ~strcmp(fields{i}, "dataset_folder") + fprintf('\nThe parameter "%s" defined in the given parameters is not used by DeepMIMO', fields{i}) + end + end + end + default_fields_exist = ~default_fields_exist; + default_nonexistent_fields = find(default_fields_exist); + for i = 1:length(default_nonexistent_fields) + field = default_fields{default_nonexistent_fields(i)}; + value = getfield(default_params, field); + params = setfield(params, field, value); + % fprintf('\nAdding default parameter: %s - %s', field, num2str(value)) + end +end + +function [params_inner] = validateAntennaParameters(params, params_inner) + assert(max(params.active_BS) <= params.num_BS, ['There are only ' num2str(params.num_BS) ' basestation in this scenario! Please set active_BS parameter in this range.']) + params_inner = checkAntennaSize(params, params_inner); + params_inner = checkAntennaOrientation(params, params_inner); + params_inner = checkAntennaSpacing(params, params_inner); + params_inner = checkAntennaFoV(params, params_inner); + +end + +function params_inner = checkAntennaFoV(params, params_inner) + % Check UE antenna FoV + UE_FoV_size = size(params.FoV_ant_UE); + assert(UE_FoV_size(2) == 2, 'The user antenna FoV parameter must be 2 dimensional [horizontal, vertical]'); + assert(params.FoV_ant_UE(1) > 0 & params.FoV_ant_UE(1) <= 360, 'The horizontal FoV of the user antenna must be in (0, 360]'); + assert(params.FoV_ant_UE(2) > 0 & params.FoV_ant_UE(2) <= 180, 'The vertical FoV of the user antenna must be in (0, 180]'); + params_inner.ant_FoV_UE = params.FoV_ant_UE; + + % Check BS antenna size + BS_FoV_size = size(params.FoV_ant_BS); + assert(BS_FoV_size(2) == 2, 'The BS antenna FoV parameter must have 2 columns in the form of [horizontal, vertical]'); + assert(all(params.FoV_ant_BS(:, 1) > 0 & params.FoV_ant_BS(:, 1) <= 360), 'The horizontal FoVs of the BS antennas must be in (0, 360]'); + assert(all(params.FoV_ant_BS(:, 2) > 0 & params.FoV_ant_BS(:, 2) <= 180), 'The vertical FoVs of the BS antennas must be in (0, 180]'); + + + if BS_FoV_size(1) ~= params.num_active_BS + if BS_FoV_size(1) == 1 + params_inner.ant_FoV_BS = repmat(params.FoV_ant_BS, params.num_active_BS, 1); + else + error('The defined BS antenna panel FoV must be either 1x2 or Nx2 dimensional, where N is the number of active BSs.') + end + else + params_inner.ant_FoV_BS = params.FoV_ant_BS; + end +end + +function params_inner = checkAntennaSize(params, params_inner) + % Check UE antenna size + ant_size = size(params.num_ant_UE); + assert(ant_size(2) == 2, 'The defined user antenna panel size must be 2 dimensional [horizontal, vertical]') + + % Check BS antenna size + ant_size = size(params.num_ant_BS); + assert(ant_size(2) == 2, 'The defined BS antenna panel size must be 2 dimensional [horizontal, vertical]') + if ant_size(1) ~= params.num_active_BS + if ant_size(1) == 1 + params_inner.num_ant_BS = repmat(params.num_ant_BS, params.num_active_BS, 1); + else + error('The defined BS antenna panel size must be either 1x2 or Nx2 dimensional, where N is the number of active BSs.') + end + else + params_inner.num_ant_BS = params.num_ant_BS; + end +end + +function params_inner = checkAntennaOrientation(params, params_inner) + % BS Antennas + array_rotation_size = size(params.array_rotation_BS); + assert(array_rotation_size(2) == 3, 'The defined BS antenna array rotation must be 3 dimensional (rotation angles around x-y-z axes)') + if array_rotation_size(1) ~= params.num_active_BS + if array_rotation_size(1) == 1 + params_inner.array_rotation_BS = repmat(params.array_rotation_BS, params.num_active_BS, 1); + else + error('The defined BS antenna array rotation size must be either 1x3 or Nx3 dimensional, where N is the number of active BSs.') + end + else + params_inner.array_rotation_BS = params.array_rotation_BS; + end + + % UE Antennas + array_rotation_size = size(params.array_rotation_UE); + if array_rotation_size(1) == 1 && array_rotation_size(2) == 3 + params_inner.array_rotation_UE = repmat(params.array_rotation_UE, params.num_user, 1); + elseif array_rotation_size(1) == 3 && array_rotation_size(2) == 2 + params_inner.array_rotation_UE = zeros(params.num_user, 3); + for i = 1:3 + params_inner.array_rotation_UE(:, i) = unifrnd(params.array_rotation_UE(i, 1), params.array_rotation_UE(i, 2), params.num_user, 1); + end + else + error('The defined user antenna array rotation size must be either 1x3 for fixed, or 3x2 for random generation.') + end +end + +function params_inner = checkAntennaSpacing(params, params_inner) + % Check BS antenna spacing + ant_spacing_size = length(params.ant_spacing_BS); + if ant_spacing_size ~= params.num_active_BS + if ant_spacing_size == 1 + params_inner.ant_spacing_BS = repmat(params.ant_spacing_BS, params.num_active_BS, 1); + else + error('The defined BS antenna spacing must be either a scalar or an N dimensional vector, where N is the number of active BSs.') + end + else + params_inner.ant_spacing_BS = params.ant_spacing_BS; + end +end + +% Find how the user files are split to multiple files with subset of users +% E.g., 0-10k 10k-20k ... etc +function params_inner = findUserFileSplit(params_inner) + % Get a list of UE split + fileList = dir(fullfile(params_inner.scenario_files, '*.mat')); + filePattern = 'BS1_UE_(\d+)-(\d+)\.mat'; + + number1 = []; + number2 = []; + + % Loop through each file and extract the numbers + for i = 1:numel(fileList) + filename = fileList(i).name; + + % Check if the file name matches the pattern + match = regexp(filename, filePattern, 'tokens'); + + if ~isempty(match) + % Extract the numbers from the file name + number1 = [number1 str2double(match{1}{1})]; + number2 = [number2 str2double(match{1}{2})]; + end + end + params_inner.UE_file_split = [number1; number2]; +end + +function [] = validateUserParameters(params) + assert(params.row_subsampling<=1 & params.row_subsampling>0, 'Row subsampling parameters must be selected in (0, 1]') + assert(params.user_subsampling<=1 & params.user_subsampling>0, 'User subsampling parameters must be selected in (0, 1]') + + assert(params.active_user_last <= params.user_grids(end, 2) & params.active_user_last >= 1, sprintf('There are total %i user rows in the scenario, please select the active user first and last in [1, %i]', params.user_grids(end, 2), params.user_grids(end, 2))); + assert(params.active_user_first <= params.active_user_last, 'active_user_last parameter must be greater than or equal to active_user_first'); +end + +function params = validateChannelParameters(params) + if params.generate_OFDM_channels + if sum(params.OFDM_sampling > params.num_OFDM) + sum(params.OFDM_sampling < 1) ~= 0 + error(sprintf('The OFDM_sampling variables must be a vector of values in [1, %i]', params.num_OFDM)) + end + end +end + +function params_inner = addPolarizationList(params, params_inner) + if params.dual_polar && params_inner.dual_polar_available + params_inner.polarization_list = ["_VV", "_VH", "_HV", "_HH"]; + elseif ~params.dual_polar && params_inner.dual_polar_available + params_inner.polarization_list = ["_VV"]; + else + params_inner.polarization_list = [""]; + end +end \ No newline at end of file diff --git a/DeepMIMO_functions/plots/plot_heatmap.m b/DeepMIMO_functions/plots/plot_heatmap.m new file mode 100644 index 0000000..06250dc --- /dev/null +++ b/DeepMIMO_functions/plots/plot_heatmap.m @@ -0,0 +1,35 @@ +function [f1] = plot_heatmap(path_loss_dB, ue_locs, bs_loc, user_loc, caxis_min, caxis_max) + if length(nargin) == 2 + draw_bs = False + draw_ue = False; + elseif + f1 = figure; + scatter(ue_locs(1, :), ue_locs(2, :), 5, path_loss_dB, 'Filled') + hold on + plot(bs_loc(1), bs_loc(2), 'ko', 'DisplayName', 'BS') + plot(ris_loc(1), ris_loc(2), 'ks', 'DisplayName', 'RIS') + plot(user_loc(1), user_loc(2), 'kx', 'MarkerSize', 7, 'DisplayName', 'UE') + xlim([min(ue_locs(1, :)), max(ue_locs(1, :))]); + ylim([min(ue_locs(2, :)), max(ue_locs(2, :))]); + + colormap(autumn(size(ue_locs, 2))) + caxis([caxis_min, caxis_max]); + cb = colorbar; + cb.Label.String = "SNR (dB)"; + cb.Label.Rotation = 270; + cb.Label.VerticalAlignment = "bottom"; + + % Define custom legend labels for specific lines + legend_labels = {'BS', 'RIS', 'UE'}; + + % Create plot objects for each line + line_objects = [plot(NaN, NaN, 'ko', 'LineWidth', 2), ... + plot(NaN, NaN, 'ks', 'LineWidth', 2), ... + plot(NaN, NaN, 'kx', 'LineWidth', 2)]; + + % Create a legend using specific plot objects and labels + legend(line_objects, legend_labels, 'Location', 'northwest'); + + % Customize font size and style of the legend + set(gca, 'FontSize', 12, 'FontName', 'Arial'); +end \ No newline at end of file diff --git a/DeepMIMO_functions/plots/plot_los_status.m b/DeepMIMO_functions/plots/plot_los_status.m new file mode 100644 index 0000000..feda03b --- /dev/null +++ b/DeepMIMO_functions/plots/plot_los_status.m @@ -0,0 +1,24 @@ +function [] = plot_los_status(bs_dataset) + + figure; + hold on; + bs_loc = bs_dataset.loc; + user_locs = zeros(length(bs_dataset.user), 2); + user_los = zeros(length(bs_dataset.user), 1); + for j = 1:length(bs_dataset.user) + user_locs(j, :) = bs_dataset.user{j}.loc(1:2); + user_los(j) = bs_dataset.user{j}.LoS_status; + end + + colors = ["rx", "bx", "gx"]; + legends = ["UE (No Path)", "UE (NLoS)", "UE (LoS)"]; + for los_status = [-1, 0, 1] + select_users = user_los == los_status; + plot(user_locs(select_users, 1), user_locs(select_users, 2), colors(los_status+2), 'DisplayName', legends(los_status+2), 'MarkerSize', 3); + end + + plot(bs_loc(1), bs_loc(2), 'ko', 'DisplayName', 'BS', 'MarkerSize', 4); + legend; + grid on; +end + \ No newline at end of file diff --git a/DeepMIMO_functions/read_raytracing.m b/DeepMIMO_functions/readers/read_raytracing_v1.m similarity index 55% rename from DeepMIMO_functions/read_raytracing.m rename to DeepMIMO_functions/readers/read_raytracing_v1.m index 8f51086..f128f55 100644 --- a/DeepMIMO_functions/read_raytracing.m +++ b/DeepMIMO_functions/readers/read_raytracing_v1.m @@ -5,7 +5,9 @@ % providing a benchmarking tool for the developed algorithms % ---------------------------------------------------------------------- % -function [channel_params,channel_params_BS,BS_loc]=read_raytracing(BS_ID, params, scenario_files) +function [channel_params,channel_params_BS,BS_loc]=read_raytracing_v1(BS_ID, params, params_inner) + +scenario_files = params_inner.scenario_files; %% Loading channel parameters between current active basesation transmitter and user receivers filename_DoD=strcat(scenario_files, '.', int2str(BS_ID),'.DoD.mat'); filename_DoA=strcat(scenario_files, '.', int2str(BS_ID),'.DoA.mat'); @@ -94,82 +96,80 @@ channel_params=channel_params_all(1,:); %% Loading channel parameters between current active basesation transmitter and all the basestation receivers -if params.enable_BS2BSchannels - filename_BSBS_DoD=strcat(scenario_files, '.', int2str(BS_ID),'.DoD.BSBS.mat'); - filename_BSBS_DoA=strcat(scenario_files, '.', int2str(BS_ID),'.DoA.BSBS.mat'); - filename_BSBS_CIR=strcat(scenario_files, '.', int2str(BS_ID),'.CIR.BSBS.mat'); - filename_BSBS_LOS=strcat(scenario_files, '.', int2str(BS_ID),'.LoS.BSBS.mat'); - filename_BSBS_PL=strcat(scenario_files, '.', int2str(BS_ID),'.PL.BSBS.mat'); - filename_BSBS_Loc=strcat(scenario_files, '.BSBS.RX_Loc.mat'); - - DoD_BSBS_array=importdata(filename_BSBS_DoD); - DoA_BSBS_array=importdata(filename_BSBS_DoA); - CIR_BSBS_array=importdata(filename_BSBS_CIR); - LOS_BSBS_array=importdata(filename_BSBS_LOS); - PL_BSBS_array=importdata(filename_BSBS_PL); - Loc_BSBS_array=importdata(filename_BSBS_Loc); - - num_paths_BSBS = double(params.num_paths); - total_num_BSs=double(DoD_BSBS_array(1)); - BS_pointer=0; - - DoD_BSBS_array(1)=[]; - DoA_BSBS_array(1)=[]; - CIR_BSBS_array(1)=[]; - LOS_BSBS_array(1)=[]; - - BS_count = 1; - for Receiver_BS_Number=1:total_num_BSs - max_paths_BSBS=double(DoD_BSBS_array(BS_pointer+2)); - num_path_BS_limited=double(min(num_paths_BSBS,max_paths_BSBS)); - if sum(Receiver_BS_Number == double(params.active_BS)) == 1 %Only read the channels related to the active basestation receivers - - if (max_paths_BSBS>0) - Relevant_data_length_BSBS=max_paths_BSBS*4; - Relevant_limited_data_length_BSBS=num_path_BS_limited*4; - - Relevant_DoD_BSBS_array=DoD_BSBS_array(BS_pointer+3:BS_pointer+2+Relevant_data_length_BSBS); - Relevant_DoA_BSBS_array=DoA_BSBS_array(BS_pointer+3:BS_pointer+2+Relevant_data_length_BSBS); - Relevant_CIR_BSBS_array=CIR_BSBS_array(BS_pointer+3:BS_pointer+2+Relevant_data_length_BSBS); - - channel_params_all_BS(BS_count).DoD_phi=Relevant_DoD_BSBS_array(2:4:Relevant_limited_data_length_BSBS); - channel_params_all_BS(BS_count).DoD_theta=Relevant_DoD_BSBS_array(3:4:Relevant_limited_data_length_BSBS); - channel_params_all_BS(BS_count).DoA_phi=Relevant_DoA_BSBS_array(2:4:Relevant_limited_data_length_BSBS); - channel_params_all_BS(BS_count).DoA_theta=Relevant_DoA_BSBS_array(3:4:Relevant_limited_data_length_BSBS); - channel_params_all_BS(BS_count).phase=Relevant_CIR_BSBS_array(2:4:Relevant_limited_data_length_BSBS); - channel_params_all_BS(BS_count).ToA=Relevant_CIR_BSBS_array(3:4:Relevant_limited_data_length_BSBS); - channel_params_all_BS(BS_count).power=1e-3*(10.^(0.1*( Relevant_CIR_BSBS_array(4:4:Relevant_limited_data_length_BSBS)+(transmit_power-tx_power_raytracing) ))); - channel_params_all_BS(BS_count).num_paths=num_path_BS_limited; - channel_params_all_BS(BS_count).loc=Loc_BSBS_array(Receiver_BS_Number,2:4); - channel_params_all_BS(BS_count).distance=PL_BSBS_array(Receiver_BS_Number,1); - channel_params_all_BS(BS_count).pathloss=PL_BSBS_array(Receiver_BS_Number,2); - channel_params_all_BS(BS_count).LoS_status=LOS_BSBS_array(Receiver_BS_Number); - - dc.add_ToA(channel_params_all_BS(BS_count).power, channel_params_all_BS(BS_count).ToA); - - else - channel_params_all_BS(BS_count).DoD_phi=[]; - channel_params_all_BS(BS_count).DoD_theta=[]; - channel_params_all_BS(BS_count).DoA_phi=[]; - channel_params_all_BS(BS_count).DoA_theta=[]; - channel_params_all_BS(BS_count).phase=[]; - channel_params_all_BS(BS_count).ToA=[]; - channel_params_all_BS(BS_count).power=[]; - channel_params_all_BS(BS_count).num_paths=0; - channel_params_all_BS(BS_count).loc=Loc_BSBS_array(Receiver_BS_Number,2:4); - channel_params_all_BS(BS_count).distance=PL_BSBS_array(Receiver_BS_Number,1); - channel_params_all_BS(BS_count).pathloss=[]; - channel_params_all_BS(BS_count).LoS_status=LOS_BSBS_array(Receiver_BS_Number); - end - BS_count = double(BS_count + 1); +filename_BSBS_DoD=strcat(scenario_files, '.', int2str(BS_ID),'.DoD.BSBS.mat'); +filename_BSBS_DoA=strcat(scenario_files, '.', int2str(BS_ID),'.DoA.BSBS.mat'); +filename_BSBS_CIR=strcat(scenario_files, '.', int2str(BS_ID),'.CIR.BSBS.mat'); +filename_BSBS_LOS=strcat(scenario_files, '.', int2str(BS_ID),'.LoS.BSBS.mat'); +filename_BSBS_PL=strcat(scenario_files, '.', int2str(BS_ID),'.PL.BSBS.mat'); +filename_BSBS_Loc=strcat(scenario_files, '.BSBS.RX_Loc.mat'); + +DoD_BSBS_array=importdata(filename_BSBS_DoD); +DoA_BSBS_array=importdata(filename_BSBS_DoA); +CIR_BSBS_array=importdata(filename_BSBS_CIR); +LOS_BSBS_array=importdata(filename_BSBS_LOS); +PL_BSBS_array=importdata(filename_BSBS_PL); +Loc_BSBS_array=importdata(filename_BSBS_Loc); + +num_paths_BSBS = double(params.num_paths); +total_num_BSs=double(DoD_BSBS_array(1)); +BS_pointer=0; + +DoD_BSBS_array(1)=[]; +DoA_BSBS_array(1)=[]; +CIR_BSBS_array(1)=[]; +LOS_BSBS_array(1)=[]; + +BS_count = 1; +for Receiver_BS_Number=1:total_num_BSs + max_paths_BSBS=double(DoD_BSBS_array(BS_pointer+2)); + num_path_BS_limited=double(min(num_paths_BSBS,max_paths_BSBS)); + if sum(Receiver_BS_Number == double(params.active_BS)) == 1 %Only read the channels related to the active basestation receivers + + if (max_paths_BSBS>0) + Relevant_data_length_BSBS=max_paths_BSBS*4; + Relevant_limited_data_length_BSBS=num_path_BS_limited*4; + + Relevant_DoD_BSBS_array=DoD_BSBS_array(BS_pointer+3:BS_pointer+2+Relevant_data_length_BSBS); + Relevant_DoA_BSBS_array=DoA_BSBS_array(BS_pointer+3:BS_pointer+2+Relevant_data_length_BSBS); + Relevant_CIR_BSBS_array=CIR_BSBS_array(BS_pointer+3:BS_pointer+2+Relevant_data_length_BSBS); + + channel_params_all_BS(BS_count).DoD_phi=Relevant_DoD_BSBS_array(2:4:Relevant_limited_data_length_BSBS); + channel_params_all_BS(BS_count).DoD_theta=Relevant_DoD_BSBS_array(3:4:Relevant_limited_data_length_BSBS); + channel_params_all_BS(BS_count).DoA_phi=Relevant_DoA_BSBS_array(2:4:Relevant_limited_data_length_BSBS); + channel_params_all_BS(BS_count).DoA_theta=Relevant_DoA_BSBS_array(3:4:Relevant_limited_data_length_BSBS); + channel_params_all_BS(BS_count).phase=Relevant_CIR_BSBS_array(2:4:Relevant_limited_data_length_BSBS); + channel_params_all_BS(BS_count).ToA=Relevant_CIR_BSBS_array(3:4:Relevant_limited_data_length_BSBS); + channel_params_all_BS(BS_count).power=1e-3*(10.^(0.1*( Relevant_CIR_BSBS_array(4:4:Relevant_limited_data_length_BSBS)+(transmit_power-tx_power_raytracing) ))); + channel_params_all_BS(BS_count).num_paths=num_path_BS_limited; + channel_params_all_BS(BS_count).loc=Loc_BSBS_array(Receiver_BS_Number,2:4); + channel_params_all_BS(BS_count).distance=PL_BSBS_array(Receiver_BS_Number,1); + channel_params_all_BS(BS_count).pathloss=PL_BSBS_array(Receiver_BS_Number,2); + channel_params_all_BS(BS_count).LoS_status=LOS_BSBS_array(Receiver_BS_Number); + + dc.add_ToA(channel_params_all_BS(BS_count).power, channel_params_all_BS(BS_count).ToA); + + else + channel_params_all_BS(BS_count).DoD_phi=[]; + channel_params_all_BS(BS_count).DoD_theta=[]; + channel_params_all_BS(BS_count).DoA_phi=[]; + channel_params_all_BS(BS_count).DoA_theta=[]; + channel_params_all_BS(BS_count).phase=[]; + channel_params_all_BS(BS_count).ToA=[]; + channel_params_all_BS(BS_count).power=[]; + channel_params_all_BS(BS_count).num_paths=0; + channel_params_all_BS(BS_count).loc=Loc_BSBS_array(Receiver_BS_Number,2:4); + channel_params_all_BS(BS_count).distance=PL_BSBS_array(Receiver_BS_Number,1); + channel_params_all_BS(BS_count).pathloss=[]; + channel_params_all_BS(BS_count).LoS_status=LOS_BSBS_array(Receiver_BS_Number); end - BS_pointer=double(BS_pointer+max_paths_BSBS*4+2); + BS_count = double(BS_count + 1); end - - dc.print_warnings('BS', BS_ID); - dc.reset() - + BS_pointer=double(BS_pointer+max_paths_BSBS*4+2); end + +dc.print_warnings('BS', BS_ID); +dc.reset() + channel_params_BS=channel_params_all_BS(1,:); diff --git a/DeepMIMO_functions/readers/read_raytracing_v3.m b/DeepMIMO_functions/readers/read_raytracing_v3.m new file mode 100644 index 0000000..decee66 --- /dev/null +++ b/DeepMIMO_functions/readers/read_raytracing_v3.m @@ -0,0 +1,163 @@ +% --------- DeepMIMO: A Generic Dataset for mmWave and massive MIMO ------% +% Authors: Umut Demirhan, Abdelrahman Taha, Ahmed Alkhateeb +% Date: March 17, 2022 +% Goal: Encouraging research on ML/DL for MIMO applications and +% providing a benchmarking tool for the developed algorithms +% ---------------------------------------------------------------------- % + +function [channel_params_user, channel_params_BS, BS_loc] = read_raytracing_v3(BS_ID, params, params_inner, channel_extension) + + if params_inner.dual_polar_available + data_key_name = strcat('channels', channel_extension); + else + data_key_name = 'channels'; + end + + num_paths = double(params.num_paths); + tx_power_raytracing = params.transmit_power_raytracing; % Current TX power in dBm + transmit_power = 30; % Target TX power in dBm (1 Watt transmit power) + power_diff = transmit_power-tx_power_raytracing; + + if params_inner.doppler_available + channel_params_all = struct('phase',[],'ToA',[],'power',[],'DoA_phi',[],'DoA_theta',[],'DoD_phi',[],'DoD_theta',[],'LoS_status',[],'num_paths',[],'loc',[],'distance',[],'pathloss',[],'Doppler_vel',[],'Doppler_acc',[]); + channel_params_all_BS = struct('phase',[],'ToA',[],'power',[],'DoA_phi',[],'DoA_theta',[],'DoD_phi',[],'DoD_theta',[],'LoS_status',[],'num_paths',[],'loc',[],'distance',[],'pathloss',[],'Doppler_vel',[],'Doppler_acc',[]); + else + channel_params_all = struct('phase',[],'ToA',[],'power',[],'DoA_phi',[],'DoA_theta',[],'DoD_phi',[],'DoD_theta',[],'LoS_status',[],'num_paths',[],'loc',[],'distance',[],'pathloss',[]); + channel_params_all_BS = struct('phase',[],'ToA',[],'power',[],'DoA_phi',[],'DoA_theta',[],'DoD_phi',[],'DoD_theta',[],'LoS_status',[],'num_paths',[],'loc',[],'distance',[],'pathloss',[]); + end + dc = duration_check(params.symbol_duration); + + file_idx = 1; + file_loaded = 0; + user_count = 1; + + if params_inner.dynamic_scenario + if ~isempty(params_inner.UE_file_split) + params.num_user = params_inner.UE_file_split(2, file_idx); + filename = strcat('BS', num2str(BS_ID), '_UE_', num2str(params_inner.UE_file_split(1, file_idx)), '-', num2str(params_inner.UE_file_split(2, file_idx)), '.mat'); + data = importdata(fullfile(params_inner.scenario_files, filename)); + user_start = params_inner.UE_file_split(1, file_idx); + + for ue_idx = 1:params.num_user + ue_idx_file = ue_idx - user_start; + max_paths = double(size(data.(data_key_name){ue_idx_file}.p, 2)); + num_path_limited = double(min(num_paths, max_paths)); + + channel_params = data.(data_key_name){ue_idx_file}.p; + add_info = data.rx_locs(ue_idx_file, :); + channel_params_all(user_count) = parse_data(params_inner.doppler_available, num_path_limited, channel_params, add_info, power_diff); + dc.add_ToA(channel_params_all(user_count).power, channel_params_all(user_count).ToA); + + user_count = user_count + 1; + end + else + params.num_user = 0; + end + else + for ue_idx = params.user_ids + % If currently not loaded + % load the file that user is contained + while ue_idx > params_inner.UE_file_split(2, file_idx) + file_idx = file_idx + 1; + file_loaded = 0; + end + if ~file_loaded + filename = strcat('BS', num2str(BS_ID), '_UE_', num2str(params_inner.UE_file_split(1, file_idx)), '-', num2str(params_inner.UE_file_split(2, file_idx)), '.mat'); + data = importdata(fullfile(params_inner.scenario_files, filename)); + user_start = params_inner.UE_file_split(1, file_idx); + file_loaded = 1; + end + + ue_idx_file = ue_idx - user_start; + max_paths = double(size(data.(data_key_name){ue_idx_file}.p, 2)); + num_path_limited = double(min(num_paths, max_paths)); + + channel_params = data.(data_key_name){ue_idx_file}.p; + add_info = data.rx_locs(ue_idx_file, :); + if isfield(data, 'tx_loc') + BS_loc = data.tx_loc; + end + channel_params_all(user_count) = parse_data(params_inner.doppler_available, num_path_limited, channel_params, add_info, power_diff); + dc.add_ToA(channel_params_all(user_count).power, channel_params_all(user_count).ToA); + + user_count = user_count + 1; + end + end + channel_params_user = channel_params_all(1,:); + + dc.print_warnings('BS', BS_ID); + dc.reset() + + %% Loading channel parameters between current active basesation transmitter and all the active basestation receivers + bs_count = 1; + filename = strcat('BS', num2str(BS_ID), '_BS.mat'); + bs_filepath = fullfile(params_inner.scenario_files, filename); + if exist(bs_filepath, 'file') + data = importdata(bs_filepath); + for bs_idx = params.active_BS + + max_paths = double(size(data.(data_key_name){bs_idx}.p, 2)); + num_path_limited = double(min(num_paths, max_paths)); + + channel_params = data.(data_key_name){bs_idx}.p; + add_info = data.rx_locs(bs_idx, :); + + if bs_idx == BS_ID + BS_loc = add_info(1:3); + end + + channel_params_all_BS(bs_count) = parse_data(params_inner.doppler_available, num_path_limited, channel_params, add_info, power_diff); + dc.add_ToA(channel_params_all_BS(bs_count).power, channel_params_all_BS(bs_count).ToA); + + bs_count = bs_count + 1; + end + + channel_params_BS = channel_params_all_BS(1,:); + + dc.print_warnings('BS', BS_ID); + dc.reset() + else + channel_params_BS = []; + end +end + +function x = parse_data(doppler_available, num_paths, paths, info, power_diff) + if num_paths > 0 + x.phase = paths(1, 1:num_paths); + x.ToA = paths(2, 1:num_paths); + x.power = 1e-3*(10.^(0.1*(paths(3, 1:num_paths) + power_diff))); + x.DoA_phi = paths(4, 1:num_paths); + x.DoA_theta = paths(5, 1:num_paths); + x.DoD_phi = paths(6, 1:num_paths); + x.DoD_theta = paths(7, 1:num_paths); + x.LoS_status = paths(8, 1:num_paths); + if doppler_available + if size(paths, 1) > 8 + x.Doppler_vel = paths(9, 1:num_paths); + x.Doppler_acc = paths(10, 1:num_paths); + else + x.Doppler_vel = zeros(size(x.DoD_phi)); + x.Doppler_acc = zeros(size(x.DoD_phi)); + end + end + else + x.phase = []; + x.ToA = []; + x.power = []; + x.DoA_phi = []; + x.DoA_theta = []; + x.DoD_phi = []; + x.DoD_theta = []; + x.LoS_status = []; + if doppler_available + x.Doppler_vel = []; + x.Doppler_acc = []; + end + end + + %add_info = data.rx_locs(ue_idx_file, :); + x.num_paths = num_paths; + x.loc = info(1:3); + x.distance = info(4); + x.pathloss = info(5); +end diff --git a/DeepMIMO_functions/validate_parameters.m b/DeepMIMO_functions/validate_parameters.m deleted file mode 100644 index c546b4d..0000000 --- a/DeepMIMO_functions/validate_parameters.m +++ /dev/null @@ -1,169 +0,0 @@ -% --------- DeepMIMO: A Generic Dataset for mmWave and massive MIMO ------% -% Authors: Ahmed Alkhateeb, Umut Demirhan, Abdelrahman Taha -% Date: March 17, 2022 -% Goal: Encouraging research on ML/DL for MIMO applications and -% providing a benchmarking tool for the developed algorithms -% ---------------------------------------------------------------------- % - -function [params, params_inner] = validate_parameters(params) - - [params] = compare_with_default_params(params); - - [params, params_inner] = additional_params(params); - - params_inner = validate_OFDM_params(params, params_inner); -end - -function [params, params_inner] = additional_params(params) - - % Add dataset path - if ~isfield(params, 'dataset_folder') - current_folder = mfilename('fullpath'); - deepmimo_folder = fileparts(fileparts(current_folder)); - params_inner.dataset_folder = fullfile(deepmimo_folder, '/Raytracing_scenarios/'); - - % Create folders if not exists - folder_one = fullfile(deepmimo_folder, '/Raytracing_scenarios/'); - folder_two = fullfile(deepmimo_folder, '/DeepMIMO_dataset/'); - if ~exist(folder_one, 'dir') - mkdir(folder_one); - end - if ~exist(folder_two, 'dir') - mkdir(folder_two) - end - else - params_inner.dataset_folder = fullfile(params.dataset_folder); - end - - scenario_folder = fullfile(params_inner.dataset_folder, params.scenario); - assert(logical(exist(scenario_folder, 'dir')), ['There is no scenario named "' params.scenario '" in the folder "' scenario_folder '/"' '. Please make sure the scenario name is correct and scenario files are downloaded and placed correctly.']); - - % Determine if the scenario is dynamic - params_inner.dynamic_scenario = 0; - if ~isempty(strfind(params.scenario, 'dyn')) - params_inner.dynamic_scenario = 1; - list_of_folders = strsplit(sprintf('/scene_%i/--', params.scene_first-1:params.scene_last-1),'--'); - list_of_folders(end) = []; - list_of_folders = fullfile(params_inner.dataset_folder, params.scenario, list_of_folders); - else - list_of_folders = {fullfile(params_inner.dataset_folder, params.scenario)}; - end - params_inner.list_of_folders = list_of_folders; - - % Read scenario parameters - params_inner.scenario_files=fullfile(list_of_folders{1}, params.scenario); % The initial of all the scenario files - load([params_inner.scenario_files, '.params.mat']) % Scenario parameter file - - % BS-BS channel parameters - if params.enable_BS2BSchannels - load([params_inner.scenario_files, '.BSBS.params.mat']) % BS2BS parameter file - params.BS_grids = BS_grids; - end - - params.symbol_duration = (params.num_OFDM) / (params.bandwidth*1e9); - params.carrier_freq = carrier_freq; % in Hz - params.transmit_power_raytracing = transmit_power; % in dBm - params.user_grids = user_grids; - params.num_BS = num_BS; - params.num_active_BS = length(params.active_BS); - - assert(params.row_subsampling<=1 & params.row_subsampling>0, 'Row subsampling parameters must be selected in (0, 1]') - assert(params.user_subsampling<=1 & params.user_subsampling>0, 'User subsampling parameters must be selected in (0, 1]') - - [params.user_ids, params.num_user] = find_users(params); -end - -% Check the validity of the given parameters -% Add default parameters if they don't exist in the current file -function [params] = compare_with_default_params(params) - default_params = read_params('default_parameters.m'); - default_fields = fieldnames(default_params); - fields = fieldnames(params); - default_fields_exist = zeros(1, length(default_fields)); - for i = 1:length(fields) - comp = strcmp(fields{i}, default_fields); - if sum(comp) == 1 - default_fields_exist(comp) = 1; - else - if ~strcmp(fields{i}, "dataset_folder") - fprintf('\nThe parameter "%s" defined in the given parameters is not used by DeepMIMO', fields{i}) - end - end - end - default_fields_exist = ~default_fields_exist; - default_nonexistent_fields = find(default_fields_exist); - for i = 1:length(default_nonexistent_fields) - field = default_fields{default_nonexistent_fields(i)}; - value = getfield(default_params, field); - params = setfield(params, field, value); - % fprintf('\nAdding default parameter: %s - %s', field, num2str(value)) - end -end - -function [params_inner] = validate_OFDM_params(params, params_inner) - % Check UE antenna size - ant_size = size(params.num_ant_UE); - assert(ant_size(2) == 3, 'The defined user antenna panel size must be 3 dimensional (in x-y-z)') - - % Check BS antenna size - ant_size = size(params.num_ant_BS); - assert(ant_size(2) == 3, 'The defined BS antenna panel size must be 3 dimensional (in x-y-z)') - if ant_size(1) ~= params.num_active_BS - if ant_size(1) == 1 - params_inner.num_ant_BS = repmat(params.num_ant_BS, params.num_active_BS, 1); - else - error('The defined BS antenna panel size must be either 1x3 or Nx3 dimensional, where N is the number of active BSs.') - end - else - params_inner.num_ant_BS = params.num_ant_BS; - end - - % Check BS and UE antenna array (panel) orientation - if params.activate_array_rotation - array_rotation_size = size(params.array_rotation_BS); - assert(array_rotation_size(2) == 3, 'The defined BS antenna array rotation must be 3 dimensional (rotation angles around x-y-z axes)') - if array_rotation_size(1) ~= params.num_active_BS - if array_rotation_size(1) == 1 - params_inner.array_rotation_BS = repmat(params.array_rotation_BS, params.num_active_BS, 1); - else - error('The defined BS antenna array rotation size must be either 1x3 or Nx3 dimensional, where N is the number of active BSs.') - end - else - params_inner.array_rotation_BS = params.array_rotation_BS; - end - else - params_inner.array_rotation_BS = zeros(params.num_active_BS,3); - end - - % Check UE antenna array (panel) orientation - if params.activate_array_rotation - array_rotation_size = size(params.array_rotation_UE); - if array_rotation_size(1) == 1 && array_rotation_size(2) == 3 - params_inner.array_rotation_UE = repmat(params.array_rotation_UE, params.num_user, 1); - elseif array_rotation_size(1) == 3 && array_rotation_size(2) == 2 - params_inner.array_rotation_UE = zeros(params.num_user, 3); - for i = 1:3 - params_inner.array_rotation_UE(:, i) = unifrnd(params.array_rotation_UE(i, 1), params.array_rotation_UE(i, 2), params.num_user, 1); - end - else - error('The defined user antenna array rotation size must be either 1x3 for fixed, or 3x2 for random generation.') - end - else - params_inner.array_rotation_UE = zeros(params.num_user, 3); - end - - - % Check BS antenna spacing - ant_spacing_size = length(params.ant_spacing_BS); - if ant_spacing_size ~= params.num_active_BS - if ant_spacing_size == 1 - params_inner.ant_spacing_BS = repmat(params.ant_spacing_BS, params.num_active_BS, 1); - else - error('The defined BS antenna spacing must be either a scalar or an N dimensional vector, where N is the number of active BSs.') - end - else - params_inner.ant_spacing_BS = params.ant_spacing_BS; - end - - -end \ No newline at end of file diff --git a/Examples/Example1.m b/Examples/Example1.m new file mode 100644 index 0000000..1eecfdb --- /dev/null +++ b/Examples/Example1.m @@ -0,0 +1,94 @@ +%% Generate Dataset +addpath(genpath('../')) +dataset_params = read_params('Example1_params.m'); + +% Generate the dataset with the loaded parameters +[DeepMIMO_dataset, dataset_params] = DeepMIMO_generator(dataset_params); + +%% LoS Status of the Users +% +% Plot LoS status of the users w.r.t. BS1 +% +plot_los_status(DeepMIMO_dataset{1}) + +% +% Plot LoS status of the users w.r.t. BS1 +% +plot_los_status(DeepMIMO_dataset{2}) + +%% Variable Inspection (BS-UE channel) +% +% Select a transmit basestation and a receive user pair. +% *Note: These variables will be used later to select a single user.* +% +TX_BS = 1; RX_User = 24331; + +% Let's check the size of the dataset +size_of_BSuser_channel = size(DeepMIMO_dataset{TX_BS}.user{RX_User}.channel) + +% BS-user link information +BS_user_link = DeepMIMO_dataset{TX_BS}.user{RX_User} + +% Channel path information +BS_user_path_params = DeepMIMO_dataset{TX_BS}.user{RX_User}.path_params + +%% Variable Inspection (BS-BS channel) +% +% Select a transmit basestation and a receive basesation pair +% +TX_BS = 1; RX_BS = 2; + +% Let's check the size of the dataset +size_of_BSBS_channel = size(DeepMIMO_dataset{TX_BS}.basestation{RX_BS}.channel) + +% BS-BS link information +BS_BS_link = DeepMIMO_dataset{TX_BS}.basestation{RX_BS} + +% Channel path information +BS_BS_path_params = DeepMIMO_dataset{TX_BS}.basestation{RX_BS}.path_params + +%% Visualization of a channel matrix + +H = squeeze(DeepMIMO_dataset{TX_BS}.user{RX_User}.channel); +subcarriers = params.OFDM_sampling; +ant_ind = 1:prod(dataset_params.num_ant_BS); + +figure; +imagesc(ant_ind, subcarriers, abs(H).'); +xlabel('TX Antennas'); +ylabel('Subcarriers'); +title('Channel Magnitude Response'); +colorbar; + +%% Visualization of the UE positions and path-losses +bs_loc = DeepMIMO_dataset{TX_BS}.loc; +num_ue = length(DeepMIMO_dataset{TX_BS}.user); % 100 rows of 181 UEs + +ue_locs = zeros(num_ue, 3); +ue_pl = zeros(num_ue, 1); +for ue_idx = 1:num_ue + ue_locs(ue_idx, :) = DeepMIMO_dataset{TX_BS}.user{ue_idx}.loc; + ue_pl(ue_idx) = DeepMIMO_dataset{TX_BS}.user{ue_idx}.pathloss; +end + +% 3D Grid visualization with basestation +figure; +scatter3(ue_locs(:, 1), ue_locs(:, 2), ue_locs(:, 3), [], ue_pl); +hold on +scatter3(bs_loc(1), bs_loc(2), bs_loc(3), 'rx'); +colorbar() +xlabel('x (m)'); +ylabel('y (m)'); +zlabel('z (m)'); +title('Path Loss (dB)') +legend('UE', 'BS', 'Location', 'best') + +% 2D Grid Visualization +figure; +scatter(ue_locs(:, 1), ue_locs(:, 2), [], ue_pl); +colorbar() +xlabel('x (m)'); +ylabel('y (m)'); +title('UE Grid Path Loss (dB)') +xlim([min(ue_locs(:, 1)), max(ue_locs(:, 1))]) +ylim([min(ue_locs(:, 2)), max(ue_locs(:, 2))]) diff --git a/Examples/Example1_params.m b/Examples/Example1_params.m new file mode 100644 index 0000000..68208a5 --- /dev/null +++ b/Examples/Example1_params.m @@ -0,0 +1,73 @@ +%%%% DeepMIMO parameters set %%%% +% A detailed description of the parameters is available on DeepMIMO.net + +%Ray-tracing scenario +params.scenario = 'Boston5G_28_RIS'; % The adopted ray tracing scenario [check the available scenarios at https://deepmimo.net/scenarios/] + +%Dynamic Scenario Scenes [only for dynamic (multiple-scene) scenarios] +params.scene_first = 1; +params.scene_last = 1; + + +% Active base stations +params.active_BS = [1, 2]; % Includes the numbers of the active BSs (values from 1-18 for 'O1')(check the scenario description at https://deepmimo.net/scenarios/ for the BS numbers) + +% Active users +params.active_user_first = 1; % The first row of the considered user section (check the scenario description for the user row map) +params.active_user_last = 1622; % The last row of the considered user section (check the scenario description for the user row map) + +% Subsampling of active users +%--> Setting both subsampling parameters to 1 activate all the users indicated previously +params.row_subsampling = 1; % Randomly select round(row_subsampling*(active_user_last-params.active_user_first)) rows +params.user_subsampling = 0.05; % Randomly select round(user_subsampling*number_of_users_in_row) users in each row + +% Antenna array dimensions +params.num_ant_BS = [16, 1]; % Horizontal - Vertical +params.num_ant_UE = [1, 1]; % Horizontal - Vertical + +params.FoV_ant_BS = [360, 180]; % Degrees in horizontal-vertical Max- 360 180 +params.FoV_ant_UE = [360, 180]; % Degrees in horizontal-vertical + +% Antenna array orientations +params.array_rotation_BS = [0, 0, -90]; +params.array_rotation_UE = [0, 0, 0]; +% 3D rotation angles in degrees around the x,y,z axes respectively +% The rotations around x,y,z are also called as slant, downtilt, and bearing angles (of an antenna towards +x) +% The origin of these rotations is the position of the first BS antenna element +% The rotation sequence applied: (a) rotate around z-axis, then (b) rotate around y-axis, then (c) rotate around x-axis. +% To define different orientations for the active BSs, add multiple rows.. +% Example: For two active BSs with different array orientations, you can define +% params.array_rotation_BS = [[10, 30, 45]; [0, 30, 0]]; + +% User antenna orientation settings +% For uniform random selection in +% [x_min, x_max], [y_min, y_max], [z_min, z_max] +% set [[x_min, x_max]; [y_min, y_max]; [z_min, z_max]] +% params.array_rotation_UE = [[0, 30]; [30, 60]; [60, 90]]; + +% Antenna array spacing +params.ant_spacing_BS = .5; % ratio of the wavelength; for half wavelength enter .5 +params.ant_spacing_UE = .5; % ratio of the wavelength; for half wavelength enter .5 + + +% Antenna element radiation pattern +params.radiation_pattern = 0; % 0: Isotropic and + % 1: Half-wave dipole + + +% System parameters +params.bandwidth = 0.05; % The bandwidth in GHz +params.activate_RX_filter = 0; % 0 No RX filter + % 1 Apply RX low-pass filter (ideal: Sinc in the time domain) + +% Channel parameters # Activate OFDM +params.generate_OFDM_channels = 1; % 1: activate frequency domain (FD) channel generation for OFDM systems + % 0: activate instead time domain (TD) channel impulse response generation for non-OFDM systems +params.num_paths = 25; % Maximum number of paths to be considered (a value between 1 and 25), e.g., choose 1 if you are only interested in the strongest path + +% OFDM parameters +params.num_OFDM = 512; % Number of OFDM subcarriers +params.OFDM_sampling = [1:8:512]; % The constructed channels will be calculated only at the sampled subcarriers (to reduce the size of the dataset) + +params.enable_Doppler = 0; % Enable Doppler shift (if available in the scenario) +params.dual_polar = 0; % Enable cross dual-polar antenna (if available in the scenario) \ No newline at end of file diff --git a/parameters.m b/parameters.m index e7c327e..a570a5b 100644 --- a/parameters.m +++ b/parameters.m @@ -13,7 +13,7 @@ % Active users params.active_user_first = 1; % The first row of the considered user section (check the scenario description for the user row map) -params.active_user_last = 1; % The last row of the considered user section (check the scenario description for the user row map) +params.active_user_last = 44; % The last row of the considered user section (check the scenario description for the user row map) % Subsampling of active users %--> Setting both subsampling parameters to 1 activate all the users indicated previously @@ -21,18 +21,15 @@ params.user_subsampling = 1; % Randomly select round(user_subsampling*number_of_users_in_row) users in each row % Antenna array dimensions -params.num_ant_BS = [1, 8, 4]; % Number of antenna elements for the BS arrays in the x,y,z-axes -% By defauly, all BSs will have the same array sizes -% To define different array sizes for the selected active BSs, you can add multiple rows. -% Example: For two active BSs with a 8x4 y-z UPA in the first BS and 4x4 -% x-z UPA for the second BS, you write -% params.num_ant_BS = [[1, 8, 4]; [1, 4, 4]]; +params.num_ant_BS = [8, 1]; % Horizontal - Vertical +params.num_ant_UE = [1, 1]; % Horizontal - Vertical -params.num_ant_UE = [1, 4, 2]; % Number of antenna elements for the user arrays in the x,y,z-axes +params.FoV_ant_BS = [180, 180]; % Degrees in horizontal-vertical Max- 360 180 +params.FoV_ant_UE = [360, 180]; % Degrees in horizontal-vertical % Antenna array orientations -params.activate_array_rotation = 0; % 0 -> no array rotation - 1 -> apply the array rotation defined in params.array_rotation_BS -params.array_rotation_BS = [5, 10, 20]; +params.array_rotation_BS = [0, -45, 0]; +params.array_rotation_UE = [0, 0, 0]; % 3D rotation angles in degrees around the x,y,z axes respectively % The rotations around x,y,z are also called as slant, downtilt, and bearing angles (of an antenna towards +x) % The origin of these rotations is the position of the first BS antenna element @@ -41,36 +38,35 @@ % Example: For two active BSs with different array orientations, you can define % params.array_rotation_BS = [[10, 30, 45]; [0, 30, 0]]; -params.array_rotation_UE = [0, 30, 0]; % User antenna orientation settings % For uniform random selection in % [x_min, x_max], [y_min, y_max], [z_min, z_max] % set [[x_min, x_max]; [y_min, y_max]; [z_min, z_max]] % params.array_rotation_UE = [[0, 30]; [30, 60]; [60, 90]]; -params.enable_BS2BSchannels = 1; % Enable generating BS to BS channel (could be useful for IAB, RIS, repeaters, etc.) - % Antenna array spacing params.ant_spacing_BS = .5; % ratio of the wavelength; for half wavelength enter .5 params.ant_spacing_UE = .5; % ratio of the wavelength; for half wavelength enter .5 + % Antenna element radiation pattern params.radiation_pattern = 0; % 0: Isotropic and % 1: Half-wave dipole - + + % System parameters params.bandwidth = 0.05; % The bandwidth in GHz -params.activate_RX_filter = 0; % 0 No RX filter +params.activate_RX_filter = 1; % 0 No RX filter % 1 Apply RX low-pass filter (ideal: Sinc in the time domain) % Channel parameters # Activate OFDM params.generate_OFDM_channels = 1; % 1: activate frequency domain (FD) channel generation for OFDM systems % 0: activate instead time domain (TD) channel impulse response generation for non-OFDM systems -params.num_paths = 5; % Maximum number of paths to be considered (a value between 1 and 25), e.g., choose 1 if you are only interested in the strongest path +params.num_paths = 25; % Maximum number of paths to be considered (a value between 1 and 25), e.g., choose 1 if you are only interested in the strongest path % OFDM parameters params.num_OFDM = 512; % Number of OFDM subcarriers -params.OFDM_sampling_factor = 1; % The constructed channels will be calculated only at the sampled subcarriers (to reduce the size of the dataset) -params.OFDM_limit = 64; % Only the first params.OFDM_limit subcarriers will be considered +params.OFDM_sampling = [1]; % The constructed channels will be calculated only at the sampled subcarriers (to reduce the size of the dataset) -params.saveDataset = 0; % 0: Will return the dataset without saving it (highly recommended!) \ No newline at end of file +params.enable_Doppler = 0; % Enable Doppler shift (if available in the scenario) +params.dual_polar = 0; % Enable cross dual-polar antenna (if available in the scenario) \ No newline at end of file