首页 > 其他分享 >Unsourced Multiple Access With Random User Activity论文复现

Unsourced Multiple Access With Random User Activity论文复现

时间:2023-12-08 21:37:43浏览次数:27  
标签:MD Ka Random Multiple epsilon Unsourced FA P1 end

仿真内容

文件中包含了一个关于无源多用户接入(Unsourced Multiple Access,UMA)系统的 MATLAB 数值例程,用于评估随机用户活动情况下的随机编码界限。

这个工作主要在论文 [1] 中介绍,该论文题为 "Unsourced Multiple Access With Random User Activity",于 2022 年 1 月提交给 IEEE Transactions on Information Theory。

这个工作的部分内容也在论文 [2] 中介绍,该论文题为 "Massive Uncoordinated Access With Random User Activity",于 2021 年 7 月在 IEEE International Symposium on Information Theory (ISIT) 中展示。

如果你使用了这些代码,请引用上述的论文。

代码介绍部分

  1. /RCU_KaKnown/

    这个文件夹包含了关于无源多用户接入系统中的每用户误差概率(PUPE)的随机编码界限。具体包括以下文件:

RCU_KaFixedKnown.m

  对于活跃用户数 Ka 固定且已知的情况下,计算 PUPE 的随机编码界限。

RCU_KaRandomKnown.m

 对于活跃用户数 Ka 是随机的情况下,计算 PUPE 的随机编码界限。

RCU_KaPoissonKnown.m

对于活跃用户数 Ka 服从泊松分布且已知的情况下,计算 PUPE 的随机编码界限。

EbN0_KaPoissonKnown.m

找到使得活跃用户数 Ka 服从泊松分布且已知时 PUPE 的随机编码界限低于某个阈值的最小所需 EbN0。

binary_search.m,

golden_search.m

辅助函数。

  1. /RCU_KaUnknown/

: 这个文件夹包含了关于无源多用户接入系统中,活跃用户数 Ka 是随机且未知的情况下的随机编码界限,这是论文 [1] 和 [2] 中提出的。具体包括以下文件:

RCU_KaRandomUnknown.m

对于活跃用户数 Ka 是随机的情况下,计算 PUPE 的随机编码界限。

RCU_KaPoissonUnknown.m

对于活跃用户数 Ka 服从泊松分布的情况下,计算 PUPE 的随机编码界限。

RCU_floor_KaRandomUnknown.m

论文 [1, Theorem 3] 中对误差底线的特征化。

EbN0_KaPoissonUnknown.m

找到使得活跃用户数 Ka 服从泊松分布且未知时 PUPE 的随机编码界限在某个阈值以下的最小所需 EbN0。

binary_search_P_MDFA.m,

golden_search_P1_MDFA

辅助函数。

  1. /SA-MPR/

这个文件夹包含了上述界限在带有多包接收(MPR)的时隙ALOHA(SA-MPR)系统中的应用。

EbN0_SAMPR_KaPoissonKnown.m

找到使得 SA-MPR 中活跃用户数 Ka 服从泊松分布且已知时的最小所需 EbN0。

EbN0_SAMPR_KaPoissonUnknown.m

找到使得 SA-MPR 中活跃用户数 Ka 服从泊松分布且未知时的最小所需 EbN0。参考论文 [1, Corollary 2]。

  1. /TIN/

这个文件夹包含了一个将干扰视为噪声(Treat Interference as Noise,TIN)的方案的随机编码界限。

EbN0_TIN_KaPoissonUnknown.m

找到使得 TIN 中活跃用户数 Ka 服从泊松分布且未知时的最小所需 EbN0。

注意: SPARC 和 enhance SPARC 方案的代码由 Krishna R. Narayanan 的研究组提供,因此未包含在此存储库中。

RCU_KaKnown

binary_search.m

function [epsilon, P] = binary_search(f,x1,x2,TARGET,TOL)
% search the value of P such that min_{P1} f(P,P1) is from TARGET - TOL to TARGET

iter = 20;                       % maximum number of iterations
k1 = 0;                            % iteratin index

% we use a golden search to compute min_{P1} f(P,P1)
fx = golden_search(f,1e-9,(x1+x2)/2,(x1+x2)/200); 

while (TARGET < fx || fx<TARGET - TOL) && (k1<iter || TARGET < fx)
    if k1 > 0
        fx = golden_search(f,0,(x1+x2)/2,(x1+x2)/200); 
    end
    if TARGET > fx
        x2 = (x1+x2)/2; %set new end of interval        
    else
        x1 = (x1+x2)/2; %replace as new start index
    end
    k1=k1+1;
end

epsilon = fx;
P   = x1;
end

golden_search.m

function [epsilon, P1] = golden_search(f, START_INT, END_INT, TOL)
% minimize f(P1) over P1. epsilon = min_{P1} f(P1)

P = END_INT;
iter = 20;                      % maximum number of iterations
tau = double((sqrt(5)-1)/2);    % golden proportion coefficient, around 0.618
k2 = 0;                         % iteration index

x1 = START_INT+(1-tau)*(END_INT-START_INT);             
x2 = START_INT+tau*(END_INT-START_INT);

f_x1 = f(P,x1);                    
f_x2 = f(P,x2);

while ((abs(END_INT-START_INT)>TOL) && (k2<iter))
    if f_x1 < f_x2 %function smaller in x1 than in x2
        END_INT = x2; % make interval smaller
        x2 = x1; % set new end of interval
        x1 = START_INT+(1-tau)*(END_INT-START_INT); % find new beginning
        f_x2 = f_x1; % already have value in x1
        f_x1 = f(P,x1); % compute new value for new beginning
    else
        START_INT=x1; % function smaller in x2 than in x1 so set new start indx to x1
        x1 = x2; % replace as new start index
        x2=START_INT+tau*(END_INT-START_INT); % compute new end index
        f_x1= f_x2;
        f_x2 = f(P,x2);
    end
    k2=k2+1;
end

if f_x1 < f_x2
    P1 = x1;
    epsilon = f_x1;
else
    P1 = x2;
    epsilon = f_x2;
end

end

EbN0_KaPoissonKnown.m

function data = EbN0_KaPoissonKnown(k, n, epsilon, E_Ka)
% function data = EbN0_KaPoissonKnown(k, n, epsilon, E_Ka)
% Find the minimal required EbN0 (in dB) such that the PUPE is below a 
% certain threshold epsilon for a system with the number of active 
% users following a Poisson distribution but known.
%
% INPUTS
%   k   : number of bits per symbol
%   n   : framelength (number of complex DoFs)
%   epsilon : target PUPE
%   E_Ka    : average number of active users
%
% OUTPUT
%   data : store the system parameters and the minimal required EbN0

tic
DEBUG = 1;

%% debugging mode
if DEBUG == 1 
    k       = 100; 
    n       = 15000;
    epsilon = 0.1; 
    E_Ka      = 2; 
end

%% Poissom PMF of Ka, can be modified to consider other distributions 
p_Ka = @(K) poisspdf(K,E_Ka); 

%% The range of power to search
EbN0db_lowest = -0.5;
EbN0db_highest = 3;
    
P_lowest = k*10^(EbN0db_lowest/10)/n;
P_highest = k*10^(EbN0db_highest/10)/n;

%% Function to compute the RCU bound
f_rcu = @(P,P1) RCU_KaRandomKnown(P,P1,k,n,E_Ka,p_Ka);

%% Search for the minimal required EbN0
[eps_RCU, P_RCU] = binary_search(f_rcu, P_lowest, P_highest, epsilon,epsilon/100);
EbN0db_RCU = 10*log10(n*P_RCU/(k));

%% Save the results
sim_time = toc;
data.EbN0db = EbN0db_RCU;
data.E_Ka   = E_Ka;
data.eps_est= eps_RCU;
data.epsilon= epsilon;
data.k      = k;
data.n      = n;
data.sim_time = sim_time;

if DEBUG ~= 1
    filename = ['EbN0_KaPoissonKnown_EKa_' num2str(E_Ka) '_epsilon_' num2str(epsilon) '_k_' num2str(k) '_n_' num2str(n) '.mat'];
    save(filename, 'data', '-v7.3');
else
    keyboard
end

end

RCU_KaPoissonKnown.m

function data = RCU_KaPoissonKnown(k, n, E_Ka, EbN0db)
% function data = RCU_KaPoissonKnown(k, n, E_Ka, EbN0db)
% Compute the RCU bound for the PUPE in Theorem 1 of
%
% [1] Y. Polyanskiy, "A perspective on massive random-access," 2017 IEEE 
% International Symposium on Information Theory (ISIT), 2017, pp.
% 2523-2527.
% 
% extended to the complex-valued model and the case where Ka follows a 
% Poisson distribution and is unknown. See also
% 
% [2] K.-H. Ngo, A. Lancho, G. Durisi and A. G. i. Amat, "Unsourced
% Multiple Access With Random User Activity," submitted to IEEE Trans. Inf.
% Theory, Jan. 2022.
%
% INPUTS
%   k   : number of bits per symbol
%   n   : framelength (number of complex DoFs)
%   E_Ka   : average number of active users
%   EbN0db : energy per bit in dB
% Note: E_Ka and EbN0db can be vectors.
%
% OUTPUTS
%   data : store the system parameters and the computed RCU bound

