├── .gitignore ├── mats.list ├── h2.list ├── g1.list ├── matlab ├── H_5gnr_ldpc.mat ├── wifi_ieee802_11n_N648_M234.mat ├── wimax_ieee802_16_N2304_M768.mat ├── pchk2gen.m ├── main.m ├── inv_GF2.m ├── test_ldpc.m ├── demo_1_main.m └── LDPCCode.m ├── bram_init.coe ├── h3.list ├── h1.list ├── hdl ├── top.v ├── encode.v └── memory.v ├── README.md ├── test ├── tb_encode.v ├── tb_memory.v └── tb_top.v ├── notes.md ├── mats.txt └── search.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.vcd 2 | *.out 3 | sim/ 4 | matlab/H_5gnr_ldpc.csv 5 | -------------------------------------------------------------------------------- /mats.list: -------------------------------------------------------------------------------- 1 | 10100 2 | 10010 3 | 10001 4 | 01100 5 | 01010 6 | 01001 7 | 8 | -------------------------------------------------------------------------------- /h2.list: -------------------------------------------------------------------------------- 1 | 11100010000 2 | 00011101000 3 | 10010000100 4 | 01001000010 5 | 00100100001 6 | 7 | -------------------------------------------------------------------------------- /g1.list: -------------------------------------------------------------------------------- 1 | 10000010100 2 | 01000010010 3 | 00100010001 4 | 00010001100 5 | 00001001010 6 | 00000101001 7 | -------------------------------------------------------------------------------- /matlab/H_5gnr_ldpc.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodePurble/ldpc-fpga/HEAD/matlab/H_5gnr_ldpc.mat -------------------------------------------------------------------------------- /matlab/wifi_ieee802_11n_N648_M234.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodePurble/ldpc-fpga/HEAD/matlab/wifi_ieee802_11n_N648_M234.mat -------------------------------------------------------------------------------- /matlab/wimax_ieee802_16_N2304_M768.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodePurble/ldpc-fpga/HEAD/matlab/wimax_ieee802_16_N2304_M768.mat -------------------------------------------------------------------------------- /bram_init.coe: -------------------------------------------------------------------------------- 1 | memory_initialization_radix=2; 2 | memory_initialization_vector=10000010100 01000010010 00100010001 00010001100 00001001010 00000101001; 3 | -------------------------------------------------------------------------------- /matlab/pchk2gen.m: -------------------------------------------------------------------------------- 1 | function [G] = pchk2gen(H, n, k) 2 | A = H(1:end, 1:k); 3 | B = H(1:end, (k+1):end); 4 | 5 | B_trans_inv_gf2 = inv_GF2(B'); 6 | G = [eye(k), mod(A' * B_trans_inv_gf2, 2)]; 7 | end 8 | -------------------------------------------------------------------------------- /h3.list: -------------------------------------------------------------------------------- 1 | 0010000101001000 2 | 0001001010001000 3 | 0100101001000000 4 | 0001010000100100 5 | 0010000010000011 6 | 1000010011000000 7 | 0001000100010010 8 | 0100010000010001 9 | 1000001000000101 10 | 0010100000010100 11 | 0100000000101010 12 | 1000100100100000 13 | 14 | -------------------------------------------------------------------------------- /h1.list: -------------------------------------------------------------------------------- 1 | 11110000000000000000 2 | 00001111000000000000 3 | 00000000111100000000 4 | 00000000000011110000 5 | 00000000000000001111 6 | 10001000100010000000 7 | 01000100010000001000 8 | 00100010000001000100 9 | 00010000001000100010 10 | 00000001000100010001 11 | 10000100000100000100 12 | 01000010001000010000 13 | 00100001000010000010 14 | 00010000100001001000 15 | 00001000010000100001 16 | 17 | -------------------------------------------------------------------------------- /hdl/top.v: -------------------------------------------------------------------------------- 1 | module top( 2 | info_bits, 3 | generator, 4 | codeword, 5 | clk, 6 | i_en 7 | ); 8 | parameter N = 11; 9 | parameter K = 6; 10 | 11 | input clk, i_en; 12 | input [K-1:0] info_bits; 13 | input [(K*N)-1:0] generator; 14 | output [N-1:0] codeword; 15 | 16 | encode #(.N(N), .K(K)) enc( 17 | .info_bits(info_bits), 18 | .generator(generator), 19 | .codeword(codeword), 20 | .clk(clk), 21 | .i_en(i_en) 22 | ); 23 | endmodule 24 | -------------------------------------------------------------------------------- /hdl/encode.v: -------------------------------------------------------------------------------- 1 | module encode( 2 | info_bits, 3 | generator, 4 | codeword, 5 | clk, 6 | i_en 7 | ); 8 | 9 | parameter N = 6; 10 | parameter K = 3; 11 | 12 | input clk, i_en; 13 | input [K-1:0] info_bits; 14 | input [(K*N)-1:0] generator; 15 | output reg [N-1:0] codeword; 16 | 17 | always @(posedge clk) 18 | begin 19 | if(i_en) 20 | begin: gen 21 | integer i, j; 22 | for(i = 0; i < N; i=i+1) begin 23 | codeword[i] = 0; 24 | for(j = 0; j < K; j=j+1) begin 25 | codeword[i] = codeword[i] ^ (info_bits[j] & generator[j*N + i]); 26 | end 27 | end 28 | end 29 | end 30 | endmodule 31 | 32 | -------------------------------------------------------------------------------- /hdl/memory.v: -------------------------------------------------------------------------------- 1 | // simple 2-port memory 2 | module memory( 3 | clk, 4 | addr, 5 | rw, // 0 is read, 1 is write 6 | o_en, 7 | data_out, 8 | data_in 9 | ); 10 | 11 | parameter ADDR_W = 3; 12 | parameter DATA_W = 5; 13 | input [ADDR_W-1:0] addr; 14 | input clk, o_en, rw; 15 | input [DATA_W-1:0] data_in; 16 | output reg [DATA_W-1:0] data_out; 17 | 18 | reg [DATA_W-1:0] mem [0:(2**ADDR_W)]; 19 | always @(posedge clk) 20 | begin 21 | if(~rw) begin 22 | if(~o_en) begin 23 | data_out = 'hz; 24 | end 25 | else begin 26 | data_out <= mem[addr]; 27 | end 28 | end 29 | else begin 30 | mem[addr] <= data_in; 31 | end 32 | end 33 | 34 | endmodule 35 | 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ldpc-fpga 2 | Playground for implementing LDPC codes on FPGA 3 | 4 | The work contained in this repository is focused on implementing a multiplier to be used to in an LDPC encoder. The multiplier used modulo-2 arithmetic. 5 | 6 | * The [`main`](https://github.com/CodePurble/ldpc-fpga/tree/main) branch contains a brute-force and naive implementation of the multiplier (it is unlikely to be of any practical use. 7 | * The [`re-arch`](https://github.com/CodePurble/ldpc-fpga/tree/re-arch) branch contains a more practical design for the multiplier. **Highly recommended you check this branch, since more meaningful stuff is here** 8 | 9 | Both implementations are, however, intended to be very fast. Take a look at [`notes.md`](https://github.com/CodePurble/ldpc-fpga/blob/main/notes.md) for details on the size of parity check matrices that are used in various standards. 10 | -------------------------------------------------------------------------------- /test/tb_encode.v: -------------------------------------------------------------------------------- 1 | module tb_encode; 2 | parameter N = 11; 3 | parameter K = 6; 4 | 5 | reg clk, i_en; 6 | reg [K-1:0] info_bits; 7 | /* reg [((K)*(N-K))-1:0] generator; */ 8 | reg [(K*N)-1:0] generator; 9 | wire [N-1:0] codeword; 10 | 11 | encode #(.N(N), .K(K)) uut( 12 | .info_bits(info_bits), 13 | .generator(generator), 14 | .codeword(codeword), 15 | .clk(clk), 16 | .i_en(i_en) 17 | ); 18 | 19 | initial clk = 1'b1; 20 | always #10 clk = ~clk; 21 | 22 | initial 23 | begin 24 | $dumpfile("../sim/tb_encode_dump.vcd"); 25 | $dumpvars(0, tb_encode); 26 | generator = 66'b100000101000100001001000100010001000100011000000100101000000101001; 27 | /* generator = 30'b101001001010001011000101001001; */ 28 | i_en = 1; 29 | info_bits = 6'b111111; 30 | #30 $finish; 31 | end 32 | 33 | initial 34 | begin 35 | $monitor("info=%b, code=%b", info_bits, codeword); 36 | end 37 | endmodule 38 | 39 | -------------------------------------------------------------------------------- /test/tb_memory.v: -------------------------------------------------------------------------------- 1 | module tb_memory(); 2 | 3 | parameter ADDR_W = 3; 4 | parameter DATA_W = 5; 5 | reg [ADDR_W-1:0] addr; 6 | reg clk, o_en, rw; 7 | reg [DATA_W-1:0] data_in; 8 | wire [DATA_W-1:0] data_out; 9 | 10 | memory #(.ADDR_W(ADDR_W), .DATA_W(DATA_W)) uut( 11 | .addr(addr), 12 | .o_en(o_en), 13 | .data_in(data_in), 14 | .data_out(data_out), 15 | .rw(rw), 16 | .clk(clk) 17 | ); 18 | 19 | initial 20 | begin 21 | clk = 0; 22 | o_en = 0; 23 | $dumpfile("../sim/tb_memory_dump.vcd"); 24 | $dumpvars(0, tb_memory); 25 | end 26 | 27 | always #10 clk = ~clk; 28 | 29 | initial 30 | begin: test 31 | integer i; 32 | 33 | rw = 1; 34 | for(i = 0; i < 2**ADDR_W; i+=1) begin 35 | #20 addr = i; 36 | data_in = i; 37 | end 38 | 39 | rw = 0; 40 | o_en = 1; 41 | for(i = 0; i < 2**ADDR_W; i+=1) begin 42 | #20 addr = i; 43 | end 44 | #20 $finish; 45 | end 46 | 47 | endmodule 48 | -------------------------------------------------------------------------------- /matlab/main.m: -------------------------------------------------------------------------------- 1 | n = 16; 2 | k = 4; 3 | A3 = [ 4 | [0,0,1,0]; 5 | [0,0,0,1]; 6 | [0,1,0,0]; 7 | [0,0,0,1]; 8 | [0,0,1,0]; 9 | [1,0,0,0]; 10 | [0,0,0,1]; 11 | [0,1,0,0]; 12 | [1,0,0,0]; 13 | [0,0,1,0]; 14 | [0,1,0,0]; 15 | [1,0,0,0]; 16 | ]; 17 | 18 | B3 = [ 19 | [0,0,0,1,0,1,0,0,1,0,0,0]; 20 | [0,0,1,0,1,0,0,0,1,0,0,0]; 21 | [1,0,1,0,0,1,0,0,0,0,0,0]; 22 | [0,1,0,0,0,0,1,0,0,1,0,0]; 23 | [0,0,0,0,1,0,0,0,0,0,1,1]; 24 | [0,1,0,0,1,1,0,0,0,0,0,0]; 25 | [0,0,0,1,0,0,0,1,0,0,1,0]; 26 | [0,1,0,0,0,0,0,1,0,0,0,1]; 27 | [0,0,1,0,0,0,0,0,0,1,0,1]; 28 | [1,0,0,0,0,0,0,1,0,1,0,0]; 29 | [0,0,0,0,0,0,1,0,1,0,1,0]; 30 | [1,0,0,1,0,0,1,0,0,0,0,0]; 31 | ]; 32 | 33 | H3 = [A3, B3]; 34 | 35 | B3_inv = inv_GF2(B3'); 36 | G1 = [eye(k), mod(A3'*B3_inv, 2)]; 37 | G2 = pchk2gen(H3, n, k); 38 | isequal(G1, G2); 39 | 40 | mat = load('H_5gnr_ldpc.mat', "H"); 41 | H_full = full(mat.H); 42 | writematrix(H_full, "H_5gnr_ldpc.csv"); 43 | -------------------------------------------------------------------------------- /test/tb_top.v: -------------------------------------------------------------------------------- 1 | module tb_top(); 2 | 3 | parameter N = 11; 4 | parameter K = 6; 5 | reg enc_i_en, clk; 6 | reg [K-1:0] info_bits; 7 | reg [(K*N)-1:0] generator; 8 | wire [N-1:0] codeword; 9 | 10 | top #(.N(N), .K(K)) uut( 11 | .info_bits(info_bits), 12 | .generator(generator), 13 | .codeword(codeword), 14 | .clk(clk), 15 | .i_en(enc_i_en) 16 | ); 17 | 18 | reg [N-1:0] pmat_mem [0:K-1]; 19 | 20 | initial 21 | begin 22 | clk = 0; 23 | enc_i_en = 0; 24 | 25 | $dumpfile("../sim/tb_top.vcd"); 26 | $dumpvars(0, tb_top); 27 | $readmemb("../g1.list", pmat_mem); 28 | end 29 | always #10 clk = ~clk; 30 | 31 | initial 32 | begin: info 33 | integer i; 34 | for(i = 0; i < K; i=i+1) begin 35 | generator = {generator, pmat_mem[i]}; 36 | end 37 | $display("gen:%b", generator); 38 | info_bits = 6'b111111; 39 | #10 enc_i_en = 1; 40 | #20 $finish; 41 | end 42 | 43 | initial 44 | begin 45 | $monitor("code: %b", codeword); 46 | end 47 | 48 | endmodule 49 | 50 | -------------------------------------------------------------------------------- /matlab/inv_GF2.m: -------------------------------------------------------------------------------- 1 | function [Ainv] = inv_GF2(A) 2 | dim = size(A); 3 | rows = dim(1); 4 | cols = dim(2); 5 | 6 | unity = eye(rows, cols); 7 | Ainv = zeros(rows, cols); 8 | for i = 1:rows 9 | % ith column of the inverse is the solution to the system of equations 10 | % Ax = b, where b (in this case) is the ith column of an identity 11 | % matrix of appropriate dimensions 12 | % Modulo 2 arithmetic is used everywhere (see what is GF(2)) 13 | % 14 | % see `help gflineq` for more info 15 | % PS: this will not work in octave, matlab only 16 | Ainv(1:rows, i) = gflineq(A, unity(1:rows, i)); 17 | end 18 | end 19 | 20 | % Test code 21 | % n = 16; 22 | % k = 4; 23 | % A3 = [ 24 | % [0,0,1,0]; 25 | % [0,0,0,1]; 26 | % [0,1,0,0]; 27 | % [0,0,0,1]; 28 | % [0,0,1,0]; 29 | % [1,0,0,0]; 30 | % [0,0,0,1]; 31 | % [0,1,0,0]; 32 | % [1,0,0,0]; 33 | % [0,0,1,0]; 34 | % [0,1,0,0]; 35 | % [1,0,0,0]; 36 | % ]; 37 | 38 | % B3 = [ 39 | % [0,0,0,1,0,1,0,0,1,0,0,0]; 40 | % [0,0,1,0,1,0,0,0,1,0,0,0]; 41 | % [1,0,1,0,0,1,0,0,0,0,0,0]; 42 | % [0,1,0,0,0,0,1,0,0,1,0,0]; 43 | % [0,0,0,0,1,0,0,0,0,0,1,1]; 44 | % [0,1,0,0,1,1,0,0,0,0,0,0]; 45 | % [0,0,0,1,0,0,0,1,0,0,1,0]; 46 | % [0,1,0,0,0,0,0,1,0,0,0,1]; 47 | % [0,0,1,0,0,0,0,0,0,1,0,1]; 48 | % [1,0,0,0,0,0,0,1,0,1,0,0]; 49 | % [0,0,0,0,0,0,1,0,1,0,1,0]; 50 | % [1,0,0,1,0,0,1,0,0,0,0,0]; 51 | % ]; 52 | 53 | % H3 = [A3, B3]; 54 | 55 | % B3_inv = inv_GF2(B3'); 56 | % G = [eye(k), mod(A3'*B3_inv, 2)] 57 | 58 | -------------------------------------------------------------------------------- /notes.md: -------------------------------------------------------------------------------- 1 | # Notes 2 | 3 | ## LDPC codes from communication standards 4 | 5 | **NOTE: The dimensions of H in ALL CASES are `(n-k) x n`** 6 | 7 | ### DOCSIS 3.1 (Data Over Cable Service Interface Specification) 8 | 9 | | `n` | `k` | `m = n - k` | Code rate `R = k/n` | 10 | |---------------|-------|-------------|---------------------| 11 | | 16200 (Long) | 14400 | 1800 | 0.889 | 12 | | 5940 (Medium) | 5040 | 900 | 0.8484 | 13 | | 1080 (Short) | 810 | 270 | 0.75 | 14 | 15 | ### WiFi `IEEE 802.11n` 16 | 17 | | `n` | `k` | `m = n - k` | Code rate `R = k/n` | 18 | |------|------|-------------|---------------------| 19 | | 648 | 234 | 234 | 0.5 | 20 | | | 432 | 216 | 0.67 | 21 | | | 486 | 162 | 0.75 | 22 | | | 540 | 108 | 0.83 | 23 | |------|------|-------------|---------------------| 24 | | 1296 | 648 | 648 | 0.5 | 25 | | | 864 | 432 | 0.67 | 26 | | | 486 | 234 | 0.75 | 27 | | | 1080 | 216 | 0.83 | 28 | |------|------|-------------|---------------------| 29 | | 1944 | 972 | 972 | 0.5 | 30 | | | 1296 | 648 | 0.67 | 31 | | | 1458 | 486 | 0.75 | 32 | | | 1710 | 234 | 0.83 | 33 | 34 | ### WiMax `IEEE 802.16` 35 | 36 | | `n` | `k` | `m = n - k` | Code rate `R = k/n` | 37 | |------|------|-------------|---------------------| 38 | | 2304 | 1152 | 1152 | 0.5 | 39 | | | 1536 | 768 | 0.67 | 40 | | | 1728 | 576 | 0.75 | 41 | | | 1920 | 384 | 0.83 | 42 | 43 | ### 5G-NR 44 | 45 | | `n` | `k` | `m = n - k` | Code rate `R = k/n` | 46 | |--------|------|-------------|---------------------| 47 | | 26,112 | 8448 | 17,664 | 0.323 | 48 | 49 | 50 | > [REF] Mahmudul Hasan, "LDPC Codes from Communication Standards," webdemo, 51 | > Institute of Telecommunications, University of Stuttgart, Germany, Sep. 2021. 52 | > [Online] Available: http://webdemo.inue.uni-stuttgart.de 53 | > 54 | > Bibtex entry: `ldpcwebdemo` 55 | > 56 | > 5G-NR https://github.com/xiaoshaoning/5g-ldpc/blob/master/H.mat 57 | -------------------------------------------------------------------------------- /mats.txt: -------------------------------------------------------------------------------- 1 | H1 = [ 2 | [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], 3 | [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], 4 | [0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0], 5 | [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0], 6 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1], 7 | 8 | [1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0], 9 | [0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0], 10 | [0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0], 11 | [0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0], 12 | [0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1], 13 | 14 | [1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0], 15 | [0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0], 16 | [0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0], 17 | [0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,1,0,0,0], 18 | [0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1] 19 | ] 20 | 21 | H2 = [P^|I] 22 | H2 = [ 23 | [1,1,1,0,0,0|1,0,0,0,0], 24 | [0,0,0,1,1,1|0,1,0,0,0], 25 | [1,0,0,1,0,0|0,0,1,0,0], 26 | [0,1,0,0,1,0|0,0,0,1,0], 27 | [0,0,1,0,0,1|0,0,0,0,1], 28 | ] 29 | 30 | 31 | G2 = [I|P] 32 | G2 = [ 33 | [1,0,0,0,0,0|1,0,1,0,0], 34 | [0,1,0,0,0,0|1,0,0,1,0], 35 | [0,0,1,0,0,0|1,0,0,0,1], 36 | [0,0,0,1,0,0|0,1,1,0,0], 37 | [0,0,0,0,1,0|0,1,0,1,0], 38 | [0,0,0,0,0,1|0,1,0,0,1], 39 | ] 40 | 41 | H3 = [A3|B3] 42 | H3 = [ 43 | [0,0,1,0,0,0,0,1,0,1,0,0,1,0,0,0]; 44 | [0,0,0,1,0,0,1,0,1,0,0,0,1,0,0,0]; 45 | [0,1,0,0,1,0,1,0,0,1,0,0,0,0,0,0]; 46 | [0,0,0,1,0,1,0,0,0,0,1,0,0,1,0,0]; 47 | [0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,1]; 48 | [1,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0]; 49 | [0,0,0,1,0,0,0,1,0,0,0,1,0,0,1,0]; 50 | [0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1]; 51 | [1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1]; 52 | [0,0,1,0,1,0,0,0,0,0,0,1,0,1,0,0]; 53 | [0,1,0,0,0,0,0,0,0,0,1,0,1,0,1,0]; 54 | [1,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0]; 55 | ] 56 | 57 | A3 = [ 58 | [0,0,1,0]; 59 | [0,0,0,1]; 60 | [0,1,0,0]; 61 | [0,0,0,1]; 62 | [0,0,1,0]; 63 | [1,0,0,0]; 64 | [0,0,0,1]; 65 | [0,1,0,0]; 66 | [1,0,0,0]; 67 | [0,0,1,0]; 68 | [0,1,0,0]; 69 | [1,0,0,0]; 70 | ] 71 | 72 | B3 = [ 73 | [0,0,0,1,0,1,0,0,1,0,0,0]; 74 | [0,0,1,0,1,0,0,0,1,0,0,0]; 75 | [1,0,1,0,0,1,0,0,0,0,0,0]; 76 | [0,1,0,0,0,0,1,0,0,1,0,0]; 77 | [0,0,0,0,1,0,0,0,0,0,1,1]; 78 | [0,1,0,0,1,1,0,0,0,0,0,0]; 79 | [0,0,0,1,0,0,0,1,0,0,1,0]; 80 | [0,1,0,0,0,0,0,1,0,0,0,1]; 81 | [0,0,1,0,0,0,0,0,0,1,0,1]; 82 | [1,0,0,0,0,0,0,1,0,1,0,0]; 83 | [0,0,0,0,0,0,1,0,1,0,1,0]; 84 | [1,0,0,1,0,0,1,0,0,0,0,0]; 85 | ] 86 | -------------------------------------------------------------------------------- /search.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void swap_rows(int s_rows, int s_cols, int r1, int r2, int *arr); 5 | void swap_cols(int s_rows, int s_cols, int c1, int c2, int *arr); 6 | void print_mat(int rows, int cols, int *mat); 7 | void read_mat(const char* fname, int r, int c, int *dest); 8 | int* get_cols_with_ones(int rows, int cols, int *mat, int wr); 9 | 10 | int main() 11 | { 12 | const int n = 11; 13 | const int k = 6; 14 | const int m = n - k; 15 | const int wc = 2; 16 | const int wr = 3; 17 | int *h_mat = calloc(m*n, sizeof(int)); 18 | read_mat("h2.txt", m, n, h_mat); 19 | int *cols_with_ones = get_cols_with_ones(m, n, h_mat, wr); 20 | for(int i = 0; i < m; i++) { 21 | for(int j = 0; j < wr; j++) { 22 | if(cols_with_ones[i*wr + j]) { 23 | } 24 | } 25 | } 26 | 27 | 28 | free(cols_with_ones); 29 | free(h_mat); 30 | return 0; 31 | } 32 | 33 | int* get_cols_with_ones(int rows, int cols, int *mat, int wr) 34 | { 35 | int *cols_with_ones = calloc(rows*wr, sizeof(int)); 36 | int ind; 37 | for(int i = 0; i < rows; i++) { 38 | ind = 0; 39 | for(int j = 0; j < cols; j++) { 40 | if(mat[i*cols + j] == 1) { 41 | cols_with_ones[i*wr + ind] = j; 42 | ind++; 43 | } 44 | } 45 | } 46 | return cols_with_ones; 47 | } 48 | 49 | void read_mat(const char* fname, int r, int c, int *dest) 50 | { 51 | FILE *fp = fopen(fname, "r"); 52 | char ch; 53 | int i = 0; 54 | int j = 0; 55 | while((ch = getc(fp)) != EOF) { 56 | if(ch != '\n') { 57 | dest[i*c + j] = ch - '0'; 58 | j++; 59 | } 60 | else { 61 | j = 0; 62 | i++; 63 | } 64 | } 65 | } 66 | 67 | void print_mat(int rows, int cols, int *mat) 68 | { 69 | for(int i = 0; i < rows; i++) { 70 | for(int j = 0; j < cols; j++) { 71 | printf("%3d", mat[i*cols + j]); 72 | } 73 | printf("\n"); 74 | } 75 | printf("\n"); 76 | } 77 | 78 | void swap_rows(int s_rows, int s_cols, int r1, int r2, int *arr) 79 | { 80 | if(r1 > s_rows || r2 > s_rows) { 81 | return; 82 | } 83 | int temp; 84 | for(int i = 0; i < s_cols; i++) { 85 | temp = arr[r1*s_cols + i]; 86 | arr[r1*s_cols + i] = arr[r2*s_cols + i]; 87 | arr[r2*s_cols + i] = temp; 88 | } 89 | } 90 | 91 | void swap_cols(int s_rows, int s_cols, int c1, int c2, int *arr) 92 | { 93 | if(c1 > s_cols || c2 > s_cols) { 94 | return; 95 | } 96 | int temp; 97 | for(int i = 0; i < s_rows; i++) { 98 | temp = arr[i*s_cols + c1]; 99 | arr[i*s_cols + c1] = arr[i*s_cols + c2]; 100 | arr[i*s_cols + c2] = temp; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /matlab/test_ldpc.m: -------------------------------------------------------------------------------- 1 | % global col_weight_vec row_weight_vec; 2 | % global max_col_weight max_row_weight; 3 | % global cols_with_ones rows_with_ones; 4 | 5 | N = 20; 6 | K = 5; 7 | M = N - K; 8 | Z = 5; 9 | H = [ 10 | [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; 11 | [0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0]; 12 | [0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0]; 13 | [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0]; 14 | [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1]; 15 | 16 | [1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0]; 17 | [0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0]; 18 | [0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0]; 19 | [0,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0]; 20 | [0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1]; 21 | 22 | [1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0]; 23 | [0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0]; 24 | [0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0]; 25 | [0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,1,0,0,0]; 26 | [0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1] 27 | ]; 28 | 29 | %{ 30 | N = 11; 31 | K = 5; 32 | M = 5; 33 | %M = N - K; 34 | Z = 5; 35 | H = [ 36 | [1,0,0,0,0,1,1,1,0,0,0], 37 | [0,1,0,0,0,0,0,0,1,1,1], 38 | [0,0,1,0,0,1,0,0,1,0,0], 39 | [0,0,0,1,0,0,1,0,0,1,0], 40 | [0,0,0,0,1,0,0,1,0,0,1], 41 | ]; 42 | %} 43 | 44 | % N = 20; 45 | % K = 5; 46 | % M = N - K; 47 | % Z = 5; 48 | function [cols_with_ones, rows_with_ones, row_weight_vec, col_weight_vec] = efficient_pcm(N, M, H) 49 | col_weight_vec = sum(H, 1); 50 | row_weight_vec = sum(H, 2); 51 | max_col_weight = max(col_weight_vec); 52 | max_row_weight = max(row_weight_vec); 53 | rows_with_ones = zeros(N, max_col_weight); 54 | cols_with_ones = zeros(M, max_row_weight); 55 | for i_row = 1 : M 56 | index = 1; 57 | for i_col = 1 : N 58 | if H(i_row, i_col) 59 | cols_with_ones(i_row, index) = i_col; 60 | index = index + 1; 61 | endif 62 | endfor 63 | endfor 64 | 65 | for i_col = 1 : N 66 | index = 1; 67 | for i_row = 1 : M 68 | if H(i_row, i_col) 69 | rows_with_ones(i_col, index) = i_row; 70 | index = index + 1; 71 | endif 72 | endfor 73 | endfor 74 | endfunction 75 | 76 | function [codeword] = encode_bits(N, K, M, H, Z, rows_with_ones, cols_with_ones, info_bits) 77 | col_weight_vec = sum(H, 1); 78 | row_weight_vec = sum(H, 2); 79 | max_col_weight = max(col_weight_vec); 80 | max_row_weight = max(row_weight_vec); 81 | % Does encoding by back substitution 82 | % Assumes a very specific structure on the partiy check matrix 83 | codeword = zeros(N, 1); 84 | codeword(1:K) = info_bits; 85 | 86 | parity = zeros(M, 1); 87 | for i_row = 1 : M 88 | for i_col = 1 : max_row_weight 89 | if (cols_with_ones(i_row, i_col) > 0) && ... 90 | (cols_with_ones(i_row, i_col) <= K) 91 | 92 | parity(i_row) = parity(i_row) + ... 93 | codeword(cols_with_ones(i_row, i_col)); 94 | endif 95 | endfor 96 | endfor 97 | 98 | parity = mod(parity, 2); 99 | 100 | for i = 1 : Z 101 | codeword(K + i) = mod(sum(parity(i:Z:end)), 2); 102 | endfor 103 | 104 | for i_row = 1 : M 105 | for i_col = 1 : max_row_weight 106 | if (cols_with_ones(i_row, i_col) > K) && ... 107 | (cols_with_ones(i_row, i_col) <= K + Z) 108 | 109 | parity(i_row) = mod(parity(i_row) + ... 110 | codeword(cols_with_ones(i_row, i_col)), 2); 111 | endif 112 | endfor 113 | endfor 114 | 115 | for i_col = K + Z + 1 : Z: N 116 | codeword(i_col: i_col + Z - 1) = parity(i_col - K - Z : i_col - K - 1); 117 | 118 | parity(i_col - K : i_col - K + Z - 1) = ... 119 | mod(parity(i_col - K - Z : i_col - K - 1) + ... 120 | parity(i_col - K : i_col + Z - K - 1), 2); 121 | endfor 122 | endfunction 123 | 124 | function [b] = check_codeword(x, M, cols_with_ones, row_weight_vec) 125 | b = 1; 126 | for i_check = 1 : M 127 | c = 0; 128 | for i_n = 1 : row_weight_vec(i_check) 129 | c = c + x(cols_with_ones(i_check, i_n)); 130 | endfor 131 | if mod(c, 2) == 1 132 | b = 0; 133 | break; 134 | endif 135 | endfor 136 | endfunction 137 | 138 | 139 | function [decoded_codeword, error_vec] = ... 140 | decode_llr( 141 | M, N, row_weight_vec, col_weight_vec, ... 142 | rows_with_ones, cols_with_ones, input_llr_vec, max_iter, min_sum 143 | ) 144 | eta = zeros(M, N); 145 | lasteta = zeros(M, N); 146 | updated_llr_vec = input_llr_vec; 147 | error_vec = zeros(max_iter, 1); 148 | for iter = 1 : max_iter 149 | for i_m = 1 : M 150 | for i_n1 = 1 : row_weight_vec(i_m) 151 | n1 = rows_with_ones(i_m, i_n1); 152 | if min_sum 153 | pr = 100; 154 | else 155 | pr = 1; 156 | endif 157 | for i_n2 = 1 : row_weight_vec(i_m) 158 | if i_n1 == i_n2 159 | continue; 160 | endif 161 | n2 = rows_with_ones(i_m, i_n2); 162 | l1 = (updated_llr_vec(n2) - lasteta(i_m, n2)); 163 | l1 = min(l1, 20); 164 | l1 = max(l1, -20); 165 | if min_sum 166 | pr = sign(pr) * sign(l1) * min(abs(l1), abs(pr)); 167 | else 168 | pr = pr * tanh(l1/2); 169 | endif 170 | endfor 171 | if min_sum 172 | eta(i_m, n1) = pr; 173 | else 174 | eta(i_m, n1) = 2 * atanh(pr); 175 | endif 176 | endfor 177 | endfor 178 | 179 | lasteta = eta; 180 | 181 | for i_n = 1 : N 182 | updated_llr_vec(i_n) = input_llr_vec(i_n); 183 | for i_m = 1 : col_weight_vec(i_n) 184 | m = cols_with_ones(i_n, i_m); 185 | updated_llr_vec(i_n) = updated_llr_vec(i_n) + eta(m,i_n); 186 | endfor 187 | endfor 188 | 189 | decoded_codeword = (updated_llr_vec < 0); 190 | if check_codeword(decoded_codeword) 191 | return; 192 | else 193 | error_vec(iter) = 1; 194 | endif 195 | endfor 196 | endfunction 197 | 198 | [cols_with_ones, rows_with_ones, row_weight_vec, col_weight_vec] = ... 199 | efficient_pcm(N, M, H); 200 | cols_with_ones 201 | rows_with_ones 202 | 203 | info_bits = [1 1 0 0 1] 204 | 205 | [codeword] = encode_bits(N, K, M, H, Z, rows_with_ones, cols_with_ones, info_bits); 206 | codeword' 207 | 208 | %codeword(1) = codeword(1) & 0 209 | 210 | [b] = check_codeword(codeword, M, cols_with_ones, row_weight_vec) 211 | -------------------------------------------------------------------------------- /matlab/demo_1_main.m: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % .m script of web demo "Insert title here" 3 | % Written for GNU Octave 4 | % 5 | % INSTITUTE OF TELECOMMUNICATIONS 6 | % University of Stuttgart 7 | % www.inue-uni-stuttgart.de 8 | % author: Mahmudul Hasan 9 | % date: 02.18.2016 10 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 11 | %matrixH(select8,text3,text4,select5,hr1,enum4,uploadfile1,filename) 12 | function [LinkMat] = demo_1_main( code1, code2, code3,enum4, filename) 13 | % function [link_mat] = demo_1_fun(text1, enum1, checkbox1, range1, select1, filename) 14 | % 15 | % % matrixH takes degree profiles, density in percentage from user and filename to save on 16 | % % Create an invisible figure. 17 | 18 | fig = figure(1); %set(fig, "visible", "off"); 19 | 20 | set(fig, "visible", "off"); 21 | 22 | 23 | 24 | landscape = "-S930,350"; 25 | portrait = "-S640,480"; 26 | 27 | output_format = portrait; % default 28 | 29 | 30 | set(0, "defaultlinelinewidth", 2); 31 | set(0, "defaultaxesfontsize", 8); 32 | set(0, "defaultaxesfontname", "Helvetica"); 33 | set(0, "defaulttextfontsize", 8); 34 | set(0, "defaulttextfontname", "Helvetica"); 35 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 36 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 37 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 38 | t=[]; 39 | t1=[]; 40 | 41 | if code1==0 && code2==0&& code3==0 42 | 43 | H=load('A.mat'); 44 | H=H.ans; 45 | t3=['n=8']; 46 | t4=['n-k=8']; 47 | 48 | 49 | elseif code1==3 50 | 51 | H = load('docsis_short.mat'); 52 | H=H.B; 53 | t3=['n=1080']; 54 | t4=['n-k=270']; 55 | t=['H of LDPC for Docsis short code with block size ',t3]; 56 | t1=['Degree profiles of LDPC for Docsis short code with block size ',t3]; 57 | 58 | elseif code1==2 59 | H = load('docsis_medium.mat'); 60 | H=H.C; 61 | t3=['n=5940']; 62 | t4=['n-k=900']; 63 | t=['H of LDPC for Docsis medium code with block size ',t3]; 64 | t1=['Degree profiles of LDPC for Docsis medium code with block size ',t3]; 65 | 66 | elseif code1==1 67 | H = load('docsis_long.mat'); 68 | H=H.D; 69 | t3=['n=16200']; 70 | t4=['n-k=1800']; 71 | t=['H of LDPC for Docsis long code with block size ',t3]; 72 | t1=['Degree profiles of LDPC for Docsis long code with block size ',t3]; 73 | 74 | end 75 | 76 | if code2==1 77 | H = load('code_.5_802.11_L_27.mat'); 78 | H = H.E; 79 | t3=['n=648']; 80 | t4=['n-k=324']; 81 | t= ['H of Wifi IEEE 802.11n with Rate = 0.5 and block size ',t3]; 82 | t1=['Degree profiles of Wifi IEEE 802.11n with Rate = 0.5 and block size',t3]; 83 | 84 | elseif code2==2 85 | H = load('code_.67_802.11_L_27.mat'); 86 | H = H.F; 87 | t3=['n=648']; 88 | t4=['n-k=216']; 89 | t= ['H of Wifi IEEE 802.11n with Rate = 0.67 and block size ',t3]; 90 | t1=['Degree profiles of Wifi IEEE 802.11n with Rate = 0.67 and block size ',t3]; 91 | 92 | elseif code2==3 93 | H = load('code_.75_802.11_L_27.mat'); 94 | H = H.G; 95 | t3=['n=648']; 96 | t4=['n-k=162']; 97 | t= ['H of Wifi IEEE 802.11n with Rate = 0.75 and block size ',t3]; 98 | t1=['Degree profiles of Wifi IEEE 802.11n with Rate = 0.75 and block size ',t3]; 99 | 100 | elseif code2==4 101 | H = load('code_.83_802.11_L_27.mat'); 102 | H = H.H; 103 | t3=['n=648']; 104 | t4=['n-k=108']; 105 | t= ['H of Wifi IEEE 802.11n with Rate = 0.83 and block size ',t3]; 106 | t1=['Degree profiles of Wifi IEEE 802.11n with Rate = 0.83 and block size ',t3]; 107 | 108 | elseif code2==5 109 | H = load('code_.5_802.11_L_54.mat'); 110 | H = H.I; 111 | t3=['n=1296']; 112 | t4=['n-k=648']; 113 | t= ['H of Wifi IEEE 802.11n with Rate = 0.5 and block size ',t3]; 114 | t1=['Degree profiles of Wifi IEEE 802.11n with Rate = 0.5 and block size ',t3]; 115 | 116 | elseif code2==6 117 | H = load('code_.67_802.11_L_54.mat'); 118 | H = H.J; 119 | t3=['n=1296']; 120 | t4=['n-k=432']; 121 | t= ['H of Wifi IEEE 802.11n with Rate = 0.67 and block size ',t3]; 122 | t1=['Degree profiles of Wifi IEEE 802.11n with Rate = 0.67 and block size ',t3]; 123 | 124 | elseif code2==7 125 | H = load('code_.75_802.11_L_54.mat'); 126 | H = H.K; 127 | t3=['n=1296']; 128 | t4=['n-k=324']; 129 | t= ['H of Wifi IEEE 802.11n with Rate = 0.75 and block size ',t3]; 130 | t1=['Degree profiles of Wifi IEEE 802.11n with Rate = 0.75 and block size ',t3]; 131 | 132 | elseif code2==8 133 | H = load('code_.83_802.11_L_54.mat'); 134 | H = H.L; 135 | t3=['n=1296']; 136 | t4=['n-k=216']; 137 | t= ['H of Wifi IEEE 802.11n with Rate = 0.83 and block size ',t3]; 138 | t1=['Degree profiles of Wifi IEEE 802.11n with Rate = 0.83 and block size ',t3]; 139 | 140 | elseif code2==9 141 | H = load('code_.5_802.11_L_81.mat'); 142 | H = H.M; 143 | t3=['n=1944']; 144 | t4=['n-k=972']; 145 | t= ['H of Wifi IEEE 802.11n with Rate = 0.5 and block size ',t3]; 146 | t1=['Degree profiles of Wifi IEEE 802.11n with Rate = 0.5 and block size ',t3]; 147 | 148 | elseif code2==10 149 | H = load('code_.67_802.11_L_81.mat'); 150 | H = H.N; 151 | t3=['n=1944']; 152 | t4=['n-k=648']; 153 | t= ['H of Wifi IEEE 802.11n with Rate = 0.67 and block size ',t3]; 154 | t1=['Degree profiles of Wifi IEEE 802.11n with Rate = 0.67 and block size ',t3]; 155 | 156 | elseif code2==11 157 | H = load('code_.75_802.11_L_81.mat'); 158 | H = H.O; 159 | t3=['n=1944']; 160 | t4=['n-k=486']; 161 | t= ['H of Wifi IEEE 802.11n with Rate = 0.75 and block size ',t3]; 162 | t1=['Degree profiles of Wifi IEEE 802.11n with Rate = 0.75 and block size ',t3]; 163 | 164 | elseif code2==12 165 | H = load('code_.83_802.11_L_81.mat'); 166 | H = H.P; 167 | t3=['n=1944']; 168 | t4=['n-k=324']; 169 | t= ['H of Wifi IEEE 802.11n with Rate = 0.83 and block size ',t3]; 170 | t1=['Degree profiles of Wifi IEEE 802.11n with Rate = 0.83 and block size',t3]; 171 | 172 | 173 | end 174 | 175 | 176 | if code3==1 177 | H = load('wimax_.50.mat'); 178 | H = H.Q; 179 | t3=['n=2304']; 180 | t4=['n-k=1152']; 181 | t= ['H of WiMax IEEE 802.16 with Rate = 0.5 and block size ',t3]; 182 | t1=['Degree profiles of WiMax IEEE 802.16 with Rate = 0.5 and block size ',t3]; 183 | 184 | elseif code3==2 185 | 186 | H = load('wimax_.67A.mat'); 187 | H = H.R; 188 | t3=['n=2304']; 189 | t4=['n-k=768']; 190 | t= ['H of WiMax IEEE 802.16 with Rate = 0.67A and block size ',t3]; 191 | t1=['Degree profiles of WiMax IEEE 802.16 with Rate = 0.67A and block size ',t3]; 192 | 193 | elseif code3==3 194 | H = load('wimax_.67B.mat'); 195 | H = H.S; 196 | t3=['n=2304']; 197 | t4=['n-k=768']; 198 | t= ['H of WiMax IEEE 802.16 with Rate = 0.67B and block size ',t3]; 199 | t1=['Degree profiles of WiMax IEEE 802.16 with Rate = 0.67B and block size ',t3]; 200 | 201 | elseif code3==4 202 | H = load('wimax_.75A.mat'); 203 | H = H.T; 204 | t3=['n=2304']; 205 | t4=['n-k=576']; 206 | t= ['H of WiMax IEEE 802.16 with Rate = 0.75A and block size',t3]; 207 | t1=['Degree profiles of WiMax IEEE 802.16 with Rate = 0.75A and block size',t3]; 208 | 209 | elseif code3==5 210 | H = load('wimax_.75B.mat'); 211 | H = H.U; 212 | t3=['n=2304']; 213 | t4=['n-k=576']; 214 | t= ['H of WiMax IEEE 802.16 with Rate = 0.75B and block size ',t3]; 215 | t1=['Degree profiles of WiMax IEEE 802.16 with Rate = 0.75B and block size ',t3]; 216 | 217 | elseif code3==6 218 | H = load('wimax_.83.mat'); 219 | H = H.V; 220 | t3=['n=2304']; 221 | t4=['n-k=384']; 222 | t= ['H of WiMax IEEE 802.16 with Rate = 0.83 and block size ',t3]; 223 | t1=['Degree profiles of WiMax IEEE 802.16 with Rate = 0.83 and block size ',t3]; 224 | 225 | end 226 | 227 | if enum4==0 228 | spy(H ,'+',0.5); % Plots matrix H 229 | xlabel(t3); % Remove x-label 230 | ylabel(t4); 231 | %set(gca,'XTick',[]); % Remove numbers on x-axis 232 | %set(gca,'YTick',[]); % Remove numbers on y-axis 233 | title(t); % Add title 234 | else 235 | dvi = sum(H,1); % <-- Following 6 lines to compute the average dv and dc as it might be an irregular code 236 | dci = sum(H,2)'; 237 | [adv,bdv] = hist(dvi,unique(dvi)); 238 | [adc,bdc] = hist(dci,unique(dci)); 239 | adv(adv == 0) = NaN; 240 | stem(bdv,adv,'linewidth',2); 241 | hold on; 242 | adc(adc == 0) = NaN; 243 | stem (bdc,adc, 'linewidth',2,"r"); 244 | xlim([min(min(bdv),min(bdc))-1 max(max(bdv),max(bdc))+1]); 245 | title(t1); 246 | xlabel('Degree of nodes'); 247 | ylabel('Number of nodes'); 248 | grid on; 249 | axis on; 250 | legend('dv','dc','location','NorthEast'); 251 | 252 | end 253 | %Create an image file. This image is displayed on the webpage. Its size 254 | % must be 640x480. 255 | %print(filename, "-dgif","-S640,480", "-r0"); 256 | print(filename, "-dpng", output_format); 257 | % print(filename, "-dpng",output_format); 258 | %print(filename, "-djpg","-S1280,960", "-r0"); 259 | 260 | % print(["fig_",filename], "-dsvg",output_format); 261 | 262 | 263 | 264 | matrixfile = strrep(filename,'_plot.png',sprintf('_matrix_N%d_M%d',size(H,2),size(H,1))); 265 | save('-mat7-binary',[matrixfile,'.mat'], 'H'); 266 | LinkMat = ['Parity-check matrix (MATLAB .mat file)']; 267 | % print(filename, "-dgif","-S640,480", "-r0"); % Prints the figure 268 | end 269 | -------------------------------------------------------------------------------- /matlab/LDPCCode.m: -------------------------------------------------------------------------------- 1 | classdef LDPCCode < handle 2 | % Implements LDPC functionality 3 | % 4 | 5 | properties 6 | H; 7 | N; 8 | K; 9 | M; 10 | max_col_weight; 11 | max_row_weight; 12 | col_weight_vec; 13 | row_weight_vec; 14 | 15 | % Each row contains entries that represent the columns of the corresponding 16 | % row in H where 1's are present 17 | % (read row-wise) 18 | cols_with_ones; 19 | 20 | % Each row contains entries that represent the rows of the corresponding 21 | % column in H where 1's are present 22 | % (read row-wise) 23 | rows_with_ones; 24 | Z; 25 | endproperties 26 | 27 | methods 28 | function obj = LDPCCode(block_length, info_length) 29 | obj.N = block_length; 30 | obj.K = info_length; 31 | obj.M = obj.N - obj.K; 32 | endfunction 33 | 34 | function generate_Gallager_LDPC(obj) 35 | obj.H = zeros(obj.M, obj.N); 36 | w_r = 6; 37 | w_c = 3; 38 | A_0 = zeros(obj.M/w_c, obj.N); 39 | for i_row = 1 : obj.M/w_c 40 | A_0(i_row, (i_row - 1)*w_r + 1:i_row*w_r) = 1; 41 | endfor 42 | for i_col = 1 : w_c 43 | obj.H((i_col-1)*obj.M/w_c + 1 : i_col * obj.M/w_c, :) = A_0(:,randperm(size(A_0,2))); 44 | endfor 45 | endfunction 46 | 47 | function get_one_indices(obj) 48 | obj.col_weight_vec = sum(obj.H, 1); 49 | obj.row_weight_vec = sum(obj.H, 2); 50 | obj.max_col_weight = max(obj.col_weight_vec); 51 | obj.max_row_weight = max(obj.row_weight_vec); 52 | obj.cols_with_ones = zeros(obj.N, obj.max_col_weight); 53 | obj.rows_with_ones = zeros(obj.M, obj.max_row_weight); 54 | for i_row = 1 : obj.M 55 | index = 1; 56 | for i_col = 1 : obj.N 57 | if obj.H(i_row, i_col) 58 | obj.rows_with_ones(i_row, index) = i_col; 59 | index = index + 1; 60 | endif 61 | endfor 62 | endfor 63 | 64 | for i_col = 1 : obj.N 65 | index = 1; 66 | for i_row = 1 : obj.M 67 | if obj.H(i_row, i_col) 68 | obj.cols_with_ones(i_col, index) = i_row; 69 | index = index + 1; 70 | endif 71 | endfor 72 | endfor 73 | 74 | endfunction 75 | 76 | function [codeword] = encode_bits(obj, info_bits) 77 | % Does encoding by back substitution 78 | % Assumes a very specific structure on the partiy check matrix 79 | codeword = zeros(obj.N, 1); 80 | codeword(1:obj.K) = info_bits; 81 | 82 | parity = zeros(obj.M, 1); 83 | for i_row = 1 : obj.M 84 | for i_col = 1 : obj.max_row_weight 85 | if (obj.rows_with_ones(i_row, i_col) > 0) && (obj.rows_with_ones(i_row, i_col) <= obj.K) 86 | parity(i_row) = parity(i_row) + codeword(obj.rows_with_ones(i_row, i_col)); 87 | endif 88 | endfor 89 | endfor 90 | 91 | parity = mod(parity, 2); 92 | 93 | for i = 1 : obj.Z 94 | codeword(obj.K + i) = mod(sum(parity(i:obj.Z:end)), 2); 95 | endfor 96 | 97 | for i_row = 1 : obj.M 98 | for i_col = 1 : obj.max_row_weight 99 | if (obj.rows_with_ones(i_row, i_col) > obj.K) && (obj.rows_with_ones(i_row, i_col) <= obj.K + obj.Z) 100 | parity(i_row) = mod(parity(i_row) + codeword(obj.rows_with_ones(i_row, i_col)), 2); 101 | endif 102 | endfor 103 | endfor 104 | 105 | for i_col = obj.K + obj.Z + 1 : obj.Z: obj.N 106 | codeword(i_col: i_col + obj.Z - 1) = parity(i_col - obj.K - obj.Z : i_col - obj.K - 1); 107 | parity(i_col - obj.K : i_col - obj.K + obj.Z - 1) = mod(parity(i_col - obj.K - obj.Z : i_col - obj.K - 1) + ... 108 | parity(i_col - obj.K : i_col + obj.Z - obj.K - 1), 2); 109 | endfor 110 | 111 | endfunction 112 | 113 | function [decoded_codeword, error_vec] = decode_llr(obj, input_llr_vec, max_iter, min_sum) 114 | eta = zeros(obj.M, obj.N); 115 | lasteta = zeros(obj.M, obj.N); 116 | updated_llr_vec = input_llr_vec; 117 | error_vec = zeros(max_iter, 1); 118 | for iter = 1 : max_iter 119 | 120 | for i_m = 1 : obj.M 121 | for i_n1 = 1 : obj.row_weight_vec(i_m) 122 | n1 = obj.rows_with_ones(i_m, i_n1); 123 | if min_sum 124 | pr = 100; 125 | else 126 | pr = 1; 127 | endif 128 | for i_n2 = 1 : obj.row_weight_vec(i_m) 129 | if i_n1 == i_n2 130 | continue; 131 | endif 132 | n2 = obj.rows_with_ones(i_m, i_n2); 133 | l1 = (updated_llr_vec(n2) - lasteta(i_m, n2)); 134 | l1 = min(l1, 20); 135 | l1 = max(l1, -20); 136 | if min_sum 137 | pr = sign(pr) * sign(l1) * min(abs(l1), abs(pr)); 138 | else 139 | pr = pr * tanh(l1/2); 140 | endif 141 | endfor 142 | if min_sum 143 | eta(i_m, n1) = pr; 144 | else 145 | eta(i_m, n1) = 2 * atanh(pr); 146 | endif 147 | endfor 148 | endfor 149 | 150 | lasteta = eta; 151 | 152 | for i_n = 1 : obj.N 153 | updated_llr_vec(i_n) = input_llr_vec(i_n); 154 | for i_m = 1 : obj.col_weight_vec(i_n) 155 | m = obj.cols_with_ones(i_n, i_m); 156 | updated_llr_vec(i_n) = updated_llr_vec(i_n) + eta(m,i_n); 157 | endfor 158 | endfor 159 | 160 | decoded_codeword = (updated_llr_vec < 0); 161 | if obj.check_codeword(decoded_codeword) 162 | return; 163 | else 164 | error_vec(iter) = 1; 165 | endif 166 | endfor 167 | endfunction 168 | 169 | function [b] = check_codeword(obj, x) 170 | b = 1; 171 | for i_check = 1 : obj.M 172 | c = 0; 173 | for i_n = 1 : obj.row_weight_vec(i_check) 174 | c = c + x(obj.rows_with_ones(i_check, i_n)); 175 | endfor 176 | if mod(c, 2) == 1 177 | b = 0; 178 | break; 179 | endif 180 | endfor 181 | endfunction 182 | 183 | 184 | function lifted_ldpc(obj, baseH, Z) 185 | circ_mat_array = {}; 186 | for i = 0 : Z - 1 187 | circ_mat = zeros(Z,Z); 188 | for j = 0 : Z - 1 189 | circ_mat(j + 1, mod(j + i, Z) + 1) = 1; 190 | endfor 191 | circ_mat_array{i + 1} = circ_mat; 192 | endfor 193 | obj.N = Z * size(baseH, 2); 194 | obj.M = Z * size(baseH, 1); 195 | obj.K = obj.N - obj.M; 196 | obj.H = zeros(obj.M, obj.N); 197 | 198 | for i_row = 1 : size(baseH, 1) 199 | for i_col = 1 : size(baseH, 2) 200 | if baseH(i_row, i_col) ~= -1 201 | obj.H( (i_row-1)*Z + 1 : i_row * Z, (i_col-1)*Z + 1 : i_col*Z) = circ_mat_array{baseH(i_row, i_col) + 1}; 202 | endif 203 | endfor 204 | endfor 205 | 206 | obj.get_one_indices(); 207 | 208 | endfunction 209 | 210 | 211 | function load_wifi_ldpc(obj, block_length, rate) 212 | 213 | H_1296_1_2 = [40 -1 -1 -1 22 -1 49 23 43 -1 -1 -1 1 0 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1; 214 | 50 1 -1 -1 48 35 -1 -1 13 -1 30 -1 -1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 -1; 215 | 39 50 -1 -1 4 -1 2 -1 -1 -1 -1 49 -1 -1 0 0 -1 -1 -1 -1 -1 -1 -1 -1; 216 | 33 -1 -1 38 37 -1 -1 4 1 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1 -1; 217 | 45 -1 -1 -1 0 22 -1 -1 20 42 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1; 218 | 51 -1 -1 48 35 -1 -1 -1 44 -1 18 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1; 219 | 47 11 -1 -1 -1 17 -1 -1 51 -1 -1 -1 0 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1; 220 | 5 -1 25 -1 6 -1 45 -1 13 40 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1; 221 | 33 -1 -1 34 24 -1 -1 -1 23 -1 -1 46 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1 -1; 222 | 1 -1 27 -1 1 -1 -1 -1 38 -1 44 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1; 223 | -1 18 -1 -1 23 -1 -1 8 0 35 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0; 224 | 49 -1 17 -1 30 -1 -1 -1 34 -1 -1 19 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0]; 225 | 226 | H_1296_2_3 = [39 31 22 43 -1 40 4 -1 11 -1 -1 50 -1 -1 -1 6 1 0 -1 -1 -1 -1 -1 -1; 227 | 25 52 41 2 6 -1 14 -1 34 -1 -1 -1 24 -1 37 -1 -1 0 0 -1 -1 -1 -1 -1; 228 | 43 31 29 0 21 -1 28 -1 -1 2 -1 -1 7 -1 17 -1 -1 -1 0 0 -1 -1 -1 -1; 229 | 20 33 48 -1 4 13 -1 26 -1 -1 22 -1 -1 46 42 -1 -1 -1 -1 0 0 -1 -1 -1; 230 | 45 7 18 51 12 25 -1 -1 -1 50 -1 -1 5 -1 -1 -1 0 -1 -1 -1 0 0 -1 -1; 231 | 35 40 32 16 5 -1 -1 18 -1 -1 43 51 -1 32 -1 -1 -1 -1 -1 -1 -1 0 0 -1; 232 | 9 24 13 22 28 -1 -1 37 -1 -1 25 -1 -1 52 -1 13 -1 -1 -1 -1 -1 -1 0 0; 233 | 32 22 4 21 16 -1 -1 -1 27 28 -1 38 -1 -1 -1 8 1 -1 -1 -1 -1 -1 -1 0]; 234 | 235 | H_1296_3_4 = [39 40 51 41 3 29 8 36 -1 14 -1 6 -1 33 -1 11 -1 4 1 0 -1 -1 -1 -1; 236 | 48 21 47 9 48 35 51 -1 38 -1 28 -1 34 -1 50 -1 50 -1 -1 0 0 -1 -1 -1; 237 | 30 39 28 42 50 39 5 17 -1 6 -1 18 -1 20 -1 15 -1 40 -1 -1 0 0 -1 -1; 238 | 29 0 1 43 36 30 47 -1 49 -1 47 -1 3 -1 35 -1 34 -1 0 -1 -1 0 0 -1; 239 | 1 32 11 23 10 44 12 7 -1 48 -1 4 -1 9 -1 17 -1 16 -1 -1 -1 -1 0 0; 240 | 13 7 15 47 23 16 47 -1 43 -1 29 -1 52 -1 2 -1 53 -1 1 -1 -1 -1 -1 0]; 241 | 242 | H_1296_5_6 = [48 29 37 52 2 16 6 14 53 31 34 5 18 42 53 31 45 -1 46 52 1 0 -1 -1; 243 | 17 4 30 7 43 11 24 6 14 21 6 39 17 40 47 7 15 41 19 -1 -1 0 0 -1; 244 | 7 2 51 31 46 23 16 11 53 40 10 7 46 53 33 35 -1 25 35 38 0 -1 0 0; 245 | 19 48 41 1 10 7 36 47 5 29 52 52 31 10 26 6 3 2 -1 51 1 -1 -1 0 ]; 246 | 247 | H_1944_1_2 = [57 -1 -1 -1 50 -1 11 -1 50 -1 79 -1 1 0 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1; 248 | 3 -1 28 -1 0 -1 -1 -1 55 7 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 -1; 249 | 30 -1 -1 -1 24 37 -1 -1 56 14 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1 -1 -1; 250 | 62 53 -1 -1 53 -1 -1 3 35 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1 -1; 251 | 40 -1 -1 20 66 -1 -1 22 28 -1 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1; 252 | 0 -1 -1 -1 8 -1 42 -1 50 -1 -1 8 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1; 253 | 69 79 79 -1 -1 -1 56 -1 52 -1 -1 -1 0 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1; 254 | 65 -1 -1 -1 38 57 -1 -1 72 -1 27 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1; 255 | 64 -1 -1 -1 14 52 -1 -1 30 -1 -1 32 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1 -1; 256 | -1 45 -1 70 0 -1 -1 -1 77 9 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1; 257 | 2 56 -1 57 35 -1 -1 -1 -1 -1 12 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0; 258 | 24 -1 61 -1 60 -1 -1 27 51 -1 -1 16 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0]; 259 | 260 | H_1944_2_3 = [61 75 4 63 56 -1 -1 -1 -1 -1 -1 8 -1 2 17 25 1 0 -1 -1 -1 -1 -1 -1; 261 | 56 74 77 20 -1 -1 -1 64 24 4 67 -1 7 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1; 262 | 28 21 68 10 7 14 65 -1 -1 -1 23 -1 -1 -1 75 -1 -1 -1 0 0 -1 -1 -1 -1; 263 | 48 38 43 78 76 -1 -1 -1 -1 5 36 -1 15 72 -1 -1 -1 -1 -1 0 0 -1 -1 -1; 264 | 40 2 53 25 -1 52 62 -1 20 -1 -1 44 -1 -1 -1 -1 0 -1 -1 -1 0 0 -1 -1; 265 | 69 23 64 10 22 -1 21 -1 -1 -1 -1 -1 68 23 29 -1 -1 -1 -1 -1 -1 0 0 -1; 266 | 12 0 68 20 55 61 -1 40 -1 -1 -1 52 -1 -1 -1 44 -1 -1 -1 -1 -1 -1 0 0; 267 | 58 8 34 64 78 -1 -1 11 78 24 -1 -1 -1 -1 -1 58 1 -1 -1 -1 -1 -1 -1 0]; 268 | 269 | 270 | H_1944_3_4 = [48 29 28 39 9 61 -1 -1 -1 63 45 80 -1 -1 -1 37 32 22 1 0 -1 -1 -1 -1; 271 | 4 49 42 48 11 30 -1 -1 -1 49 17 41 37 15 -1 54 -1 -1 -1 0 0 -1 -1 -1; 272 | 35 76 78 51 37 35 21 -1 17 64 -1 -1 -1 59 7 -1 -1 32 -1 -1 0 0 -1 -1; 273 | 9 65 44 9 54 56 73 34 42 -1 -1 -1 35 -1 -1 -1 46 39 0 -1 -1 0 0 -1; 274 | 3 62 7 80 68 26 -1 80 55 -1 36 -1 26 -1 9 -1 72 -1 -1 -1 -1 -1 0 0; 275 | 26 75 33 21 69 59 3 38 -1 -1 -1 35 -1 62 36 26 -1 -1 1 -1 -1 -1 -1 0]; 276 | 277 | 278 | H_1944_5_6 = ... 279 | [ 13 48 80 66 4 74 7 30 76 52 37 60 -1 49 73 31 74 73 23 -1 1 0 -1 -1; 280 | 69 63 74 56 64 77 57 65 6 16 51 -1 64 -1 68 9 48 62 54 27 -1 0 0 -1; 281 | 51 15 0 80 24 25 42 54 44 71 71 9 67 35 -1 58 -1 29 -1 53 0 -1 0 0; 282 | 16 29 36 41 44 56 59 37 50 24 -1 65 4 65 52 -1 4 -1 73 52 1 -1 -1 0]; 283 | 284 | 285 | H_648_1_2 = [0 -1 -1 -1 0 0 -1 -1 0 -1 -1 0 1 0 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1; 286 | 22 0 -1 -1 17 -1 0 0 12 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1 -1 -1 -1; 287 | 6 -1 0 -1 10 -1 -1 -1 24 -1 0 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1 -1 -1; 288 | 2 -1 -1 0 20 -1 -1 -1 25 0 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1 -1; 289 | 23 -1 -1 -1 3 -1 -1 -1 0 -1 9 11 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1 -1; 290 | 24 -1 23 1 17 -1 3 -1 10 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1 -1; 291 | 25 -1 -1 -1 8 -1 -1 -1 7 18 -1 -1 0 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1; 292 | 13 24 -1 -1 0 -1 8 -1 6 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1; 293 | 7 20 -1 16 22 10 -1 -1 23 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1 -1; 294 | 11 -1 -1 -1 19 -1 -1 -1 13 -1 3 17 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0 -1; 295 | 25 -1 8 -1 23 18 -1 14 9 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0 0; 296 | 3 -1 -1 -1 16 -1 -1 2 25 5 -1 -1 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 0]; 297 | 298 | H_648_2_3 = [25 26 14 -1 20 -1 2 -1 4 -1 -1 8 -1 16 -1 18 1 0 -1 -1 -1 -1 -1 -1; 299 | 10 9 15 11 -1 0 -1 1 -1 -1 18 -1 8 -1 10 -1 -1 0 0 -1 -1 -1 -1 -1; 300 | 16 2 20 26 21 -1 6 -1 1 26 -1 7 -1 -1 -1 -1 -1 -1 0 0 -1 -1 -1 -1; 301 | 10 13 5 0 -1 3 -1 7 -1 -1 26 -1 -1 13 -1 16 -1 -1 -1 0 0 -1 -1 -1; 302 | 23 14 24 -1 12 -1 19 -1 17 -1 -1 -1 20 -1 21 -1 0 -1 -1 -1 0 0 -1 -1; 303 | 6 22 9 20 -1 25 -1 17 -1 8 -1 14 -1 18 -1 -1 -1 -1 -1 -1 -1 0 0 -1; 304 | 14 23 21 11 20 -1 24 -1 18 -1 19 -1 -1 -1 -1 22 -1 -1 -1 -1 -1 -1 0 0; 305 | 17 11 11 20 -1 21 -1 26 -1 3 -1 -1 18 -1 26 -1 1 -1 -1 -1 -1 -1 -1 0]; 306 | 307 | H_648_3_4 = [16 17 22 24 9 3 14 -1 4 2 7 -1 26 -1 2 -1 21 -1 1 0 -1 -1 -1 -1; 308 | 25 12 12 3 3 26 6 21 -1 15 22 -1 15 -1 4 -1 -1 16 -1 0 0 -1 -1 -1; 309 | 25 18 26 16 22 23 9 -1 0 -1 4 -1 4 -1 8 23 11 -1 -1 -1 0 0 -1 -1; 310 | 9 7 0 1 17 -1 -1 7 3 -1 3 23 -1 16 -1 -1 21 -1 0 -1 -1 0 0 -1; 311 | 24 5 26 7 1 -1 -1 15 24 15 -1 8 -1 13 -1 13 -1 11 -1 -1 -1 -1 0 0; 312 | 2 2 19 14 24 1 15 19 -1 21 -1 2 -1 24 -1 3 -1 2 1 -1 -1 -1 -1 0]; 313 | 314 | H_648_5_6 = [17 13 8 21 9 3 18 12 10 0 4 15 19 2 5 10 26 19 13 13 1 0 -1 -1; 315 | 3 12 11 14 11 25 5 18 0 9 2 26 26 10 24 7 14 20 4 2 -1 0 0 -1; 316 | 22 16 4 3 10 21 12 5 21 14 19 5 -1 8 5 18 11 5 5 15 0 -1 0 0; 317 | 7 7 14 14 4 16 16 24 24 10 1 7 15 6 10 26 8 18 21 14 1 -1 -1 0]; 318 | 319 | if block_length == 648 320 | obj.Z = 27; 321 | elseif block_length == 1296 322 | obj.Z = 54; 323 | elseif block_length == 1944 324 | obj.Z = 81; 325 | else 326 | disp('Not supported block length value'); 327 | return; 328 | endif 329 | 330 | H_var = ['H_', num2str(block_length), '_']; 331 | if rate == 1/2 332 | H_var = [H_var, '1_2']; 333 | elseif rate == 2/3 334 | H_var = [H_var, '2_3']; 335 | elseif rate == 3/4 336 | H_var = [H_var, '3_4']; 337 | elseif rate == 5/6 338 | H_var = [H_var, '5_6']; 339 | else 340 | disp('Not supported rate value'); 341 | return; 342 | endif 343 | 344 | baseH = eval(H_var); 345 | 346 | obj.lifted_ldpc(baseH, obj.Z); 347 | 348 | endfunction 349 | 350 | endmethods 351 | 352 | endclassdef 353 | 354 | --------------------------------------------------------------------------------