├── .gitignore ├── Codes ├── CRC │ ├── crc_generator_matrix.m │ └── get_crc_objective.m ├── GA Functions │ ├── Capacity_Binary_AWGN.m │ ├── GA.m │ ├── accurate_phi.m │ ├── derivative_phi.m │ ├── get_PCi_vector.m │ ├── get_optimized_parameters.m │ ├── get_subchannel_capacity.m │ ├── main.m │ ├── phi.m │ └── phi_inverse.m ├── List Decoder Functions │ ├── calc_PM.m │ ├── conv1bTrans.m │ ├── convTrans.m │ ├── get_GN.m │ ├── get_bit_layer.m │ └── get_llr_layer.m ├── ffs.m ├── find_sMaxPos.m ├── generate_CS.m ├── get_BEC_ZWi.m ├── get_next_state.m ├── m_func.m ├── paccode.m └── smax.m ├── PPV Bound ├── converse_mc.m └── example_per.m ├── README.md ├── draw.m ├── results ├── 128-64-GA2dB-SCL32.mat ├── 128-64-RM-C8ASCL256.mat ├── 128-64-RM-SCL256.mat ├── 128-64-RM-SCL32.mat ├── PAC_2022-05-11-14-23.mat ├── PAC_2022-05-11-15-41.mat ├── PAC_2022-05-26-16-54.mat ├── PAC_2022-06-06-01-35.mat └── PPVBound-128-64.mat ├── simulation.m ├── test.m └── test_viterbi.m /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | test.asv 3 | *.asv 4 | *.mat 5 | draw.m 6 | -------------------------------------------------------------------------------- /Codes/CRC/crc_generator_matrix.m: -------------------------------------------------------------------------------- 1 | function [G, H] = crc_generator_matrix(g, K) 2 | % [1 1 1 0 1 0 1 0 1] can be used for test 3 | r = length(g) - 1; 4 | N = K + r; 5 | zero_fill = zeros(1, K-1); 6 | G = zeros(K, N); 7 | G(end, :) = [zero_fill, g]; 8 | for i = K - 1:-1:1 9 | G(i, :) = [G(i + 1, 2 : end), G(i + 1, 1)]; 10 | end 11 | for i = K - 1:-1:1 12 | for j = N - r:-1:i + 1 13 | if G(i, j) == 1 14 | G(i, :) = mod(G(i, :)+G(j, :), 2); 15 | end 16 | end 17 | end 18 | H = zeros(r, N); 19 | H(:, 1:K) = G(:, K+1:end)'; 20 | H(:, K+1:end) = eye(r); -------------------------------------------------------------------------------- /Codes/CRC/get_crc_objective.m: -------------------------------------------------------------------------------- 1 | function [gen, det, g] = get_crc_objective(crc_length) 2 | switch crc_length 3 | case 4 4 | gen = comm.CRCGenerator('Polynomial', [1, 0, 0, 1, 1], 'InitialConditions', zeros(1, 4), 'FinalXOR', zeros(1, 4)); 5 | det = comm.CRCDetector('Polynomial', [1, 0, 0, 1, 1], 'InitialConditions', zeros(1, 4), 'FinalXOR', zeros(1, 4)); 6 | g = [1, 0, 0, 1, 1]; 7 | case 6 8 | gen = comm.CRCGenerator('Polynomial', [1, 0, 0, 0, 0, 1, 1], 'InitialConditions', zeros(1, 6), 'FinalXOR', zeros(1, 6)); 9 | det = comm.CRCDetector('Polynomial', [1, 0, 0, 0, 0, 1, 1], 'InitialConditions', zeros(1, 6), 'FinalXOR', zeros(1, 6)); 10 | g = [1, 0, 0, 0, 0, 1, 1]; 11 | case 8 12 | gen = comm.CRCGenerator('Polynomial', '0xA6', 'InitialConditions', '0x00', 'FinalXOR', '0x00'); 13 | det = comm.CRCDetector('Polynomial', '0xA6', 'InitialConditions', '0x00', 'FinalXOR', '0x00'); 14 | % g = [1 0 1 0 0 1 1 0 1]; 15 | g = [1, 1, 1, 1, 1, 1, 0, 0, 1]; 16 | case 10 17 | gen = comm.CRCGenerator('Polynomial', [1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1], 'InitialConditions', zeros(1, 10), 'FinalXOR', zeros(1, 10)); 18 | det = comm.CRCDetector('Polynomial', [1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1], 'InitialConditions', zeros(1, 10), 'FinalXOR', zeros(1, 10)); 19 | g = [1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1]; 20 | case 12 21 | gen = comm.CRCGenerator('Polynomial', [1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1], 'InitialConditions', zeros(1, 12), 'FinalXOR', zeros(1, 12)); 22 | det = comm.CRCDetector('Polynomial', [1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1], 'InitialConditions', zeros(1, 12), 'FinalXOR', zeros(1, 12)); 23 | g = [1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1]; 24 | case 16 25 | gen = comm.CRCGenerator('Polynomial', [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1], 'InitialConditions', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'FinalXOR', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); 26 | det = comm.CRCDetector('Polynomial', [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1], 'InitialConditions', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'FinalXOR', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); 27 | g = [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1]; 28 | case 24 29 | gen = comm.CRCGenerator('Polynomial', [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1], 'InitialConditions', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ... 30 | 'FinalXOR', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); 31 | det = comm.CRCDetector('Polynomial', [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1], 'InitialConditions', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ... 32 | 'FinalXOR', [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); 33 | g = [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1]; 34 | otherwise 35 | disp('Unsupported CRC length. Program terminates') 36 | end -------------------------------------------------------------------------------- /Codes/GA Functions/Capacity_Binary_AWGN.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barryu9/PAC-codes/2077246aa6324d0862ada884953fe8ed7f72d203/Codes/GA Functions/Capacity_Binary_AWGN.m -------------------------------------------------------------------------------- /Codes/GA Functions/GA.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barryu9/PAC-codes/2077246aa6324d0862ada884953fe8ed7f72d203/Codes/GA Functions/GA.m -------------------------------------------------------------------------------- /Codes/GA Functions/accurate_phi.m: -------------------------------------------------------------------------------- 1 | function z = accurate_phi(x) 2 | f = @(u, x) (exp(u) - 1) ./ (exp(u) + 1) .* exp(-(u - x).^2./4./x); 3 | z = integral(@(u) f(u, x), -100, 100); 4 | z = 1 - 1 / sqrt(4*pi*x) * z; 5 | end -------------------------------------------------------------------------------- /Codes/GA Functions/derivative_phi.m: -------------------------------------------------------------------------------- 1 | function dx = derivative_phi(x) 2 | if (x >= 0) && (x <= 10) 3 | dx = -0.4527 * 0.86 * x^(-0.14) * phi(x); 4 | else 5 | dx = exp(-x/4) * sqrt(pi/x) * (-1 / 2 / x * (1 - 10 / 7 / x) - 1 / 4 * (1 - 10 / 7 / x) + 10 / 7 / x / x); 6 | end 7 | end -------------------------------------------------------------------------------- /Codes/GA Functions/get_PCi_vector.m: -------------------------------------------------------------------------------- 1 | function PCi = get_PCi_vector(ELNi) 2 | PCi = zeros(length(ELNi), 1); 3 | for i = 1:length(ELNi) 4 | PCi(i) = 0.5 * erfc(0.5*sqrt(ELNi(i))); 5 | end 6 | end -------------------------------------------------------------------------------- /Codes/GA Functions/get_optimized_parameters.m: -------------------------------------------------------------------------------- 1 | xdata = 1:10; 2 | ydata = zeros(1, length(xdata)); 3 | for i = 1:length(xdata) 4 | ydata(i) = accurate_phi(xdata(i)); 5 | end 6 | % p = lsqcurvefit(@(p, xdata) exp(p(1) .* xdata.^p(2) + p(3)), [2 7], xdata, ydata); 7 | fun = @(p) exp(p(1).*xdata.^p(2)+p(3)) - ydata; 8 | p0 = [1, 0.5, 1]; 9 | options = optimoptions('lsqnonlin', 'Display', 'iter'); 10 | p = lsqnonlin(fun, p0, [], [], options); 11 | pl = plot(xdata, [ydata; exp(p(1).*xdata.^p(2)+p(3))]); 12 | pl(1).Marker = 'd'; 13 | p1(2).Marker = '^'; -------------------------------------------------------------------------------- /Codes/GA Functions/get_subchannel_capacity.m: -------------------------------------------------------------------------------- 1 | function cap_vec = get_subchannel_capacity(u) 2 | cap_vec = zeros(1, length(u)); 3 | for i = 1:length(u) 4 | cap_vec(i) = Capacity_Binary_AWGN(u(i), sqrt(2*u(i))); 5 | end 6 | end -------------------------------------------------------------------------------- /Codes/GA Functions/main.m: -------------------------------------------------------------------------------- 1 | %rewrite Gauss Approximation for PolarCode construction 2 | %more accurate and easier to read and much quicker 3 | %GA for BPSK-AWGN BPSK = [1 -1] 4 | %such that y = bpsk + noise, llr = 2y/sigma^2 subjects to N(2/sigma^2, 4/sigma^2) when zero 5 | %code word is transmitted 6 | EbN0 = 1; 7 | R = 0.5; 8 | sigma = sqrt(1/2/R) * 10^(-EbN0 / 20); 9 | n = 10; 10 | N = 2^n; 11 | tic 12 | u = GA(sigma, N); %u is the mean value vector for subchannels after the wohle polarization process 13 | toc 14 | % cap_vec = get_subchannel_capacity(u); 15 | % ber_vec = get_PCi_vector(u); 16 | % u 17 | % cap_vec 18 | % ber_vec 19 | -------------------------------------------------------------------------------- /Codes/GA Functions/phi.m: -------------------------------------------------------------------------------- 1 | function y = phi(x) 2 | if (x >= 0) && (x <= 10) 3 | y = exp(-0.4527*x^0.859+0.0218); 4 | else 5 | y = sqrt(pi/x) * exp(-x/4) * (1 - 10 / 7 / x); 6 | end -------------------------------------------------------------------------------- /Codes/GA Functions/phi_inverse.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barryu9/PAC-codes/2077246aa6324d0862ada884953fe8ed7f72d203/Codes/GA Functions/phi_inverse.m -------------------------------------------------------------------------------- /Codes/List Decoder Functions/calc_PM.m: -------------------------------------------------------------------------------- 1 | function PM = calc_PM(PM,llr,u) 2 | if(u~=0.5*(1-sign(llr))) 3 | PM=PM+abs(llr); 4 | end 5 | 6 | end 7 | 8 | -------------------------------------------------------------------------------- /Codes/List Decoder Functions/conv1bTrans.m: -------------------------------------------------------------------------------- 1 | function [u,next_state] = conv1bTrans(v,curr_state,c) 2 | u=mod(v*c(1),2); 3 | for j=2:length(c) 4 | if(c(j)==1) 5 | u=mod(u+curr_state(j-1),2); 6 | end 7 | end 8 | next_state=[v;curr_state(1:end-1)]; 9 | end -------------------------------------------------------------------------------- /Codes/List Decoder Functions/convTrans.m: -------------------------------------------------------------------------------- 1 | function u = convTrans(v,c) 2 | u=zeros(1,length(v)); 3 | curr_state = zeros(1,length(c)-1); 4 | for i = 1:length(v) 5 | [u(i),curr_state]=conv1bTrans(v(i),curr_state,c); 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /Codes/List Decoder Functions/get_GN.m: -------------------------------------------------------------------------------- 1 | function P = get_GN(N) 2 | F = [1, 0 ; 1, 1]; 3 | P = zeros(N, N); 4 | P(1 : 2, 1 : 2) = F; 5 | for i = 2 : log2(N) 6 | P(1 : 2^i, 1 : 2^i) = kron(P(1 : 2^(i - 1), 1 : 2^(i - 1)), F); 7 | end 8 | -------------------------------------------------------------------------------- /Codes/List Decoder Functions/get_bit_layer.m: -------------------------------------------------------------------------------- 1 | function layer_vec = get_bit_layer(N) 2 | layer_vec = zeros(N, 1); 3 | for phi = 0 : N - 1 4 | psi = floor(phi/2); 5 | layer = 0; 6 | while(mod(psi, 2) == 1) 7 | psi = floor(psi/2); 8 | layer = layer + 1; 9 | end 10 | layer_vec(phi + 1) = layer; 11 | end 12 | end -------------------------------------------------------------------------------- /Codes/List Decoder Functions/get_llr_layer.m: -------------------------------------------------------------------------------- 1 | function layer_vec = get_llr_layer(N) 2 | layer_vec = zeros(N , 1); 3 | for phi = 1 : N - 1 4 | psi = phi; 5 | layer = 0; 6 | while(mod(psi, 2) == 0) 7 | psi = floor(psi/2); 8 | layer = layer + 1; 9 | end 10 | layer_vec(phi + 1) = layer; 11 | end 12 | end -------------------------------------------------------------------------------- /Codes/ffs.m: -------------------------------------------------------------------------------- 1 | function location = ffs(i, n) 2 | if i == 0 3 | location = n - 1; 4 | return 5 | end 6 | bin = abs(dec2bin(i, n)) - 48; 7 | location = 0; 8 | for j = length(bin):-1:1 9 | if (bin(j) == 1) 10 | return; 11 | end 12 | location = location + 1; 13 | end 14 | end -------------------------------------------------------------------------------- /Codes/find_sMaxPos.m: -------------------------------------------------------------------------------- 1 | function i_minus1 = find_sMaxPos(s_start, s_max, i_minus1, n) 2 | ss = s_start; 3 | while ss < s_max 4 | i_minus1 = i_minus1 - 2; 5 | if i_minus1 > 0 6 | ss = ffs(i_minus1, n); 7 | else 8 | ss = n; 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /Codes/generate_CS.m: -------------------------------------------------------------------------------- 1 | function CS_logical = generate_CS(rate_profiling, n) 2 | info_bits = zeros(1, 2^n); 3 | info_bits(rate_profiling) = 1; 4 | info_bits = logical(info_bits); 5 | 6 | B = -1 * ones(n+1, 2^n); 7 | cnt = 1; 8 | for k = 1:2^n 9 | B(n+1, k) = 0; 10 | if (info_bits(k) == 0) 11 | B(n+1, k) = 1; 12 | end 13 | end 14 | 15 | for i = n:-1:1 16 | for j = 1:2^(i - 1) 17 | B(i, j) = B(i+1, 2*j-1) + B(i+1, 2*j); 18 | end 19 | end 20 | 21 | for i = 1:n + 1 22 | for j = 1:2^(i - 1) 23 | x1 = j; 24 | x2 = j; 25 | if (B(i, j) == 0) 26 | for k = 1:(n + 1) - i 27 | x1 = 2 * x1 - 1; 28 | x2 = 2 * x2; 29 | for p = x1:x2 30 | B(i+k, p) = -1; 31 | end 32 | end 33 | CS(cnt) = x1; 34 | cnt = cnt + 1; 35 | end 36 | end 37 | end 38 | 39 | CS_logical = zeros(1, 2^n); 40 | CS_logical(CS) = 1; 41 | 42 | end 43 | -------------------------------------------------------------------------------- /Codes/get_BEC_ZWi.m: -------------------------------------------------------------------------------- 1 | function ZWi = get_BEC_ZWi(N, ZW) 2 | ZWi = zeros(N, 1); 3 | ZWi(1) = ZW; 4 | m = 1; 5 | while (m <= N/2) 6 | for k = 1:m 7 | Z_tmp = ZWi(k); 8 | ZWi(k) = 2 * Z_tmp - Z_tmp^2; %use upper bound 9 | ZWi(k+m) = Z_tmp^2; 10 | end 11 | m = m * 2; 12 | end 13 | ZWi = bitrevorder(ZWi); %perform bit-reversal order. -------------------------------------------------------------------------------- /Codes/get_next_state.m: -------------------------------------------------------------------------------- 1 | function next_state = get_next_state(input_bit,cur_state) 2 | next_state = [input_bit;cur_state(1:end-1)]; 3 | end 4 | 5 | -------------------------------------------------------------------------------- /Codes/m_func.m: -------------------------------------------------------------------------------- 1 | function m = m_func(lambda_0, u) 2 | m = -log2(1+exp(-(1 - 2 * u)*lambda_0)); 3 | % if(u==0.5*(1-sign(lambda_0))) 4 | % m = abs(lambda_0); 5 | % else 6 | % m = 0; 7 | % end 8 | end -------------------------------------------------------------------------------- /Codes/paccode.m: -------------------------------------------------------------------------------- 1 | classdef paccode 2 | %PACCODE 定义一个paccode类 3 | properties 4 | code_length %码长 5 | information_length %信息长度 6 | gen %卷积生成序列 7 | rate %码率 8 | rate_profiling %码率分布 9 | conv_depth %卷积深度 10 | GN %极化矩阵 11 | convolution_matrix %卷积矩阵 12 | lambda_offset %列表译码相关参数-'分段向量' 13 | llr_layer_vec %列表译码相关参数-'实际LLR计算执行层数' 14 | bit_layer_vec %列表译码相关参数-'实际比特返回层数' 15 | crc_length 16 | crc_parity_check 17 | H_crc 18 | llr 19 | end 20 | 21 | methods 22 | function obj = paccode(N, k, g, crc_length, rate_profiling, varargin) 23 | %PACCODE 构造此类的实例 24 | n = ceil(log2(N)); 25 | N = 2^n; 26 | 27 | obj.code_length = N; 28 | obj.information_length = k; 29 | obj.gen = g; 30 | obj.rate = k / N; 31 | 32 | obj.crc_length = crc_length; 33 | obj.conv_depth = length(g); 34 | global operation_count_C; 35 | global operation_count_P; 36 | 37 | if (strcmp(rate_profiling, 'RM')) 38 | obj.rate_profiling = RM_rate_profiling(obj); 39 | elseif (strcmp(rate_profiling, 'GA')) 40 | if (size(varargin, 2) > 0) 41 | dsnr = varargin{1}; 42 | obj.rate_profiling = GA_rate_profiling(obj, dsnr); 43 | else 44 | error('You should input the design snr (dB).') 45 | end 46 | elseif (strcmp(rate_profiling, 'RM-Polar')) 47 | if (size(varargin, 2) > 0) 48 | dsnr = varargin{1}; 49 | obj.rate_profiling = RM_Polar_rate_profiling(obj, dsnr); 50 | else 51 | error('You should input the design snr (dB).') 52 | end 53 | else 54 | error('Cannot find this rate profiling method.') 55 | end 56 | 57 | obj.GN = get_GN(obj.code_length); 58 | g_zp = [obj.gen, zeros(1, obj.code_length-obj.conv_depth)]; 59 | obj.convolution_matrix = triu(toeplitz(g_zp)); %upper-triangular Toeplitz matrix 60 | 61 | obj.lambda_offset = 2.^(0:n); 62 | obj.llr_layer_vec = get_llr_layer(N); 63 | obj.bit_layer_vec = get_bit_layer(N); 64 | 65 | if (crc_length > 0) 66 | [~, ~, g_crc] = get_crc_objective(crc_length); 67 | [G_crc, obj.H_crc] = crc_generator_matrix(g_crc, k); 68 | obj.crc_parity_check = G_crc(:, k+1:end)'; 69 | end 70 | 71 | 72 | end 73 | 74 | function info_indices = RM_rate_profiling(obj) 75 | %RM_rate_profiling RM码率分配 76 | %根据信道序号对应的二进制表示中'1'的个数进行排序,从高到低选出信息信道 77 | Channel_indices = (0:obj.code_length - 1)'; 78 | bitStr = dec2bin(Channel_indices); 79 | bit = abs(bitStr) - 48; 80 | RM_score = sum(bit, 2); 81 | [~, sorted_indices] = sort(RM_score, 'ascend'); 82 | info_indices = sort(sorted_indices(end-(obj.information_length + obj.crc_length)+1:end), 'ascend'); 83 | end 84 | 85 | function [info_indices,info_indices_revorder] = RM_Polar_rate_profiling(obj, dsnr) 86 | %RM_Polar_rate_profiling RM-Polar码率构造 87 | %使用GA算法辅助,也可以使用BEC巴氏参数等效法 88 | %dsnr是GA的design snr(以dB为单位) 89 | n = log2(obj.code_length); 90 | Channel_indices = (0:obj.code_length - 1)'; 91 | bitStr = dec2bin(Channel_indices); 92 | bit = abs(bitStr) - 48; 93 | RM_score = sum(bit, 2); 94 | sigma = 1 / sqrt(2*obj.rate) * 10^(-dsnr / 20); 95 | [channel_score, ~] = GA(sigma, obj.code_length); 96 | mask = zeros(obj.code_length, 4); 97 | for i = 1:obj.code_length 98 | mask(i, :) = [i - 1, RM_score(i), channel_score(i), 1]; 99 | end 100 | weightCount = zeros(n+1, 1); 101 | for i = 1:obj.code_length 102 | weightCount(RM_score(i)+1) = weightCount(RM_score(i)+1) + 1; 103 | end 104 | bitCnt = 0; 105 | k = 1; 106 | while bitCnt + weightCount(k) <= obj.code_length - (obj.information_length + obj.crc_length) 107 | for i = 1:obj.code_length 108 | if RM_score(i) == k - 1 109 | mask(i, 4) = 0; 110 | bitCnt = bitCnt + 1; 111 | end 112 | end 113 | k = k + 1; 114 | end 115 | mask2 = []; 116 | for i = 1:obj.code_length 117 | if mask(i, 2) == k - 1 118 | mask2 = [mask2; mask(i, :)]; 119 | end 120 | end 121 | [~, mask2_sorted_indices] = sort(mask2(:, 3), 'ascend'); 122 | mask2 = mask2(mask2_sorted_indices, :); 123 | remainder = obj.code_length - (obj.information_length + obj.crc_length) - bitCnt; 124 | for i = 1:remainder 125 | mask(mask2(i, 1)+1, 4) = 0; 126 | end 127 | acceptable_bits = logical(mask(:, 4)); 128 | % acceptable_bits=bitrevorder(acceptable_bits); 129 | mask3 = mask(acceptable_bits,:); 130 | [~, mask3_sorted_indices] = sort(mask3(:, 2), 'descend'); 131 | mask3 = mask3(mask3_sorted_indices, :); 132 | mask3(1:obj.information_length + obj.crc_length,1)=bitrevorder(mask3(1:obj.information_length + obj.crc_length,1)); 133 | info_indices = sort(mask3(1:obj.information_length + obj.crc_length,1), 'ascend')' + 1; 134 | 135 | end 136 | 137 | function [info_indices,info_indices_revorder] = GA_rate_profiling(obj, dsnr) 138 | %GA_rate_profiling GA码率分配 139 | %dsnr是GA的design snr(以dB为单位) 140 | sigma = 1 / sqrt(2*obj.rate) * 10^(-dsnr / 20); 141 | [channels, ~] = GA(sigma, obj.code_length); 142 | [~, channel_ordered] = sort(channels, 'descend'); 143 | info_indices = sort(channel_ordered(1:obj.information_length+obj.crc_length), 'ascend'); 144 | end 145 | 146 | function [Pe] = get_PE_GA(obj, dsnr) 147 | %get_PE_GA 获取各子信道错误概率 148 | %使用GA估计各子信道的错误概率,Fano译码器中使用 149 | %dsnr是GA的design snr(以dB为单位) 150 | sigma = 1 / sqrt(2*obj.rate) * 10^(-dsnr / 20); 151 | [channels, ~] = GA(sigma, obj.code_length); 152 | Pe = 1 / 2 * erfc(0.5*sqrt(channels)); 153 | end 154 | 155 | function x = encode(obj, d) 156 | %encode PAC编码 157 | %将输入的源信息d编码成PAC码 158 | if (length(d) ~= obj.information_length) 159 | error('The length of the input d is not equal to k.') 160 | end 161 | % Rate Profile 162 | if (obj.crc_length > 0) 163 | info_with_crc = [d; mod(obj.crc_parity_check*d, 2)]; 164 | else 165 | info_with_crc = d; 166 | end 167 | v = zeros(1, obj.code_length); 168 | v(obj.rate_profiling) = info_with_crc; 169 | % convolutional encoder 170 | u = mod(v*obj.convolution_matrix, 2); 171 | % Polar Encoding 172 | x = mod(u*obj.GN, 2)'; 173 | end 174 | 175 | function d_esti = SCL_decoder(obj, llr, L) 176 | %LLR-based SCL deocoder, a single function, no other sub-functions. 177 | %Frequently calling sub-functions will derease the efficiency of MATLAB 178 | %codes. 179 | %const 180 | N = obj.code_length; 181 | K = obj.information_length; 182 | g = obj.gen; 183 | obj.llr = llr; 184 | frozen_bits = ones(1, N); 185 | frozen_bits(obj.rate_profiling) = 0; 186 | %memory declared 187 | %If you can understand lazy copy and you just start learning polar codes 188 | %for just fews days, you are very clever, 189 | P = zeros(N - 1, L); %Channel llr is public-used, so N - 1 is enough. 190 | C = zeros(N - 1, 2 * L); %I do not esitimate (x1, x2, ... , xN), so N - 1 is enough. 191 | d = zeros(K, L); %unfrozen bits that polar codes carry, including crc bits. 192 | PM = zeros(L, 1); %Path metrics 193 | activepath = zeros(L, 1); %Indicate if the path is active. '1'→active; '0' otherwise. 194 | cnt_u = 1; %information bit counter 195 | %initialize 196 | activepath(1) = 1; 197 | %decoding starts 198 | %default: in the case of path clone, the origianl path always corresponds to bit 0, while the new path bit 1. 199 | curr_state = zeros(obj.conv_depth-1, L); 200 | curr_state_temp = zeros(obj.conv_depth-1, L); 201 | u_left = zeros(1, L); 202 | u_right = zeros(1, L); 203 | for phi = 0:N - 1 204 | for l_index = 1:L 205 | if activepath(l_index) == 0 206 | continue; 207 | end 208 | P(:, l_index) = update_P(obj, phi, P(:, l_index), C(:, 2*l_index-1:2*l_index)); 209 | end 210 | if frozen_bits(phi + 1) == 0 %if now we decode an unfrozen bit 211 | PM_pair = realmax * ones(2, L); 212 | for l_index = 1:L 213 | if activepath(l_index) == 0 214 | continue; 215 | end 216 | curr_state_temp(:, l_index) = curr_state(:, l_index); 217 | [u_left(l_index), curr_state(:, l_index)] = conv1bTrans(0, curr_state(:, l_index), g); 218 | [u_right(l_index), curr_state_temp(:, l_index)] = conv1bTrans(1, curr_state_temp(:, l_index), g); 219 | PM_pair(1, l_index) = calc_PM(PM(l_index), P(1, l_index), u_left(l_index)); 220 | PM_pair(2, l_index) = calc_PM(PM(l_index), P(1, l_index), u_right(l_index)); 221 | end 222 | middle = min(2*sum(activepath), L); 223 | PM_sort = sort(PM_pair(:)); 224 | PM_cv = PM_sort(middle); 225 | compare = PM_pair <= PM_cv; 226 | kill_index = zeros(L, 1); %to record the index of the path that is killed 227 | kill_cnt = 0; %the total number of killed path 228 | %the above two variables consist of a stack 229 | for i = 1:L 230 | if (compare(1, i) == 0) && (compare(2, i) == 0) %which indicates that this path should be killed 231 | activepath(i) = 0; 232 | kill_cnt = kill_cnt + 1; %push stack 233 | kill_index(kill_cnt) = i; 234 | end 235 | end 236 | for l_index = 1:L 237 | if activepath(l_index) == 0 238 | continue; 239 | end 240 | path_state = compare(1, l_index) * 2 + compare(2, l_index); 241 | switch path_state %path_state can equal to 0, but in this case we do no operation. 242 | case 1 % PM of the second row is lower 243 | d(cnt_u, l_index) = 1; 244 | C(:, 2*l_index-1:2*l_index) = update_C(obj, phi, C(:, 2*l_index-1:2*l_index), u_right(l_index)); 245 | PM(l_index) = PM_pair(2, l_index); 246 | curr_state(:, l_index) = curr_state_temp(:, l_index); 247 | case 2 % PM of the first row is lower 248 | d(cnt_u, l_index) = 0; 249 | C(:, 2*l_index-1:2*l_index) = update_C(obj, phi, C(:, 2*l_index-1:2*l_index), u_left(l_index)); 250 | PM(l_index) = PM_pair(1, l_index); 251 | case 3 % 252 | index = kill_index(kill_cnt); 253 | kill_cnt = kill_cnt - 1; %pop stack 254 | activepath(index) = 1; 255 | %lazy copy 256 | C(:, 2*index-1:2*index) = C(:, 2*l_index-1:2*l_index); 257 | P(:, index) = P(:, l_index); 258 | d(:, index) = d(:, l_index); 259 | curr_state(:, index) = curr_state_temp(:, l_index); 260 | d(cnt_u, l_index) = 0; 261 | d(cnt_u, index) = 1; 262 | C(:, 2*l_index-1:2*l_index) = update_C(obj, phi, C(:, 2*l_index-1:2*l_index), u_left(l_index)); 263 | C(:, 2*index-1:2*index) = update_C(obj, phi, C(:, 2*index-1:2*index), u_right(l_index)); 264 | PM(l_index) = PM_pair(1, l_index); 265 | PM(index) = PM_pair(2, l_index); 266 | end 267 | end 268 | cnt_u = cnt_u + 1; 269 | else %frozen bit operation 270 | for l_index = 1:L 271 | if activepath(l_index) == 0 272 | continue; 273 | end 274 | [u_temp, curr_state(:, l_index)] = conv1bTrans(0, curr_state(:, l_index), g); 275 | PM(l_index) = calc_PM(PM(l_index), P(1, l_index), u_temp); 276 | C(:, 2*l_index-1:2*l_index) = update_C(obj, phi, C(:, 2*l_index-1:2*l_index), u_temp); 277 | 278 | end 279 | end 280 | 281 | 282 | end 283 | %path selection. 284 | activepath = logical(activepath); 285 | PM_active = PM(activepath); 286 | d_active = d(:, activepath); 287 | [~, path_ordered] = sort(PM_active); 288 | if (obj.crc_length > 0) 289 | for l_index = 1:length(PM_active) 290 | path_num = path_ordered(l_index); 291 | info_with_crc = d(:, path_num); 292 | err = sum(mod(obj.H_crc*info_with_crc, 2)); 293 | if err == 0 294 | d_esti = d_active(1:end-obj.crc_length, path_num); 295 | break; 296 | else 297 | if l_index == length(PM_active) 298 | d_esti = d_active(1:end-obj.crc_length, path_ordered(1)); 299 | end 300 | end 301 | end 302 | else 303 | d_esti = d_active(1:end-obj.crc_length, path_ordered(1)); 304 | end 305 | end 306 | 307 | function [d_esti] = Fano_decoder(obj, llr, pe, Delta) 308 | % Init; 309 | c_state = zeros(obj.conv_depth-1, 1); 310 | curr_state = zeros(obj.conv_depth-1, obj.information_length); %0~k-1,1:|g|-1; 311 | i = 0; 312 | j = 0; 313 | obj.llr = llr; 314 | Threshold = 0; 315 | P = zeros(obj.code_length-1, 1); 316 | C = zeros(obj.code_length-1, 2); 317 | B = sum(log2(1-pe)); 318 | alphaq = 1; 319 | info_set = obj.rate_profiling; 320 | frozen_bits = ones(1, obj.code_length); 321 | frozen_bits(info_set) = 0; 322 | delta = zeros(obj.information_length, 1); 323 | mu = zeros(obj.code_length, 1); 324 | bmetric = zeros(obj.information_length, 1); 325 | bmetric_cut = zeros(obj.information_length, 1); 326 | u_esti = zeros(obj.code_length, 1); 327 | v_esti = zeros(obj.code_length, 1); 328 | visited_before = false; 329 | %while not end of tree do 330 | while i < obj.code_length 331 | P = update_P(obj, i, P, C); 332 | if frozen_bits(i+1) == 1 333 | [u_esti(i+1), c_state] = conv1bTrans(0, c_state, obj.gen); 334 | if i == 0 335 | mu(i+1) = B + m_func(P(1), u_esti(i+1)) - alphaq * log2(1-pe(i+1)); 336 | else 337 | mu(i+1) = mu(i) + m_func(P(1), u_esti(i+1)) - alphaq * log2(1-pe(i+1)); 338 | end 339 | curr_state(:, j+1) = c_state; 340 | C = update_C(obj, i, C, u_esti(i+1)); 341 | i = i + 1; 342 | else 343 | 344 | % look forward to best node 345 | [u_left, c_state_left] = conv1bTrans(0, c_state, obj.gen); 346 | [u_right, c_state_right] = conv1bTrans(1, c_state, obj.gen); 347 | if i == 0 348 | mu_left = B + m_func(P(1), u_left) - alphaq * log2(1-pe(i+1)); 349 | mu_right = B + m_func(P(1), u_right) - alphaq * log2(1-pe(i+1)); 350 | else 351 | mu_left = mu(i) + m_func(P(1), u_left) - alphaq * log2(1-pe(i+1)); 352 | mu_right = mu(i) + m_func(P(1), u_right) - alphaq * log2(1-pe(i+1)); 353 | end 354 | if mu_left > mu_right 355 | mu_max = mu_left; 356 | mu_min = mu_right; 357 | 358 | else 359 | mu_max = mu_right; 360 | mu_min = mu_left; 361 | end 362 | 363 | if mu_max >= Threshold 364 | if visited_before == false 365 | if mu_left > mu_right 366 | v_esti(i+1) = 0; 367 | u_esti(i+1) = u_left; 368 | else 369 | v_esti(i+1) = 1; 370 | u_esti(i+1) = u_right; 371 | end 372 | bmetric(j+1) = mu_max; 373 | bmetric_cut(j+1) = mu_min; 374 | mu(i+1) = mu_max; 375 | delta(j+1) = 0; 376 | C = update_C(obj, i, C, u_esti(i+1)); 377 | curr_state(:, j+1) = c_state; 378 | if (v_esti(i+1) == 0) 379 | c_state = c_state_left; 380 | else 381 | c_state = c_state_right; 382 | end 383 | i = i + 1; 384 | j = j + 1; 385 | else 386 | if mu_min > Threshold 387 | if mu_left < mu_right 388 | v_esti(i+1) = 0; 389 | u_esti(i+1) = u_left; 390 | else 391 | v_esti(i+1) = 1; 392 | u_esti(i+1) = u_right; 393 | end 394 | bmetric(j+1) = mu_min; 395 | bmetric_cut(j+1) = mu_max; 396 | mu(i+1) = mu_min; 397 | C = update_C(obj, i, C, u_esti(i+1)); 398 | curr_state(:, j+1) = c_state; 399 | if (v_esti(i+1) == 0) 400 | c_state = c_state_left; 401 | else 402 | c_state = c_state_right; 403 | end 404 | delta(j+1) = 1; 405 | i = i + 1; 406 | j = j + 1; 407 | visited_before = false; 408 | else 409 | if j == 0 410 | Threshold = Threshold - Delta; 411 | visited_before = false; 412 | else 413 | curr_state(:, j+1) = c_state; 414 | [Threshold, j, visited_before, P, C] = moveback(obj, bmetric, bmetric_cut, j, Threshold, delta, u_esti, P, C, llr, Delta); 415 | if j == 0 416 | c_state = zeros(obj.conv_depth-1, 1); 417 | else 418 | c_state = curr_state(:, j+1); 419 | end 420 | i = obj.rate_profiling(j+1) - 1; 421 | end 422 | end 423 | end 424 | else 425 | if j == 0 426 | while mu_max < Threshold 427 | Threshold = Threshold - Delta; 428 | end 429 | visited_before = false; 430 | else 431 | curr_state(:, j+1) = c_state; 432 | [Threshold, j, visited_before, P, C] = moveback(obj, bmetric, bmetric_cut, j, Threshold, delta, u_esti, P, C, llr, Delta); 433 | if j == 0 434 | c_state = zeros(obj.conv_depth-1, 1); 435 | else 436 | c_state = curr_state(:, j+1); 437 | end 438 | i = obj.rate_profiling(j+1) - 1; 439 | end 440 | end 441 | end 442 | end 443 | d_esti = v_esti(info_set); 444 | end 445 | 446 | function [Threshold, jj, visited_before, P, C] = moveback(obj, bmetric, bmetric_cut, j, Threshold, delta, u_esti, P, C, llr, Delta) 447 | while 1 448 | follow_other_branch = false; 449 | if j >= 1 450 | mu_pre = bmetric(j); 451 | else 452 | mu_pre = 0; 453 | end 454 | 455 | jj = j; 456 | for k = j - 1:-1:0 457 | mu_pre = bmetric(k+1); 458 | if mu_pre >= Threshold 459 | if bmetric_cut(k+1) >= Threshold 460 | jj = k; 461 | tmp = bmetric(k+1); 462 | bmetric(k+1) = bmetric_cut(k+1); 463 | bmetric_cut(k+1) = tmp; 464 | if delta(k+1) == 0 465 | follow_other_branch = true; 466 | break; 467 | elseif k == 0 468 | follow_other_branch = true; 469 | jj = 0; 470 | break; 471 | end 472 | end 473 | end 474 | if k == 0 475 | mu_pre = -100; 476 | end 477 | end 478 | 479 | i_cur = obj.rate_profiling(j+1) - 1; 480 | if (mu_pre >= Threshold) && (jj ~= 0 || follow_other_branch == true) 481 | i_start = obj.rate_profiling(jj+1) - 1; 482 | [P, C] = updateLLRsPSs(obj, i_start, i_cur, u_esti, P, C); 483 | 484 | if delta(jj+1) == 0 485 | visited_before = true; 486 | return; 487 | elseif jj == 0 488 | Threshold = Threshold - Delta; 489 | visited_before = false; 490 | return; 491 | end 492 | else 493 | Threshold = Threshold - Delta; 494 | visited_before = false; 495 | jj = j; 496 | return; 497 | end 498 | end 499 | 500 | end 501 | 502 | function [P, C] = updateLLRsPSs(obj, i_start, i_cur, u_esti, P, C) 503 | n = log2(obj.code_length); 504 | if mod(i_cur, 2) ~= 0 505 | i_cur = i_cur - 1; 506 | end 507 | if mod(i_start, 2) ~= 0 508 | i_start = i_start - 1; 509 | end 510 | s_start = ffs(i_start, n); 511 | s_max = smax(i_start, i_cur, n); 512 | 513 | if s_start <= s_max 514 | i_minus1 = find_sMaxPos(s_start, s_max, i_start, n); 515 | for i = i_minus1:i_start 516 | P = update_P(obj, i, P, C); 517 | C = update_C(obj, i, C, u_esti(i+1)); 518 | end 519 | else 520 | P = update_P(obj, i_start, P, C); 521 | end 522 | end 523 | 524 | function C = updatePSBack(obj, i_minus1, s_max, u_esti, C) 525 | k = 2^s_max; 526 | for i = i_minus1 + 1 - k:i_minus1 527 | C = update_C(obj, i, C, u_esti(i+1)); 528 | end 529 | end 530 | 531 | function d = Viterbi_decoder(obj, llr, L) 532 | N = obj.code_length; 533 | g = obj.gen; 534 | m = obj.conv_depth - 1; 535 | obj.llr=llr; 536 | path_total = 2^m * L * 2; 537 | frozen_bits = ones(1, N); 538 | frozen_bits(obj.rate_profiling) = 0; 539 | P = zeros(N-1, path_total); 540 | C = zeros(N-1, 2*path_total); 541 | u_esti = zeros(N, path_total); 542 | v_esti = zeros(N, path_total); 543 | c_state = zeros(obj.conv_depth-1, path_total); 544 | M = zeros(1, path_total); 545 | active_path = zeros(1, path_total); 546 | active_path(1) = 1; 547 | for t = 0:N - 1 548 | active_path_idx = find(active_path==1); 549 | if frozen_bits(t+1) == 1 550 | for path_index = active_path_idx 551 | P(:, path_index) = update_P(obj, t, P(:, path_index), C(:, 2*path_index-1:2*path_index)); 552 | v_esti(t+1, path_index) = 0; 553 | [u_esti(t+1, path_index), c_state(:, path_index)] = conv1bTrans(0, c_state(:, path_index), obj.gen); 554 | M(path_index) = M(path_index) - m_func(P(1, path_index), u_esti(t+1, path_index)); 555 | 556 | end 557 | else 558 | state_branch = cell(1,2^m); 559 | for path_index = active_path_idx 560 | P(:, path_index) = update_P(obj, t, P(:, path_index), C(:, 2*path_index-1:2*path_index)); 561 | %find available path 562 | copy_path_index = 1; 563 | while active_path(copy_path_index) == 1 564 | copy_path_index=copy_path_index + 1; 565 | end 566 | active_path(copy_path_index) = 1; 567 | %deepcopy 568 | P(:, copy_path_index) = P(:, path_index); 569 | C(:, 2*copy_path_index-1:2*copy_path_index) = C(:, 2*path_index-1:2*path_index); 570 | c_state(:, copy_path_index) = c_state(:, path_index); 571 | v_esti(:, copy_path_index) = v_esti(:, path_index); 572 | u_esti(:, copy_path_index) = u_esti(:, path_index); 573 | M(copy_path_index)= M(path_index); 574 | %fork 575 | v_esti(t+1, path_index) = 0; 576 | v_esti(t+1, copy_path_index) = 1; 577 | [u_esti(t+1, path_index), c_state(:, path_index)] = conv1bTrans(0, c_state(:, path_index), obj.gen); 578 | [u_esti(t+1, copy_path_index), c_state(:, copy_path_index)] = conv1bTrans(1, c_state(:, copy_path_index), obj.gen); 579 | M(copy_path_index) = M(copy_path_index) - m_func(P(1, copy_path_index), u_esti(t+1, copy_path_index)); 580 | M(path_index) = M(path_index) - m_func(P(1, path_index), u_esti(t+1, path_index)); 581 | s=0; 582 | s_copy=0; 583 | for i_s = 1:m 584 | s = s + c_state(i_s, path_index)*2^(i_s-1); 585 | s_copy = s_copy + c_state(i_s, copy_path_index)*2^(i_s-1); 586 | end 587 | s = s + 1; 588 | s_copy = s_copy + 1; 589 | state_branch{s}=[state_branch{s} path_index]; 590 | state_branch{s_copy}=[state_branch{s_copy} copy_path_index]; 591 | end 592 | 593 | if sum(active_path) > path_total / 2 594 | for branch_index = 1:2^m 595 | num_branch = length(state_branch{branch_index}); 596 | if num_branch == 0 597 | continue; 598 | end 599 | branch_path = state_branch{branch_index}; 600 | M_branch = M(branch_path); 601 | [~,M_branch_sorted_indices] = sort(M_branch,'descend'); 602 | indices_kill = M_branch_sorted_indices(1:num_branch/2); 603 | path_kill = branch_path(indices_kill); 604 | active_path(path_kill) = 0; 605 | end 606 | 607 | end 608 | end 609 | active_path_idx = find(active_path==1); 610 | for path_index = active_path_idx 611 | 612 | C(:, 2*path_index-1:2*path_index) = update_C(obj, t, C(:, 2*path_index-1:2*path_index), u_esti(t+1, path_index)); 613 | end 614 | 615 | end 616 | 617 | active_path = logical(active_path); 618 | M_active = M(active_path); 619 | v_active = v_esti(:, active_path); 620 | [~, M_active_sorted] = sort(M_active, 'ascend'); 621 | v = v_active(:, M_active_sorted(1)); 622 | d = v(obj.rate_profiling); 623 | end 624 | 625 | function P = update_P(obj, phi, P, C) 626 | global operation_count_P; 627 | N = obj.code_length; 628 | n = log2(N); 629 | layer = obj.llr_layer_vec(phi + 1); 630 | 631 | switch phi %Decoding bits u_0 and u_N/2 needs channel LLR, so the decoding of them is separated from other bits. 632 | case 0 633 | index_1 = obj.lambda_offset(n); 634 | for beta = 0:index_1 - 1 635 | P(beta + index_1) = sign(obj.llr(beta + 1)) * sign(obj.llr(beta + index_1 + 1)) * min(abs(obj.llr(beta + 1)), abs(obj.llr(beta + index_1 + 1))); 636 | operation_count_P=operation_count_P+1; 637 | end 638 | for i_layer = n - 2:-1:0 639 | index_1 = obj.lambda_offset(i_layer+1); 640 | index_2 = obj.lambda_offset(i_layer+2); 641 | for beta = 0:index_1 - 1 642 | P(beta + index_1) = sign(P(beta + index_2)) * ... 643 | sign(P(beta + index_1 + index_2)) * min(abs(P(beta + index_2)), abs(P(beta + index_1 + index_2))); 644 | operation_count_P=operation_count_P+1; 645 | end 646 | end 647 | case N / 2 648 | index_1 = obj.lambda_offset(n); 649 | for beta = 0:index_1 - 1 650 | x_tmp = C(beta + index_1, 1); 651 | P(beta + index_1) = (1 - 2 * x_tmp) * obj.llr(beta + 1) + obj.llr(beta + 1 + index_1); 652 | operation_count_P=operation_count_P+1; 653 | 654 | end 655 | for i_layer = n - 2:-1:0 656 | index_1 = obj.lambda_offset(i_layer+1); 657 | index_2 = obj.lambda_offset(i_layer+2); 658 | for beta = 0:index_1 - 1 659 | P(beta + index_1) = sign(P(beta + index_2)) * ... 660 | sign(P(beta + index_1 + index_2)) * min(abs(P(beta + index_2)), abs(P(beta + index_1 + index_2))); 661 | operation_count_P=operation_count_P+1; 662 | 663 | end 664 | end 665 | otherwise 666 | index_1 = obj.lambda_offset(layer+1); 667 | index_2 = obj.lambda_offset(layer+2); 668 | for beta = 0:index_1 - 1 669 | P(beta + index_1) = (1 - 2 * C(beta + index_1, 1)) * P(beta + index_2) + ... 670 | P(beta + index_1 + index_2); 671 | operation_count_P=operation_count_P+1; 672 | 673 | end 674 | for i_layer = layer - 1:-1:0 675 | index_1 = obj.lambda_offset(i_layer+1); 676 | index_2 = obj.lambda_offset(i_layer+2); 677 | for beta = 0:index_1 - 1 678 | P(beta + index_1) = sign(P(beta + index_2)) * ... 679 | sign(P(beta + index_1 + index_2)) * min(abs(P(beta + index_2)), ... 680 | abs(P(beta + index_1 + index_2))); 681 | operation_count_P=operation_count_P+1; 682 | 683 | end 684 | end 685 | end 686 | end 687 | 688 | function C = update_C(obj, phi, C, u) 689 | global operation_count_C; 690 | N = obj.code_length; 691 | phi_mod_2 = mod(phi, 2); 692 | C(1, 1+phi_mod_2) = u; 693 | if (phi_mod_2 == 1) && (phi ~= N - 1) 694 | layer = obj.bit_layer_vec(phi + 1); 695 | for i_layer = 0:layer - 1 696 | index_1 = obj.lambda_offset(i_layer+1); 697 | index_2 = obj.lambda_offset(i_layer+2); 698 | for beta = index_1:2 * index_1 - 1 699 | C(beta + index_1, 2) = mod(C(beta, 1)+C(beta, 2), 2); %Left Column lazy copy 700 | C(beta + index_2, 2) = C(beta, 2); 701 | operation_count_C=operation_count_C+1; 702 | 703 | end 704 | end 705 | index_1 = obj.lambda_offset(layer+1); 706 | index_2 = obj.lambda_offset(layer+2); 707 | for beta = index_1:2 * index_1 - 1 708 | C(beta + index_1, 1) = mod(C(beta, 1)+C(beta, 2), 2); %Left Column lazy copy 709 | C(beta + index_2, 1) = C(beta, 2); 710 | operation_count_C=operation_count_C+1; 711 | 712 | end 713 | end 714 | end 715 | end 716 | end 717 | -------------------------------------------------------------------------------- /Codes/smax.m: -------------------------------------------------------------------------------- 1 | function result = smax(i_start, i_cur, n) 2 | result = 0; 3 | for im = i_start:i_cur 4 | temp = ffs(im, n); 5 | if (temp > result) 6 | result = temp; 7 | end 8 | end 9 | 10 | end -------------------------------------------------------------------------------- /PPV Bound/converse_mc.m: -------------------------------------------------------------------------------- 1 | function y = converse_mc(N, Pe, x2, x3, x4) 2 | 3 | % converse_mc : Polyanskiy-Poor-Verdu (PPV) metaconverse bound for 4 | % binary transmission corrupted by AWGN (bi-AWGN channel) 5 | % 6 | % R = converse_mc(N, Pe, SNRdB, 'approx') returns the upper bound on rate 7 | % for a codeword of length N, a packet error rate of Pe, and a signal to 8 | % noise ratio of SNRdB (in dB). Multiple bound values can be obtained by 9 | % ensuring that N, Pe, and SNRdB have the same length. The specific appro- 10 | % ximation used for calculating the bound is specified by 'approx': 11 | % 12 | % 'normal' - normal approximation, the O(n^-1) approximation available 13 | % from Fig.6 (3rd block) in [1] ; this is a very fast 14 | % algorithm, but may provide a weak approximation. 15 | % 16 | % 'On2' - (default) the O(n^-2) approximation derived from Fig.6 17 | % (2nd block) in [1]; this is approximately 50 times slower 18 | % than the 'normal' option, but much more reliable at low Pe. 19 | % 20 | % 'On3' - the O(n^-3) approximation derived from Fig.6 (2nd block) 21 | % in [1]; this is twice slower than 'On2', and much more 22 | % unrealiable at high Pe. It can be used to identify the 23 | % region where 'On2' is a reliable solution, namely the 24 | % region where 'On2' and 'On3' closely match. 25 | % 26 | % 'full' - the full bound derived numerically as from [2]. 27 | % Be aware this is very slow to compute! It is also 28 | % numerically less reliable where On2 and On3 closely agree. 29 | % 30 | % SNRdB = converse_mc(N, Pe, R, 'approx','error') for a codeword of length 31 | % N, and code rate R, the function returns the SNR (in dB) at which the 32 | % lower bound on error rate is equal to Pe. Multiple bound values can be 33 | % obtained by ensuring that N, Pe, and R have the same length. The specific 34 | % approximation used for calculating the bound is specified by 'approx' 35 | % (see above). 36 | % 37 | % All bounds were derived from: 38 | % [1] T. Erseghe, "Coding in the Finite-Blocklength Regime: Bounds 39 | % based on Laplace Integrals and their Asymptotic Approximations", 40 | % IEEE Transactions on Information Theory, 62(12), pp 6854-6883, 2016 41 | % http://arxiv.org/abs/1511.04629 42 | % [2] T. Erseghe, N. Laurenti, M. Zecchin, "Coding Bounds in the 43 | % Finite-Block-Length Regime: an Application to Spread-Spectrum 44 | % Systems Design," 45 | % 2019 AEIT International Annual Conference. 46 | % 47 | % Please give credits to [1] & [2] if you use this code for your research. 48 | % 49 | % PS1: The function is implemented in MATLAB R2017a and extensively uses 50 | % the 'fmincon' solver. Different MATLAB versions may require some 51 | % modifications. 52 | % 53 | % PS2: The code is tested on a fairly large range of values. However, if 54 | % the code fails on a particular choice of parameters, please drop an 55 | % email to erseghe@dei.unipd.it and I will try to fix the bug. 56 | % 57 | % (c) T. Erseghe 2020 58 | % 59 | 60 | warning ('off','all'); 61 | 62 | if ~exist('x3') % default option 63 | x3 = 'On2'; 64 | end 65 | 66 | if ~exist('x4') % default option 67 | x4 = 'rate'; 68 | end 69 | 70 | N = N(:).'; % put into vector form 71 | Pe = Pe(:).'; % put into vector form 72 | x2 = x2(:).'; % put into vector form 73 | 74 | % ensure that all input vectors have the same length 75 | if (length(N)~=length(Pe))||(length(N)~=length(x2)) 76 | error(['Input vectors must have the same length']) 77 | end 78 | 79 | % check if correct input values are given 80 | switch x3 81 | case {'normal','On2','On3','full'} 82 | otherwise 83 | error(['Wrong input ',x3]) 84 | end 85 | switch x4 86 | case {'rate','error'} 87 | otherwise 88 | error(['Wrong input ',x4]) 89 | end 90 | 91 | 92 | % optimization settings 93 | options1 = optimoptions('fmincon',... 94 | 'Algorithm','sqp',... 95 | 'SpecifyObjectiveGradient',true,... 96 | 'SpecifyConstraintGradient',true,... 97 | 'Display', 'off',... 98 | 'TolFun',1e-20,... 99 | 'TolX', 1e-20,... 100 | 'MaxIterations',1000); 101 | options2 = optimoptions('fmincon',... 102 | 'Algorithm','sqp',... 103 | 'SpecifyObjectiveGradient',false,... 104 | 'SpecifyConstraintGradient',false,... 105 | 'Display', 'off',... 106 | 'TolFun',1e-20,... 107 | 'TolX', 1e-20,... 108 | 'MaxIterations',1000); 109 | 110 | % pre-calculate Q^(-1)(Pe) 111 | Qe = nan(size(Pe)); 112 | for pe = unique(Pe) 113 | qe = fmincon(@(x)zero_obj(x),0,[],[],[],[],[],[],... 114 | @(x)constr_Qe(x,pe),options1); 115 | Qe(Pe==pe) = qe; 116 | end 117 | 118 | if strcmp(x4,'rate') 119 | 120 | % bound on rate 121 | for k = 1:length(N) % cycle on requests 122 | 123 | n = N(k); % blocklength 124 | pe = Pe(k); % packet error probability 125 | qe = Qe(k); % Q^(-1)(pe) 126 | om = 10^(x2(k)/10); % snr value 127 | 128 | % define the saddle point starting point 129 | if ~((n==inf)||strcmp(x3,'normal')) 130 | if (k>2)&&(~isnan(y(k-2)))&&(~isnan(sb)) 131 | sb0 = sb; 132 | else 133 | [~, ~, V] = fun_HP(om,0); 134 | sb0 = -qe/sqrt(V*n); 135 | end 136 | end 137 | 138 | try 139 | if (n==inf)||strcmp(x3,'normal') 140 | % case 1: normal approximation 141 | y(k) = rate_normal(n,om,qe); 142 | 143 | elseif strcmp(x3,'On2') 144 | % case 2: O(n^-2) approximation 145 | % find saddle point 146 | sb = fmincon(@(x)zero_obj(x),sb0,[],[],[],[],[],[],... 147 | @(x)constr_om_on2_rate(x,om,pe,n),options2); 148 | % calculate rate value 149 | y(k) = -logFA_on2(sb,om,n)/log(2); 150 | 151 | elseif strcmp(x3,'On3') 152 | % case 3: O(n^-2) approximation 153 | % find saddle point 154 | sb = fmincon(@(x)zero_obj(x),sb0,[],[],[],[],[],[],... 155 | @(x)constr_om_on3_rate(x,om,pe,n),options2); 156 | % calculate rate value 157 | y(k) = -logFA_on3(sb,om,n)/log(2); 158 | 159 | elseif strcmp(x3,'full') 160 | % case 4: full bound (numerical) 161 | % find saddle point 162 | sb = fmincon(@(x)zero_obj(x),sb0,[],[],[],[],[],[],... 163 | @(x)constr_om_full_rate(x,om,pe,n),options2); 164 | % calculate rate value 165 | y(k) = -logFA_full(sb,om,n)/log(2)/n; 166 | 167 | end 168 | 169 | % clear unreliable values/correct values beyond the limits 170 | if y(k)<1/n 171 | y(k) = 0; 172 | elseif y(k)>1 173 | y(k) = 1; 174 | elseif ~isreal(y(k)) 175 | y(k) = nan; 176 | end 177 | 178 | % something did not work ! 179 | catch me 180 | y(k) = nan; 181 | end 182 | 183 | % display result 184 | disp(sprintf(... 185 | ['biawgnPPVbound(n=%d, mode=%s, approx=%s) '... 186 | 'R = %.3g log10(Pe) = %.3g snr=%gdB '], n, x4, x3,... 187 | y(k), log10(pe), x2(k))); 188 | 189 | end % end cycle on k 190 | 191 | elseif strcmp(x4,'error') 192 | 193 | % bound on error probability 194 | for k = 1:length(N) % cycle on requests 195 | 196 | n = N(k); % blocklength 197 | pe = Pe(k); % packet error probability 198 | qe = Qe(k); % Q^(-1)(pe) 199 | R = x2(k); % rate value 200 | 201 | % define the SNR starting point 202 | if k==1 203 | om0 = 1; 204 | [~, ~, V] = fun_HP(om0,0); 205 | sb0 = -qe/sqrt(V*n); 206 | elseif ~isnan(y(k-1)) % use previous value 207 | om0 = y(k-1); 208 | end 209 | if ~((n==inf)||strcmp(x3,'normal')) 210 | if (k>2)&&(~isnan(y(k-2)))&&(~isnan(x(1))) 211 | sb0 = x(1); 212 | else 213 | [~, ~, V] = fun_HP(om0,0); 214 | sb0 = -qe/sqrt(V*n); 215 | end 216 | end 217 | 218 | try 219 | if (n==inf)||strcmp(x3,'normal') 220 | % case 1: normal approximation 221 | % calculate SNR value 222 | y(k) = fmincon(@(x)zero_obj(x),om0,[],[],[],[],[],[],... 223 | @(x)constr_om_normal(x,R,qe,n),options2); 224 | 225 | elseif strcmp(x3,'On2') 226 | % case 2: O(n^-2) approximation 227 | % check that if starting point is feasible 228 | [~, con] = constr_om_on2_error([sb0; om0],R,pe,n); 229 | % find SNR/saddle point 230 | x = fmincon(@(x)zero_obj(x),[sb0; om0],[],[],[],[],[],[],... 231 | @(x)constr_om_on2_error(x,R,pe,n),options2); 232 | y(k) = x(2); 233 | 234 | elseif strcmp(x3,'On3') 235 | % case 3: O(n^-3) approximation 236 | % check if the starting point is feasible 237 | [~, con] = constr_om_on3_error([sb0; om0],R,pe,n); 238 | % find SNR/saddle point 239 | x = fmincon(@(x)zero_obj(x),[sb0; om0],[],[],[],[],[],[],... 240 | @(x)constr_om_on3_error(x,R,pe,n),options2); 241 | y(k) = x(2); 242 | 243 | elseif strcmp(x3,'full') 244 | % case 4: full bound (numerical) 245 | % check if the starting point is feasible 246 | [~, con] = constr_om_full_error([sb0; om0],R,pe,n); 247 | % find SNR/saddle point 248 | x = fmincon(@(x)zero_obj(x),[sb0; om0],[],[],[],[],[],[],... 249 | @(x)constr_om_full_error(x,R,pe,n),options2); 250 | y(k) = x(2); 251 | 252 | end 253 | 254 | % something did not work ! 255 | catch me 256 | y(k) = nan; 257 | end 258 | 259 | % display result 260 | disp(sprintf(... 261 | ['biawgnPPVbound(n=%d, mode=%s, approx=%s) '... 262 | 'snr=%gdB log10(Pe) = %.3g R = %.3g '], n, x4, x3,... 263 | 10*log10(y(k)), log10(pe), R)); 264 | 265 | end % end cycle on k 266 | 267 | % turn into dBs 268 | y = 10*log10(y); 269 | end 270 | 271 | % ------------------- FUNCTIONS FOR OPTIMIZATION ------------------------- 272 | 273 | % zero object function template (for optimization under constraints only) 274 | function [f gradf] = zero_obj(x) 275 | f = [0]; 276 | gradf = [0]; 277 | 278 | % constraint for calculationg Q^(-1)(Pe) 279 | function [c ceq gradc gradceq] = constr_Qe(x,Pe) 280 | c = []; 281 | gradc = []; 282 | ceq = [0.5*erfc((x)/sqrt(2))-Pe]; 283 | gradceq = [-exp(-x.^2/2)/sqrt(2*pi)]; 284 | 285 | % calculates HP values 286 | function [Hp, la, a2, a3, a4] = fun_HP(om,sb) 287 | IL = om*(1-2*max(sb,0))-10*sqrt(om); % lower limit for integration 288 | IU = om*(1+2*max(sb,0))+10*sqrt(om); % upper limit for integration 289 | tol = 1e-12; % tolerance for integrations 290 | h = @(x) log(1+exp(-2*x)); 291 | fHp = @(x) exp(-(x-om).^2/2/om-sb*h(x))/sqrt(2*pi*om); 292 | if sb==0 % we simplify derivation 293 | Hp = 1; 294 | else 295 | Hp = quadl(@(x)fHp(x),IL,IU,tol); 296 | end 297 | Hp1 = -quadl(@(x)fHp(x).*h(x),IL,IU,tol); 298 | la = -Hp1./Hp; 299 | if nargout<=2 300 | return 301 | end 302 | Hp2 = quadl(@(x)fHp(x).*h(x).^2,IL,IU,tol); 303 | a2 = Hp2./Hp-(Hp1./Hp).^2; 304 | if nargout<=3 305 | return 306 | end 307 | Hp3 = -quadl(@(x)fHp(x).*h(x).^3,IL,IU,tol); 308 | a3 = (Hp3./Hp-3*Hp2.*Hp1./(Hp).^2+2*(Hp1./Hp).^3)/3; 309 | if nargout<=4 310 | return 311 | end 312 | Hp4 = quadl(@(x)fHp(x).*h(x).^4,IL,IU,tol); 313 | a4 = (Hp4./Hp-4*Hp3.*Hp1./(Hp).^2-3*(Hp2./Hp).^2 ... 314 | +12*Hp2.*(Hp1)^2./(Hp).^3-6*(Hp1./Hp).^4)/12; 315 | 316 | % calculates rate under the normal approximation 317 | function R = rate_normal(n,om,qe) 318 | if (n==inf) 319 | [~, la] = fun_HP(om,0); 320 | C = 1 - la/log(2); % capacity 321 | R = C; % rate 322 | else 323 | [~, la, V] = fun_HP(om,0); 324 | C = 1 - la/log(2); % capacity 325 | R = C - qe*log2(exp(1))*sqrt(V/n) + log2(n)/2/n; % rate 326 | end 327 | 328 | % log(FA) function under the O(n^-2) approximation 329 | function y = logFA_on2(sb,om,n) 330 | sa = sb+1; 331 | [Hp, la, a2] = fun_HP(om,sb); 332 | y = la*sa + log(Hp/2)-log(2*pi*n*sa^2*a2)/2/n; 333 | 334 | % log(MD) function under the O(n^-2) approximation 335 | function y = logMD_on2(sb,om,n) 336 | [Hp, la, a2] = fun_HP(om,sb); 337 | y = la.*sb + log(Hp) -log(2*pi*n*sb.^2.*a2)/2/n; 338 | 339 | % log(FA) function under the O(n^-3) approximation 340 | function y = logFA_on3(sb,om,n) 341 | sa = sb+1; 342 | [Hp, la, a2, a3, a4] = fun_HP(om,sb); 343 | y = la*sa + log(Hp/2)-log(2*pi*n*sa^2*a2)/2/n; 344 | g = (12*a2.*a4-15*a3.^2)./a2.^3/8 - 3*a3./(2*sa.*a2.^2)-1./(a2.*sa.^2); 345 | y = y + log(1+g/n)/n; 346 | 347 | % log(MD) function under the O(n^-3) approximation 348 | function y = logMD_on3(sb,om,n) 349 | [Hp, la, a2, a3, a4] = fun_HP(om,sb); 350 | y = la.*sb + log(Hp) -log(2*pi*n*sb.^2.*a2)/2/n; 351 | g = (12*a2.*a4-15*a3.^2)./a2.^3/8 - 3*a3./(2*sb.*a2.^2)-1./(a2.*sb.^2); 352 | y = y + log(1+g/n)/n; 353 | 354 | % log(FA) function under the full approximation 355 | function y = logFA_full(sb,om,n) 356 | [~, la, a2, a3] = fun_HP(om,sb); 357 | % integration path 358 | t0 = 1; % this is set heuristically 359 | pb = @(t) sb + 1i*t/sqrt(a2) + a3*((t<=t0).*t.^2+(t>t0)*t0^2)/(2*a2^2); 360 | pb1 = @(t) 1i/sqrt(a2) + a3*(t<=t0).*t/(a2^2); 361 | % integrals 362 | h = @(x) log(1+exp(-2*x)); 363 | I1 = 40; 364 | H = @(s) (1/sqrt(2*pi*om))*quadl(@(x)exp((-1/(2*om))*(x-om).^2-s*h(x)),-I1,I1); 365 | Beta = @(s) 2*(la*s+log(H(s))); 366 | Alpha = @(s) Beta(s-1)-2*log(2)+2*la; 367 | I = 40; % this is set heuristically 368 | tol = 1e-12; % tolerance for integrations 369 | y = integral(@(u)imag(exp(Alpha(pb(u)+1)*n/2).*pb1(u)./(1+pb(u)))/pi,0,I,'AbsTol',tol,'ArrayValued',true); 370 | y = y + 1.0*(sb<-1.0) + 0.5*(sb==-1.0); 371 | y = log(y); 372 | 373 | % log(MD) function under the full approximation 374 | function y = logMD_full(sb,om,n) 375 | [~, la, a2, a3] = fun_HP(om,sb); 376 | % integration path 377 | t0 = 1; % this is set heuristically 378 | pb = @(t) sb + 1i*t/sqrt(a2) + a3*((t<=t0).*t.^2+(t>t0)*t0^2)/(2*a2^2); 379 | pb1 = @(t) 1i/sqrt(a2) + a3*(t<=t0).*t/(a2^2); 380 | % integrals 381 | h = @(x) log(1+exp(-2*x)); 382 | I1 = 40; 383 | H = @(s) (1/sqrt(2*pi*om))*quadl(@(x)exp((-1/(2*om))*(x-om).^2-s*h(x)),-I1,I1); 384 | Beta = @(s) 2*(la*s+log(H(s))); 385 | I = 40; % this is set heuristically 386 | tol = 1e-12; % tolerance for integrations 387 | y = integral(@(u)imag(exp(Beta(pb(u))*n/2).*pb1(u)./(-pb(u)))/pi,0,I,'AbsTol',tol,'ArrayValued',true); 388 | y = y + 1.0*(sb>0.0) + 0.5*(sb==0.0); 389 | y = log(y); 390 | 391 | % constraints for calculating the error rate bound under the normal 392 | % approximation 393 | function [c ceq gradc gradceq] = constr_om_normal(x,R,qe,n) 394 | c = []; 395 | gradc = []; 396 | ceq = [rate_normal(n,x,qe)-R]; 397 | gradceq = []; % too long to derive !!! 398 | 399 | % constraints for calculating the code rate bound under the O(n^-2) 400 | % approximation 401 | function [c ceq gradc gradceq] = constr_om_on2_rate(sb,om,Pe,n) 402 | c = []; 403 | gradc = []; 404 | ceq = [logMD_on2(sb,om,n)-log(Pe)/n]; 405 | gradceq = []; % too long to derive !!! 406 | 407 | % constraints for calculating the error rate bound under the O(n^-2) 408 | % approximation 409 | function [c ceq gradc gradceq] = constr_om_on2_error(x,R,Pe,n) 410 | c = []; 411 | gradc = []; 412 | ceq = [logMD_on2(x(1),x(2),n)-log(Pe)/n; ... 413 | logFA_on2(x(1),x(2),n)+R*log(2)]; 414 | gradceq = []; % too long to derive !!! 415 | 416 | % constraints for calculating the code rate bound under the O(n^-3) 417 | % approximation 418 | function [c ceq gradc gradceq] = constr_om_on3_rate(sb,om,Pe,n) 419 | c = []; 420 | gradc = []; 421 | ceq = [logMD_on3(sb,om,n)-log(Pe)/n]; 422 | gradceq = []; % too long to derive !!! 423 | 424 | % constraints for calculating the error rate bound under the O(n^-3) 425 | % approximation 426 | function [c ceq gradc gradceq] = constr_om_on3_error(x,R,Pe,n) 427 | c = []; 428 | gradc = []; 429 | ceq = [logMD_on3(x(1),x(2),n)-log(Pe)/n; ... 430 | logFA_on3(x(1),x(2),n)+R*log(2)]; 431 | gradceq = []; % too long to derive !!! 432 | 433 | % constraints for calculating the code rate bound under the full 434 | % approximation 435 | function [c ceq gradc gradceq] = constr_om_full_rate(sb,om,Pe,n) 436 | c = []; 437 | gradc = []; 438 | ceq = [logMD_full(sb,om,n)-log(Pe)]; 439 | gradceq = []; % too long to derive !!! 440 | 441 | % constraints for calculating the error rate bound under the full 442 | % approximation 443 | function [c ceq gradc gradceq] = constr_om_full_error(x,R,Pe,n) 444 | c = []; 445 | gradc = []; 446 | ceq = [logMD_full(x(1),x(2),n)-log(Pe); ... 447 | logFA_full(x(1),x(2),n)+n*R*log(2)]; 448 | gradceq = []; % too long to derive !!! 449 | -------------------------------------------------------------------------------- /PPV Bound/example_per.m: -------------------------------------------------------------------------------- 1 | % PACKET ERROR RATE BOUNDS - LOWER BOUNDS ON ERROR RATE 2 | 3 | if(1) % set to (1) if you wish to run the converse_mc function 4 | 5 | n = 1e3; 6 | R = 1/2; 7 | Pev = 10.^([-0.5:-0.25:-1.75,-2:-0.5:-7]); 8 | uno = ones(size(Pev)); 9 | 10 | % expected execution times evaluated on a MacBook Pro 11 | % normal approximation - expected execution time 2 sec 12 | tic; SNRdBNA = converse_mc(n*uno,Pev,R*uno,'normal','error'); toc 13 | % O(n^-2) approximation - expected execution time 20 sec 14 | tic; SNRdBPPV2 = converse_mc(n*uno,Pev,R*uno,'On2','error'); toc 15 | % O(n^-3) approximation - expected execution time 50 sec 16 | tic; SNRdBPPV3 = converse_mc(n*uno,Pev,R*uno,'On3','error'); toc 17 | % full approximation - expected execution time 40 min 18 | tic; SNRdBPPV = converse_mc(n*uno,Pev,R*uno,'full','error'); toc 19 | 20 | % save('example_per.mat') 21 | else 22 | load('example_per.mat') 23 | end 24 | 25 | % display results 26 | close all 27 | figure(1) 28 | set(0,'defaulttextinterpreter','latex') 29 | semilogy(SNRdBPPV3,Pev,'-.',SNRdBPPV,Pev,'-',SNRdBPPV2,Pev,'--',SNRdBNA,Pev,'-.x') 30 | xlabel('SNR $E_b/N_0$') 31 | ylabel('packet error probability $P_e$') 32 | title(['n = ' num2str(n) ', R = ', num2str(R)]) 33 | legend({},'interpreter','latex') 34 | legend('$O(n^{-3}\,)$ approx','full approx','$O(n^{-2}\,)$ approx $\quad$',... 35 | 'normal approx','Location','Best') 36 | grid 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PAC-codes 2 | 3 | ## Introduction 4 | A matlab implementation of Arikan's PAC-codes (In development) 5 | 6 | Arikan教授的PAC码的Matlab实现 (开发中) 7 | 8 | ## Available functions 9 | 10 | 1. PAC codes' construction (RM Rules and GA method) 11 | 2. PAC codes' (CRC-aided) SCL decoder 12 | 3. PAC codes' List Viterbi decoder 13 | 4. PAC codes' Fano decoder 14 | 5. Dispersion Bound 15 | 16 | ## Referrences 17 | 18 | [1]E. Arıkan, “From sequential decoding to channel polarization and back again,” arXiv preprint arXiv:1908.09594, 2019. 19 | 20 | [2]M. Rowshan, A. Burg, and E. Viterbo, “Polarization-Adjusted Convolutional (PAC) Codes: Sequential Decoding vs List Decoding,” IEEE Trans. Veh. Technol., vol. 70, no. 2, pp. 1434–1447, Feb. 2021, doi: 10.1109/TVT.2021.3052550. 21 | 22 | [3]M. Rowshan and E. Viterbo, “List Viterbi decoding of PAC codes,” IEEE Transactions on Vehicular Technology, vol. 70, no. 3, pp. 2428–2435, 2021. 23 | 24 | ## Other Referrences 25 | 1. https://github.com/YuYongRun/PolarCodeDecodersInMatlab 26 | 2. https://github.com/mohammad-rowshan/List-Decoder-for-Polar-Codes-and-PAC-Codes 27 | 3. https://github.com/mohammad-rowshan/List-Viterbi-Decoder-for-PAC-Codes 28 | 4. https://github.com/yp-mit/spectre 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /draw.m: -------------------------------------------------------------------------------- 1 | figure; 2 | semilogy(snr_dB, complexity(1,:), '-o', 'LineWidth', 1); 3 | 4 | % semilogy(SNRdBNA,Pev,'-','LineWidth',1); 5 | % axis([0.5, 3, 1e-5, 1]) 6 | % legend('Fano','SCL-32, GA','SCL-32, RM','SCL-256, RM','C8ASCL-256, RM','Viterbi, L=4, m=6, RM','Dispersion Bound') 7 | 8 | title('PAC Codes (128,64)') 9 | xlabel('SNR') 10 | ylabel('Average Computation Times') 11 | hold on 12 | grid on; 13 | 14 | semilogy(snr_dB, complexity(2,:), '-o', 'LineWidth', 1); 15 | semilogy(snr_dB, complexity(3,:), '-o', 'LineWidth', 1); 16 | semilogy(snr_dB, complexity(3,:), '-v', 'LineWidth', 1); 17 | legend('Fano','SCL-32','SCL-256','Viterbi L=4,m=6') 18 | -------------------------------------------------------------------------------- /results/128-64-GA2dB-SCL32.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barryu9/PAC-codes/2077246aa6324d0862ada884953fe8ed7f72d203/results/128-64-GA2dB-SCL32.mat -------------------------------------------------------------------------------- /results/128-64-RM-C8ASCL256.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barryu9/PAC-codes/2077246aa6324d0862ada884953fe8ed7f72d203/results/128-64-RM-C8ASCL256.mat -------------------------------------------------------------------------------- /results/128-64-RM-SCL256.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barryu9/PAC-codes/2077246aa6324d0862ada884953fe8ed7f72d203/results/128-64-RM-SCL256.mat -------------------------------------------------------------------------------- /results/128-64-RM-SCL32.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barryu9/PAC-codes/2077246aa6324d0862ada884953fe8ed7f72d203/results/128-64-RM-SCL32.mat -------------------------------------------------------------------------------- /results/PAC_2022-05-11-14-23.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barryu9/PAC-codes/2077246aa6324d0862ada884953fe8ed7f72d203/results/PAC_2022-05-11-14-23.mat -------------------------------------------------------------------------------- /results/PAC_2022-05-11-15-41.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barryu9/PAC-codes/2077246aa6324d0862ada884953fe8ed7f72d203/results/PAC_2022-05-11-15-41.mat -------------------------------------------------------------------------------- /results/PAC_2022-05-26-16-54.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barryu9/PAC-codes/2077246aa6324d0862ada884953fe8ed7f72d203/results/PAC_2022-05-26-16-54.mat -------------------------------------------------------------------------------- /results/PAC_2022-06-06-01-35.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barryu9/PAC-codes/2077246aa6324d0862ada884953fe8ed7f72d203/results/PAC_2022-06-06-01-35.mat -------------------------------------------------------------------------------- /results/PPVBound-128-64.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/barryu9/PAC-codes/2077246aa6324d0862ada884953fe8ed7f72d203/results/PPVBound-128-64.mat -------------------------------------------------------------------------------- /simulation.m: -------------------------------------------------------------------------------- 1 | clear 2 | addpath(genpath('Codes/')) 3 | tic; 4 | N = 64; 5 | k = 32; 6 | g = [1,0,1,1,0,1,1];%c=[c_0,c_1,...,c_m] 7 | snr_dB = 3; 8 | % snr_dB = 3; 9 | 10 | Rate_Profiling_method = 'GA'; 11 | dsnr = 3.5; 12 | crc_length = 0; 13 | 14 | pac = paccode(N,k,g,crc_length,Rate_Profiling_method,dsnr); 15 | n_iter=[60000]; 16 | 17 | frame_errors_count=zeros(1,length(snr_dB)); 18 | operation_count_C_c=zeros(1,length(snr_dB)); 19 | operation_count_P_c=zeros(1,length(snr_dB)); 20 | 21 | bit_errors_count=zeros(1,length(snr_dB)); 22 | FER=zeros(1,length(snr_dB)); 23 | BER=zeros(1,length(snr_dB)); 24 | L=32; 25 | pe=zeros(1,N); 26 | delta=1; 27 | global operation_count_C; 28 | global operation_count_P; 29 | for i=1:length(snr_dB) 30 | for ii = 1:n_iter(i) 31 | operation_count_C=0; 32 | operation_count_P=0; 33 | 34 | u= double(rand(k,1)>0.5); 35 | x = pac.encode(u); 36 | sigma = 1/sqrt(2 * pac.rate) * 10^(-snr_dB(i)/20); 37 | bpsk = 1 - 2 * x; 38 | noise = randn(N, 1); 39 | y = bpsk + sigma * noise; 40 | llr = 2/sigma^2*y; 41 | d = pac.Fano_decoder(llr,pe,delta); 42 | % d = pac.SCL_decoder(llr,256); 43 | % d = pac.Viterbi_decoder(llr,4); 44 | 45 | operation_count_C_c(i)=operation_count_C_c(i)+operation_count_C; 46 | operation_count_P_c(i)=operation_count_P_c(i)+operation_count_P; 47 | 48 | errs=sum(sum(u~=d)); 49 | if(errs>0) 50 | frame_errors_count(i)=frame_errors_count(i)+1; 51 | bit_errors_count(i)=bit_errors_count(i)+errs; 52 | end 53 | if(mod(ii, 1)==0) 54 | display_info(N,k,snr_dB(i),ii,n_iter(i),L,frame_errors_count(i),bit_errors_count(i),operation_count_C_c(i),operation_count_P_c(i)); 55 | end 56 | end 57 | 58 | end 59 | 60 | avg_operation_count_C=operation_count_C_c./n_iter; 61 | avg_operation_count_P=operation_count_P_c./n_iter; 62 | avg_operation_count=avg_operation_count_C+avg_operation_count_P; 63 | FER=frame_errors_count./n_iter; 64 | BER=bit_errors_count./(n_iter.*k); 65 | save(['results\PAC_',datestr(datetime('now'),'yyyy-mm-dd-HH-MM'),'.mat']) 66 | 67 | figure; 68 | semilogy(snr_dB,FER,'-o','LineWidth',1); 69 | grid on; 70 | toc; 71 | 72 | function display_info(N,k,snr_dB,iter_count,n_iter,L,frame_errors_count,bit_errors_count,operation_count_C,operation_count_P) 73 | disp(' '); 74 | disp(['Sim iteration running = ' num2str(iter_count) '/' num2str(n_iter)]); 75 | disp(['N = ' num2str(N) ' K = ' num2str(k)]); 76 | % disp(['List size = ' num2str(L)]); 77 | disp('SNR BLER BER avg_C_count avg_P_count total_count'); 78 | disp(num2str([snr_dB frame_errors_count./iter_count bit_errors_count./(iter_count*k) operation_count_C./iter_count operation_count_P./iter_count (operation_count_C+operation_count_P)./iter_count])); 79 | disp(' ') 80 | end 81 | 82 | 83 | -------------------------------------------------------------------------------- /test.m: -------------------------------------------------------------------------------- 1 | % g = [1,0,1,1,0,1,1] 2 | % generate_CS([6,7,8,11,12,13,14,15,16],4) 3 | 4 | clear 5 | addpath(genpath('Codes/')) 6 | 7 | N = 128; 8 | k = 64; 9 | g = [1, 0, 1, 1, 0, 1, 1]; %c=[c_0,c_1,...,c_m] 10 | snr_dB = 1.5; 11 | pac = paccode(N, k, g, 0, 'RM-Polar', 3); 12 | 13 | Pe = pac.get_PE_GA(4); 14 | sigma = 1 / sqrt(2*pac.R) * 10^(-snr_dB / 20); 15 | 16 | % 17 | % u=[0;1;1;0]; 18 | % llr = [-6.24841359764031 1.32876011828409 -1.42233129484890 4.05711149046604 -3.63127705148068 2.81019082828330 1.54540323409445 -3.36647459351069]'; 19 | % [d]= pac.My_Fano_decoder(llr,Pe,1); 20 | 21 | error = 0; 22 | for i = 1:5000 23 | u = double(rand(k, 1) > 0.5); 24 | x = pac.encode(u); 25 | bpsk = 1 - 2 * x; 26 | noise = randn(N, 1); 27 | y = bpsk + sigma * noise; 28 | llr = 2 / sigma^2 * y; 29 | [d] = pac.My_Fano_decoder(llr, Pe, 1); 30 | i 31 | if (sum(sum(u ~= d)) > 0) 32 | error = error + 1; 33 | error 34 | end 35 | end 36 | 37 | error / i -------------------------------------------------------------------------------- /test_viterbi.m: -------------------------------------------------------------------------------- 1 | % % g = [1,0,1,1,0,1,1] 2 | % % generate_CS([6,7,8,11,12,13,14,15,16],4) 3 | % 4 | % clear 5 | % addpath(genpath('Codes/')) 6 | % 7 | % N = 128; 8 | % k = 64; 9 | % g = [1, 0, 1, 1, 0, 1, 1]; %c=[c_0,c_1,...,c_m] 10 | % snr_dB = 1; 11 | % pac = paccode(N, k, g, 0, 'GA', 2); 12 | % 13 | % sigma = 1 / sqrt(2*pac.R) * 10^(-snr_dB / 20); 14 | % 15 | % error = 0; 16 | % for i = 1:500 17 | % u = double(rand(k, 1) > 0.5); 18 | % x = pac.encode(u); 19 | % bpsk = 1 - 2 * x; 20 | % noise = randn(N, 1); 21 | % y = bpsk + sigma * noise; 22 | % llr = 2 / sigma^2 * y; 23 | % d = pac.Viterbi_decoder(llr, 4); 24 | % i 25 | % if (sum(sum(u ~= d)) > 0) 26 | % error = error + 1 27 | % 28 | % end 29 | % end 30 | % 31 | % error / i 32 | 33 | --------------------------------------------------------------------------------