%   P   : symbol power budget
%   P1  : the actual power used (denoted by P' in [1] and [2])

tic
DEBUG = 0;

%% debugging mode
if DEBUG == 1
    k    = 128; 
    n    = 19200; 
    E_Ka = 50; 
    EbN0db = 0; 
end

%% symbol power budget
P_list = k.*10.^(EbN0db./10)./n;

%% initialization
epsilon = zeros(length(EbN0db),length(E_Ka));
P1 = zeros(length(EbN0db),length(E_Ka));

%% Compute the RCU bound
for idxEKa = 1:length(E_Ka)
    E_Ka = E_Ka(idxEKa);
    p_Ka = @(K) poisspdf(K,E_Ka);
    for idxEbN0 = 1:length(EbN0db)
        P = P_list(idxEbN0);

        f_rcu = @(P,P1) RCU(P,P1,k,n,E_Ka,p_Ka);
        
        [Pe_tmp,P1_tmp] = golden_search(f_rcu,0,P,P/100); % Optimize P'

        epsilon(idxEbN0,idxEKa) = Pe_tmp;
        P1(idxEbN0,idxEKa) = P1_tmp;
    end
end

%% Save the results
sim_time = toc;
data.EbN0db = EbN0db;
data.E_Ka    = E_Ka;
data.p_Ka   = 'Poisson';
data.epsilon= epsilon;
data.k      = k;
data.n      = n;
data.P1     = P1;
data.sim_time = sim_time;

if DEBUG ~= 1
    filename = ['RCU_KaPoissonKnown_EKa_' num2str(min(E_Ka)) 'to' ...
            num2str(max(E_Ka)) '_k_' num2str(k) '_n_' num2str(n) ...
            '_EbN0db_' num2str(min(EbN0db)) 'to' num2str(max(EbN0db)) '.mat'];
    save(filename, 'data', '-v7.3');
else
    keyboard
end

end

RCU_KaFixedKnown.m

function [epsilon, P, P1_opt] = RCU_KaFixedKnown(k,n,Ka,EbN0db)
% function [epsilon] = RCU_KaFixedKnown(k,n,Ka,EbN0db)
% Compute the RCU bound for the PUPE in Theorem 1 of
%
% [1] Y. Polyanskiy, "A perspective on massive random-access," 2017 IEEE 
% International Symposium on Information Theory (ISIT), 2017, pp.
% 2523-2527.

%%这个函数是用来计算 Polyanskiy 在他的论文中提到的 RCU(Random Coding Unbounded)界限的

% extended to the complex-valued model. 
%
% INPUTS
%   k   : number of bits per symbol  每符号比特数
%   n   : framelength (number of complex DoFs)  帧长
%   Ka  : number of active users  活跃用户数量
%   EbN0db : energy per bit in dB  每比特能量(dB)
% 
% OUTPUTS
%   epsilon : the bound on PUPE given in [1, Eq. (3)]
     %   epsilon,即ε,表示[1]中给出的PUPE的界线
%   P       : symbol power budget imposed by the EbN0
%   P1_opt  : the optimal value of P', the actual power used

%% Example of parameters (for debugging)
% k = 100;
% n = 15000;
% Ka = 100;
% EbN0db = 2;

%% Power and codebook size
P = k*10^(EbN0db/10)/n;
M       = 2^k;

%% Initialization
% for the sum over t in Eq. (3)
t_vec = 1:Ka;

% for the optimization over rho and rho1 in E(t)
rho_vec = linspace(0,1,100); % This goes from 0 to 1 in principle
rho1_vec= linspace(0,1,100); % From 0 to 1
rho = repmat(rho_vec,length(rho1_vec),1,length(t_vec));
rho1 = permute(repmat(rho1_vec,length(rho_vec),1,length(t_vec)),[2,1,3]);
t=permute(repmat(t_vec,length(rho1_vec),1,length(rho_vec)),[1,3,2]);

% Some functions for the computation of pt as defined in [1, Th. 1]
R1_f = @(n,M,t)  1./n*log(M)-1./(n*t).*gammaln(t+1);
R2_f = @(n,Ka,t) 1/n*(gammaln(Ka+1)-gammaln(t+1)-gammaln(Ka-t+1));
D_f  = @(P1,t,rho,rho1) (P1.*t-1).^2 + 4*P1.*t.*(1+rho.*rho1)./(1+rho);
lambda_f = @(P1,t,rho,rho1) (P1.*t-1+sqrt(D_f(P1,t,rho,rho1)))./(2.*(1+rho1.*rho).*P1.*t); % max(roots_edit([P1.*t.*(rho+1).*(rho.*rho1+1) -P1.*t.*(rho+1) -1]));
mu_f = @(P1,t,rho,rho1) rho.*lambda_f(P1,t,rho,rho1)./(1+P1.*t.*lambda_f(P1,t,rho,rho1));
a_f = @(P1,t,rho,rho1) rho.*log(1+P1.*t.*lambda_f(P1,t,rho,rho1))+log(1+P1.*t.*mu_f(P1,t,rho,rho1));
b_f = @(P1,t,rho,rho1) rho.*lambda_f(P1,t,rho,rho1)- mu_f(P1,t,rho,rho1)./(1+P1.*t.*mu_f(P1,t,rho,rho1));
E0_f = @(P1,t,rho,rho1) rho1.*a_f(P1,t,rho,rho1) + log(1-b_f(P1,t,rho,rho1).*rho1);
Et_f = @(P1,t,rho,rho1,n,M,Ka) squeeze(max(max(-rho.*rho1.*t.*R1_f(n,M,t) - rho1.*R2_f(n,Ka,t) + E0_f(P1,t,rho,rho1))));
pt_f   = @(P1,t,rho,rho1,n,M,Ka) exp(-n*Et_f(P1,t,rho,rho1,n,M,Ka));

% number of samples for empirical evaluation of the CDF of It in qt
Niq = 1000;

% for the optimization over P' (here denoted by P1)
P1_vec = linspace(1e-9,P,20);
epsilon = zeros(size(P1_vec));

%% Evaluation of the bound, optimized over P'
% Note: one can perform a golden search for the optimal P'. We do it in the
% evaluation of the RCU bound for Ka random.
for pp = 1:length(P1_vec)

 P1 = P1_vec(pp);

 % Computation of p0
 p0  = nchoosek(Ka,2)/M + Ka*gammainc(n*P/P1,n,'upper');

 % Computation of pt
 pt = pt_f(P1,t,rho,rho1,n,M,Ka);

 % Computation of qt (for t = 1 only, as in [1])
 It = zeros(1,1000);
 for II = 1:Niq
     Zi = sqrt(.5)*(randn(1,n) + 1i*randn(1,n));
     codebook = sqrt(.5*P1)*(randn(Ka,n) + 1i*randn(Ka,n));
     it   = n*log(1+P1) + (sum(abs(repmat(Zi,Ka,1)+codebook).^2,2)./(1+P1)-sum(abs(repmat(Zi,Ka,1)).^2,2));
     It(II) = min(it);
 end

 [prob,gam] = ecdf(It);
 qt = min(prob + exp(n*(R1_f(n,M,1)+R2_f(n,Ka,1))-gam));

 % Computation of RHS of [1, Eq. (3)] for a given P' < P
 epsilon(pp) = t_vec(1)/Ka*min(pt(1),qt) + t_vec(2:end)/Ka*pt(2:end) + p0;
end

% Take the minimum over P'
[epsilon,idx_P1opt] = min([epsilon 1]); 
P1_opt = P1_vec(idx_P1opt);

RCU_KaRandomKnown.m

function [epsilon] = RCU_KaRandomKnown(P,P1,k,n,E_Ka,p_Ka) 
% function [epsilon] = RCU_KaRandomKnown(P,P1,k,n,E_Ka,p_Ka)
% Compute the RCU bound for the PUPE in Theorem 1 of
%
% [1] Y. Polyanskiy, "A perspective on massive random-access," 2017 IEEE 
% International Symposium on Information Theory (ISIT), 2017, pp.
% 2523-2527.
% 
% extended to the complex-valued model and the case where Ka is random and 
% unknown. See also
% 
% [2] K.-H. Ngo, A. Lancho, G. Durisi and A. G. i. Amat, "Unsourced
% Multiple Access With Random User Activity," submitted to IEEE Trans. Inf.
% Theory, Jan. 2022.
%
% INPUTS
%   P   : symbol power budget
%   P1  : the actual power used (denoted by P' in [1] and [2])
%   k   : number of bits per symbol
%   n   : framelength (number of complex DoFs)
%   E_Ka : average number of active users
%   p_Ka : PMF of the number of active users Ka
% 
% OUTPUTS
%   epsilon : (extended) bound on PUPE given in [1, Eq. (3)]

% codebook size
M       = 2^k;

% number of samples for empirical evaluation of the CDF of It in qt
Niq     = 1000;

%% Computation of p0 (with some additional terms w.r.t. p0 in [1] due to the randomness of Ka. See [2].)
% find K_l and K_u such that the probability that Ka is not in [K_l:K_u] is small 
K_l = floor(E_Ka); K_u = ceil(E_Ka);
while p_Ka(K_l-1) > 1e-9
    K_l = K_l - 1;
end
K_l = max(K_l,0);
while p_Ka(K_u+1) > 1e-9
    K_u = K_u + 1;
end

p01 = 0;
for Ka_tmp = K_l:K_u   
    p01_tmp = 1; 
    for ii = 1:Ka_tmp-1
        p01_tmp = p01_tmp*(1-ii/M);
    end
    p01 = p01 + p_Ka(Ka_tmp)*p01_tmp;
%     p01 = p01 + p_Ka(Ka_tmp)*nchoosek(Ka_tmp,2)/M;
end
p0 = 2 - p01 - sum(p_Ka(K_l:K_u)) + E_Ka*gammainc(n*P/P1,n,'upper');

%% Initialize epsilon to p0
epsilon = p0;

%% Compute the RCU bound, averaged over the distribution of Ka
parfor Ka = max(K_l,1):K_u  
    
    %% Computation of pt
    % Initialize for the sum over t and the optimization over rho and rho1
    rho_vec = linspace(0,1,100); 
    rho1_vec= linspace(0,1,100); 
    t_vec   = 1:Ka;
    rho     = repmat(rho_vec,length(rho1_vec),1,length(t_vec));
    rho1    = permute(repmat(rho1_vec,length(rho_vec),1,length(t_vec)),[2,1,3]);
    t       = permute(repmat(t_vec,length(rho1_vec),1,length(rho_vec)),[1 3 2]);

    % Some functions for the computation of pt as defined in [1, Th. 1]
    R1_f = @(n,M,t)  1./n*log(M)-1./(n*t).*gammaln(t+1);
    R2_f = @(n,Ka,t) 1/n*(gammaln(Ka+1)-gammaln(t+1)-gammaln(Ka-t+1));
    D_f  = @(P1,t,rho,rho1) (P1.*t-1).^2 + 4*P1.*t.*(1+rho.*rho1)./(1+rho);
    lambda_f = @(P1,t,rho,rho1) (P1.*t-1+sqrt(D_f(P1,t,rho,rho1)))./(2.*(1+rho1.*rho).*P1.*t); % max(roots_edit([P1.*t.*(rho+1).*(rho.*rho1+1) -P1.*t.*(rho+1) -1]));
    mu_f = @(P1,t,rho,rho1) rho.*lambda_f(P1,t,rho,rho1)./(1+P1.*t.*lambda_f(P1,t,rho,rho1));
    a_f = @(P1,t,rho,rho1) rho.*log(1+P1.*t.*lambda_f(P1,t,rho,rho1))+log(1+P1.*t.*mu_f(P1,t,rho,rho1));
    b_f = @(P1,t,rho,rho1) rho.*lambda_f(P1,t,rho,rho1)- mu_f(P1,t,rho,rho1)./(1+P1.*t.*mu_f(P1,t,rho,rho1));
    E0_f = @(P1,t,rho,rho1) rho1.*a_f(P1,t,rho,rho1) + log(1-b_f(P1,t,rho,rho1).*rho1);
    Et_f = @(P1,t,rho,rho1,n,M,Ka) squeeze(max(max(-rho.*rho1.*t.*R1_f(n,M,t) - rho1.*R2_f(n,Ka,t) + E0_f(P1,t,rho,rho1))));
    pt_f   = @(P1,t,rho,rho1,n,M,Ka) exp(-n*Et_f(P1,t,rho,rho1,n,M,Ka));

    % Compute pt
    pt = pt_f(P1,t,rho,rho1,n,M,Ka);

    %% Computation of qt (for t = 1 only, as in [1])
    qt = 1;
    % compute qt for Ka < 50 only due to complexity issue
    if Ka < 50 
        It = zeros(1,Niq);
        for II = 1:Niq
            Zi = sqrt(.5)*(randn(1,n) + 1i*randn(1,n));
            codebook = sqrt(.5*P1)*(randn(Ka,n) + 1i*randn(Ka,n));
            it   = n*log(1+P1) + (sum(abs(repmat(Zi,Ka,1)+codebook).^2,2)./(1+P1)-sum(abs(repmat(Zi,Ka,1)).^2,2));
            It(II) = min(it);
        end
        [prob,gam] = ecdf(It);
        qt = min(prob + exp(n*(R1_f(n,M,1)+R2_f(n,Ka,1))-gam));
    end
    
    %% Take the min of pt and qt 
    pt(1) = min(pt(1),qt);

    %% Compute epsilon, the RHS of [1, Eq. (3)]
    epsilon = epsilon + (t_vec/Ka*pt)*feval(p_Ka,Ka);
end
end

RCU_KaUnknown

golden_search_P1_MDFA.m

function [eps_MD, eps_FA, P1] = golden_search_P1_MDFA(f, START_INT, END_INT, TOL, type, weight_MD, weight_FA)
% Minimize a weighted sum of eps_MD and eps_FA over P1 \in [0,P], where 
% eps_MD and eps_FA are given by f(P,P1), which is the RCU bound in Theorem
% 1 of 
%
% [1] K.-H. Ngo, A. Lancho, G. Durisi and A. G. i. Amat, "Unsourced
% Multiple Access With Random User Activity," submitted to IEEE Trans. Inf.
% Theory, Jan. 2022.

if strcmp(type,'max')
    g = @(fMD,fFA) max(fMD,fFA);
elseif strcmp(type,'weighted')
    g = @(fMD,fFA) fMD*weight_MD + fFA*weight_FA;
end

P = END_INT;                  % power budget

tau = double((sqrt(5)-1)/2);  % golden proportion coefficient, around 0.618

iter = 20;                    % maximum number of iterations
k2 = 0;                       % iteration index

x1 = START_INT+(1-tau)*(END_INT-START_INT);            
x2 = START_INT+tau*(END_INT-START_INT);

[fMD_x1,fFA_x1] = f(P,x1); 
[fMD_x2,fFA_x2] = f(P,x2);

while ((abs(END_INT-START_INT)>TOL) && (k2<iter))
    if g(fMD_x1, fFA_x1) < g(fMD_x2, fFA_x2) %function smaller in x1 than in x2
        END_INT = x2; %make interval smaller
        x2 = x1; %set new end of interval
        x1 = START_INT+(1-tau)*(END_INT-START_INT); %find new beginning
        fMD_x2 = fMD_x1;%already have value in x1
        fFA_x2 = fFA_x1;
        [fMD_x1,fFA_x1] = f(P,x1); %%compute new value for new beginning
    else
        START_INT=x1; %function smaller in x2 than in x1 so set new start indx to x1
        x1 = x2; %replace as new start index
        x2=START_INT+tau*(END_INT-START_INT); %compute new end index
        fMD_x1= fMD_x2;
        fFA_x1 = fFA_x2;        
        [fMD_x2,fFA_x2] = f(P,x2);
    end
    k2=k2+1;
end

% Return the solution
if g(fMD_x1, fFA_x1) < g(fMD_x2, fFA_x2)
    P1 = x1;
    eps_MD = fMD_x1;
    eps_FA = fFA_x1;
else
    P1 = x2;
    eps_MD = fMD_x2;
    eps_FA = fFA_x2;
end

end

RCU_floor_KaRandomUnknown.m

function [floor_MD,floor_FA] = RCU_floor_KaRandomUnknown(rad_l,rad_u,k,n,E_Ka,p_Ka)
% function [floor_MD,floor_FA] = RCU_floor(rad_l,rad_u,k,n,E_Ka,p_Ka)
% Compute the error floors for the RCU bounds of the misdetection and false
% alarm probabilities, characterized in Theorem 3 of
%
% [1] K.-H. Ngo, A. Lancho, G. Durisi and A. G. i. Amat, "Unsourced
% Multiple Access With Random User Activity," submitted to IEEE Trans. Inf.
% Theory, Jan. 2022.
% 
% for a system with random and unknown number of active users.
%
% INPUTS
%   rad_l : lower decoding radius
%   rad_u : upper decoding radius
%   k     : number of bits per symbol
%   n     : framelength (number of complex DoFs)
%   E_Ka  : average number of active users
%   p_Ka  : PMF of the number of active users Ka
% 
% OUTPUTS
%   floor_MD, floor_FA : the error floors

% codebook size
M       = 2^k;

%% Computation of \bar{p}
K_l = floor(E_Ka); K_u = ceil(E_Ka);
while p_Ka(K_l-1) >  1e-12
    K_l = K_l - 1;
end
K_l = max(K_l,0);
while p_Ka(K_u+1) > 1e-12
    K_u = K_u + 1;
end

p01 = 0;
for Ka_tmp = K_l:K_u   
    p01_tmp = 1; 
    for ii = 1:Ka_tmp-1
        p01_tmp = p01_tmp*(1-ii/M);
    end
    p01 = p01 + p_Ka(Ka_tmp)*p01_tmp;
end
pbar = 1 - p01 + 1 - sum(p_Ka(K_l:K_u));

%% Initialize floor_MD and floor_FA to be \bar{p}
floor_MD = pbar;
floor_FA = pbar;

%% The sum over Ka
parfor Ka = K_l:K_u  
% Compute \xi(Ka,Ka')
KaEst_thres = @(Ka,KaEst) n.*log(Ka./KaEst)./(Ka./KaEst-1);

P_Ka_KaEst_list_a = gammainc(KaEst_thres(Ka,K_l:Ka-1),n,'lower');
P_Ka_KaEst_list_b = gammainc(KaEst_thres(Ka,Ka+1:K_u),n,'upper');
P_Ka_Ka = 1 - max([P_Ka_KaEst_list_a P_Ka_KaEst_list_b]);
P_Ka_KaEst_list = [P_Ka_KaEst_list_a'; P_Ka_Ka; P_Ka_KaEst_list_b'];

%% The sum over Ka'
for KaEst = K_l:K_u
    if KaEst == 0
        P_Ka_KaEst = 0;
    else
        P_Ka_KaEst = P_Ka_KaEst_list(KaEst - K_l + 1);
    end

    KaEst_l = max(KaEst - rad_l,K_l);
    KaEst_u = min(KaEst + rad_u,K_u);

    if Ka > 0
        floor_MD = floor_MD + feval(p_Ka, Ka)*max(Ka-KaEst_u,0)*P_Ka_KaEst/Ka;
    end

    Mrx = (Ka + max(KaEst_l-Ka,0) - max(Ka-KaEst_u,0)); % number of decoded codewords
    if Mrx > 0
        floor_FA = floor_FA + feval(p_Ka, Ka)*max(KaEst_l-Ka,0)*P_Ka_KaEst/Mrx;
    end
end
end
floor_MD = min(floor_MD,1);
floor_FA = min(floor_FA,1);
end

binary_search_P_MDFA.m

function [eps_MD, eps_FA, P,P1] = binary_search_P_MDFA(f,x1,x2,TARGET_MD,TARGET_FA,TOL,fixP1)
% Search the value of P such that eps_MD \in [TARGET_MD - TOL, TARGET_MD]
% and eps_FA \in [TARGET_FA - TOL, TARGET_FA] where eps_MD and eps_FA are 
% obtained from a f(P,P1), which is the RCU bound in Theorem 1 of 
%
% [1] K.-H. Ngo, A. Lancho, G. Durisi and A. G. i. Amat, "Unsourced
% Multiple Access With Random User Activity," submitted to IEEE Trans. Inf.
% Theory, Jan. 2022.

iter= 20;                       % maximum number of iterations
k1=0;                            % number of iterations

%% We can either optimize over P1 or choose a fixed value of P1. The latter 
%% is faster. Our experiments suggest that the optimal P1 is around 0.96*P
fracP1 = 0.96;
if fixP1 == 0
    if TARGET_MD == TARGET_FA
        search_P1 = @(x) golden_search_P1_MDFA(f,1e-9,x,x/100,'max',[],[]);
    else
        % Calculate the weights based on the target MD and FA probabilities 
        weight_MD = 1/(1 + TARGET_MD/TARGET_FA);
        weight_FA = 1/(1 + TARGET_FA/TARGET_MD);
        
        search_P1 = @(x) golden_search_P1_MDFA(f,1e-9,x,x/100,'weighted',weight_MD, weight_FA);
    end
else
    search_P1 = @(x) compute_MDFA_fixedP1(f, x, fracP1);
end

%% Search for P
[eps_MD_tmp,eps_FA_tmp,P1_tmp] = search_P1(x2);
[eps_MD_tmp1,eps_FA_tmp1,P1_tmp1] = search_P1(x1);
if x1 == x2
    P = x1;
    eps_MD = eps_MD_tmp;
    eps_FA = eps_FA_tmp;
    P1 = P1_tmp;
elseif eps_MD_tmp > TARGET_MD || eps_FA_tmp > TARGET_FA
    warning('Impossible to achieve the target within the given range of power :( ');
    P = x2;
    eps_MD = eps_MD_tmp;
    eps_FA = eps_FA_tmp;
    P1 = P1_tmp;
elseif eps_MD_tmp1 < TARGET_MD || eps_FA_tmp1 < TARGET_FA
    warning('All power values in the range can achieve the target :) ');
    P = x1;
    eps_MD = eps_MD_tmp1;
    eps_FA = eps_FA_tmp1;
    P1 = P1_tmp1;
else
    [fx_MD,fx_FA,P1_tmp] = search_P1((x1+x2)/2); 

    while ~((TARGET_MD >= fx_MD && fx_MD >= TARGET_MD - TOL && TARGET_FA >= fx_FA) || ...
            (TARGET_FA >= fx_FA && fx_FA >= TARGET_FA - TOL && TARGET_MD >= fx_MD) ...
            || (k1>iter)) 
        if k1 > 0
            [fx_MD,fx_FA,P1_tmp] = search_P1((x1+x2)/2); 
        end
        if TARGET_MD > fx_MD && TARGET_FA > fx_FA
            x2 = (x1+x2)/2; % set new end of interval        
        else
            x1 = (x1+x2)/2; % replace as new start index
        end
        k1 = k1+1;
    end

    eps_MD = fx_MD;
    eps_FA = fx_FA;
    P   = x2;
    P1 = P1_tmp;
end
end

function [eps_MD, eps_FA, P1] = compute_MDFA_fixedP1(f, P, fracP1)
    P1 = P*fracP1;
    [eps_MD, eps_FA] = f(P,P1);
end

EbN0_KaPoissonUnknown.m

function data = EbN0_KaPoissonUnknown(k, n, epsilon_MD, epsilon_FA, E_Ka, rad_l, rad_u)
% function data = EbN0_KaPoissonUnknown(k, n, epsilon_MD, epsilon_FA, E_Ka)
% Find the minimal required EbN0 (in dB) such that the misdetection and 
% false alarm probabilities are below the thresholds epsilon_MD and 
% epsilon_FA, respectively, for a system with the number of active 
% users following a Poisson distribution and unknown.
%
% INPUTS
%   k   : number of bits per symbol
%   n   : framelength (number of complex DoFs)
%   epsilon_MD : target misdetection probability
%   epsilon_FA : target false alarm probability
%   E_Ka  : average number of active users
%   rad_l : lower decoding radius
%   rad_u : upper decoding radius
%
% OUTPUT
%   data : store the system parameters and the minimal required EbN0

tic
DEBUG = 0;

%% debugging mode
if DEBUG == 1
    k       = 128; % Number of bits
    n       = 19200; % Frame length
    epsilon_MD = .1; % Per-user error probability
    epsilon_FA = .1; % Per-user error probability
    E_Ka    = 50;
    rad_l = 0;
    rad_u = 0;
end

%% Poissom PMF of Ka, can be modified to consider other distributions 
p_Ka    = @(K) poisspdf(K,E_Ka);

%% The range of power to search
EbN0db_lowest = -2;
EbN0db_highest = 15;
    
P_lowest = k*10^(EbN0db_lowest/10)/n;
P_highest = k*10^(EbN0db_highest/10)/n;

%% The below can be used to find suitable decoding radii
% rad_l = 0;  rad_u = 0;
% 
% [floor_MD,floor_FA] = RCU_floor(rad_l,rad_u,k,n,E_Ka,p_Ka);
% while floor_MD > epsilon_MD || floor_FA > epsilon_FA
%     if floor_MD > epsilon_MD
%         rad_u = rad_u + 1;
%     end
%     if floor_FA > epsilon_FA
%         rad_l = rad_l + 1;
%     end
%     [floor_MD,floor_FA] = RCU_floor(rad_l,rad_u,k,n,E_Ka,p_Ka);
% end
% if (epsilon_MD < 1e-1) || (epsilon_FA < 1e-1)
%     rad_u = rad_u + 2;
%     rad_l = rad_l + 2;
% end

%% Function to compute the RCU bound
f_rcu = @(P,P1) RCU_KaRandomUnknown(P,P1,rad_l,rad_u,k,n,E_Ka,p_Ka);

%% Search for the minimal required EbN0
[eps_RCU_MD, eps_RCU_FA, P_RCU,P1] = binary_search_P_MDFA(f_rcu, P_lowest, P_highest,...
    epsilon_MD,epsilon_FA,min(epsilon_MD,epsilon_FA)/100,0);
EbN0db_RCU = 10*log10(n*P_RCU/k);

%% Save the results
sim_time = toc;
data.EbN0db = EbN0db_RCU;
data.E_Ka   = E_Ka;
data.p_Ka   = 'Poisson';
data.eps_est_MD = eps_RCU_MD;
data.eps_est_FA = eps_RCU_FA;
data.epsilon_MD = epsilon_MD;
data.epsilon_FA = epsilon_FA;
data.rad_l = rad_l;
data.rad_u = rad_u;
data.k      = k;
data.n      = n;
data.P1     = P1;
data.sim_time = sim_time;

if DEBUG ~= 1
    filename = ['EbN0_KaPoissonUnknown_EKa_' num2str(E_Ka) '_epsilonMD_' ...
        num2str(epsilon_MD) '_epsilonFA_' num2str(epsilon_FA) ...
        '_k_' num2str(k) '_n_' num2str(n) '.mat'];
    save(filename, 'data', '-v7.3');
else
    keyboard
end

end

RCU_KaPoissonUnknown.m

function data = RCU_KaPoissonUnknown(k, n, E_Ka_list, EbN0db, rad_l_list, rad_u_list)
% function data = RCU_KaPoissonUnknown(k, n, E_Ka_list, EbN0db, rad_l_list, rad_u_list)
% Compute the RCU bound for the PUPE for a system with number of users 
% unknown and following a Poission distribution. The bound is given in 
% Theorem 1 of
%
% [1] K.-H. Ngo, A. Lancho, G. Durisi and A. G. i. Amat, "Unsourced
% Multiple Access With Random User Activity," submitted to IEEE Trans. Inf.
% Theory, Jan. 2022.
%
% INPUTS
%   k   : number of bits per symbol
%   n   : framelength (number of complex DoFs)
%   E_Ka_list  : set of values for the average number of active users
%   EbN0db     : energy per bit in dB
%   rad_l_list : set of values for the lower decoding radius
%   rad_u_list : set of corresponding upper decoding radius
% Note: rad_l_list and rad_u_list are of the same length
%
% OUTPUTS
%   data : store the system parameters and the computed RCU bound

tic
DEBUG = 0;

%% debugging mode
if DEBUG == 1
    k       = 128; 
    n       = 19200; 
    EbN0db  = 4; 
    E_Ka_list   = 50;   
    rad_l_list  = [0];
    rad_u_list = [0];
end

%% codebook size
M = 2^k;

%% symbol power budget
P_list = k.*10.^(EbN0db./10)./n;

%% initialization
p_MD = ones(length(EbN0db),length(E_Ka_list),length(rad_l_list));
p_FA = ones(length(EbN0db),length(E_Ka_list),length(rad_l_list));
P1 = zeros(length(EbN0db),length(E_Ka_list),length(rad_l_list));

%% Compute the RCU
for idxEKa = 1:length(E_Ka_list)
E_Ka = E_Ka_list(idxEKa);
p_Ka    = @(K) poisspdf(K,E_Ka);
for idxRad = 1:length(rad_l_list)
rad_l = rad_l_list(idxRad); % lower decoding radius
rad_u = rad_u_list(idxRad); % upper decoding radius
for idxEbN0 = 1:length(EbN0db)
    P = P_list(idxEbN0);
    
    f_rcu = @(P,P1) RCU_KaRandomUnknown(P,P1,rad_l,rad_u,k,n,E_Ka,p_Ka);
    
    % Optimize P1 to minimize max(p_MD,p_FA)
    [p_MD_tmp,p_FA_tmp,P1_tmp] = golden_search_P1_MDFA(f_rcu,0,P,P/200,'max',[],[]); 
    
    % To minimize a weighted sum of p_MD and p_FA, use the below
%     weight_MD = 1;
%     weight_FA = 1;
%     [p_MD_tmp,p_FA_tmp,P1_tmp] = golden_search_P1_MDFA(f_rcu,0,P,P/100,'weighted',weight_MD,weight_FA); 
    
    p_MD(idxEbN0,idxEKa,idxRad) = p_MD_tmp;
    p_FA(idxEbN0,idxEKa,idxRad) = p_FA_tmp;
    P1(idxEbN0,idxEKa,idxRad) = P1_tmp;
end
end
end
p_MD = squeeze(p_MD);
p_FA = squeeze(p_FA);
P1 = squeeze(P1);

%% Save the results
sim_time = toc;
data.EbN0db = EbN0db;
data.E_Ka   = E_Ka_list;
data.p_Ka   = 'Poisson';
data.k      = k;
data.n      = n;
data.rad_lower = rad_l;
data.rad_upper = rad_u;
data.p_MD   = p_MD;
data.p_FA   = p_FA;
data.P1     = P1;
data.sim_time = sim_time;

if DEBUG ~= 1
        filename = ['RCU_KaPoissonUnknown_EKa_' num2str(min(E_Ka_list)) 'to' ...
            num2str(max(E_Ka_list)) '_k_' num2str(k) '_n_' num2str(n) ...
            '_radL_' sprintf('%d', rad_l_list) ...
            '_radU_' sprintf('%d', rad_u_list) ...
            '_EbN0db_' num2str(min(EbN0db)) 'to' num2str(max(EbN0db)) '.mat'];
    save(filename, 'data', '-v7.3');
else
    keyboard
end

end

RCU_KaRandomUnknown.m

function [eps_MD,eps_FA] = RCU_KaRandomUnknown(P,P1,rad_l,rad_u,k,n,E_Ka,p_Ka)
% function [eps_MD,eps_FA] = RCU_KaRandomUnknown(P,P1,rad_l,rad_u,k,n,E_Ka,p_Ka)
% Compute the RCU bound for the PUPE in Theorem 1 of
%
% [1] K.-H. Ngo, A. Lancho, G. Durisi and A. G. i. Amat, "Unsourced
% Multiple Access With Random User Activity," submitted to IEEE Trans. Inf.
% Theory, Jan. 2022.
% 
% for a system with random and unknown number of active users.
%
% INPUTS
%   P   : symbol power budget
%   P1  : the actual power used (denoted by P' in [1] and [2])
%   rad_l : lower decoding radius
%   rad_u : upper decoding radius
%   k     : number of bits per symbol
%   n     : framelength (number of complex DoFs)
%   E_Ka  : average number of active users
%   p_Ka  : PMF of the number of active users Ka
% 
% OUTPUTS
%   eps_MD, eps_FA : RCU bounds on the misdetection and false alarm 
%                       probabilities, respectively

% codebook size
M       = 2^k;

% number of samples for empirical evaluation of the CDF of It in qt
Niq     = 1000;

%% Computation of \tilde{p}
% Compute the error floors [1, Th. 3]
[floor_MD,floor_FA] = RCU_floor_KaRandomUnknown(rad_l,rad_u,k,n,E_Ka,p_Ka);

% Find K_l and K_u such that Pr[Ka \notin [K_l:K_u]] is small
K_l = floor(E_Ka); K_u = ceil(E_Ka);
while p_Ka(K_l-1) > max(.0001*min(floor_MD,floor_FA),1e-9)
    K_l = K_l - 1;
end
K_l = max(K_l,0);
while p_Ka(K_u+1) > max(.0001*min(floor_MD,floor_FA),1e-9)
    K_u = K_u + 1;
end

p01 = 0;
for Ka_tmp = K_l:K_u   
    p01_tmp = 1; 
    for ii = 1:Ka_tmp-1
        p01_tmp = p01_tmp*(1-ii/M);
    end
    p01 = p01 + p_Ka(Ka_tmp)*p01_tmp;
end
ptilde = 1 - p01 + 1 - sum(p_Ka(K_l:K_u)) + E_Ka*gammainc(n*P/P1,n,'upper');

if ptilde >= 1
    eps_MD = 1;
    eps_FA = 1;
    return
end

%% Initialize eps_MD and eps_FA to be p0
eps_MD = ptilde;
eps_FA = ptilde;

%% The expectation w.r.t. Ka
parfor Ka = K_l:K_u
%% Compute the term \xi(Ka,Ka') using [1, Th. 2]
% The function \zeta for ML esimator of Ka
KaEst_thres = @(Ka,KaEst,P1) n.*(log(1+Ka.*P1) - log(1+KaEst.*P1))./((1+Ka.*P1)./(1+KaEst.*P1)-1);

% For energy-based estimator of Ka, use the below
% KaEst_thres = @(Ka,KaEst,P1) n./(1+Ka.*P1).*(1+(Ka+KaEst).*P1/2); 

% Option 1: compute the exact term defined in [1]
% tic
% P_Ka_KaEst_list = zeros(Ka_u - Ka_l + 1,1);
% for idx = 1:Ka_u - Ka_l + 1
%     KaEst = Ka_l + idx - 1;
%     P_Ka_KaEst_list_a = gammainc(KaEst_thres(Ka,Ka_l:KaEst-1,P1),n,'lower');
%     P_Ka_KaEst_list_b = gammainc(KaEst_thres(Ka,KaEst+1:Ka_u,P1),n,'upper');
%     P_Ka_KaEst_list(idx) = 1 - max([P_Ka_KaEst_list_a P_Ka_KaEst_list_b]);
% end
% toc

% Option 2: slight relaxation that is faster
% tic
P_Ka_KaEst_list_a = gammainc(KaEst_thres(Ka,K_l:Ka-1,P1),n,'lower');
P_Ka_KaEst_list_b = gammainc(KaEst_thres(Ka,Ka+1:K_u,P1),n,'upper');
P_Ka_Ka = 1 - max([P_Ka_KaEst_list_a P_Ka_KaEst_list_b]);
P_Ka_KaEst_list = [P_Ka_KaEst_list_a'; P_Ka_Ka; P_Ka_KaEst_list_b'];
% toc

%% The expectation w.r.t. Ka'
for KaEst = K_l:K_u
    
    % \xi(Ka,Ka')
    xi_Ka_KaEst = P_Ka_KaEst_list(KaEst - K_l + 1);

    % \underbar{Ka'}
    KaEst_l = max(KaEst - rad_l,K_l);

    % \overbar{Ka'}
    KaEst_u = min(KaEst + rad_u,K_u);

    % Sets of possible values of t and t'
    t_vec = 0:min(min(KaEst_u,Ka),M-KaEst_l-max(Ka-KaEst_u,0));
    t1_l = max(Ka-KaEst_u,0) - max(Ka-KaEst_l,0);
    t1_u = max(KaEst_u-Ka,0) - max(KaEst_l-Ka,0);
    t1_vec = zeros(length(t_vec),KaEst_u-KaEst_l+1);
    for idxT = 1:length(t_vec)
        t1_vec(idxT,:) = t1_l+t_vec(idxT):t1_u+t_vec(idxT);
    end

    %% Computation of pt:

    % Definitions of functions R_1 and R_2
    if M-max(Ka,KaEst_l) <= 2^20
        R1_f = @(n,Ka,K1,M,t1) (gammaln(M-max(Ka,K1) + 1) - gammaln(M-max(Ka,K1)-t1+ 1) - gammaln(t1+1))/n;
    else
        R1_f = @(n,Ka,K1,M,t1) t1./n.*log(M-max(Ka,K1))-1./n.*gammaln(t1+1); 
    end
    R2_f = @(n,Ka,K1,t) 1/n*(gammaln(min(Ka,K1)+1)-gammaln(t+1)-gammaln(min(Ka,K1)-t+1));
    
    % First, consider t1 > 0
    t1_vec2 = t1_vec;
    t1_vec2(t1_vec2<0) = 0;
    
    % Initialize for the optimization over rho and rho1
    rho_vec =  linspace(1e-9,1,50); 
    rho1_vec = linspace(1e-9,1,50); 
    
    rho = permute(repmat(rho_vec,length(rho1_vec),1,length(t_vec),size(t1_vec,2)),[2,1,3,4]);
    rho1 = repmat(rho1_vec,length(rho_vec),1,length(t_vec),size(t1_vec,2));
    t = permute(repmat(t_vec,length(rho_vec),1,length(rho1_vec),size(t1_vec,2)),[1,3,2,4]);
    t1 = permute(repmat(t1_vec2,1,1,length(rho_vec),length(rho1_vec)),[3,4,1,2]);
    
    % Precompute some quantities
    P2 = 1+(max(Ka-KaEst_u,0)+max(KaEst_l-Ka,0)).*P1;
    P3 = P1.*(t1+rho.*t);
    P4 = rho.*rho1.*P3.*P2;
    P5 = rho1.*(rho-1).*t1.*P1;

    % Find optimal lambda that maximizes E0(t,t')
    c1_f = - P3.*P4.*P5 - (rho1+1).*t1.*P1.*P3.*P4;
    c2_f = P5.*(P3.^2 - P4) + rho1.*(t1.*P1.*P3.^2 - P3.*P4) ...
            - (2.*t1.*P1 + P3).*P4;
    c3_f = 2.*P3.*P5 + rho1.*(P3.^2 + t1.*P1.*P3) - 2.*P4;
    c4_f = P5 + rho1.*P3; 

    Delta0_f = c2_f.^2 - 3.*c1_f.*c3_f;
    Delta1_f = 2.*c2_f.^3 - 9.*c1_f.*c2_f.*c3_f + 27.*c1_f.^2.*c4_f;
    Q_f = ((Delta1_f + sqrt(Delta1_f.^2 - 4.*Delta0_f.^3))./2).^(1/3);

    lambda = real(-(c2_f + Q_f + Delta0_f./Q_f)./3./c1_f);
    
    % Compute E0(t,t') 
    E0_f = rho1.*(rho-1).*log(1+lambda.*P1.*t1) ...
        + (rho1-1).*log(1+lambda.*P3) ...
        + log(1+lambda.*P3 - lambda.^2.*P4);
    
    % Compute E(t,t') 
    Ett_f = reshape(max(max(-rho.*rho1.*R1_f(n,Ka,KaEst_l,M,t1) ...
        - rho1.*R2_f(n,Ka,KaEst_u,t) + E0_f)),[length(t_vec) size(t1_vec,2)]); 
    
    % Compute p_{t,t'}
    ptt = min(exp(-n.*Ett_f),1);

    % Now, consider the case t1 = 0, where the optimal lambda is the root 
    % of a quadratic function
    rho = permute(repmat(rho_vec,length(rho1_vec),1,length(t_vec)),[2,1,3]);
    rho1 = repmat(rho1_vec,length(rho_vec),1,length(t_vec));
    t = permute(repmat(t_vec,length(rho_vec),1,length(rho1_vec)),[1,3,2]);
    P3 = P1.*rho.*t;
    P4 = rho.*rho1.*P3.*P2;

    c2_f = -(rho1+1).*P3.*P4;
    c3_f = rho1.*P3.^2 - 2.*P4;
    c4_f = rho1.*P3;
    Delta = c3_f.^2 - 4.*c2_f.*c4_f;
    lambda = -(c3_f+sqrt(Delta))./2./c2_f;
    E0_f = (rho1-1).*log(1+lambda.*P3) + log(1+lambda.*P3 - lambda.^2.*P4);
    Ett_f = squeeze(max(max(- rho1.*R2_f(n,Ka,KaEst_u,t) + E0_f))); 
    ptt_t1zero = min(exp(-n.*Ett_f),1);
    
    % Combine the cases t1 > 0 and t1 = 0
    ptt(t1_vec > min(KaEst_u-max(KaEst_l-Ka,0),M-max(KaEst_l,Ka))) = 0;
    ptt(t1_vec < 0) = 0;
    for idxT = 1:length(t_vec)
    for idxT1 = 1:size(t1_vec,2)
        if t1_vec(idxT,idxT1) == 0
            ptt(idxT,idxT1) = ptt_t1zero(idxT);
        end
    end
    end

    % Compute pt
    pt = min(sum(ptt,2),1);
    
    %% Computation of qt for t = 1:
    qt = 1;
    qtt = 1;

    if t_vec(end) >= 1

    t1_set = t1_vec2(2,:);
    
    % Compute qt for t = 1 and Ka <= 50 only due to complexity issue
    if t_vec(1) <= 1 && Ka <= 150
        It = zeros(1,Niq);
        for II = 1:Niq
            Zi = sqrt(.5)*(randn(1,n) + 1i*randn(1,n));
            DefaultFA = sqrt(.5*max(KaEst_l-Ka,0)*P1)*(randn(1,n) + 1i*randn(1,n));
            codebook = sqrt(.5*P1)*(randn(min(Ka,KaEst_u),n) + 1i*randn(min(Ka,KaEst_u),n));

            it = n*log(1+(1+max(Ka-KaEst_u,0))*P1) + ...
                (sum(abs(repmat(Zi+DefaultFA,min(Ka,KaEst_u),1)+codebook).^2,2)./...
                    (1+(1+max(Ka-KaEst_u,0))*P1)-sum(abs(repmat(Zi,min(Ka,KaEst_u),1)).^2,2));
            It(II) = min(it);
        end
        [prob,gam] = ecdf(It);
        qt = min(prob + sum(exp(repmat(n*(R1_f(n,Ka,KaEst_l,M,t1_set)+R2_f(n,Ka,KaEst_u,1)),length(gam),1)-gam),2));
        qtt = min(repmat(prob,1,length(t1_set)) + exp(n*(R1_f(n,Ka,KaEst_l,M,t1_set)+R2_f(n,Ka,KaEst_u,1))-gam));
    end 
    
    % Take the min of pt and qt
    pt(2) = min(pt(2),qt);
    ptt(2,:) = min(ptt(2,:),qtt);
    end
    
    % Take the min of pt, qt, and xi(Ka,Ka')
    pt = min(pt,xi_Ka_KaEst);
    ptt = min(ptt,xi_Ka_KaEst);

    %% Computation epsilon_MD and epsilon_FA for a given P'< P
    if Ka > 0
        eps_MD = eps_MD + feval(p_Ka, Ka)*(sum((t_vec + max(Ka-KaEst_u,0))*pt)/Ka);
    end

    t_vec_2 = repmat(t_vec,size(t1_vec,2),1).';
    Mrx = (Ka-t_vec_2+t1_vec + max(KaEst_l-Ka,0) - max(Ka-KaEst_u,0)); % number of decoded codewords
    Mrx(Mrx == 0) = inf; 
    eps_FA = eps_FA + feval(p_Ka, Ka)*sum(sum(ptt.*(t1_vec + max(KaEst_l-Ka,0))./Mrx,1));
end
% if eps_MD >= 1 && eps_FA >= 1
%     break;
% end
end
eps_MD = min(eps_MD,1);
eps_FA = min(eps_FA,1);
end

SA-MPR

EbN0_SAMPR_KaPoissonKnown.m

function data = EbN0_SAMPR_KaPoissonKnown(k, n, epsilon, E_Ka, SlotIdxCoding)
% function data = EbN0_SAMPR_KaPoissonKnown(k, n, epsilon, E_Ka, SlotIdxCoding)
% Find the minimal required EbN0 (in dB) such that the PUPE achieved with 
% slotted ALOHA (SA) with multi-packet reception (MPR) is below a 
% certain threshold epsilon for a system with the number of active 
% users following a Poisson distribution, but known.
%
% INPUTS
%   k   : number of bits per symbol
%   n   : framelength (number of complex DoFs)
%   epsilon : target PUPE
%   E_Ka    : average number of active users
%   SlotIdxCoding : 1 if slot-index coding is employed, 0 otherwise
%
% OUTPUT
%   data : store the system parameters and the minimal required EbN0

addpath ../RCU_KaKnown

tic
DEBUG = 0;

%% debugging mode
if DEBUG == 1
    k       = 128; 
    n       = 19200; 
    epsilon = .1; 
    E_Ka    = 50;
end

%% Poissom PMF of Ka, can be modified to consider other distributions 
p_Ka    = @(K) poisspdf(K,E_Ka);

%% The range of power to search
EbN0db_lowest = -1;
EbN0db_highest = 15;
    
P_lowest = k*10^(EbN0db_lowest/10)/n;
P_highest = k*10^(EbN0db_highest/10)/n;

%% Function to compute the RCU bound
if SlotIdxCoding == 1
    f_rcu = @(P,P1,L) RCU_KaRandomKnown(P*L,P1*L,k-floor(log2(L)),...
                ceil(n/L),E_Ka/L,@(Ksa) PMF_Ksa(p_Ka,E_Ka,L,Ksa)); 
else
    f_rcu = @(P,P1,L) RCU_KaRandomKnown(P*L,P1*L,k,ceil(n/L),E_Ka/L,...
                @(Ksa) PMF_Ksa(p_Ka,E_Ka,L,Ksa)); 
end

%% Search for the minimal required EbN0
% The RCU is optimized over P1 and L
[eps_RCU,P_RCU,P1,L] = binary_search_P_SAMPR_KaKnown(f_rcu, P_lowest, P_highest,...
    epsilon,epsilon/100,E_Ka);
EbN0db_RCU = 10*log10(n*P_RCU/k);

%% Save the results
sim_time = toc;
data.EbN0db = EbN0db_RCU;
data.E_Ka   = E_Ka;
data.p_Ka   = 'Poisson';
data.eps_RCU = eps_RCU;
data.epsilon = epsilon;
data.k      = k;
data.n      = n;
data.P1     = P1;
data.nSlot  = L; 
data.SlotIdxCoding  = SlotIdxCoding; 
data.sim_time = sim_time;

if DEBUG ~= 1
    if SlotIdxCoding == 1
        filename = ['EbN0_SAMPR_SlotIdxCoding_KaPoissonKnown_EKa_' num2str(E_Ka) ...
            '_epsilon_' num2str(epsilon) '_k_' num2str(k) '_n_' num2str(n) '.mat'];
    else
        filename = ['EbN0_SAMPR_KaPoissonKnown_EKa_' num2str(E_Ka) ...
            '_epsilon_' num2str(epsilon) '_k_' num2str(k) '_n_' num2str(n) '.mat'];
    end
    save(filename, 'data', '-v7.3');
else
    keyboard
end

end

%%
function PMF_Ksa = PMF_Ksa(p_Ka,E_Ka,L,Ksa)
% Compute the PMF of the number of active users per slot

PMF_Ksa = zeros(size(Ksa));
 
K_u = E_Ka;
while p_Ka(K_u+1) > eps
    K_u = K_u + 1;
end
K_u = max(K_u,10000);

PMF_Ksa_scalar = @(T) sum(p_Ka(0:K_u).*binopdf(T,0:K_u,1/L));
for idxKsa = 1:length(Ksa)
    PMF_Ksa(idxKsa) = PMF_Ksa_scalar(Ksa(idxKsa));
end
end

%%
function [rcu,P,P1,nSlot] = binary_search_P_SAMPR_KaKnown(f,x1,x2,TARGET,TOL,E_Ka)
% Search for the value of P such that the RCU bound of the PUPE of SAMPR 
% given by min_{P1,L} f(P,P1,L) is between TARGET - TOL and TARGET

iter= 20;                       % maximum number of iterations
k1=0;                            % iteration index

[rcu_tmp,P1_tmp,nSlot_tmp] = golden_search_P1_SAMPR_KaKnown(f,1e-9,x2,x2/100,E_Ka);
[rcu_tmp1,P1_tmp1,nSlot_tmp1] = golden_search_P1_SAMPR_KaKnown(f,1e-9,x1,x1/100,E_Ka);

if x1 == x2
    P = x1;
    rcu = rcu_tmp;
    P1 = P1_tmp;
    nSlot = nSlot_tmp;
elseif rcu_tmp >= TARGET
    warning('Impossible to achieve the target within the given range of parameter :( ');
    P = x2;
    rcu = rcu_tmp;
    P1 = P1_tmp;
    nSlot = nSlot_tmp;
elseif rcu_tmp1 <= TARGET
    warning('All parameter values in the range can achieve the target :) ');
    P = x1;
    rcu = rcu_tmp1;
    P1 = P1_tmp1;
    nSlot = nSlot_tmp1;
else
    
[fx,P1_tmp,nSlot_tmp]=...
    golden_search_P1_SAMPR_KaKnown(f,1e-9,(x1+x2)/2,(x1+x2)/200,E_Ka); 

while (TARGET < fx || fx < TARGET - TOL) && (k1<iter || TARGET < fx)
    if k1 > 0
        [fx,P1_tmp,nSlot_tmp]=...
            golden_search_P1_SAMPR_KaKnown(f,0,(x1+x2)/2,(x1+x2)/200,E_Ka); 
    end
    if TARGET > fx
        x2 = (x1+x2)/2; %set new end of interval        
    else
        x1 = (x1+x2)/2; %replace as new start index
    end
    k1=k1+1;
end

rcu = fx;
P   = x2;
P1 = P1_tmp;
nSlot = nSlot_tmp;
end
end

%%
function [rcu, P1,nSlot] = golden_search_P1_SAMPR_KaKnown(f, START_INT, END_INT, TOL, E_Ka)
% Minimize min_L f(P,P1,L) over P1 for given P

P = END_INT;
iter= 20;                       % maximum number of iterations
tau=double((sqrt(5)-1)/2);      % golden proportion coefficient, around 0.618
k2=0;                            % number of iterations
x1=START_INT+(1-tau)*(END_INT-START_INT);             % computing x values
x2=START_INT+tau*(END_INT-START_INT);

TOL_nSlot = 1;
nSlot_l = E_Ka;
nSlot_u = 6*E_Ka;

[f_x1,nSlot_1] = golden_search_nSlot_SAMPR_KaKnown(f,P,x1,nSlot_l,nSlot_u,TOL_nSlot); %f(P,x1); %     % computing values in x points
[f_x2,nSlot_2] = golden_search_nSlot_SAMPR_KaKnown(f,P,x2,nSlot_l,nSlot_u,TOL_nSlot); %f(P,x2);

while ((abs(END_INT-START_INT)>TOL) && (k2<iter))
    if f_x1 < f_x2 %function smaller in x1 than in x2
        END_INT = x2; %make interval smaller
        x2 = x1; %set new end of interval
        x1 = START_INT+(1-tau)*(END_INT-START_INT); %find new beginning
        f_x2 = f_x1;%already have value in x1
        nSlot_2 = nSlot_1;
%         [fMD_x1,fFA_x1] = f(P,x1,2*E_Ka);
        [f_x1,nSlot_1] = ...
            golden_search_nSlot_SAMPR_KaKnown(f, P,x1,nSlot_l,nSlot_u,TOL_nSlot); %f(P,x1); %%compute new value for new beginning
    else
        START_INT=x1; %function smaller in x2 than in x1 so set new start indx to x1
        x1 = x2; %replace as new start index
        x2=START_INT+tau*(END_INT-START_INT); %compute new end index
        f_x1= f_x2;
        nSlot_1 = nSlot_2;
%         [fMD_x2,fFA_x2] = f(P,x2,2*E_Ka);
        [f_x2,nSlot_2] = ...
            golden_search_nSlot_SAMPR_KaKnown(f, P,x2,nSlot_l,nSlot_u,TOL_nSlot); %f(P,x2);
    end
    k2=k2+1;
end

if f_x1 < f_x2
    P1=x1;
    rcu = f_x1;
    nSlot = nSlot_1;
else
    P1=x2;
    rcu = f_x2;
    nSlot = nSlot_2;
end

end

%%
function [rcu, nSlot] = golden_search_nSlot_SAMPR_KaKnown(f, P,P1,START_INT,END_INT,TOL)
% Minimize f(P,P1,L) over L for given P and P1

iter= 20;                       % maximum number of iterations
tau=double((sqrt(5)-1)/2);      % golden proportion coefficient, around 0.618
k2=0;                            % number of iterations
x1=max(round(START_INT+(1-tau)*(END_INT-START_INT)),0);             % computing x values
x2=round(START_INT+tau*(END_INT-START_INT));

f_x1 = f(P,P1,x1);    % computing values in x points
f_x2 = f(P,P1,x2); 

while ((abs(END_INT-START_INT)>TOL) && (k2<iter))
    if f_x1 < f_x2 %function smaller in x1 than in x2
        END_INT = x2; %make interval smaller
        x2 = x1; %set new end of interval
        x1 = max(round(START_INT+(1-tau)*(END_INT-START_INT)),0); %find new beginning
        f_x2 = f_x1;%already have value in x1
        f_x1 = f(P,P1,x1); %compute new value for new beginning
    else
        START_INT=x1; %function smaller in x2 than in x1 so set new start indx to x1
        x1 = x2; %replace as new start index
        x2 = round(START_INT+tau*(END_INT-START_INT)); %compute new end index
        f_x1= f_x2;
        f_x2 = f(P,P1,x2); % 
    end
    k2=k2+1;
end

if f_x1 < f_x2
    nSlot=x1;
    rcu = f_x1;
else
    nSlot=x2;
    rcu = f_x2;
end
end

EbN0_SAMPR_KaPoissonUnknown.m

function data = EbN0_SAMPR_KaPoissonUnknown(k, n, epsilon_MD, epsilon_FA, E_Ka, SlotIdxCoding)
% function data = EbN0_ALOHA_KaPoissonUnknown(k, n, epsilon, E_Ka, SlotIdxCoding)
% Find the minimal required EbN0 (in dB) such that the misdetection and 
% false alarm probabilities achieved with slotted ALOHA (SA) with 
% multi-packet reception (MPR) is below certain thresholds epsilon_MD and
% epsilon_FA, respectively, for a system with the number of active 
% users following a Poisson distribution, and unknown. See Corollary 2 in 
%
% [1] K.-H. Ngo, A. Lancho, G. Durisi and A. G. i. Amat, "Unsourced
% Multiple Access With Random User Activity," submitted to IEEE Trans. Inf.
% Theory, Jan. 2022.
%
% INPUTS
%   k   : number of bits per symbol
%   n   : framelength (number of complex DoFs)
%   epsilon_MD : target misdetection probability
%   epsilon_FA : target false alarm probability
%   E_Ka    : average number of active users
%   SlotIdxCoding : 1 if slot-index coding is employed, 0 otherwise 
%
% OUTPUT
%   data : store the system parameters and the minimal required EbN0

addpath ../RCU_KaUnknown

tic
DEBUG = 0;

%% debugging mode
if DEBUG == 1
    k       = 128; 
    n       = 19200; 
    epsilon_MD = .1; 
    epsilon_FA = .1; 
    E_Ka    = 50; 
    SlotIdxCoding = 0;
end

%% Poissom PMF of Ka, can be modified to consider other distributions 
p_Ka = @(K) poisspdf(K,E_Ka);

%% The range of power to search
EbN0db_lowest = -1;
EbN0db_highest = 16;
P_lowest = k*10^(EbN0db_lowest/10)/n;
P_highest = k*10^(EbN0db_highest/10)/n;

%% Function to compute the RCU bound
if SlotIdxCoding == 1
    f_rcu = @(P,P1,L,DecRad) RCU_KaRandomUnknown(P*L,P1*L,DecRad,DecRad,k-floor(log2(L)),...
                floor(n/L),E_Ka/L,@(Ksa) PMF_Ksa(p_Ka,E_Ka,L,Ksa));
else
    f_rcu = @(P,P1,L,DecRad) RCU_KaRandomUnknown(P*L,P1*L,DecRad,DecRad,k,floor(n/L),...
                E_Ka/L,@(Ksa) PMF_Ksa(p_Ka,E_Ka,L,Ksa));
end

%% Search for the minimal required EbN0
% The RCU is optimized over P1, L, and the decoding radius
[eps_RCU_MD, eps_RCU_FA, P_RCU,P1,L,DecRad] = binary_search_P_SAMPR(f_rcu, ...
    P_lowest, P_highest,epsilon_MD,epsilon_FA,min(epsilon_MD,epsilon_FA)/100,E_Ka);
EbN0db_RCU = 10*log10(n*P_RCU/k);

%% Save the results
sim_time = toc;
data.EbN0db = EbN0db_RCU;
data.E_Ka   = E_Ka;
data.p_Ka   = 'Poisson';
data.eps_RCU_MD = eps_RCU_MD;
data.eps_RCU_FA = eps_RCU_FA;
data.epsilon_MD = epsilon_MD;
data.epsilon_FA = epsilon_FA;
data.DecRad = DecRad;
data.k      = k;
data.n      = n;
data.P1     = P1;
data.nSlot  = L; 
data.SlotIdxCoding = SlotIdxCoding; 
data.sim_time = sim_time;

if DEBUG ~= 1
    if SlotIdxCoding == 1
        filename = ['EbN0_SAMPR_SlotIdxCoding_KaPoissonUnknown_EKa_' num2str(E_Ka)...
            '_epsilonMD_' num2str(epsilon_MD) '_epsilonFA_' num2str(epsilon_FA)...
                '_k_' num2str(k) '_n_' num2str(n) '.mat'];
    else
        filename = ['EbN0_SAMPR_KaPoissonUnknown_EKa_' num2str(E_Ka) ...
            '_epsilonMD_' num2str(epsilon_MD) '_epsilonFA_' num2str(epsilon_FA) ...
                '_k_' num2str(k) '_n_' num2str(n) '.mat'];
    end
    save(filename, 'data', '-v7.3');
else
    keyboard
end

end

%%
function PMF_Ksa = PMF_Ksa(p_Ka,E_Ka,L,Ksa)
% Compute the PMF of the number of active users per slot

PMF_Ksa = zeros(size(Ksa));
 
K_u = E_Ka;
while p_Ka(K_u+1) > eps
    K_u = K_u + 1;
end
K_u = max(K_u,10000);

PMF_Ksa_scalar = @(T) sum(p_Ka(0:K_u).*binopdf(T,0:K_u,1/L));
for idxKsa = 1:length(Ksa)
    PMF_Ksa(idxKsa) = PMF_Ksa_scalar(Ksa(idxKsa));
end
end

%%
function [rcu_MD, rcu_FA, P,P1,nSlot,DecRad] = binary_search_P_SAMPR(f,x1,x2,TARGET_MD,TARGET_FA,TOL,E_Ka)
% Search for the value of P such that the RCU bound of the PUPE of SAMPR 
% given by min_{P1,L,DecRad} weightedSum[f(P,P1,L,DecRad)] is between 
% TARGET - TOL and TARGET

weight_MD = 1/(1 + TARGET_MD/TARGET_FA);
weight_FA = 1/(1 + TARGET_FA/TARGET_MD);

iter= 20;                       % maximum number of iterations
k1=0;                            % number of iterations

[rcu_MD_tmp,rcu_FA_tmp,P1_tmp,nSlot_tmp,DecRad_tmp] = ...
    golden_search_P1_SAMPR(f,1e-9,x2,x2/100, weight_MD, weight_FA,E_Ka);
[rcu_MD_tmp1,rcu_FA_tmp1,P1_tmp1,nSlot_tmp1,DecRad_tmp1] = ...
    golden_search_P1_SAMPR(f,1e-9,x1,x1/100, weight_MD, weight_FA,E_Ka);
if x1 == x2
    P = x1;
    rcu_MD = rcu_MD_tmp;
    rcu_FA = rcu_FA_tmp;
    P1 = P1_tmp;
    nSlot = nSlot_tmp;
    DecRad = DecRad_tmp;
elseif rcu_MD_tmp >= TARGET_MD || rcu_FA_tmp >= TARGET_FA
    warning('Impossible to achieve the target within the given range of parameter :( ');
    P = x2;
    rcu_MD = rcu_MD_tmp;
    rcu_FA = rcu_FA_tmp;
    P1 = P1_tmp;
    nSlot = nSlot_tmp;
    DecRad = DecRad_tmp;
elseif rcu_MD_tmp1 <= TARGET_MD && rcu_FA_tmp1 <= TARGET_FA
    warning('All parameter values in the range can achieve the target :) ');
    P = x1;
    rcu_MD = rcu_MD_tmp1;
    rcu_FA = rcu_FA_tmp1;
    P1 = P1_tmp1;
    nSlot = nSlot_tmp1;
    DecRad = DecRad_tmp1;
else
    
[fx_MD,fx_FA,P1_tmp,nSlot_tmp,DecRad_tmp]=...
    golden_search_P1_SAMPR(f,1e-9,(x1+x2)/2,(x1+x2)/200, weight_MD, weight_FA,E_Ka);

while ~((TARGET_MD >= fx_MD && fx_MD >= TARGET_MD - TOL && TARGET_FA >= fx_FA) || ...
        (TARGET_FA >= fx_FA && fx_FA >= TARGET_FA - TOL && TARGET_MD >= fx_MD) ...
        || (k1>iter))
    if k1 > 0
        [fx_MD,fx_FA,P1_tmp,nSlot_tmp,DecRad_tmp]=...
            golden_search_P1_SAMPR(f,0,(x1+x2)/2,(x1+x2)/200, weight_MD, weight_FA,E_Ka); 
    end
    if TARGET_MD > fx_MD && TARGET_FA > fx_FA
        x2 = (x1+x2)/2; %set new end of interval        
    else
        x1 = (x1+x2)/2; %replace as new start index
    end
    k1=k1+1;
end

rcu_MD = fx_MD;
rcu_FA = fx_FA;
P   = x2;
P1 = P1_tmp;
nSlot = nSlot_tmp;
DecRad = DecRad_tmp;
end
end

%%
function [rcu_MD, rcu_FA, P1,nSlot,DecRad] = golden_search_P1_SAMPR(f, START_INT, END_INT, TOL, weight_MD, weight_FA,E_Ka)
% Optimize P1

P = END_INT;
iter= 20;                       % maximum number of iterations
tau=double((sqrt(5)-1)/2);      % golden proportion coefficient, around 0.618
k2=0;                            % number of iterations
x1=START_INT+(1-tau)*(END_INT-START_INT);             % computing x values
x2=START_INT+tau*(END_INT-START_INT);

% K_l = Ka;
% K_u = 1.5*E_Ka;

TOL_nSlot = 1;
nSlot_l = E_Ka;
nSlot_u = 6*E_Ka;

[fMD_x1,fFA_x1,nSlot_1,DecRad_1] = ...
    golden_search_nSlot_SAMPR(f, P,x1,nSlot_l,nSlot_u,TOL_nSlot,weight_MD,weight_FA); 
[fMD_x2,fFA_x2,nSlot_2,DecRad_2] = ...
    golden_search_nSlot_SAMPR(f, P,x2,nSlot_l,nSlot_u,TOL_nSlot,weight_MD,weight_FA);

while ((abs(END_INT-START_INT)>TOL) && (k2<iter))
    if fMD_x1*weight_MD + fFA_x1*weight_FA < fMD_x2*weight_MD + fFA_x2*weight_FA %function smaller in x1 than in x2
        END_INT = x2; %make interval smaller
        x2 = x1; %set new end of interval
        x1 = START_INT+(1-tau)*(END_INT-START_INT); %find new beginning
        fMD_x2 = fMD_x1;%already have value in x1
        fFA_x2 = fFA_x1;
        DecRad_2 = DecRad_1;
        nSlot_2 = nSlot_1;
        [fMD_x1,fFA_x1,nSlot_1,DecRad_1] = ...
            golden_search_nSlot_SAMPR(f, P,x1,nSlot_l,nSlot_u,TOL_nSlot,weight_MD,weight_FA); %compute new value for new beginning
    else
        START_INT=x1; %function smaller in x2 than in x1 so set new start indx to x1
        x1 = x2; %replace as new start index
        x2=START_INT+tau*(END_INT-START_INT); %compute new end index
        fMD_x1= fMD_x2;
        fFA_x1 = fFA_x2;
        nSlot_1 = nSlot_2;
        DecRad_1 = DecRad_2;
        [fMD_x2,fFA_x2,nSlot_2,DecRad_2] = ...
            golden_search_nSlot_SAMPR(f, P,x2,nSlot_l,nSlot_u,TOL_nSlot,weight_MD,weight_FA); 
    end
    k2=k2+1;
end

if fMD_x1*weight_MD + fFA_x1*weight_FA < fMD_x2*weight_MD + fFA_x2*weight_FA 
    P1=x1;
    rcu_MD = fMD_x1;
    rcu_FA = fFA_x1;
    nSlot = nSlot_1;
    DecRad = DecRad_1;
else
    P1=x2;
    rcu_MD = fMD_x2;
    rcu_FA = fFA_x2;
    nSlot = nSlot_2;
    DecRad = DecRad_2;
end

end

%%
function [rcu_MD, rcu_FA, nSlot, DecRad] = golden_search_nSlot_SAMPR(f, P,P1,START_INT,END_INT,TOL,weight_MD,weight_FA)
% Optimize the number of slots

iter= 20;                       % maximum number of iterations
tau=double((sqrt(5)-1)/2);      % golden proportion coefficient, around 0.618
k2=0;                            % number of iterations
x1=max(round(START_INT+(1-tau)*(END_INT-START_INT)),0);             % computing x values
x2=round(START_INT+tau*(END_INT-START_INT));

[fMD_x1,fFA_x1,DecRad_x1] = linear_search_DecRad_SAMPR(f,P,P1,x1,weight_MD,weight_FA); % computing values in x points
[fMD_x2,fFA_x2,DecRad_x2] = linear_search_DecRad_SAMPR(f,P,P1,x2,weight_MD,weight_FA); 

while ((abs(END_INT-START_INT)>TOL) && (k2<iter))
    if fMD_x1*weight_MD + fFA_x1*weight_FA < fMD_x2*weight_MD + fFA_x2*weight_FA %function smaller in x1 than in x2
        END_INT = x2; %make interval smaller
        x2 = x1; %set new end of interval
        x1 = max(round(START_INT+(1-tau)*(END_INT-START_INT)),0); %find new beginning
        fMD_x2 = fMD_x1;%already have value in x1
        fFA_x2 = fFA_x1;
        DecRad_x2 = DecRad_x1;
        if fixListSize
            [fMD_x1,fFA_x1] = f(P,P1,x1); DecRad_x1 = 0;
        else
            [fMD_x1,fFA_x1,DecRad_x1] = linear_search_DecRad_SAMPR(f,P,P1,x1,weight_MD,weight_FA); %compute new value for new beginning
        end
    else
        START_INT=x1; %function smaller in x2 than in x1 so set new start indx to x1
        x1 = x2; %replace as new start index
        x2 = round(START_INT+tau*(END_INT-START_INT)); %compute new end index
        fMD_x1= fMD_x2;
        fFA_x1 = fFA_x2;
        DecRad_x2 = 0;
        if fixListSize
            [fMD_x2,fFA_x2] = f(P,P1,x2);
        else
            [fMD_x2,fFA_x2,DecRad_x2] = linear_search_DecRad_SAMPR(f,P,P1,x2,weight_MD,weight_FA); 
        end
    end
    k2=k2+1;
end

if fMD_x1*weight_MD + fFA_x1*weight_FA < fMD_x2*weight_MD + fFA_x2*weight_FA
    nSlot=x1;
    rcu_MD = fMD_x1;
    rcu_FA = fFA_x1;
    DecRad = DecRad_x1;
else
    nSlot=x2;
    rcu_MD = fMD_x2;
    rcu_FA = fFA_x2;
    DecRad = DecRad_x2;
end
end

%%
function [fMD,fFA,DecRad] = linear_search_DecRad_SAMPR(f,P,P1,x,weight_MD,weight_FA)
% Optimize the decoding radius

maxrad = 5; % search decoding radius from 0 to 4
fMD = zeros(maxrad,1);
fFA = zeros(maxrad,1);
for ii = 1:maxrad
    [fMD_tmp, fFA_tmp] = f(P,P1,x,ii-1);
    fMD(ii) = fMD_tmp;
    fFA(ii) = fFA_tmp;
end
[~,idxMin] = min(fMD*weight_MD + fFA*weight_FA);
fMD = fMD(idxMin);
fFA = fFA(idxMin);
iiset = 0:maxrad-1;
DecRad = iiset(idxMin);
% DecRad = 0;
% [fMD, fFA] = f(P,P1,x,DecRad);
end

TIN

EbN0_TIN_KaPoissonUnknown.m

function data = EbN0_TIN_KaPoissonUnknown(k, n, epsilon_MD, epsilon_FA, E_Ka, normalApprox)
% function data = EbN0_TIN_KaPoissonUnknown(k, n, epsilon_MD, epsilon_FA, E_Ka, normalApprox)
% Find the minimal required EbN0 (in dB) such that the misdetection and 
% false alarm probabilities achieved with treating-interference-as-noise
% (TIN) is below certain thresholds epsilon_MD and
% epsilon_FA, respectively, for a system with the number of active 
% users following a Poisson distribution, and unknown. See Theorem 4 in 
%
% [1] K.-H. Ngo, A. Lancho, G. Durisi and A. G. i. Amat, "Unsourced
% Multiple Access With Random User Activity," submitted to IEEE Trans. Inf.
% Theory, Jan. 2022.
%
% INPUTS
%   k   : number of bits per symbol
%   n   : framelength (number of complex DoFs)
%   epsilon_MD : target misdetection probability
%   epsilon_FA : target false alarm probability
%   E_Ka    : average number of active users
%   normalApprox : 1 if normal approximation is used, 0 otherwise 
%
% OUTPUT
%   data : store the system parameters and the minimal required EbN0

tic
DEBUG = 0;

%% debugging mode
if DEBUG == 1
    k       = 128; % Number of bits
    n       = 19200; % Frame length
    epsilon_MD = .1; % Per-user error probability
    epsilon_FA = .1; % Per-user error probability
    E_Ka    = 100; 
    normalApprox = 1;
end

%% Poissom PMF of Ka, can be modified to consider other distributions 
p_Ka    = @(K) poisspdf(K,E_Ka);

%% The range of power to search
EbN0db_lowest = 0;
EbN0db_highest = 15;
    
P_lowest = k*10^(EbN0db_lowest/10)/n;
P_highest = k*10^(EbN0db_highest/10)/n;

%% Function to compute the RCUs-TIN bound
f_TIN = @(P,P1,s) RCUs_TIN(P,P1,s,k,n,E_Ka,p_Ka,normalApprox);

%% Search for the minimal required EbN0
[eps_TIN_MD, eps_TIN_FA, P,P1,sopt] = binary_search_TIN(f_TIN, P_lowest, P_highest,...
    epsilon_MD,epsilon_FA,min(epsilon_MD,epsilon_FA)/100,normalApprox);
EbN0db = 10*log10(n*P/k);

%% Save the results
sim_time = toc;
data.EbN0db = EbN0db;
data.E_Ka   = E_Ka;
data.p_Ka   = 'Poisson';
data.eps_TIN_MD = eps_TIN_MD;
data.eps_TIN_FA = eps_TIN_FA;
data.epsilon_MD = epsilon_MD;
data.epsilon_FA = epsilon_FA;
data.k      = k;
data.n      = n;
data.P1     = P1;
data.s      = sopt;
data.normalApprox = normalApprox;
data.sim_time = sim_time;

if DEBUG ~= 1
    filename = ['EbN0_TIN_KaPoissonUnknown_EKa_' num2str(E_Ka) '_epsilonMD_' ...
        num2str(epsilon_MD) '_epsilonFA_' num2str(epsilon_FA) ...
        '_k_' num2str(k) '_n_' num2str(n) '.mat'];
    save(filename, 'data', '-v7.3');
else
    keyboard
end

end

%%
function Pe = eta_s(n,P,R,Ka_vec,s,N)
% Computation \eta_s in [1, th. 4], which is also a RCUs bound for the 
% noncoherent Rayleigh block-fading channel.
%
% INPUTS:
% n     = blocklength
% P     = transmit power (no dB!)
% R     = Values of Rate ln(M)/n at which the bound will be computed
% Ka    = Number of active users
% s     = parameter to optimize in the RCUs (s>0)
% N     = Number of samples to generate the generalized info. density
%
% OUTPUT:
% Pe = Error probability obtained as a result of the computation of the bound

Pe  = nan(size(Ka_vec));
parfor ii = 1:length(Ka_vec)
    Ka = Ka_vec(ii);
    snr = P/(1+(Ka-1)*P);
    x   = sqrt(0.5*snr)*(randn(n,N) + 1i*randn(n,N)); % signal tx by one of the users
    z   = sqrt(0.5)*(randn(n,N) + 1i*randn(n,N)); % Noise plus interference
    y   = x + z; % Received signal
    
    i_s = -s*vecnorm(y-x).^2 + s*vecnorm(y).^2/(1+s*snr) + n*log(1+s*snr); % generalized information density
    
    Pe(ii)  = mean( exp( - max(0, i_s - log(exp(n*R)-1))));
end
end

%%
function [eps_MD,eps_FA] = RCUs_TIN(P,P1,s,k,n,E_Ka,p_Ka,normalApprox)

% codebook size
M       = 2^k;

%% COMPUTATION OF \tilde{p}
K_l = floor(E_Ka); K_u = ceil(E_Ka);
while p_Ka(K_l-1) > 1e-9
    K_l = K_l - 1;
end
K_l = max(K_l,0);
while p_Ka(K_u+1) > 1e-9
    K_u = K_u + 1;
end

p01 = 0;
for Ka_tmp = K_l:K_u   
    p01_tmp = 1; 
    for ii = 1:Ka_tmp-1
        p01_tmp = p01_tmp*(1-ii/M);
    end
    p01 = p01 + p_Ka(Ka_tmp)*p01_tmp;
end
ptilde = E_Ka*gammainc(n*P/P1,n,'upper') + 1 - p01 + 1 - sum(p_Ka(K_l:K_u)); 

%% Initialize eps_MD and eps_FA to be \tilde{p}
eps_MD = ptilde;
eps_FA = ptilde;

%% Compute the \xi(Ka,Ka') term for Ka and Ka' from K_l to K_u
if K_l == K_u
    xi_Ka_KaEst = 1;
else
    xi_Ka_KaEst = zeros(K_u-K_l+1,K_u-K_l+1);
    for Ka = K_l:K_u
        KaEst_thres = @(Ka,KaEst,P1) n.*(log(1+Ka.*P1) - log(1+KaEst.*P1))./((1+Ka.*P1)./(1+KaEst.*P1)-1);
        P_Ka_KaEst_list_a = gammainc(KaEst_thres(Ka,K_l:Ka-1,P1),n,'lower');
        P_Ka_KaEst_list_b = gammainc(KaEst_thres(Ka,Ka+1:K_u,P1),n,'upper');
        P_Ka_Ka = 1 - max([P_Ka_KaEst_list_a P_Ka_KaEst_list_b]);
        xi_Ka_KaEst(:,Ka-K_l+1) = [P_Ka_KaEst_list_a'; P_Ka_Ka; P_Ka_KaEst_list_b'];
    end
end

%% Compute the \eta_s terms
N = 1e2;
R = k/n*log(2);

if normalApprox
    C_TIN = @(Ka,P) log(1+P./(1+P.*(Ka-1)));
    V_TIN = @(Ka,P) sqrt(2.*P.*(log(exp(1))).^2./(1+Ka.*P));
    eta_s_vec = qfunc((n.*C_TIN((K_l:K_u)',P1) - log(M-1)) ./ (sqrt(n).*V_TIN((K_l:K_u)',P1)));
else
    eta_s_vec = eta_s(n,P1,R,(K_l:K_u)',s,N);
end

%% The sum over Ka
parfor Ka = K_l:K_u
    nAdditionalMDFA = min(min((K_l:K_u)',M-max(Ka,(K_l:K_u)')),Ka);
    eta = min(eta_s_vec,xi_Ka_KaEst(Ka-K_l+1,:)');
    
    % the sum over Ka' is implemented by the inner products 
    if Ka > 0
        eps_MD = eps_MD + (feval(p_Ka,Ka)/Ka)*(nAdditionalMDFA'*eta + max(Ka-(K_l:K_u),0)*xi_Ka_KaEst(Ka-K_l+1,:)');
    end
    if K_l == 0
        eps_FA = eps_FA + ...
            feval(p_Ka,Ka)*sum((nAdditionalMDFA(2:end).*eta(2:end) + max((K_l+1:K_u)'-Ka,0).*xi_Ka_KaEst(Ka-K_l+1,2:end)')./(K_l+1:K_u)');
    else
        eps_FA = eps_FA + ...
            feval(p_Ka,Ka)*sum((nAdditionalMDFA.*eta + max((K_l:K_u)'-Ka,0).*xi_Ka_KaEst(Ka-K_l+1,:)')./(K_l:K_u)');
    end
    
%     if eps_MD >= 1 && eps_FA >= 1
%         break;
%     end
end
eps_MD = min(eps_MD,1);
eps_FA = min(eps_FA,1);
end

%%
function [rcu_MD, rcu_FA, P,P1,s_opt] = binary_search_TIN(f,x1,x2,TARGET_MD,TARGET_FA,TOL,normalApprox)
% Search for P

weight_MD = 1/(1 + TARGET_MD/TARGET_FA);
weight_FA = 1/(1 + TARGET_FA/TARGET_MD);

iter= 20;                       % maximum number of iterations
k1=0;                            % number of iterations

[rcu_MD_tmp,rcu_FA_tmp,P1_tmp,s_tmp] = golden_search_P1_TIN(f,1e-9,x2,x2/200, weight_MD, weight_FA,normalApprox);
[rcu_MD_tmp1,rcu_FA_tmp1,P1_tmp1,s_tmp1] = golden_search_P1_TIN(f,1e-9,x1,x1/200, weight_MD, weight_FA,normalApprox);
if x1 == x2
    P = x1;
    rcu_MD = rcu_MD_tmp;
    rcu_FA = rcu_FA_tmp;
    P1 = P1_tmp;
    s_opt = s_tmp;
elseif rcu_MD_tmp > TARGET_MD || rcu_FA_tmp > TARGET_FA
    warning('Impossible to achieve the target within the given range of parameter :( ');
    P = x2;
    rcu_MD = rcu_MD_tmp;
    rcu_FA = rcu_FA_tmp;
    P1 = P1_tmp;
    s_opt = s_tmp1;
elseif rcu_MD_tmp1 < TARGET_MD || rcu_FA_tmp1 < TARGET_FA
    warning('All parameter values in the range can achieve the target :) ');
    P = x1;
    rcu_MD = rcu_MD_tmp1;
    rcu_FA = rcu_FA_tmp1;
    P1 = P1_tmp1;
    s_opt = s_tmp1;
else
    
[fx_MD,fx_FA,P1_tmp,s_tmp]=golden_search_P1_TIN(f,1e-9,(x1+x2)/2,(x1+x2)/200, weight_MD, weight_FA,normalApprox); % computing values in x points

while ~((TARGET_MD >= fx_MD && fx_MD >= TARGET_MD - TOL && TARGET_FA >= fx_FA) || ...
        (TARGET_FA >= fx_FA && fx_FA >= TARGET_FA - TOL && TARGET_MD >= fx_MD) ...
        || (k1>iter)) 
    if k1 > 0
        [fx_MD,fx_FA,P1_tmp,s_tmp]=golden_search_P1_TIN(f,0,(x1+x2)/2,(x1+x2)/200, weight_MD, weight_FA,normalApprox); 
    end
    if TARGET_MD > fx_MD && TARGET_FA > fx_FA
        x2 = (x1+x2)/2; %set new end of interval        
    else
        x1 = (x1+x2)/2; %replace as new start index
    end
    k1=k1+1;
end

rcu_MD = fx_MD;
rcu_FA = fx_FA;
P   = x2;
P1 = P1_tmp;
s_opt = s_tmp;
end
end

%%
function [rcu_MD, rcu_FA, P1,s_opt] = golden_search_P1_TIN(f, START_INT, END_INT, TOL, weight_MD, weight_FA,normalApprox)
% Optimize P1

P = END_INT;
iter= 20;                       % maximum number of iterations
tau=double((sqrt(5)-1)/2);      % golden proportion coefficient, around 0.618
k2=0;                            % number of iterations
x1=START_INT+(1-tau)*(END_INT-START_INT);             % computing x values
x2=START_INT+tau*(END_INT-START_INT);

s_start = 0;
s_end = 2;

if normalApprox
    [fMD_x1,fFA_x1] = f(P,x1,1);    s_opt1 = 1;
    [fMD_x2,fFA_x2] = f(P,x2,1);    s_opt2 = 1;
else
    [fMD_x1,fFA_x1,s_opt1] = golden_search_s_TIN(f, P, x1, s_start, s_end, TOL, weight_MD, weight_FA);
    [fMD_x2,fFA_x2,s_opt2] = golden_search_s_TIN(f, P, x2, s_start, s_end, TOL, weight_MD, weight_FA);
end

while ((abs(END_INT-START_INT)>TOL) && (k2<iter))
    if fMD_x1*weight_MD + fFA_x1*weight_FA < fMD_x2*weight_MD + fFA_x2*weight_FA %function smaller in x1 than in x2
        END_INT = x2; %make interval smaller
        x2 = x1; %set new end of interval
        x1 = START_INT+(1-tau)*(END_INT-START_INT); %find new beginning
        fMD_x2 = fMD_x1; %already have value in x1
        fFA_x2 = fFA_x1;
        s_opt2 = s_opt1;
        if normalApprox
            [fMD_x1,fFA_x1] = f(P,x1,1);    s_opt1 = 1;
        else
            [fMD_x1,fFA_x1,s_opt1] = golden_search_s_TIN(f, P, x1, s_start, s_end, TOL, weight_MD, weight_FA); %%compute new value for new beginning
        end
    else
        START_INT=x1; %function smaller in x2 than in x1 so set new start indx to x1
        x1 = x2; %replace as new start index
        x2=START_INT+tau*(END_INT-START_INT); %compute new end index
        fMD_x1= fMD_x2;
        fFA_x1 = fFA_x2;
        s_opt1 = s_opt2;
        if normalApprox
            [fMD_x2,fFA_x2] = f(P,x2,1);    s_opt2 = 1;
        else
            [fMD_x2,fFA_x2,s_opt2] = golden_search_s_TIN(f, P, x2, s_start, s_end, TOL, weight_MD, weight_FA);
        end
    end
    k2=k2+1;
end

if fMD_x1*weight_MD + fFA_x1*weight_FA < fMD_x2*weight_MD + fFA_x2*weight_FA 
    P1=x1;
    s_opt = s_opt1;
    rcu_MD = fMD_x1;
    rcu_FA = fFA_x1;
else
    P1=x2;
    s_opt = s_opt2;
    rcu_MD = fMD_x2;
    rcu_FA = fFA_x2;
end

end

%%
function [rcu_MD, rcu_FA, s_opt] = golden_search_s_TIN(f, P, P1, START_INT, END_INT, TOL, weight_MD, weight_FA)
% Optimize s

iter= 20;                       % maximum number of iterations
tau=double((sqrt(5)-1)/2);      % golden proportion coefficient, around 0.618
k2=0;                            % number of iterations
x1=START_INT+(1-tau)*(END_INT-START_INT);             % computing x values
x2=START_INT+tau*(END_INT-START_INT);

[fMD_x1,fFA_x1] = f(P,P1,x1);
[fMD_x2,fFA_x2] = f(P,P1,x2);

while ((abs(END_INT-START_INT)>TOL) && (k2<iter))
    if fMD_x1*weight_MD + fFA_x1*weight_FA < fMD_x2*weight_MD + fFA_x2*weight_FA %function smaller in x1 than in x2
        END_INT = x2; %make interval smaller
        x2 = x1; %set new end of interval
        x1 = START_INT+(1-tau)*(END_INT-START_INT); %find new beginning
        fMD_x2 = fMD_x1;%already have value in x1
        fFA_x2 = fFA_x1;
        [fMD_x1,fFA_x1] = f(P,P1,x1); %%compute new value for new beginning
    else
        START_INT=x1; %function smaller in x2 than in x1 so set new start indx to x1
        x1 = x2; %replace as new start index
        x2=START_INT+tau*(END_INT-START_INT); %compute new end index
        fMD_x1= fMD_x2;
        fFA_x1 = fFA_x2;
        [fMD_x2,fFA_x2] = f(P,P1,x2);
    end
    k2=k2+1;
end

if fMD_x1*weight_MD + fFA_x1*weight_FA < fMD_x2*weight_MD + fFA_x2*weight_FA 
    s_opt=x1;
    rcu_MD = fMD_x1;
    rcu_FA = fFA_x1;
else
    s_opt=x2;
    rcu_MD = fMD_x2;
    rcu_FA = fFA_x2;
end

end

标签:MD,Ka,Random,Multiple,epsilon,Unsourced,FA,P1,end
From: https://www.cnblogs.com/zhuxiaohuo/p/17889067.html

相关文章

  • KEILC51编译问题ERROR L104: MULTIPLE PUBLIC DEFINITIONS重复定义
    这个问题是keil中比较常见的,但对于很多新手比较头疼的像出现这种104的报错 出现上述错误则是因为函数Delay_ms重复定义,我们只需要把这个函数名改一个就OK了 我们可以把.c.h文件的Delay_ms改为Delay1_ms,在调用函数也改为Delay1_ms,然后编译就不会出错了。 ......
  • LPI-IBWA: Predicting lncRNA-protein interactions based on an improved Bi-Random
    LPI-IBWA:PredictinglncRNA-proteininteractionsbasedonanimprovedBi-RandomwalkalgorithmMinzhuXie 1, RuijieXie 2, HaoWang 3Affiliations expandPMID: 37972912 DOI: 10.1016/j.ymeth.2023.11.007 SigninAbstractManystudies......
  • [ARC165E] Random Isolation 题解
    题目链接点击打开链接题目解法略有些套路的概率题,不过中间的把操作序列看成排列的操作还是很妙的首先套路的考虑期望的线性性,有两个方式:把贡献放在点上或点集上,这里采用后面的方式做对于每一个树上的集合\(S\),假设大小为\(n\),相邻的点为\(m\)考虑这个集合独立的限制为:相......
  • B4185. LPI-IBWA:Predicting lncRNA-protein Interactions Based on Improved Bi-Ran
    B4185.LPI-IBWA:PredictinglncRNA-proteinInteractionsBasedonImprovedBi-RandomWalkAlgorithmMinzhuXie1,HaoWang1 andRuijieXi11HunanNormalUniversityAbstract:Manystudieshaveshownthatlong-chainnoncodingRNAs(lncRNAs)areinvolvedinav......
  • Tightly Secure Lattice Identity-Based Signature in the Quantum Random Oracle Mod
    Abstract.Wepresentaquantumlysecureidentity-basedsignatureschemebasedonthestandardshortintegersolutionproblem,featuringtightsecurityreductionsinthequantumandclassicrandomoraclemodels.Theschemehasshortsignatures.Eachsignat......
  • FPGA入门笔记007_A——按键消抖模块设计与验证(状态机、$random、仿真模型、task语法)
    实验现象:每次按下按键0,4个LED显示状态以二进制加法格式加1。每次按下按键1,4个LED显示状态以二进制加法格式减1。知识点:1、testbench中随机数发生函数$random的使用;2、仿真模型的概念1、按键波形分析:按键未按,FPGA管脚检测到高电平。按键按下,FPGA管脚检测到低电平。2、设......
  • C++随机数random库 介绍及应用
    一、摘要随机数可以应用在很多场景下如游戏抽卡、抽奖、场景生成、洗牌,歌曲app中的随机播放,社交app中的匹配等以及随机化算法。以下是针对C中随机函数rand、C++random库使用的总结,以及一些随机应用例子二、C/C++中的rand函数使用时需要引入头文件<stdlib.h>该函数返回一个......
  • java基础学习:random随机数,random案例
    1.Random使用步骤:  packagecom.itheima.Random;importjava.util.Random;publicclassRandom1{publicstaticvoidmain(String[]args){Randomrandom=newRandom();for(inti=1;i<=10;i++){intdata=random.nextInt(1......
  • [ABC277G] Random Walk to Millionaire 题解
    题目链接点击打开链接题目解法首先\(O(n^3)\)的\(dp\)是显然的,令\(f_{i,j,k}\)为第\(i\)步在\(j\),当前等级为\(k\)的\([i,n]\)步获得钱数的期望,转移枚举出边即可一个很妙的优化是:贡献都是\(k^2\)的形式,所以我们考虑维护\(k\)的\(0,1,2\)次幂,即\(\sum,\sum......
  • 神经网络入门篇:详解随机初始化(Random+Initialization)
    当训练神经网络时,权重随机初始化是很重要的。对于逻辑回归,把权重初始化为0当然也是可以的。但是对于一个神经网络,如果把权重或者参数都初始化为0,那么梯度下降将不会起作用。来看看这是为什么。有两个输入特征,\(n^{[0]}=2\),2个隐藏层单元\(n^{[1]}\)就等于2。因此与一个隐藏层......