%% MU-MIMO channel matrix generation
% For any queries, please contact R.S. Prasobh Sankar (prasobhsankar1@gmail.com)
%
%%%%%% Input parameters %%%%%%%%%%%%%%%%%%%%%%

% K - number of single antenna UEs
% L - number of paths per UE (we assume that all UEs have same number of
% paths)
% N_r - number of antennas at the BS
% d - inter-element spacing at the BS
% aspread_aoa - Assumed range of AoAs.
% [AoAs will be drawn from -aspread_aoa to aspread_aoa]
% spacing_aoa - minimum separation of paths for a given UE
% fade - nature of fade. 
%       0 is pure Los (unit modulus path gains)
%       1 is Rayleigh fading
%       2 is arbitrary fading
% trunc_pd -  pdf distribution to be used in case of arbitrary fades. Set
% this to 0 otherwise.
% Example: 
%     pd = makedist('Normal',0,sqrt(0.5));  trunc_pd = truncate(pd,dist_min,inf);
%     Results in real and imaginary parts of path gains (say, \alpha) to follow a
%     truncated Gaussian distribution with 0 <= |Re(\alpha)|,|Im(\alpha)| <= dist_min 


% Output parameters
% H - generated channel matrix (N_r \times K)
% aoa_true -  generated angles of arrivals (L \times K)
% alpha_true - generated path gains (L \times K)

function [H aoa_true alpha_true] = get_MUMIMO_channel(K,L,N_r,d,aspread_aoa, spacing_aoa, fade, trunc_pd)

aoa_true = zeros(L,K);
alpha_true = zeros(L,K);

H = zeros(N_r, K);
for i=1:K
    
        % Generating AoAs
        
        n=2*aspread_aoa;
        k=L;
        b=spacing_aoa;  % Min. spacing 
        [as,is]=sort(randperm(n-(k-1)*(b-1),k)); % if it throws an error then b/k/n are not compatible
        a = as + (0:k-1)*(b-1);
        a = a(is) - aspread_aoa;
        aoa_true(:,i) = (sort(a)).';
        
        % Generating path gains
        if(fade==0)   % Pure LoS     
            path_gain_angle = 2*pi*rand(L,1) - pi;
            alpha_true(:,i) = ones(L,1).*exp(1j.*path_gain_angle); 
        elseif(fade == 1) % Rayleigh fading
            alpha_true(:,i) = sqrt(1/2).*( randn(L,1) + 1j.*randn(L,1));
        elseif(fade == 2) % Arbitrary fading
            s_set_r = 2.*(rand(L,1)>0.5)-1;
            s_set_i = 2.*(rand(L,1)>0.5)-1;
            a_r = s_set_r.*random(trunc_pd,L,1);
            a_i = s_set_i.*random(trunc_pd,L,1);
            alpha_true(:,i) = a_r + (1j).*a_i;
        end
        
        H(:,i) = sqrt(1/L).*gen_a(N_r, d, aoa_true(:,i))*alpha_true(:,i); % Channel matrix
        
end

end