├── .gitignore ├── H.mat ├── LICENSE ├── NR_ldpc.alist ├── R1-1711982_BG1.xlsx ├── R1-1711982_BG2.xlsx ├── README.md ├── alist2sparse.m ├── alist_generate.m ├── base_graph_1_check_node_list.mat ├── base_graph_2_check_node_list.mat ├── decLDPC_layered.m ├── ldpc_decode.m ├── ldpc_decode_1.m ├── ldpc_encode.m ├── ldpc_encode.m.bak ├── ldpc_encode_2.m ├── ldpc_encode_optimized.m ├── ldpc_h2g.c ├── ldpc_h2g.m ├── lifting_size_table_lookup.m ├── ntz.m ├── parity_check_matrices_calculation.m ├── parity_check_matrices_protocol_1.mat ├── parity_check_matrices_protocol_2.mat ├── tanner_LDPC.m ├── test_all_ldpc_cases.m ├── test_ldpc.m ├── test_ldpc_encode.m └── test_ldpc_encode_2.m /.gitignore: -------------------------------------------------------------------------------- 1 | *.mexa64 2 | -------------------------------------------------------------------------------- /H.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshaoning/5g-ldpc/0887c1b810c4755fe410bd314522d10bf20aa656/H.mat -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Xiao, Shaoning 萧少宁 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /R1-1711982_BG1.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshaoning/5g-ldpc/0887c1b810c4755fe410bd314522d10bf20aa656/R1-1711982_BG1.xlsx -------------------------------------------------------------------------------- /R1-1711982_BG2.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshaoning/5g-ldpc/0887c1b810c4755fe410bd314522d10bf20aa656/R1-1711982_BG2.xlsx -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 5g ldpc codes 2 | ============= 3 | 4 | To test the LDPC encoding and decoding functions, run the following function under matlab 5 | ``` 6 | test_all_ldpc_cases 7 | ``` 8 | 9 | The LDPC decoding function decLDPC_layered.m is from [Simulator for LDPC decoding in IEEE 802.11n](http://www.csl.cornell.edu/~studer/software_ldpc.html) and the author is Christoph Studer. I made some small modifications on it to accelerate its execution. 10 | 11 | The LDPC decoding function ldpc_decode.m is from https://github.com/willemolding/FastPythonLDPC . 12 | 13 | The two included excel files are from 3gpp. 14 | The matlab codes other than decLDPC_layered.m and ldpc_decode.m follow the MIT license. 15 | -------------------------------------------------------------------------------- /alist2sparse.m: -------------------------------------------------------------------------------- 1 | function [H] = alist2sparse(fname) 2 | % reads binary parity check matrix in "alist" format from file FNAME and 3 | % converts it to sparse matrix used in MATLAB routines. 4 | % This is an interface to matrices at http://wol.ra.phy.cam.ac.uk/mackay/codes/ 5 | % 6 | % Example 7 | % [H] = alist2sparse('A'); % A is the ascii file in alist format 8 | 9 | 10 | % Copyright (c) 1999 by Igor Kozintsev igor@ifp.uiuc.edu 11 | % $Revision: 1.1 $ $Date: 2000/03/23 $ Bug fixed by Hatim Behairy 12 | 13 | fid = fopen(fname); 14 | n = fscanf(fid,'%d',1); 15 | m = fscanf(fid,'%d',1); 16 | maxinrow = fscanf(fid,'%d',1); 17 | junk = fscanf(fid,'%d',1); % no need 18 | num = fscanf(fid,'%d',[1 n]); % number of elements in rows 19 | 20 | num2(1:n)=maxinrow; 21 | junk = fscanf(fid,'%d',[1 m]); % no need 22 | 23 | position = zeros(n,maxinrow); 24 | for i=1:n 25 | for j=1:num2(i) 26 | position(i,j) = fscanf(fid,'%d',1); 27 | end 28 | end 29 | 30 | ii = zeros(1,sum(num)); 31 | jj = ii; 32 | k = 1; 33 | for i=1:n 34 | for j=1:num(i) 35 | jj(k) = i; 36 | ii(k) = position(i,j); 37 | ss = 1; 38 | k = k+1 ; 39 | end 40 | end 41 | H = sparse(ii,jj,ss,m,n); 42 | fclose(fid); -------------------------------------------------------------------------------- /alist_generate.m: -------------------------------------------------------------------------------- 1 | function alist_generate 2 | 3 | load H 4 | % H = dvbs2ldpc(1/2); 5 | % H = [0 0 1 0 0 0 0 1 0 1 0 0 1 0 0 0; ... 6 | % 0 0 0 1 0 0 1 0 1 0 0 0 1 0 0 0; ... 7 | % 0 1 0 0 1 0 1 0 0 1 0 0 0 0 0 0; ... 8 | % 0 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0; ... 9 | % 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 1; ... 10 | % 1 0 0 0 0 1 0 0 1 1 0 0 0 0 0 0; ... 11 | % 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0; ... 12 | % 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1; ... 13 | % 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 1; ... 14 | % 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0; ... 15 | % 0 1 0 0 0 0 0 0 0 0 1 0 1 0 1 0; ... 16 | % 1 0 0 0 1 0 0 1 0 0 1 0 0 0 0 0]; 17 | 18 | [N, M] = size(H); 19 | 20 | fid = fopen('NR_ldpc.alist', 'w'); 21 | % fid = fopen('dvbs2_ldpc_12.alist', 'w'); 22 | fprintf(fid, '%d %d\n', N, M); 23 | 24 | H = full(H); 25 | 26 | row_non_zero_entry_number = sum(H, 2).'; 27 | column_non_zero_entry_number = sum(H, 1); 28 | 29 | fprintf(fid, '%d %d\n', max(row_non_zero_entry_number), max(column_non_zero_entry_number)); 30 | 31 | for index = 1:N 32 | fprintf(fid, '%d ', row_non_zero_entry_number(index)); 33 | end 34 | 35 | fprintf(fid, '\n'); 36 | 37 | for index = 1:M 38 | fprintf(fid, '%d ', column_non_zero_entry_number(index)); 39 | end 40 | 41 | fprintf(fid, '\n'); 42 | 43 | for row_index = 1:N 44 | non_zero_entry_positions = find(H(row_index, :) ~= 0); 45 | 46 | for index = 1:max(row_non_zero_entry_number) % length(non_zero_entry_positions) 47 | if index <= length(non_zero_entry_positions) 48 | fprintf(fid, '%d ', non_zero_entry_positions(index)); 49 | else 50 | fprintf(fid, '0 '); 51 | end 52 | end 53 | 54 | fprintf(fid, '\n'); 55 | end 56 | 57 | for column_index = 1:M 58 | non_zero_entry_positions = find(H(:, column_index) ~= 0); 59 | 60 | for index = 1:max(column_non_zero_entry_number) 61 | if index <= length(non_zero_entry_positions) 62 | fprintf(fid, '%d ', non_zero_entry_positions(index)); 63 | else 64 | fprintf(fid, '0 '); 65 | end 66 | end 67 | 68 | fprintf(fid, '\n'); 69 | end 70 | 71 | fclose(fid); 72 | 73 | end -------------------------------------------------------------------------------- /base_graph_1_check_node_list.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshaoning/5g-ldpc/0887c1b810c4755fe410bd314522d10bf20aa656/base_graph_1_check_node_list.mat -------------------------------------------------------------------------------- /base_graph_2_check_node_list.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshaoning/5g-ldpc/0887c1b810c4755fe410bd314522d10bf20aa656/base_graph_2_check_node_list.mat -------------------------------------------------------------------------------- /decLDPC_layered.m: -------------------------------------------------------------------------------- 1 | % ========================================================================= 2 | % Title : LDPC decoder with layered detection schedule 3 | % File : decLDPC_layered.m 4 | % ------------------------------------------------------------------------- 5 | % Description : 6 | % Layered LDPC detection according to E. Sharon, S. Litsyn, and J. 7 | % Goldberger 2004. Supports SPA and MPA. Note that this LDPC decoder 8 | % requires LLRs defined according to L=log(Pr[x=0]/Pr[x=1]). 9 | % ------------------------------------------------------------------------- 10 | % Revisions : 11 | % Date Version Author Description 12 | % 20-may-11 1.2 studer cleanup for reproducible research 13 | % 04-jul-07 1.1 studer some bugfixes 14 | % 02-jul-07 1.0 studer file created 15 | % ------------------------------------------------------------------------- 16 | % (C) 2006-2011 Communication Theory Group 17 | % ETH Zurich, 8092 Zurich, Switzerland 18 | % Author: Dr. Christoph Studer (e-mail: studer@rice.edu) 19 | % ========================================================================= 20 | 21 | function [bit_output,LLR_D2,NumC,NumV] = decLDPC_layered(TxRx,LDPC,LLR_A2, base_graph_check_node_list, Z_c) 22 | % -- initializations 23 | % numOfEntries = sum(sum(LDPC.H==1)); 24 | % Rcv = spalloc(LDPC.par_bits,LDPC.tot_bits,numOfEntries); % msg matrix 25 | Rcv = zeros(LDPC.par_bits, LDPC.tot_bits); 26 | LLR_D2 = [zeros(1, 2*Z_c), LLR_A2]; 27 | % initialize with input bitslis 28 | % bit_output = zeros(1, LDPC.inf_bits); 29 | NumC = 0; % number of computed check nodes 30 | NumV = 0; % number of computed variable nodes 31 | 32 | % === TEST 33 | % vMask = ones(LDPC.par_bits,1); % indicates NCU needs work 34 | % WORKLOAD = 0; 35 | 36 | % -- BEGIN loop over LDPC-internal iterations 37 | for iter=1:TxRx.Decoder.LDPC.Iterations 38 | 39 | %%% % -- count the number of nonzero entries of H*x 40 | % errors = 0; 41 | 42 | switch (TxRx.Decoder.LDPC.Type) 43 | case 'SPA' % -- sum-product algorithm 44 | % == for all parity check node 45 | for j=1:LDPC.par_bits 46 | % idx = find(LDPC.H(j,:)==1); % slow 47 | idx = base_graph_check_node_list{j}; 48 | S = LLR_D2(idx)-full(Rcv(j,idx)); 49 | Spsi = sum(-log(1e-300+tanh(abs(S)*0.5))); 50 | Ssgn = prod(sign(S)); 51 | for v=1:length(idx) 52 | Qtemp = LLR_D2(idx(v)) - Rcv(j,idx(v)); 53 | Qtemppsi = -log(1e-300+tanh(abs(Qtemp)*0.5)); 54 | Qtempsgn = Ssgn*sign(Qtemp); 55 | Rcv(j,idx(v)) = Qtempsgn*(-log(1e-300+tanh(abs(Spsi-Qtemppsi)*0.5))); 56 | LLR_D2(idx(v)) = Qtemp + Rcv(j,idx(v)); 57 | % -- count number variable & check nodes computed 58 | NumC = NumC + 1; 59 | NumV = NumV + 1; 60 | end 61 | 62 | end 63 | case 'MPA' % -- max-log approximation (max-product algorithm) 64 | % == for all parity check node 65 | for j=1:LDPC.par_bits 66 | %idx = find(LDPC.H(j,:)==1); % slow 67 | idx = base_graph_check_node_list{j}; 68 | S = LLR_D2(idx)-full(Rcv(j,idx)); 69 | for v=1:length(idx) 70 | Stmp = S; 71 | Stmp(v) = []; % clear row 72 | Rcv(j,idx(v)) = min(abs(Stmp))*prod(sign(Stmp)); 73 | LLR_D2(idx(v)) = S(v) + Rcv(j,idx(v)); 74 | % --variable node & check node computed 75 | NumC = NumC + 1; 76 | NumV = NumV + 1; 77 | end 78 | end 79 | case 'OMS' % -- offset min-sum [Chen05] 80 | % == for all parity check node 81 | for j=1:LDPC.par_bits 82 | idx = find(LDPC.H(j,:)==1); % slow 83 | % idx = base_graph_check_node_list{j}; 84 | S = LLR_D2(idx)-Rcv(j,idx); 85 | Stmp_abs = abs(S); 86 | 87 | [Stmp_abs_min, min_position] = min(Stmp_abs); 88 | Stmp_abs_without_min = Stmp_abs; 89 | Stmp_abs_without_min(min_position) = []; 90 | Stmp_abs_second_min = min(Stmp_abs_without_min); 91 | 92 | Stmp_sign_1 = sign(S); 93 | Stmp_sign_1(Stmp_sign_1==0) = 1; 94 | Stmp_sign_prod = prod(Stmp_sign_1); 95 | for v=1:length(idx) 96 | if v == min_position 97 | Magnitude = Stmp_abs_second_min; 98 | else 99 | Magnitude = Stmp_abs_min; 100 | end 101 | 102 | Signum = Stmp_sign_prod * Stmp_sign_1(v); 103 | 104 | Rcv(j,idx(v)) = Signum*Magnitude; 105 | LLR_D2(idx(v)) = S(v) + Rcv(j,idx(v)); 106 | % --variable node & check node computed 107 | NumC = NumC + 1; 108 | NumV = NumV + 1; 109 | end 110 | end 111 | otherwise 112 | error('Unknown TxRx.Decoder.LDPC.Type.') 113 | end 114 | 115 | end 116 | 117 | % -- compute binary-valued estimates 118 | bit_output = 0.5*(1-mysign(LLR_D2(1:LDPC.inf_bits))); 119 | 120 | clear Rcv 121 | 122 | return 123 | 124 | function s = mysign(inp) 125 | s = 2*double(inp>0)-1; 126 | return -------------------------------------------------------------------------------- /ldpc_decode.m: -------------------------------------------------------------------------------- 1 | function [x_hat, success, k, prob ] = ldpc_decode(f0,f1,H,max_iter) 2 | % decoding of binary LDPC as in Elec. Letters by MacKay&Neal 13March1997 3 | % For notations see the same reference. 4 | % function [x_hat, success, k] = ldpc_decode(y,f0,f1,H) 5 | % outputs the estimate x_hat of the ENCODED sequence for 6 | % the received vector y with channel likelihoods of '0' and '1's 7 | % in f0 and f1 and parity check matrix H. Success==1 signals 8 | % successful decoding. Maximum number of iterations is set to 100. 9 | % k returns number of iterations until convergence. 10 | % 11 | % Example: 12 | % We assume G is systematic G=[A|I] and, obviously, mod(G*H',2)=0 13 | % sigma = 1; % AWGN noise deviation 14 | % x = (sign(randn(1,size(G,1)))+1)/2; % random bits 15 | % y = mod(x*G,2); % coding 16 | % z = 2*y-1; % BPSK modulation 17 | % z=z + sigma*randn(1,size(G,2)); % AWGN transmission 18 | % 19 | % f1=1./(1+exp(-2*z/sigma^2)); % likelihoods 20 | % f0=1-f1; 21 | % [z_hat, success, k] = ldpc_decode(z,f0,f1,H); 22 | % x_hat = z_hat(size(G,2)+1-size(G,1):size(G,2)); 23 | % x_hat = x_hat'; 24 | 25 | % Copyright (c) 1999 by Igor Kozintsev igor@ifp.uiuc.edu 26 | % $Revision: 1.1 $ $Date: 1999/07/11 $ 27 | % fixed high-SNR decoding 28 | 29 | [m,n] = size(H); if m>n, H=H'; [m,n] = size(H); end 30 | if ~issparse(H) % make H sparse if it is not sparse yet 31 | [ii,jj,sH] = find(H); 32 | H = sparse(ii,jj,sH,m,n); 33 | end 34 | 35 | %initialization 36 | [ii,jj] = find(H); % subscript index to nonzero elements of H 37 | indx = sub2ind(size(H),ii,jj); % linear index to nonzero elements of H 38 | q0 = H * spdiags(f0(:),0,n,n); 39 | sq0 = full(q0(indx)); 40 | sff0 = sq0; 41 | 42 | q1 = H * spdiags(f1(:),0,n,n); 43 | sq1 = full(q1(indx)); 44 | sff1 = sq1; 45 | 46 | %iterations 47 | k=0; 48 | success = 0; 49 | while ((success == 0) && (k < max_iter)) 50 | k = k+1; 51 | 52 | %horizontal step 53 | sdq = sq0 - sq1; sdq(sdq==0) = 1e-20; % if f0 = f1 = .5 54 | dq = sparse(ii,jj,sdq,m,n); 55 | Pdq_v = full(real(exp(sum(spfun('log',dq),2)))); % this is ugly but works :) 56 | Pdq = spdiags(Pdq_v(:),0,m,m) * H; 57 | sPdq = full(Pdq(indx)); 58 | sr0 = (1+sPdq./sdq)./2; sr0(abs(sr0) < 1e-20) = 1e-20; 59 | sr1 = (1-sPdq./sdq)./2; sr1(abs(sr1) < 1e-20) = 1e-20; 60 | r0 = sparse(ii,jj,sr0,m,n); 61 | r1 = sparse(ii,jj,sr1,m,n); 62 | 63 | %vertical step 64 | Pr0_v = full(real(exp(sum(spfun('log',r0),1)))); 65 | Pr0 = H * spdiags(Pr0_v(:),0,n,n); 66 | sPr0 = full(Pr0(indx)); 67 | Q0 = full(sum(sparse(ii,jj,sPr0.*sff0,m,n),1))'; 68 | sq0 = sPr0.*sff0./sr0; 69 | 70 | Pr1_v = full(real(exp(sum(spfun('log',r1),1)))); 71 | Pr1 = H * spdiags(Pr1_v(:),0,n,n); 72 | sPr1 = full(Pr1(indx)); 73 | Q1 = full(sum(sparse(ii,jj,sPr1.*sff1,m,n),1))'; 74 | sq1 = sPr1.*sff1./sr1; 75 | 76 | sqq = sq0+sq1; 77 | sq0 = sq0./sqq; 78 | sq1 = sq1./sqq; 79 | 80 | %tentative decoding 81 | QQ = Q0+Q1; 82 | prob = Q1./QQ; 83 | Q0 = Q0./QQ; 84 | Q1 = Q1./QQ; 85 | 86 | tent = (Q1-Q0); % soft? 87 | x_hat = (sign(tent)+1)/2; % hard bits estimated 88 | if rem(H*x_hat,2) == 0, success = 1; end 89 | end 90 | 91 | -------------------------------------------------------------------------------- /ldpc_decode_1.m: -------------------------------------------------------------------------------- 1 | function [x_hat, success, k] = ldpc_decode_1(f,H,qq) 2 | % decoding of LDPC over GFqq, qq = 2,4,8,16,32,64,128 and 256 3 | % as in Comm. Letters by Davey&MacKay June 1998 with e few modifications. 4 | % For notations see the same reference. 5 | % outputs the estimate "x_hat" of the ENCODED sequence for 6 | % the received vector with channel likelihoods "f". 7 | % "f" ([2^qq][n]) stores the likelihoods for "n" symbols in natural 8 | % ordering. E.g., y(3,5) is the probability of 5-th symbol is equal to "2". 9 | % "H" is the parity check matrix. Success==1 signals 10 | % successful decoding. Maximum number of iterations is set to 100. 11 | % k returns number of iterations until convergence. 12 | % 13 | % Examples: 14 | % We assume G is systematic G=[A|I] and G*H'=0 over GFq 15 | % Binary case 16 | % sigma = 1; % AWGN noise deviation 17 | % x = (sign(randn(1,size(G,1)))+1)/2; % random bits 18 | % y = mod(x*G,2); % encoding 19 | % z = 2*y-1; % BPSK modulation 20 | % z=z + sigma*randn(1,size(G,2)); % AWGN transmission 21 | % 22 | % f1=1./(1+exp(-2*z/sigma^2)); % likelihoods 23 | % f1 = (f1(:))'; % make it a row vector 24 | % f0=1-f1; 25 | % [z_hat, success, k] = ldpc_decode([f0;f1],H,2); 26 | % x_hat = z_hat(size(G,2)+1-size(G,1):size(G,2)); 27 | % x_hat = x_hat'; 28 | % 29 | % Nonbinary case 30 | % sigma = 1; % AWGN noise deviation 31 | % q = 4; % Field parameter 32 | % nbits = log2(q); % bits per symbol 33 | % h = ldpc_generate(400,600,2.5,q,123); % Generate H 34 | % [H,G] = ldpc_h2g(h,q); % find systematic G and modify H 35 | % x = floor(rand(1,size(G,1))*q); % random symbols 36 | % y = ldpc_encode(x,G,q); % encoding 37 | % yb = (fliplr(de2bi(y,nbits)))'; % convert total index to binary format 38 | % yb = yb(:); % make a vector 39 | % zb = 2*yb-1; % BPSK modulation 40 | % zb=zb + sigma*randn(size(zb)); % AWGN transmission 41 | % 42 | % f1=1./(1+exp(-2*zb/sigma^2)); % likelihoods for bits 43 | % f1 = f1(:); % make it a vector 44 | % f1 = reshape(f1,nbits,length(y)); % reshape for finding priors on symbols 45 | % f0=1-f1; 46 | % junk = ones(q,length(y)); % this is a placeholder in the next function 47 | % [v0, v1, pp] = bits_smbl_msg(f0,f1,junk); 48 | % [z_hat, success, k] = ldpc_decode(pp,H,q); 49 | % x_hat = z_hat(size(G,2)+1-size(G,1):size(G,2)); 50 | % x_hat = x_hat'; 51 | 52 | 53 | % Copyright (c) 1999 by Igor Kozintsev igor@ifp.uiuc.edu 54 | % $Revision: 1.2 $ $Date: 1999/11/23 $ 55 | % fixed high-SNR decoding 56 | % works for GFq, q= 2^m now 57 | 58 | if qq==2 % binary case first, just use the old code 59 | 60 | [m,n] = size(H); if m>n, H=H'; [m,n] = size(H); end 61 | if ~issparse(H) % make H sparse if it is not sparse yet 62 | [ii,jj,sH] = find(H); 63 | H = sparse(ii,jj,sH,m,n); 64 | end 65 | 66 | f0 = f(1,:); % prob of 0 67 | f1 = f(2,:); 68 | 69 | %initialization 70 | [ii,jj,sH] = find(H); % subscript index to nonzero elements of H 71 | indx = sub2ind(size(H),ii,jj); % linear index to nonzero elements of H 72 | q0 = H * spdiags(f0(:),0,n,n); 73 | sq0 = full(q0(indx)); 74 | sff0 = sq0; 75 | 76 | q1 = H * spdiags(f1(:),0,n,n); 77 | sq1 = full(q1(indx)); 78 | sff1 = sq1; 79 | 80 | %iterations 81 | k=0; 82 | success = 0; 83 | max_iter = 100; 84 | while ((success == 0) & (k < max_iter)), 85 | k = k+1; 86 | 87 | %horizontal step 88 | sdq = sq0 - sq1; sdq(find(sdq==0)) = 1e-20; % if f0 = f1 = .5 89 | dq = sparse(ii,jj,sdq,m,n); 90 | Pdq_v = full(real(exp(sum(spfun('log',dq),2)))); % this is ugly but works :) 91 | Pdq = spdiags(Pdq_v(:),0,m,m) * H; 92 | sPdq = full(Pdq(indx)); 93 | sr0 = (1+sPdq./sdq)./2; sr0(find(abs(sr0) < 1e-20)) = 1e-20; 94 | sr1 = (1-sPdq./sdq)./2; sr1(find(abs(sr1) < 1e-20)) = 1e-20; 95 | r0 = sparse(ii,jj,sr0,m,n); 96 | r1 = sparse(ii,jj,sr1,m,n); 97 | 98 | %vertical step 99 | Pr0_v = full(real(exp(sum(spfun('log',r0),1)))); 100 | Pr0 = H * spdiags(Pr0_v(:),0,n,n); 101 | sPr0 = full(Pr0(indx)); 102 | Q0 = full(sum(sparse(ii,jj,sPr0.*sff0,m,n),1))'; 103 | sq0 = sPr0.*sff0./sr0; 104 | 105 | Pr1_v = full(real(exp(sum(spfun('log',r1),1)))); 106 | Pr1 = H * spdiags(Pr1_v(:),0,n,n); 107 | sPr1 = full(Pr1(indx)); 108 | Q1 = full(sum(sparse(ii,jj,sPr1.*sff1,m,n),1))'; 109 | sq1 = sPr1.*sff1./sr1; 110 | 111 | sqq = sq0+sq1; 112 | sq0 = sq0./sqq; 113 | sq1 = sq1./sqq; 114 | 115 | %tentative decoding 116 | QQ = Q0+Q1; 117 | Q0 = Q0./QQ; 118 | Q1 = Q1./QQ; 119 | 120 | x_hat = (sign(Q1-Q0)+1)/2; 121 | if rem(H*x_hat,2) == 0, success = 1; end 122 | end 123 | % end of binary case 124 | 125 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 126 | 127 | else % GFq, nonbinary 128 | % our strategy is "divide and concur" - we partition H into several matrices with 129 | % the fixed number of variables per function in each of them and the other way around 130 | 131 | [m,n] = size(H); if m>n, H=H'; [m,n] = size(H); end 132 | if ~issparse(H) % make H sparse if it is not sparse yet 133 | [ii,jj,sH] = find(H); 134 | H = sparse(ii,jj,sH,m,n); 135 | end 136 | 137 | %initialization 138 | [ii,jj,sH] = find(H); % subscript index to nonzero elements of H 139 | W = sparse(ii,jj,ones(size(ii)),m,n); %indicator function 140 | nvars = full(sum(W,2)); % number of variables participating each check function 141 | minvars = min(nvars); % min number of variables in a function 142 | maxvars = max(nvars); % max number of variables in a function 143 | 144 | nfuns = full(sum(W,1)); % number of functions per variable 145 | minfuns = min(nfuns); % min number of functions per variable 146 | maxfuns = max(nfuns); % max number of functions per variable 147 | 148 | % the following will be used in solving linear equations over GFq 149 | M=log2(qq); % GFq exponent 150 | [tuple power] = gftuple([-1:2^M-2]', M, 2); 151 | alpha = tuple * 2.^[0 : M - 1]'; 152 | beta(alpha + 1) = 0 : 2^M - 1; 153 | 154 | 155 | % create cell arays which contain sparse matrices with fixed # of variables in rows 156 | for nnvars = minvars:maxvars 157 | tmp = zeros(size(H)); 158 | rows = find(nvars == nnvars); %rows of H having 'nnvars' variables 159 | tmp(rows,:) = H(rows,:); 160 | [jjj,iii,ssH] = find(tmp'); 161 | iir{nnvars} = reshape(iii,nnvars,length(iii)/nnvars)'; 162 | jjr{nnvars} = reshape(jjj,nnvars,length(jjj)/nnvars)'; 163 | Hr{nnvars} = reshape(ssH,nnvars,length(ssH)/nnvars)';% separate parity matrices 164 | q{nnvars} = reshape(f(:,jjr{nnvars})',[size(jjr{nnvars}),qq]); %initialize to channel likelihoods 165 | 166 | % Prestore valid configurations in array X 167 | if(~isempty(Hr{nnvars})) % make sure the are functions for this case 168 | Hleft = Hr{nnvars}(:,1); % will solve for these varibles 169 | Hright = Hr{nnvars}(:,2:nnvars); % while setting these arbitrary 170 | for i=0:(qq^(nnvars-1)-1) % there are qq^(nnvars-1) different combinations 171 | xr = (fliplr(de2bi(i,nnvars-1,qq))); % current nonzero combination 172 | 173 | % find the remaining variable to satisfy the parity checks 174 | right_part = ones(size(Hleft))*(-Inf); %exponent over GFq 175 | for j=1:(nnvars-1) % multiply each column of Hright by the symbol from x and accumulate 176 | rr1 = power(beta(xr(j)+1)+1); % get expon. representation of xr(i) 177 | rr2 = power(beta(Hright(:,j)+1)+1);% same for the column of Hright 178 | rr3 = gfmul(rr1,rr2,tuple)'; % this is exponential representation of the product 179 | right_part = gfadd(right_part,rr3,tuple); 180 | end 181 | left_part = mod((qq-1)+ right_part - power(beta(Hleft+1)+1),qq-1); 182 | xl=zeros(size(left_part)); 183 | nzindx = find(isfinite(left_part)); 184 | xl(nzindx) = alpha(left_part(nzindx)+2); 185 | x = [xl repmat(xr,[length(xl),1])]; %this is a valid configuration 186 | X{nnvars}(i+1,:,:) = x; 187 | end 188 | end 189 | 190 | 191 | end 192 | 193 | % create cell arays which contain sparse matrices with fixed # of functions in columns 194 | for nnfuns = minfuns:maxfuns 195 | tmp = zeros(size(H)); 196 | cols = find(nfuns == nnfuns); %rows of H having 'nnvars' variables 197 | tmp(:,cols) = H(:,cols); 198 | [iii,jjj,ssH] = find(tmp); 199 | iic{nnfuns} = reshape(iii,nnfuns,length(iii)/nnfuns); 200 | jjc{nnfuns} = reshape(jjj,nnfuns,length(jjj)/nnfuns); 201 | Hc{nnfuns} = reshape(ssH,nnfuns,length(ssH)/nnfuns);% separate parity matrices 202 | ff{nnfuns} = reshape(f(:,jjc{nnfuns})',[size(jjc{nnfuns}),qq]); % this will not change 203 | end 204 | 205 | %iterations 206 | k=0; 207 | success = 0; 208 | max_iter = 100; 209 | while ((success == 0) & (k < max_iter)), 210 | k = k+1 211 | 212 | buffer = zeros([size(H),qq]); 213 | 214 | % Horizontal step - forming messages to variables from the parity check functions 215 | % each Hr is processed separately 216 | for nnvars = minvars:maxvars 217 | if(~isempty(Hr{nnvars})) % make sure the are functions for this case 218 | result = zeros([size(Hr{nnvars}) qq]); % will store the intermediate result 219 | for i=0:(qq^(nnvars-1)-1) % there are qq^(nnvars-1) different combinations 220 | x = squeeze(X{nnvars}(i+1,:,:)); %lookup a valid configuration 221 | 222 | %calculate products 223 | a = cumsum(ones(size(x)),1); 224 | b = cumsum(ones(size(x)),2); 225 | idx = sub2ind(size(q{nnvars}),a,b,x+1); %index of current configuration in 3D 226 | pp = repmat(prod(q{nnvars}(idx),2),[1,size(x,2)]); %product for this configuration 227 | 228 | denom = q{nnvars}(idx); 229 | denom(find(denom==0)) = realmin; 230 | result(idx) = result(idx) + pp./denom; 231 | end 232 | 233 | % update global distribution 234 | a = repmat(iir{nnvars},[1,1,qq]); 235 | b = repmat(jjr{nnvars},[1,1,qq]); 236 | c = permute(repmat((1:qq)',[1 size(a,1) size(a,2)]),[2 3 1]); 237 | gidx = sub2ind(size(buffer),a,b,c); 238 | buffer(gidx) = result; 239 | end 240 | end 241 | 242 | % initialize r from the global data in buffer 243 | for nnfuns = minfuns:maxfuns 244 | a = repmat(iic{nnfuns},[1,1,qq]); 245 | b = repmat(jjc{nnfuns},[1,1,qq]); 246 | c = permute(repmat((1:qq)',[1 size(a,1) size(a,2)]),[2 3 1]); 247 | gidx = sub2ind(size(buffer),a,b,c); 248 | r{nnfuns} = buffer(gidx); 249 | end 250 | 251 | 252 | %vertical step 253 | buffer = zeros([size(H),qq]); 254 | QQ = zeros(qq,size(H,2)); 255 | for nnfuns = minfuns:maxfuns 256 | if(~isempty(Hc{nnfuns})) % make sure the are variables for this case 257 | %calculate products 258 | pp = repmat( prod ( r{nnfuns},1),[size(r{nnfuns},1),1]).*ff{nnfuns}; %product for this configuration 259 | denom = r{nnfuns}; 260 | denom(find(denom==0)) = realmin; 261 | result = pp./denom; 262 | result = result./repmat((sum(result,3)),[1,1,qq]); %normalize to distribution 263 | % update global distribution 264 | a = repmat(iic{nnfuns},[1,1,qq]); 265 | b = repmat(jjc{nnfuns},[1,1,qq]); 266 | c = permute(repmat((1:qq)',[1 size(a,1) size(a,2)]),[2 3 1]); 267 | gidx = sub2ind(size(buffer),a,b,c); 268 | buffer(gidx) = result; 269 | 270 | Q{nnfuns} = pp.*ff{nnfuns}; 271 | b = repmat(jjc{nnfuns}(1,:),[qq,1]); 272 | c = repmat((1:qq)',[1, size(b,2)]); 273 | qidx = sub2ind(size(QQ),c,b); 274 | QQ(qidx) = squeeze(Q{nnfuns}(1,:,:))'; 275 | end 276 | end 277 | 278 | 279 | 280 | % initialize q from the global data in buffer 281 | for nnvars = minvars:maxvars 282 | a = repmat(iir{nnvars},[1,1,qq]); 283 | b = repmat(jjr{nnvars},[1,1,qq]); 284 | c = permute(repmat((1:qq)',[1 size(a,1) size(a,2)]),[2 3 1]); 285 | gidx = sub2ind(size(buffer),a,b,c); 286 | q{nnvars} = buffer(gidx); 287 | end 288 | 289 | 290 | %tentative decoding 291 | QQ = QQ ./ repmat(sum(QQ,1),[qq 1]); %normalize - can be used as soft outputs 292 | [xi xj sx] = find(QQ == repmat(max(QQ),[size(QQ,1),1])); 293 | x_hat = xi-1; 294 | if ldpc_encode(x_hat,H',qq) == 0, success = 1; end 295 | end 296 | end % end of nonbinary case -------------------------------------------------------------------------------- /ldpc_encode.m: -------------------------------------------------------------------------------- 1 | % 5g ldpc encoding 2 | % input: s, bit sequence of dimension K * 1 3 | % output: encoded_bits, bit sequence 4 | % reference: 3GPP TS 38.212 section 5.3.2 5 | % author: Xiao, Shaoning 萧少宁 6 | % license: MIT 7 | 8 | function [encoded_bits, H, Z_c, encoded_bits_original] = ldpc_encode(s, base_graph_index) 9 | 10 | K = length(s); 11 | 12 | encoded_bits = zeros(3*K, 1); 13 | 14 | if base_graph_index == 1 15 | a = 4; 16 | b = 22; 17 | c = 26; 18 | d = 42; 19 | e = 46; 20 | z = K/b; 21 | Z_c = z; 22 | N = 66 * Z_c; 23 | z = K/b; 24 | set_index = lifting_size_table_lookup(z); 25 | load parity_check_matrices_protocol_1 26 | BG = parity_check_matrices_protocol_1(:, :, set_index); %#ok 27 | elseif base_graph_index == 2 28 | a = 4; 29 | b = 10; 30 | c = 14; 31 | d = 38; 32 | e = 42; 33 | z = K/b; 34 | Z_c = z; 35 | N = 50 * Z_c; 36 | set_index = lifting_size_table_lookup(z); 37 | load parity_check_matrices_protocol_2 38 | BG = parity_check_matrices_protocol_2(:, :, set_index); %#ok 39 | else 40 | error('wrong base graph index in ldpc encoding.'); 41 | end 42 | 43 | BG(BG ~= -1) = mod(BG(BG ~= -1), Z_c); 44 | 45 | for k = (2*Z_c):(K-1) 46 | if s(k+1) ~= -1 47 | encoded_bits(k-2*Z_c+1) = s(k+1); 48 | else 49 | s(k+1) = 0; 50 | encoded_bits(k-2*Z_c+1) = -1; 51 | end 52 | end 53 | 54 | % set_index = lifting_size_table_lookup(Z_c); 55 | % BG = parity_check_matrices_protocol(:, :, set_index); 56 | 57 | A_prime = BG(1:a, 1:b); 58 | B_prime = BG(1:a, (b+1):c); 59 | C_prime = BG((a+1):e, 1:b); 60 | D_prime = BG((a+1):e, (b+1):c); 61 | 62 | z = Z_c; 63 | 64 | A = spalloc(a*z, b*z, nnz(A_prime + ones(size(A_prime)))); 65 | 66 | for row_index = 1:a 67 | for column_index = 1:b 68 | if A_prime(row_index, column_index) ~= -1 69 | A((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = sparse(1:z, [(mod(A_prime(row_index, column_index), z)+1):z, 1:mod(A_prime(row_index, column_index), z)], ones(1, z), z, z); 70 | end 71 | end 72 | end 73 | 74 | B = spalloc(a*z, a*z, nnz(B_prime + ones(size(B_prime)))); 75 | 76 | for row_index = 1:a 77 | for column_index = 1:a 78 | if B_prime(row_index, column_index) ~= -1 79 | B((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = sparse(1:z, [(mod(B_prime(row_index, column_index), z)+1):z, 1:mod(B_prime(row_index, column_index), z)], ones(1, z), z, z); 80 | end 81 | end 82 | end 83 | 84 | C = spalloc(d*z, b*z, nnz(C_prime + ones(size(C_prime)))); 85 | 86 | for row_index = 1:d 87 | for column_index = 1:b 88 | if C_prime(row_index, column_index) ~= -1 89 | C((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = sparse(1:z, [(mod(C_prime(row_index, column_index), z)+1):z, 1:mod(C_prime(row_index, column_index), z)], ones(1, z), z, z); 90 | end 91 | end 92 | end 93 | 94 | D = spalloc(d*z, a*z, nnz(D_prime + ones(size(D_prime)))); 95 | 96 | for row_index = 1:d 97 | for column_index = 1:a 98 | if D_prime(row_index, column_index) ~= -1 99 | D((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = sparse(1:z, [(mod(D_prime(row_index, column_index), z)+1):z, 1:mod(D_prime(row_index, column_index), z)], ones(1, z), z, z); 100 | else 101 | D((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = spalloc(z, z, 0); 102 | end 103 | end 104 | end 105 | 106 | B_inv = spalloc(a*z, a*z, 20*z); 107 | 108 | if (base_graph_index == 1) && (set_index ~= 7) 109 | B_inv(1:z, 1:z) = speye(z); 110 | B_inv(1:z, 1+z:2*z) = speye(z); 111 | B_inv(1:z, 1+2*z:3*z) = speye(z); 112 | B_inv(1:z, 1+3*z:4*z) = speye(z); 113 | B_inv(1+z:2*z, 1:z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 114 | B_inv(1+z:2*z, 1+z:2*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 115 | B_inv(1+z:2*z, 1+2*z:3*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 116 | B_inv(1+z:2*z, 1+3*z:4*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 117 | B_inv(1+2*z:3*z, 1:z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 118 | B_inv(1+2*z:3*z, 1+z:2*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 119 | B_inv(1+2*z:3*z, 1+2*z:3*z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 120 | B_inv(1+2*z:3*z, 1+3*z:4*z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 121 | B_inv(1+3*z:4*z, 1:z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 122 | B_inv(1+3*z:4*z, 1+z:2*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 123 | B_inv(1+3*z:4*z, 1+2*z:3*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 124 | B_inv(1+3*z:4*z, 1+3*z:4*z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 125 | elseif (base_graph_index == 2) && ((set_index ~= 4) && (set_index ~= 8)) 126 | B_inv(1:z, 1:z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 127 | B_inv(1:z, 1+z:2*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 128 | B_inv(1:z, 1+2*z:3*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 129 | B_inv(1:z, 1+3*z:4*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 130 | B_inv(1+z:2*z, 1:z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 131 | B_inv(1+z:2*z, 1+z:2*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 132 | B_inv(1+z:2*z, 1+2*z:3*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 133 | B_inv(1+z:2*z, 1+3*z:4*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 134 | B_inv(1+2*z:3*z, 1:z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 135 | B_inv(1+2*z:3*z, 1+z:2*z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 136 | B_inv(1+2*z:3*z, 1+2*z:3*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 137 | B_inv(1+2*z:3*z, 1+3*z:4*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 138 | B_inv(1+3*z:4*z, 1:z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 139 | B_inv(1+3*z:4*z, 1+z:2*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 140 | B_inv(1+3*z:4*z, 1+2*z:3*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 141 | B_inv(1+3*z:4*z, 1+3*z:4*z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 142 | elseif (base_graph_index == 1) && (z == 208) 143 | B_inv(1:z, 1:z) = sparse(circshift(eye(208), 105)); 144 | B_inv(1:z, 1+z:2*z) = sparse(circshift(eye(208), 105)); 145 | B_inv(1:z, 1+2*z:3*z) = sparse(circshift(eye(208), 105)); 146 | B_inv(1:z, 1+3*z:4*z) = sparse(circshift(eye(208), 105)); 147 | B_inv(1+z:2*z, 1:z) = speye(208) + sparse(circshift(eye(208), 105)); 148 | B_inv(1+z:2*z, 1+z:2*z) = sparse(circshift(eye(208), 105)); 149 | B_inv(1+z:2*z, 1+2*z:3*z) = sparse(circshift(eye(208), 105)); 150 | B_inv(1+z:2*z, 1+3*z:4*z) = sparse(circshift(eye(208), 105)); 151 | B_inv(1+2*z:3*z, 1:z) = sparse(circshift(eye(208), 105)); 152 | B_inv(1+2*z:3*z, 1+z:2*z) = sparse(circshift(eye(208), 105)); 153 | B_inv(1+2*z:3*z, 1+2*z:3*z) = speye(208) + sparse(circshift(eye(208), 105)); 154 | B_inv(1+2*z:3*z, 1+3*z:4*z) = speye(208) + sparse(circshift(eye(208), 105)); 155 | B_inv(1+3*z:4*z, 1:z) = sparse(circshift(eye(208), 105)); 156 | B_inv(1+3*z:4*z, 1+z:2*z) = sparse(circshift(eye(208), 105)); 157 | B_inv(1+3*z:4*z, 1+2*z:3*z) = sparse(circshift(eye(208), 105)); 158 | B_inv(1+3*z:4*z, 1+3*z:4*z) = speye(208) + sparse(circshift(eye(208), 105)); 159 | elseif (base_graph_index == 1) && ((z ~= 208) && (set_index == 7)) 160 | B_inv(1:z, 1:z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 161 | B_inv(1:z, 1+z:2*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 162 | B_inv(1:z, 1+2*z:3*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 163 | B_inv(1:z, 1+3*z:4*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 164 | B_inv(1+z:2*z, 1:z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 165 | B_inv(1+z:2*z, 1+z:2*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 166 | B_inv(1+z:2*z, 1+2*z:3*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 167 | B_inv(1+z:2*z, 1+3*z:4*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 168 | B_inv(1+2*z:3*z, 1:z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 169 | B_inv(1+2*z:3*z, 1+z:2*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 170 | B_inv(1+2*z:3*z, 1+2*z:3*z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 171 | B_inv(1+2*z:3*z, 1+3*z:4*z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 172 | B_inv(1+3*z:4*z, 1:z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 173 | B_inv(1+3*z:4*z, 1+z:2*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 174 | B_inv(1+3*z:4*z, 1+2*z:3*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 175 | B_inv(1+3*z:4*z, 1+3*z:4*z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 176 | elseif (base_graph_index == 2) && ((set_index == 4) || (set_index == 8)) 177 | B_inv(1:z, 1:z) = speye(z); 178 | B_inv(1:z, 1+z:2*z) = speye(z); 179 | B_inv(1:z, 1+2*z:3*z) = speye(z); 180 | B_inv(1:z, 1+3*z:4*z) = speye(z); 181 | B_inv(1+z:2*z, 1:z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 182 | B_inv(1+z:2*z, 1+z:2*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 183 | B_inv(1+z:2*z, 1+2*z:3*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 184 | B_inv(1+z:2*z, 1+3*z:4*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 185 | B_inv(1+2*z:3*z, 1:z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 186 | B_inv(1+2*z:3*z, 1+z:2*z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 187 | B_inv(1+2*z:3*z, 1+2*z:3*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 188 | B_inv(1+2*z:3*z, 1+3*z:4*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 189 | B_inv(1+3*z:4*z, 1:z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 190 | B_inv(1+3*z:4*z, 1+z:2*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 191 | B_inv(1+3*z:4*z, 1+2*z:3*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 192 | B_inv(1+3*z:4*z, 1+3*z:4*z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 193 | end 194 | 195 | s = s(:); 196 | 197 | p_1 = mod(B_inv * (A * s), 2); 198 | p_2 = mod(C * s + D * p_1, 2); 199 | 200 | w = [p_1; p_2]; 201 | 202 | for k = K:(N+2*Z_c-1) 203 | encoded_bits(k-2*Z_c+1) = w(k-K+1); 204 | end 205 | 206 | H = [A, B, spalloc(a*z, d*z, 0); C, D, speye(d*z)]; 207 | 208 | encoded_bits_original = [s; w]; 209 | 210 | % mod(H * [s; p_1; p_2]) = 0 211 | 212 | clear A 213 | clear B 214 | clear C 215 | clear D 216 | clear B_inv 217 | clear A_prime 218 | clear B_prime 219 | clear C_prime 220 | clear D_prime 221 | 222 | end 223 | -------------------------------------------------------------------------------- /ldpc_encode.m.bak: -------------------------------------------------------------------------------- 1 | % 5g ldpc encoding 2 | % input: s, bit sequence of dimension K * 1 3 | % output: encoded_bits, bit sequence 4 | % reference: 3GPP TS 38.212 section 5.3.2 5 | % author: Xiao, Shaoning 萧少宁 6 | % license: MIT 7 | 8 | function [encoded_bits, H] = ldpc_encode(s, base_graph_index) 9 | 10 | K = length(s); 11 | 12 | if base_graph_index == 1 13 | a = 4; 14 | b = 22; 15 | c = 26; 16 | d = 42; 17 | e = 46; 18 | 19 | z = K/b; 20 | set_index = lifting_size_table_lookup(z); 21 | 22 | load parity_check_matrices_protocol_1 23 | BG = parity_check_matrices_protocol_1(:, :, set_index); %#ok 24 | elseif base_graph_index == 2 25 | a = 4; 26 | b = 10; 27 | c = 14; 28 | d = 38; 29 | e = 42; 30 | 31 | z = K/b; 32 | set_index = lifting_size_table_lookup(z); 33 | 34 | load parity_check_matrices_protocol_2 35 | BG = parity_check_matrices_protocol_2(:, :, set_index); %#ok 36 | else 37 | error('wrong base graph index in ldpc encoding.'); 38 | end 39 | 40 | A_prime = BG(1:a, 1:b); 41 | B_prime = BG(1:a, (b+1):c); 42 | C_prime = BG((a+1):e, 1:b); 43 | D_prime = BG((a+1):e, (b+1):c); 44 | 45 | A = spalloc(a*z, b*z, nnz(A_prime + ones(size(A_prime)))); 46 | 47 | for row_index = 1:a 48 | for column_index = 1:b 49 | if A_prime(row_index, column_index) ~= -1 50 | A((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = sparse(1:z, [A_prime(row_index, column_index)+1:z, 1:A_prime(row_index, column_index)], ones(1, z), z, z); 51 | else 52 | A((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = spalloc(z, z, 0); 53 | end 54 | end 55 | end 56 | 57 | B = spalloc(a*z, a*z, nnz(B_prime + ones(size(B_prime)))); 58 | 59 | for row_index = 1:a 60 | for column_index = 1:a 61 | if B_prime(row_index, column_index) ~= -1 62 | B((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = sparse(1:z, [B_prime(row_index, column_index)+1:z, 1:B_prime(row_index, column_index)], ones(1, z), z, z); 63 | else 64 | B((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = spalloc(z, z, 0); 65 | end 66 | end 67 | end 68 | 69 | C = spalloc(d*z, b*z, nnz(C_prime + ones(size(C_prime)))); 70 | 71 | for row_index = 1:d 72 | for column_index = 1:b 73 | if C_prime(row_index, column_index) ~= -1 74 | C((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = sparse(1:z, [C_prime(row_index, column_index)+1:z, 1:C_prime(row_index, column_index)], ones(1, z), z, z); 75 | else 76 | C((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = spalloc(z, z, 0); 77 | end 78 | end 79 | end 80 | 81 | D = spalloc(d*z, a*z, nnz(D_prime + ones(size(D_prime)))); 82 | 83 | for row_index = 1:d 84 | for column_index = 1:a 85 | if D_prime(row_index, column_index) ~= -1 86 | D((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = sparse(1:z, [D_prime(row_index, column_index)+1:z, 1:D_prime(row_index, column_index)], ones(1, z), z, z); 87 | else 88 | D((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = spalloc(z, z, 0); 89 | end 90 | end 91 | end 92 | 93 | B_inv = spalloc(a*z, a*z, 20*z); 94 | 95 | if base_graph_index == 1 96 | B_inv(1:z, 1:z) = speye(z); 97 | B_inv(1:z, 1+z:2*z) = speye(z); 98 | B_inv(1:z, 1+2*z:3*z) = speye(z); 99 | B_inv(1:z, 1+3*z:4*z) = speye(z); 100 | B_inv(1+z:2*z, 1:z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 101 | B_inv(1+z:2*z, 1+z:2*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 102 | B_inv(1+z:2*z, 1+2*z:3*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 103 | B_inv(1+z:2*z, 1+3*z:4*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 104 | B_inv(1+2*z:3*z, 1:z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 105 | B_inv(1+2*z:3*z, 1+z:2*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 106 | B_inv(1+2*z:3*z, 1+2*z:3*z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 107 | B_inv(1+2*z:3*z, 1+3*z:4*z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 108 | B_inv(1+3*z:4*z, 1:z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 109 | B_inv(1+3*z:4*z, 1+z:2*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 110 | B_inv(1+3*z:4*z, 1+2*z:3*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 111 | B_inv(1+3*z:4*z, 1+3*z:4*z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 112 | else 113 | B_inv(1:z, 1:z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 114 | B_inv(1:z, 1+z:2*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 115 | B_inv(1:z, 1+2*z:3*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 116 | B_inv(1:z, 1+3*z:4*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 117 | B_inv(1+z:2*z, 1:z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 118 | B_inv(1+z:2*z, 1+z:2*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 119 | B_inv(1+z:2*z, 1+2*z:3*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 120 | B_inv(1+z:2*z, 1+3*z:4*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 121 | B_inv(1+2*z:3*z, 1:z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 122 | B_inv(1+2*z:3*z, 1+z:2*z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 123 | B_inv(1+2*z:3*z, 1+2*z:3*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 124 | B_inv(1+2*z:3*z, 1+3*z:4*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 125 | B_inv(1+3*z:4*z, 1:z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 126 | B_inv(1+3*z:4*z, 1+z:2*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 127 | B_inv(1+3*z:4*z, 1+2*z:3*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 128 | B_inv(1+3*z:4*z, 1+3*z:4*z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 129 | end 130 | 131 | s = s(:); 132 | 133 | p_1 = mod(B_inv * (A * s), 2); 134 | p_2 = mod(C * s + D * p_1, 2); 135 | 136 | encoded_bits = [s; p_1; p_2]; 137 | 138 | H = [A, B, spalloc(a*z, d*z, 0); C, D, speye(d*z)]; 139 | 140 | clear A 141 | clear B 142 | clear C 143 | clear D 144 | clear B_inv 145 | clear A_prime 146 | clear B_prime 147 | clear C_prime 148 | clear D_prime 149 | 150 | end -------------------------------------------------------------------------------- /ldpc_encode_2.m: -------------------------------------------------------------------------------- 1 | % 5g ldpc encoding 2 | % input: s, bit sequence of dimension K * 1 3 | % output: encoded_bits, bit sequence 4 | % reference: 3GPP TS 38.212 section 5.3.2 5 | % author: Xiao, Shaoning 萧少宁 6 | % license: MIT 7 | 8 | function [encoded_bits, H] = ldpc_encode_2(s) 9 | 10 | K = length(s); 11 | 12 | z = K/10; 13 | 14 | set_index = lifting_size_table_lookup(z); 15 | 16 | load parity_check_matrices_protocol_2 17 | 18 | BG_2 = parity_check_matrices_protocol_2(:, :, set_index); %#ok 19 | 20 | A_prime = BG_2(1:4, 1:10); 21 | B_prime = BG_2(1:4, 11:14); 22 | C_prime = BG_2(5:42, 1:10); 23 | D_prime = BG_2(5:42, 11:14); 24 | 25 | A = zeros(4*z, 10*z); 26 | 27 | for row_index = 1:4 28 | for column_index = 1:10 29 | if A_prime(row_index, column_index) ~= -1 30 | A((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = circshift(eye(z), -A_prime(row_index, column_index)); 31 | else 32 | A((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = zeros(z, z); 33 | end 34 | end 35 | end 36 | 37 | B = zeros(4*z, 4*z); 38 | 39 | for row_index = 1:4 40 | for column_index = 1:4 41 | if B_prime(row_index, column_index) ~= -1 42 | B((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = circshift(eye(z), -B_prime(row_index, column_index)); 43 | else 44 | B((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = zeros(z, z); 45 | end 46 | end 47 | end 48 | 49 | C = zeros(38*z, 10*z); 50 | 51 | for row_index = 1:38 52 | for column_index = 1:10 53 | if C_prime(row_index, column_index) ~= -1 54 | C((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = circshift(eye(z), -C_prime(row_index, column_index)); 55 | else 56 | C((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = zeros(z, z); 57 | end 58 | end 59 | end 60 | 61 | D = zeros(38*z, 4*z); 62 | 63 | for row_index = 1:38 64 | for column_index = 1:4 65 | if D_prime(row_index, column_index) ~= -1 66 | D((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = circshift(eye(z), -D_prime(row_index, column_index)); 67 | else 68 | D((row_index-1)*z+1:row_index*z, (column_index-1)*z+1:column_index*z) = zeros(z, z); 69 | end 70 | end 71 | end 72 | 73 | B_inv = zeros(4*z, 4*z); 74 | B_inv(1:z, 1:z) = circshift(eye(z), 1); 75 | B_inv(1:z, 1+z:2*z) = circshift(eye(z), 1); 76 | B_inv(1:z, 1+2*z:3*z) = circshift(eye(z), 1); 77 | B_inv(1:z, 1+3*z:4*z) = circshift(eye(z), 1); 78 | B_inv(1+z:2*z, 1:z) = eye(z) + circshift(eye(z), 1); 79 | B_inv(1+z:2*z, 1+z:2*z) = circshift(eye(z), 1); 80 | B_inv(1+z:2*z, 1+2*z:3*z) = circshift(eye(z), 1); 81 | B_inv(1+z:2*z, 1+3*z:4*z) = circshift(eye(z), 1); 82 | B_inv(1+2*z:3*z, 1:z) = eye(z) + circshift(eye(z), 1); 83 | B_inv(1+2*z:3*z, 1+z:2*z) = eye(z) + circshift(eye(z), 1); 84 | B_inv(1+2*z:3*z, 1+2*z:3*z) = circshift(eye(z), 1); 85 | B_inv(1+2*z:3*z, 1+3*z:4*z) = circshift(eye(z), 1); 86 | B_inv(1+3*z:4*z, 1:z) = circshift(eye(z), 1); 87 | B_inv(1+3*z:4*z, 1+z:2*z) = circshift(eye(z), 1); 88 | B_inv(1+3*z:4*z, 1+2*z:3*z) = circshift(eye(z), 1); 89 | B_inv(1+3*z:4*z, 1+3*z:4*z) = eye(z) + circshift(eye(z), 1); 90 | 91 | s = s(:); 92 | 93 | p_1 = mod(B_inv * (A * s), 2); 94 | p_2 = mod(C * s + D * p_1, 2); 95 | 96 | encoded_bits = [s; p_1; p_2]; 97 | 98 | H = [sparse(A), sparse(B), sparse(zeros(4*z, 38*z)); sparse(C), sparse(D), sparse(eye(38*z))]; 99 | 100 | end -------------------------------------------------------------------------------- /ldpc_encode_optimized.m: -------------------------------------------------------------------------------- 1 | % 5g ldpc encoding 2 | % input: s, bit sequence of dimension K * 1 3 | % output: encoded_bits, bit sequence 4 | % reference: 3GPP TS 38.212 section 5.3.2 5 | % author: Xiao, Shaoning 萧少宁 6 | % license: MIT 7 | 8 | function [encoded_bits, H, Z_c, encoded_bits_original] = ldpc_encode_optimized(s, base_graph_index) 9 | 10 | K = length(s); 11 | 12 | encoded_bits = zeros(3*K, 1); 13 | 14 | if base_graph_index == 1 15 | a = 4; 16 | b = 22; 17 | c = 26; 18 | d = 42; 19 | e = 46; 20 | z = K/b; 21 | Z_c = z; 22 | N = 66 * Z_c; 23 | z = K/b; 24 | set_index = lifting_size_table_lookup(z); 25 | load parity_check_matrices_protocol_1 26 | BG = parity_check_matrices_protocol_1(:, :, set_index); %#ok 27 | elseif base_graph_index == 2 28 | a = 4; 29 | b = 10; 30 | c = 14; 31 | d = 38; 32 | e = 42; 33 | z = K/b; 34 | Z_c = z; 35 | N = 50 * Z_c; 36 | set_index = lifting_size_table_lookup(z); 37 | load parity_check_matrices_protocol_2 38 | BG = parity_check_matrices_protocol_2(:, :, set_index); %#ok 39 | else 40 | error('wrong base graph index in ldpc encoding.'); 41 | end 42 | 43 | BG(BG ~= -1) = mod(BG(BG ~= -1), Z_c); 44 | 45 | for k = (2*Z_c):(K-1) 46 | if s(k+1) ~= -1 47 | encoded_bits(k-2*Z_c+1) = s(k+1); 48 | else 49 | s(k+1) = 0; 50 | encoded_bits(k-2*Z_c+1) = -1; 51 | end 52 | end 53 | 54 | % set_index = lifting_size_table_lookup(Z_c); 55 | % BG = parity_check_matrices_protocol(:, :, set_index); 56 | 57 | A_prime = BG(1:a, 1:b); 58 | B_prime = BG(1:a, (b+1):c); 59 | C_prime = BG((a+1):e, 1:b); 60 | D_prime = BG((a+1):e, (b+1):c); 61 | 62 | z = Z_c; 63 | 64 | a_row_list = []; 65 | a_column_list = []; 66 | a_none_zero_entry_number = 0; 67 | for row_index = 1:a 68 | for column_index = 1:b 69 | if A_prime(row_index, column_index) ~= -1 70 | a_none_zero_entry_number = a_none_zero_entry_number + 1; 71 | a_row_list = [a_row_list, (row_index-1)*z+1:row_index*z]; 72 | a_column_list = [a_column_list, (column_index-1)*z+1+mod(A_prime(row_index, column_index), z):column_index*z, (column_index-1)*z+1:(column_index-1)*z+mod(A_prime(row_index, column_index), z)]; 73 | end 74 | end 75 | end 76 | 77 | A = sparse(a_row_list, a_column_list, ones(1, z * a_none_zero_entry_number), z * a, z * b); 78 | 79 | b_row_list = []; 80 | b_column_list = []; 81 | b_none_zero_entry_number = 0; 82 | for row_index = 1:a 83 | for column_index = 1:a 84 | if B_prime(row_index, column_index) ~= -1 85 | b_none_zero_entry_number = b_none_zero_entry_number + 1; 86 | b_row_list = [b_row_list, (row_index-1)*z+1:row_index*z]; 87 | b_column_list = [b_column_list, (column_index-1)*z+1+mod(B_prime(row_index, column_index), z):column_index*z, (column_index-1)*z+1:(column_index-1)*z+mod(B_prime(row_index, column_index), z)]; 88 | end 89 | end 90 | end 91 | 92 | B = sparse(b_row_list, b_column_list, ones(1, z * b_none_zero_entry_number), z * a, z * a); 93 | 94 | c_row_list = []; 95 | c_column_list = []; 96 | c_none_zero_entry_number = 0; 97 | for row_index = 1:d 98 | for column_index = 1:b 99 | if C_prime(row_index, column_index) ~= -1 100 | c_none_zero_entry_number = c_none_zero_entry_number + 1; 101 | c_row_list = [c_row_list, (row_index-1)*z+1:row_index*z]; 102 | c_column_list = [c_column_list, (column_index-1)*z+1+mod(C_prime(row_index, column_index), z):column_index*z, (column_index-1)*z+1:(column_index-1)*z+mod(C_prime(row_index, column_index), z)]; 103 | end 104 | end 105 | end 106 | 107 | C = sparse(c_row_list, c_column_list, ones(1, z * c_none_zero_entry_number), z * d, z * b); 108 | 109 | d_row_list = []; 110 | d_column_list = []; 111 | d_none_zero_entry_number = 0; 112 | for row_index = 1:d 113 | for column_index = 1:a 114 | if D_prime(row_index, column_index) ~= -1 115 | d_none_zero_entry_number = d_none_zero_entry_number + 1; 116 | d_row_list = [d_row_list, (row_index-1)*z+1:row_index*z]; 117 | d_column_list = [d_column_list, (column_index-1)*z+1+mod(D_prime(row_index, column_index), z):column_index*z, (column_index-1)*z+1:(column_index-1)*z+mod(D_prime(row_index, column_index), z)]; 118 | end 119 | end 120 | end 121 | 122 | D = sparse(d_row_list, d_column_list, ones(1, z * d_none_zero_entry_number), z * d, z * a); 123 | 124 | B_inv = spalloc(a*z, a*z, 20*z); 125 | 126 | if (base_graph_index == 1) && (set_index ~= 7) 127 | B_inv(1:z, 1:z) = speye(z); 128 | B_inv(1:z, 1+z:2*z) = speye(z); 129 | B_inv(1:z, 1+2*z:3*z) = speye(z); 130 | B_inv(1:z, 1+3*z:4*z) = speye(z); 131 | B_inv(1+z:2*z, 1:z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 132 | B_inv(1+z:2*z, 1+z:2*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 133 | B_inv(1+z:2*z, 1+2*z:3*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 134 | B_inv(1+z:2*z, 1+3*z:4*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 135 | B_inv(1+2*z:3*z, 1:z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 136 | B_inv(1+2*z:3*z, 1+z:2*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 137 | B_inv(1+2*z:3*z, 1+2*z:3*z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 138 | B_inv(1+2*z:3*z, 1+3*z:4*z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 139 | B_inv(1+3*z:4*z, 1:z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 140 | B_inv(1+3*z:4*z, 1+z:2*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 141 | B_inv(1+3*z:4*z, 1+2*z:3*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 142 | B_inv(1+3*z:4*z, 1+3*z:4*z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 143 | elseif (base_graph_index == 2) && ((set_index ~= 4) && (set_index ~= 8)) 144 | B_inv(1:z, 1:z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 145 | B_inv(1:z, 1+z:2*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 146 | B_inv(1:z, 1+2*z:3*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 147 | B_inv(1:z, 1+3*z:4*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 148 | B_inv(1+z:2*z, 1:z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 149 | B_inv(1+z:2*z, 1+z:2*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 150 | B_inv(1+z:2*z, 1+2*z:3*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 151 | B_inv(1+z:2*z, 1+3*z:4*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 152 | B_inv(1+2*z:3*z, 1:z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 153 | B_inv(1+2*z:3*z, 1+z:2*z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 154 | B_inv(1+2*z:3*z, 1+2*z:3*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 155 | B_inv(1+2*z:3*z, 1+3*z:4*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 156 | B_inv(1+3*z:4*z, 1:z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 157 | B_inv(1+3*z:4*z, 1+z:2*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 158 | B_inv(1+3*z:4*z, 1+2*z:3*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 159 | B_inv(1+3*z:4*z, 1+3*z:4*z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 160 | elseif (base_graph_index == 1) && (z == 208) 161 | B_inv(1:z, 1:z) = sparse(circshift(eye(208), 105)); 162 | B_inv(1:z, 1+z:2*z) = sparse(circshift(eye(208), 105)); 163 | B_inv(1:z, 1+2*z:3*z) = sparse(circshift(eye(208), 105)); 164 | B_inv(1:z, 1+3*z:4*z) = sparse(circshift(eye(208), 105)); 165 | B_inv(1+z:2*z, 1:z) = speye(208) + sparse(circshift(eye(208), 105)); 166 | B_inv(1+z:2*z, 1+z:2*z) = sparse(circshift(eye(208), 105)); 167 | B_inv(1+z:2*z, 1+2*z:3*z) = sparse(circshift(eye(208), 105)); 168 | B_inv(1+z:2*z, 1+3*z:4*z) = sparse(circshift(eye(208), 105)); 169 | B_inv(1+2*z:3*z, 1:z) = sparse(circshift(eye(208), 105)); 170 | B_inv(1+2*z:3*z, 1+z:2*z) = sparse(circshift(eye(208), 105)); 171 | B_inv(1+2*z:3*z, 1+2*z:3*z) = speye(208) + sparse(circshift(eye(208), 105)); 172 | B_inv(1+2*z:3*z, 1+3*z:4*z) = speye(208) + sparse(circshift(eye(208), 105)); 173 | B_inv(1+3*z:4*z, 1:z) = sparse(circshift(eye(208), 105)); 174 | B_inv(1+3*z:4*z, 1+z:2*z) = sparse(circshift(eye(208), 105)); 175 | B_inv(1+3*z:4*z, 1+2*z:3*z) = sparse(circshift(eye(208), 105)); 176 | B_inv(1+3*z:4*z, 1+3*z:4*z) = speye(208) + sparse(circshift(eye(208), 105)); 177 | elseif (base_graph_index == 1) && ((z ~= 208) && (set_index == 7)) 178 | B_inv(1:z, 1:z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 179 | B_inv(1:z, 1+z:2*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 180 | B_inv(1:z, 1+2*z:3*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 181 | B_inv(1:z, 1+3*z:4*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 182 | B_inv(1+z:2*z, 1:z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 183 | B_inv(1+z:2*z, 1+z:2*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 184 | B_inv(1+z:2*z, 1+2*z:3*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 185 | B_inv(1+z:2*z, 1+3*z:4*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 186 | B_inv(1+2*z:3*z, 1:z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 187 | B_inv(1+2*z:3*z, 1+z:2*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 188 | B_inv(1+2*z:3*z, 1+2*z:3*z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 189 | B_inv(1+2*z:3*z, 1+3*z:4*z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 190 | B_inv(1+3*z:4*z, 1:z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 191 | B_inv(1+3*z:4*z, 1+z:2*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 192 | B_inv(1+3*z:4*z, 1+2*z:3*z) = sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 193 | B_inv(1+3*z:4*z, 1+3*z:4*z) = speye(z) + sparse(1:z, [z, 1:(z-1)], ones(1, z), z, z); 194 | elseif (base_graph_index == 2) && ((set_index == 4) || (set_index == 8)) 195 | B_inv(1:z, 1:z) = speye(z); 196 | B_inv(1:z, 1+z:2*z) = speye(z); 197 | B_inv(1:z, 1+2*z:3*z) = speye(z); 198 | B_inv(1:z, 1+3*z:4*z) = speye(z); 199 | B_inv(1+z:2*z, 1:z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 200 | B_inv(1+z:2*z, 1+z:2*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 201 | B_inv(1+z:2*z, 1+2*z:3*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 202 | B_inv(1+z:2*z, 1+3*z:4*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 203 | B_inv(1+2*z:3*z, 1:z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 204 | B_inv(1+2*z:3*z, 1+z:2*z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 205 | B_inv(1+2*z:3*z, 1+2*z:3*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 206 | B_inv(1+2*z:3*z, 1+3*z:4*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 207 | B_inv(1+3*z:4*z, 1:z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 208 | B_inv(1+3*z:4*z, 1+z:2*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 209 | B_inv(1+3*z:4*z, 1+2*z:3*z) = sparse(1:z, [2:z, 1], ones(1, z), z, z); 210 | B_inv(1+3*z:4*z, 1+3*z:4*z) = speye(z) + sparse(1:z, [2:z, 1], ones(1, z), z, z); 211 | end 212 | 213 | s = s(:); 214 | 215 | p_1 = mod(B_inv * (A * s), 2); 216 | p_2 = mod(C * s + D * p_1, 2); 217 | 218 | w = [p_1; p_2]; 219 | 220 | for k = K:(N+2*Z_c-1) 221 | encoded_bits(k-2*Z_c+1) = w(k-K+1); 222 | end 223 | 224 | H = [A, B, spalloc(a*z, d*z, 0); C, D, speye(d*z)]; 225 | 226 | encoded_bits_original = [s; w]; 227 | 228 | % mod(H * [s; p_1; p_2]) = 0 229 | 230 | clear A 231 | clear B 232 | clear C 233 | clear D 234 | clear B_inv 235 | clear A_prime 236 | clear B_prime 237 | clear C_prime 238 | clear D_prime 239 | 240 | end 241 | -------------------------------------------------------------------------------- /ldpc_h2g.c: -------------------------------------------------------------------------------- 1 | /* Invert sparse binary H for LDPC*/ 2 | /* Author : Igor Kozintsev igor@ifp.uiuc.edu 3 | Please let me know if you find bugs in this code (I did test 4 | it but I still have some doubts). All other comments are welcome 5 | too :) ! 6 | I use a simple algorithm to invert H. 7 | We convert H to [I | A] 8 | [junk ] 9 | using column reodering and row operations (junk - a few rows of H 10 | which are linearly dependent on the previous ones) 11 | G is then found as G = [A'|I] 12 | G is stored as array of doubles in Matlab which is very inefficient. 13 | Internal representation in this programm is unsigned char. Please modify 14 | the part which writes G if you wish. 15 | */ 16 | #include 17 | #include "mex.h" 18 | 19 | /* Input Arguments: tentative H matrix*/ 20 | #define H_IN prhs[0] 21 | #define Q_IN prhs[1] /* field base */ 22 | 23 | /* Output Arguments: final matrices*/ 24 | #define H_OUT plhs[0] 25 | #define G_OUT plhs[1] 26 | 27 | 28 | 29 | 30 | 31 | 32 | /************************************ GFq math *******************************/ 33 | 34 | /* This file contains lookup tables and routines required 35 | * to perform the field operations over GF(q), i.e. addition 36 | * and multiplication. 37 | * 38 | * Addition is easy, we use exclusive-or operation. 39 | * For multiplication we need two tables for each q. 40 | * The first is the logarithm table, and the second 41 | * is the exponential table. We catch multiplication 42 | * by zero and one separately. 43 | * 44 | * Source for tables: MacWilliams and Sloane, fig 4.5 45 | * 46 | * WARNING: for speed, no check is made that legal values 47 | * are supplied. 48 | */ 49 | const int log4[4] = {0,0,1,2}; /* stores i at address \alpha^i */ 50 | const int log8[8] = {0,0,1,3,2,6,4,5}; 51 | const int log16[16] = {0,0,1,4,2,8,5,10,3,14,9,7,6,13,11,12}; 52 | const int log32[32] = {0,0,1,18,2,5,19,11,3,29,6,27,20,8,12,23,4,\ 53 | 10,30,17,7,22,28,26,21,25,9,16,13,14,24,15}; 54 | const int log64[64] = {0,0,1,6,2,12,7,26,3,32,13,35,8,48,27,18,4,24,\ 55 | 33,16,14,52,36,54,9,45,49,38,28,41,19,56,5,62,\ 56 | 25,11,34,31,17,47,15,23,53,51,37,44,55,40,10,\ 57 | 61,46,30,50,22,39,43,29,60,42,21,20,59,57,58}; 58 | const int log128[128] = {0,0,1,31,2,62,32,103,3,7,63,15,33,84,104,\ 59 | 93, 4,124,8,121,64,79,16,115,34,11,85,38,105,46,94,51,\ 60 | 5,82,125,60,9,44,122,77,65,67,80,42,17,69,116,23,35,118,\ 61 | 12,28,86,25,39,57,106,19,47,89,95,71,52,110,6,14,83,92,126,\ 62 | 30,61,102,10,37,45,50,123,120,78,114,66,41,68,22,81,59,43,76,\ 63 | 18,88,70,109,117,27,24,56,36,49,119,113,13,91,29,101,87,108,\ 64 | 26,55,40,21,58,75,107,54,20,74,48,112,90,100,96,97,72,98,53,73,111,99}; 65 | const int log256[256] = {0,0,1,25,2,50,26,198,3,223,51,238,27,104,199,75,4,100,\ 66 | 224,14,52,141,239,129,28,193,105,248,200,8,76,113,5,138,101,47,225,\ 67 | 36,15,33,53,147,142,218,240,18,130,69,29,181,194,125,106,39,249,185,\ 68 | 201,154,9,120,77,228,114,166,6,191,139,98,102,221,48,253,226,152,37,\ 69 | 179,16,145,34,136,54,208,148,206,143,150,219,189,241,210,19,92,131,\ 70 | 56,70,64,30,66,182,163,195,72,126,110,107,58,40,84,250,133,186,61,202,\ 71 | 94,155,159,10,21,121,43,78,212,229,172,115,243,167,87,7,112,192,247,\ 72 | 140,128,99,13,103,74,222,237,49,197,254,24,227,165,153,119,38,184,180,\ 73 | 124,17,68,146,217,35,32,137,46,55,63,209,91,149,188,207,205,144,135,151,\ 74 | 178,220,252,190,97,242,86,211,171,20,42,93,158,132,60,57,83,71,109,65,\ 75 | 162,31,45,67,216,183,123,164,118,196,23,73,236,127,12,111,246,108,161,59,\ 76 | 82,41,157,85,170,251,96,134,177,187,204,62,90,203,89,95,176,156,169,160,\ 77 | 81,11,245,22,235,122,117,44,215,79,174,213,233,230,231,173,232,116,214,\ 78 | 244,234,168,80,88,175}; 79 | 80 | const int exp4[3] = {1,2,3}; /* stores \alpha^i at address i */ 81 | const int exp8[7] = {1,2,4,3,6,7,5}; 82 | const int exp16[15] = {1,2,4,8,3,6,12,11,5,10,7,14,15,13,9}; 83 | const int exp32[31] = {1,2,4,8,16,5,10,20,13,26,17,7,14,28,29,31,\ 84 | 27,19,3,6,12,24,21,15,30,25,23,11,22,9,18}; 85 | const int exp64[63] = {1,2,4,8,16,32,3,6,12,24,48,35,5,10,20,40,19,\ 86 | 38,15,30,60,59,53,41,17,34,7,14,28,56,51,37,\ 87 | 9,18,36,11,22,44,27,54,47,29,58,55,45,25,50,\ 88 | 39,13,26,52,43,21,42,23,46,31,62,63,61,57,49,33}; 89 | const int exp128[127] = {1,2,4,8,16,32,64,9,18,36,72,25,50,100,65,11,\ 90 | 22,44,88,57,114,109,83,47,94,53,106,93,51,102,69,3,6,12,24,\ 91 | 48,96,73,27,54,108,81,43,86,37,74,29,58,116,97,75,31,62,124,\ 92 | 113,107,95,55,110,85,35,70,5,10,20,40,80,41,82,45,90,61,122,\ 93 | 125,115,111,87,39,78,21,42,84,33,66,13,26,52,104,89,59,118,101,\ 94 | 67,15,30,60,120,121,123,127,119,103,71,7,14,28,56,112,105,91,63,\ 95 | 126,117,99,79,23,46,92,49,98,77,19,38,76,17,34,68}; 96 | 97 | const int exp256[255] = {1,2,4,8,16,32,64,128,29,58,116,232,205,135,19,38,76,\ 98 | 152,45,90,180,117,234,201,143,3,6,12,24,48,96,192,157,39,78,156,\ 99 | 37,74,148,53,106,212,181,119,238,193,159,35,70,140,5,10,20,40,80,\ 100 | 160,93,186,105,210,185,111,222,161,95,190,97,194,153,47,94,188,101,\ 101 | 202,137,15,30,60,120,240,253,231,211,187,107,214,177,127,254,\ 102 | 225,223,163,91,182,113,226,217,175,67,134,17,34,68,136,13,26,52,104,\ 103 | 208,189,103,206,129,31,62,124,248,237,199,147,59,118,236,197,151,51,\ 104 | 102,204,133,23,46,92,184,109,218,169,79,158,33,66,132,21,42,84,168,\ 105 | 77,154,41,82,164,85,170,73,146,57,114,228,213,183,115,230,209,191,99,\ 106 | 198,145,63,126,252,229,215,179,123,246,241,255,227,219,171,75,150,49,\ 107 | 98,196,149,55,110,220,165,87,174,65,130,25,50,100,200,141,7,14,28,56,\ 108 | 112,224,221,167,83,166,81,162,89,178,121,242,249,239,195,155,43,86,172,\ 109 | 69,138,9,18,36,72,144,61,122,244,245,247,243,251,235,203,139,11,22,44,\ 110 | 88,176,125,250,233,207,131,27,54,108,216,173,71,142}; 111 | 112 | 113 | /* For testing: 114 | main(){ 115 | 116 | u_int i,j,q; 117 | 118 | while(1){ 119 | printf("please enter a b q:"); 120 | scanf("%u %u %u",&i,&j,&q); 121 | printf("\n a * b in GF(q) = %u\n",GFq_m(i,j,q)); 122 | } 123 | } 124 | */ 125 | 126 | int GFq_m(int a, int b, int q) 127 | { 128 | 129 | if ( a == 0 || b == 0 ) return 0 ; 130 | if ( a == 1 ) return b ; 131 | if ( b == 1 ) return a ; 132 | switch (q){ 133 | case 256: 134 | return exp256[(log256[a]+log256[b])%255]; 135 | case 128: 136 | return exp128[(log128[a]+log128[b])%127]; 137 | case 64: 138 | return exp64[(log64[a]+log64[b])%63]; 139 | case 32: 140 | return exp32[(log32[a]+log32[b])%31]; 141 | case 16: 142 | return exp16[(log16[a]+log16[b])%15]; 143 | case 8: 144 | return exp8[(log8[a]+log8[b])%7]; 145 | case 4: 146 | return exp4[(log4[a]+log4[b])%3]; 147 | } 148 | mexErrMsgTxt(1,"GFq_m: I'm afraid I don't know how to multiply in GFq\n"); 149 | return 0 ; 150 | } 151 | 152 | int GFq_inv(int a, int q) 153 | { 154 | 155 | if ( a == 0) mexErrMsgTxt(1,"GFq_inv: no inverse for 0!\n");; 156 | if ( a == 1 ) return 1 ; 157 | switch (q){ 158 | case 256: 159 | return exp256[(255-log256[a])]; 160 | case 128: 161 | return exp128[(127-log128[a])]; 162 | case 64: 163 | return exp64[(63-log64[a])]; 164 | case 32: 165 | return exp32[(31-log32[a])]; 166 | case 16: 167 | return exp16[(15-log16[a])]; 168 | case 8: 169 | return exp8[(7-log8[a])]; 170 | case 4: 171 | return exp4[(3-log4[a])]; 172 | } 173 | mexErrMsgTxt(1,"GFq_inv: not defined inverse for GFq\n"); 174 | return 0 ; 175 | } 176 | 177 | int GFq_a(int a, int b) 178 | { 179 | return a^b; 180 | } 181 | 182 | /************************************ end GFq math *******************************/ 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | void mexFunction( 191 | int nlhs, mxArray *plhs[], 192 | int nrhs, const mxArray *prhs[] 193 | ) 194 | { 195 | unsigned char **HH, **GG; 196 | int ii, jj, *ir, *jc, rdep, tmp, d, q, scale; 197 | double *sr1, *sr2, *g; 198 | int N,M,K,i,j,k,kk,nz,*irs1,*jcs1, *irs2, *jcs2; 199 | 200 | /* Check for proper number of arguments */ 201 | if (nrhs != 2) { 202 | mexErrMsgTxt("h2g requires two input arguments."); 203 | } else if (nlhs != 2) { 204 | mexErrMsgTxt("h2g requires two output arguments."); 205 | } else if (!mxIsSparse(H_IN)) { 206 | mexErrMsgTxt("h2g requires sparse H matrix."); 207 | } 208 | 209 | /* get the field base */ 210 | q = (int)mxGetScalar(Q_IN); 211 | 212 | /* read sparse matrix H */ 213 | sr1 = mxGetPr(H_IN); 214 | irs1 = mxGetIr(H_IN); /* row */ 215 | jcs1 = mxGetJc(H_IN); /* column */ 216 | nz = mxGetNzmax(H_IN); /* number of nonzero elements (they are ones)*/ 217 | M = mxGetM(H_IN); 218 | N = mxGetN(H_IN); 219 | 220 | 221 | /* create working array HH[row][column]*/ 222 | HH = (unsigned char **)mxMalloc(M*sizeof(unsigned char *)); 223 | for(i=0 ; i 15 15 | error('wrong input parameter Z in lift_size_table_lookup.'); 16 | end 17 | 18 | set_index = lut(first_element); 19 | 20 | if set_index == 0 21 | error('wrong input parameter Z in lift_size_table_lookup.'); 22 | end 23 | 24 | end -------------------------------------------------------------------------------- /ntz.m: -------------------------------------------------------------------------------- 1 | % number of trailing zeros, binary search 2 | % according to Henry S. Warren, Jr's Hacker's Delight. 3 | function y = ntz(x) 4 | 5 | n = 1; 6 | 7 | if x == 0 8 | y = 32; 9 | return 10 | end 11 | 12 | % if bitand(x, 65535) == 0 13 | % n = n + 16; 14 | % x = bitshift(x, -16); 15 | % end 16 | 17 | if bitand(x, 255) == 0 18 | n = n + 8; 19 | x = bitshift(x, -8); 20 | end 21 | 22 | if bitand(x, 15) == 0 23 | n = n + 4; 24 | x = bitshift(x, -4); 25 | end 26 | 27 | if bitand(x, 3) == 0 28 | n = n + 2; 29 | x = bitshift(x, -2); 30 | end 31 | 32 | y = n - bitand(x, 1); 33 | 34 | end -------------------------------------------------------------------------------- /parity_check_matrices_calculation.m: -------------------------------------------------------------------------------- 1 | % 5g ldpc parity check matrices 2 | % reference: 3GPP TS 38.212 section 5.3.2 3 | % author: Xiao, Shaoning 萧少宁 4 | % license: MIT 5 | 6 | function parity_check_matrices_calculation 7 | 8 | parity_check_matrices_protocol_1 = zeros(46, 68, 8); 9 | for index = 1:8 10 | parity_check_matrices_protocol_1(:, :, index) = xlsread('R1-1711982_BG1.xlsx', index+1); 11 | end 12 | 13 | save parity_check_matrices_protocol_1 parity_check_matrices_protocol_1 14 | 15 | parity_check_matrices_protocol_2 = zeros(42, 52, 8); 16 | for index = 1:8 17 | parity_check_matrices_protocol_2(:, :, index) = xlsread('R1-1711982_BG2.xlsx', index+1); 18 | end 19 | 20 | save parity_check_matrices_protocol_2 parity_check_matrices_protocol_2 21 | 22 | end -------------------------------------------------------------------------------- /parity_check_matrices_protocol_1.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshaoning/5g-ldpc/0887c1b810c4755fe410bd314522d10bf20aa656/parity_check_matrices_protocol_1.mat -------------------------------------------------------------------------------- /parity_check_matrices_protocol_2.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoshaoning/5g-ldpc/0887c1b810c4755fe410bd314522d10bf20aa656/parity_check_matrices_protocol_2.mat -------------------------------------------------------------------------------- /tanner_LDPC.m: -------------------------------------------------------------------------------- 1 | % Name: tanner_LDPC.m 2 | % Description: This script displays different parameters of an LDPC code 3 | % given his A-list format file. 4 | % Copyright (c) 2009. Robert Morelos-Zaragoza. All rights reserved. 5 | 6 | % clear all 7 | % 8 | % name = input('enter file name: '); 9 | name = 'NR_ldpc'; 10 | [H] = alist2sparse('NR_ldpc.alist') 11 | 12 | figure(1) 13 | spy(H) 14 | title( strcat('H matrix of LDPC code with A-list file name: ', name)) 15 | 16 | n1 = size(H,1); n2 = size(H,2); 17 | 18 | % Adjacency matrix as defined in Matlab 19 | A = [ zeros(n2) H'; H zeros(n1) ]; 20 | 21 | xy = []; 22 | for i=1:n2 23 | xy = [ xy; i 2 ]; % Locations of code nodes 24 | end 25 | for i=1:n1 26 | xy = [ xy; i 1 ]; % Locations of check nodes 27 | end 28 | 29 | figure(2) 30 | gplot(A,xy) 31 | axis([0 n2+1 0.9 2.1]) 32 | title( strcat('Tanner graph of LDPC code with A-list file name: ', name)) 33 | 34 | figure(3) 35 | for i=1:n1 36 | cnd(i) = sum(H(i,:)); 37 | end 38 | stem(cnd) 39 | title('Check node degree distribution') 40 | 41 | figure(4) 42 | for j=1:n2 43 | vnd(j) = sum(H(:,j)); 44 | end 45 | stem(vnd) 46 | title('Variable node degree distribution') 47 | 48 | fprintf('Density = %e\n',nnz(H)/(n1*n2)); 49 | -------------------------------------------------------------------------------- /test_all_ldpc_cases.m: -------------------------------------------------------------------------------- 1 | base_graph_list = 1:2; 2 | 3 | Z_c_list = [2, 4, 8, 16, 32, 64, 128, 256, ... 4 | 3, 6, 12, 24, 48, 96, 192, 384, ... 5 | 5, 10, 20, 40, 80, 160, 320, ... 6 | 7, 14, 28, 56, 112, 224, ... 7 | 9, 18, 36, 72, 144, 288, ... 8 | 11, 22, 44, 88, 176, 352, ... 9 | 13, 26, 52, 104, 208, ... 10 | 15, 30, 60, 120, 240]; 11 | 12 | pass_or_failure = 1; 13 | for base_graph = base_graph_list 14 | for Z_c = Z_c_list 15 | pass_flag = test_ldpc(base_graph, Z_c); 16 | if ~pass_flag 17 | pass_or_failure = 0; 18 | disp(['The case base_graph = ', num2str(base_graph), ' Z_c= ', num2str(Z_c), ' passed.']); 19 | break; 20 | else 21 | disp(['case base_graph = ', num2str(base_graph), ' Z_c= ', num2str(Z_c), ' passed.']); 22 | end 23 | end 24 | end 25 | 26 | if pass_or_failure == 1 27 | disp('test passed.'); 28 | else 29 | disp('test failed.'); 30 | end 31 | -------------------------------------------------------------------------------- /test_ldpc.m: -------------------------------------------------------------------------------- 1 | % 5g ldpc encoding and decoding test 2 | % reference: 3GPP TS 38.212 section 5.3.2 3 | % author: Xiao, Shaoning 萧少宁 4 | % license: MIT 5 | 6 | function pass_flag = test_ldpc(varargin) 7 | 8 | if nargin == 0 9 | base_graph_index = 1; 10 | Z_c = 384; 11 | elseif nargin == 1 12 | base_graph_index = varargin{1}; 13 | Z_c = 384; 14 | elseif nargin == 2 15 | base_graph_index = varargin{1}; 16 | Z_c = varargin{2}; 17 | end 18 | 19 | SNR_list = 10; 20 | 21 | trial_number = 1; 22 | 23 | BLER = zeros(1, length(SNR_list)); 24 | 25 | TxRx.Decoder.LDPC.Iterations = 30; 26 | TxRx.Decoder.LDPC.Type = 'OMS'; 27 | % TxRx.Decoder.LDPC.Type = 'MPA'; 28 | 29 | if base_graph_index == 1 30 | load base_graph_1_check_node_list 31 | base_graph_check_node_list = base_graph_1_check_node_list; 32 | LDPC.inf_bits = 22 * Z_c; 33 | elseif base_graph_index == 2 34 | load base_graph_2_check_node_list 35 | base_graph_check_node_list = base_graph_2_check_node_list; 36 | LDPC.inf_bits = 10 * Z_c; 37 | else 38 | error('wrong base graph index.'); 39 | end 40 | 41 | for SNR_list_index = 1:length(SNR_list) 42 | 43 | sigma_square = 10^(-SNR_list(SNR_list_index)/10); 44 | 45 | for trial = 1:trial_number 46 | 47 | tx_bits = randi([0, 1], LDPC.inf_bits, 1); 48 | 49 | % [encoded_bits, LDPC.H, Z_c] = ldpc_encode(tx_bits, base_graph_index); 50 | [encoded_bits, LDPC.H, Z_c] = ldpc_encode_optimized(tx_bits, base_graph_index); 51 | 52 | [LDPC.par_bits, LDPC.tot_bits] = size(LDPC.H); 53 | 54 | symbols = 1 - 2 * encoded_bits; 55 | 56 | noise = randn(size(symbols)); 57 | 58 | waveform = symbols + noise * sqrt(sigma_square); 59 | 60 | LLR_received = 2 * waveform / sigma_square; 61 | 62 | rx_bits = decLDPC_layered(TxRx, LDPC, LLR_received.', base_graph_check_node_list, Z_c); 63 | 64 | % f0=1./(1+exp(-2*LLR_received)); 65 | % f1 = 1 - f0; 66 | % f = [f0, f1].'; 67 | % rx_bits_prime = ldpc_decode(f0,f1, full(LDPC.H), TxRx.Decoder.LDPC.Iterations); 68 | % 69 | % ldpc_dec = comm.LDPCDecoder(LDPC.H); 70 | % LLR_received_extended = [zeros(2*Z_c, 1); LLR_received]; 71 | % decoded_bits = step(ldpc_dec, LLR_received_extended); 72 | % 73 | % [rx_bits_prime, success, k] = ldpc_decode_1(f, full(LDPC.H), 2); 74 | rx_bits = rx_bits(:); 75 | 76 | if ~isequal(tx_bits, rx_bits) 77 | BLER(SNR_list_index) = BLER(SNR_list_index) + 1; 78 | end 79 | 80 | % if ~isequal(rx_bits_prime(1:LDPC.inf_bits), tx_bits) 81 | % BLER(SNR_list_index) = BLER(SNR_list_index) + 1; 82 | % end 83 | % 84 | % if ~isequal(double(decoded_bits), tx_bits) 85 | % BLER(SNR_list_index) = BLER(SNR_list_index) + 1; 86 | % end 87 | 88 | end 89 | 90 | end 91 | 92 | fprintf('BLER is %f\n', BLER/trial_number); 93 | 94 | if BLER < 1e-10 95 | pass_flag = true; 96 | else 97 | pass_flag = false; 98 | end 99 | 100 | end -------------------------------------------------------------------------------- /test_ldpc_encode.m: -------------------------------------------------------------------------------- 1 | % 5g ldpc encoding test 2 | % reference: 3GPP TS 38.212 section 5.3.2 3 | % author: Xiao, Shaoning 萧少宁 4 | % license: MIT 5 | % currently the only supported case is K = 8448 6 | 7 | function test_ldpc_encode 8 | 9 | K = 8448; 10 | z = 384; 11 | 12 | s = randi([0, 1], K, 1); 13 | 14 | [~, ~, ~, encoded_bits_original] = ldpc_encode(s, 1); 15 | 16 | load H 17 | 18 | x = mod(H * encoded_bits_original, 2); 19 | 20 | if isequal(x, zeros(46*z, 1)) 21 | disp('LDPC encoding test passed.'); 22 | else 23 | disp('LDPC encoding test failed.'); 24 | end 25 | 26 | end -------------------------------------------------------------------------------- /test_ldpc_encode_2.m: -------------------------------------------------------------------------------- 1 | % 5g ldpc encoding test 2 | % reference: 3GPP TS 38.212 section 5.3.2 3 | % author: Xiao, Shaoning 萧少宁 4 | % license: MIT 5 | % currently the only supported case is K = 3840 6 | 7 | function test_ldpc_encode_2 8 | 9 | K = 3840; 10 | z = 384; 11 | 12 | s = randi([0, 1], K, 1); 13 | 14 | [~, H, ~, encoded_bits_original] = ldpc_encode(s, 2); 15 | 16 | x = mod(H * encoded_bits_original, 2); 17 | 18 | y = zeros(42*z, 1); 19 | 20 | if isequal(x, y) 21 | disp('LDPC encoding test passed.'); 22 | else 23 | disp('LDPC encoding test failed.'); 24 | end 25 | 26 | end --------------------------------------------------------------------------------