5G NR PUSCH详解(3)——信道编码(LDPC)
admin
2023-06-23 03:20:32
0
UE(i).a = randi([0 1], [UE(i).tbs 1]);
UE(i).g = nr_sch_encode(UE(i).a, UE(i).I_mcs, UE(i).N_layer, 0, UE(i).ctbs, UE(i).higher_layer_parameters.MCS_Table_PUSCH);
%[g] = nr_sch_encode(a, I_mcs, N_layers, rv_id, ctbs, mcs_tbl)
%
% Encodes 5G NR PUSCH/PDSCH channels using LDPC codes according to
% 3GPP 38.212 sec. 6.2 and 7.2.
%
% Arguments:
% a - binary transport block vector
% I_mcs - MCS index
% N_layers - number of layers
% rv_id - redundancy version index (0, 1, 2 or 3)
% ctbs - transport block size after encoding
% mcs_tbl - index of MCS table (1 - 64-QAM, 2 - 256-QAM)
%
% Returns:
% g - encoded binary transport block vector

function [g] = nr_sch_encode(a, I_mcs, N_layers, rv_id, ctbs, mcs_tbl)
if nargin < 6
mcs_tbl = 1;
end

% convert a to row vector
a = reshape(a, 1, []);
A = length(a);

% Transport Block crc attachment
if A > 3824
p = nr_38_212_crc_calc(a, '24A');
else
p = nr_38_212_crc_calc(a, 16);
end
b = [a, p];

% resolve MCS and select LDPC graph
[Q_m, R] = nr_resolve_mcs(I_mcs, mcs_tbl);
if (A <= 292) || (A <= 3824 && R <= 0.67) || (R <= 0.25)
base_graph = 2;
else
base_graph = 1;
end

c = nr_38_212_code_block_segmentation_ldpc(b, base_graph);
[d,Z_c] = nr_38_212_channel_coding_ldpc(c, base_graph);
g = nr_38_212_rate_matching_ldpc(d, base_graph, Z_c, N_layers, Q_m, rv_id, ctbs);

g(g == -1) = 0;
g = g(:);
end

参数解析:

输出参数:

速率匹配后输出串行数据流。

输入参数:

  1. UE(i).a

TB块

2. I_mcs

MCS索引

3. N_layers

MIMO的层数

4. rv_id

RV初始位置

5. ctbs

速率匹配后应输出的比特数

6. mcs_tbl

MCS对应的两个表格

注:关于MCS问题可以参考:

一、TB+CRC

if A > 3824
p = nr_38_212_crc_calc(a, '24A');
else
p = nr_38_212_crc_calc(a, 16);
end

标准中明确规定,当TB块大于3824时,采用24bitCRC,当TB块<=3824时,采用16比特的CRC。

%p = nr_38_212_crc_calc(b, crc_gen)
%
% Calculates CRC as defined in 3GPP 38.212 sec. 5.1.
%
% Arguments:
% b - binary vector
% crc_gen - polynomial selection:
% 6, 11, 16, '24a', '24b' or '24c'
%
% Returns:
% p - binary vector of calculated CRC bits


function p = nr_38_212_crc_calc(b, crc_gen)
if crc_gen == 6
crc_poly = [1,1,0,0,0,0,1];
elseif crc_gen == 11
crc_poly = [1,1,1,0,0,0,1,0,0,0,0,1];
elseif crc_gen == 16
crc_poly = [1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1];
elseif strcmpi(crc_gen, '24a')
crc_poly = [1,1,0,0,0,0,1,1,0,0,1,0,0,1,1,0,0,1,1,1,1,1,0,1,1];
elseif strcmpi(crc_gen, '24b')
crc_poly = [1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1];
elseif strcmpi(crc_gen, '24c')
crc_poly = [1,1,0,1,1,0,0,1,0,1,0,1,1,0,0,0,1,0,0,0,1,0,1,1,1];
else
error('Invalid crc_gen (%s)', crc_gen);
end

try
p = crc_calc_mex(b, crc_poly);
return;
catch
persistent flag
if isempty(flag)
disp('nr_38_211_crc_calc: compile mex file to reduce execution time');
flag = 0;
end
end

lfsr = zeros(1,length(crc_poly));
b_ext = [b, zeros(1,length(crc_poly)-1)];

for n = 1:length(b_ext)
lfsr = [lfsr(2:end) b_ext(n)];
if (lfsr(1) ~= 0)
lfsr = mod(lfsr + crc_poly, 2);
end
end

p = lfsr(2:end);
end

crc_calc_mex函数:

/* p = crc_calc_mex(b, crc_poly)
*
* Matlab MEX acceleration for nr_38_212_crc_calc function.
*
*/

#include "mex.h"

#define CRC_LFSR_LEN_MAX 25

void crc_calc(double* din, size_t din_len, double* poly, size_t poly_len, double* dout) {
int i, n;
int lfsr[CRC_LFSR_LEN_MAX] = {0};

for (i = 0; i < din_len+poly_len-1; i++) {
/* shift */
for (n = 0; n < poly_len-1; n++)
lfsr[n] = lfsr[n+1];
lfsr[poly_len-1] = (i < din_len) ? (int)din[i] : 0;
/* add polynomial */
if (lfsr[0] != 0)
for (n = 0; n < poly_len; n++)
lfsr[n] = (lfsr[n] + (int)poly[n]) & 1;
}

for (i = 0; i < poly_len-1; i++)
dout[i] = (double) lfsr[i+1];
}

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
double* din;
size_t din_len;
double* poly;
size_t poly_len;
double* dout;

/* check for proper number of arguments */
if(nrhs != 2) {
mexErrMsgIdAndTxt("crc_calc:nrhs","Two inputs required.");
}

if(nlhs != 1) {
mexErrMsgIdAndTxt("crc_calc:nlhs","One output required.");
}

/* get the input arguments */
din_len = mxGetN(prhs[0]);
din = mxGetPr(prhs[0]);
poly_len = mxGetN(prhs[1]);
poly = mxGetPr(prhs[1]);

if (poly_len > CRC_LFSR_LEN_MAX) {
mexErrMsgIdAndTxt("crc_calc:poly_len","Polynomial length is too high. Recompile mex function with sufficient CRC_LFSR_LEN_MAX.");
}

/* create the output matrix */
plhs[0] = mxCreateDoubleMatrix(1, (mwSize)(poly_len-1), mxREAL);
dout = mxGetPr(plhs[0]);

/* call the computational routine */
crc_calc(din, din_len, poly, poly_len, dout);
}

具体的计算方法后面会单出一篇文章。

二、选基图

% resolve MCS and select LDPC graph
[Q_m, R] = nr_resolve_mcs(I_mcs, mcs_tbl);
if (A <= 292) || (A <= 3824 && R <= 0.67) || (R <= 0.25)
base_graph = 2;
else
base_graph = 1;
end

这篇文章中有详细的介绍。

三、码块分割

c = nr_38_212_code_block_segmentation_ldpc(b, base_graph);

输入参数:

TB+CRC后的数据:b

基图:0或1

%c = nr_38_212_code_block_segmentation_ldpc(b, base_graph)
%
% Performs code block segmentation of 5G NR SCH according to 3GPP 38.212
% sec. 5.2.2.
%
% Arguments:
% b - binary vector of information bits
% base_graph - LDPC base graph (1 or 2)
%
% Returns:
% c - segmented codeblocks (each row as a codeblock)
% the size is [num_codeblocks,num_bits_per_codeblock]


function c = nr_38_212_code_block_segmentation_ldpc(b, base_graph)
if base_graph == 1
K_cb = 8448;
elseif base_graph == 2
K_cb = 3840;
else
error('base_graph permitted values are 1 or 2');
end

B = length(b);

if B < K_cb
L = 0;
C = 1;
Bp = B;
else
L = 24;
C = ceil(B / (K_cb - L));
Bp = B + C * L;
end

if base_graph == 1
K_b = 22;
else
if B > 640
K_b = 10;
elseif B > 560
K_b = 9;
elseif B > 192
K_b = 8;
else
K_b = 6;
end
end

Z_c = 1000;
for i_LS = 0 : 7
Z = nr_ldpc_lifting_size_tbl_5_3_2_1(i_LS);
for z = Z
if z < Z_c && C * K_b * z >= Bp
Z_c = z;
end
end
end

if base_graph == 1
K = 22 * Z_c;
else
K = 10 * Z_c;
end

Kp = Bp / C;

c = ones(C, K) * -1; % null filler bits

s = 1;
for r = 0 : C-1
b_cur = b(s:s+Kp-L-1);
s = s + Kp-L;

c(r+1,1:Kp-L) = b_cur;

if C > 1
b_cur_crc = b_cur;
b_cur_crc(b_cur_crc == -1) = 0;
c(r+1,Kp-L+1:Kp) = nr_38_212_crc_calc(b_cur_crc, '24B');
end
end
end

nr_ldpc_lifting_size_tbl_5_3_2_1表格:

%Z = nr_ldpc_lifting_size_tbl_5_3_2_1(i_LS)
%
% Returns a vector consisting of lifting size values belonging
% to a specified lifting size set.
% Implements tables from 3GPP 38.212 5.3.2-1.
%
% Arguments:
% base_graph - LDPC base graph (1 or 2)
% i_LS - lifting size set index
%
% Returns:
% Z - vector of lifting sizes


function Z = nr_ldpc_lifting_size_tbl_5_3_2_1(i_LS)
switch i_LS
case 0
Z = [2, 4, 8, 16, 32, 64, 128, 256];
case 1
Z = [3, 6, 12, 24, 48, 96, 192, 384];
case 2
Z = [5, 10, 20, 40, 80, 160, 320];
case 3
Z = [7, 14, 28, 56, 112, 224];
case 4
Z = [9, 18, 36, 72, 144, 288];
case 5
Z = [11, 22, 44, 88, 176, 352];
case 6
Z = [13, 26, 52, 104, 208];
case 7
Z = [15, 30, 60, 120, 240];
otherwise
error('invalid value of i_LS');
end
end

这里的具体实现在PDSCH那篇文章中都有讲。

四、信道编码

[d,Z_c] = nr_38_212_channel_coding_ldpc(c, base_graph);

我先把部分核心代码列出,具体实现参考LDPC编译码系列文章:

%[d] = nr_38_212_channel_coding_ldpc(c, base_graph)
%
% Performs encoding of 5G NR SCH according to 3GPP 38.212 sec. 5.3.2.
%
% Arguments:
% c - codeblocks to be encoded (each row is a separate codeblock)
% base_graph - LDPC base graph (1 or 2)
%
% Returns:
% d - encoded codeblocks


function [d,Z_c] = nr_38_212_channel_coding_ldpc(c, base_graph)
persistent H base_graph_int Z_c_int

if isempty(base_graph_int)
base_graph_int = 0;
end
if isempty(Z_c_int)
Z_c_int = 0;
end

C = size(c,1);
K = size(c,2);

if base_graph == 1
Z_c = K / 22;
N = 66 * Z_c;
elseif base_graph == 2
Z_c = K / 10;
N = 50 * Z_c;
else
error('base_graph permitted values are 1 or 2');
end

if (Z_c ~= Z_c_int) || (base_graph ~= base_graph_int)
Z_c_int = Z_c;
base_graph_int = base_graph;
H = nr_ldpc_parity_check_matrix(base_graph, Z_c);
end

% insert information bits
d = ones(C,N) * -1;

d(:,1:K-2*Z_c) = c(:,1+2*Z_c:K);

c(c == -1) = 0;

% generate and insert parity bits
for r = 1:C
p = ldpc_encode_nr(c(r,:)', H, Z_c);
d(r,1+K-2*Z_c:N) = p;
end
end
%[p] = ldpc_encode_nr(s, H, Z_c)
%
% Implementation of simplified Richardson's efficient LDPC encoder (see [1]).
% Assumes E = 0 and T = I, which is true for 5G NR LDPC
% parity check matrices.
%
% [1] T. Richardson and R. Urbanke, "Efficient Encoding of Low-Density
% Parity-Check Codes", IEEE Trans. Inf. Theory, vol. 47, no. 2,
% pp. 638-656, Feb. 2001.
%
% Arguments:
% s - vector of information bits
% H - parity check matrix
% Z_c - lifting size of matrix H
%
% Returns:
% p - vector of generated parity bits


function p = ldpc_encode_nr(s, H, Z_c)
persistent C_int D_int Dinv_C

s = s(:);

n = size(H,2);
r = size(H,1);
k = n - r;
g = 4 * Z_c;

A = H(g+1:end, 1:k);
B = H(g+1:end, k+1:k+g);
C = H(1:g, 1:k);
D = H(1:g, k+1:k+g);

% E = H(1:g, k+g+1:end);
% T = H(g+1:end, k+g+1:end);
% assert(nnz(E) == 0, 'LDPC parity matrix error: E is expected to be a zero matrix');
% assert(all(all(T == eye(r-g))), 'LDPC parity matrix error: T is expected to be a binary identity matrix');

if ~isequal(D_int, D) || ~isequal(C_int, C)
C_int = C;
D_int = D;

Dinv = mod(round(inv(D)), 2);
Dinv_C = mod(Dinv * C, 2);
end

p1 = mod(Dinv_C * s, 2);
p2 = mod(A * s + B * p1, 2);

p = [p1; p2];

assert(any(mod(H * [s;p], 2)) == 0, 'LDPC encoder error: parity check failed');
end

五、速率匹配

g = nr_38_212_rate_matching_ldpc(d, base_graph, Z_c, N_layers, Q_m, rv_id, ctbs);
%g = nr_38_212_rate_matching_ldpc(d, base_graph, N_layers, Q_m, rv_id, ctbs)
%
% Performs rate matching and code block concatenaion of 5G NR SCH according
% to 3GPP 38.212 sec. 5.2.4 and 5.5.
%
% Arguments:
% d - matrix of encoded codeblocks (each row as a codeblock)
% the size is [num_codeblocks,num_enc_bits_per_codeblock]
% base_graph - LDPC base graph (1 or 2)
% N_layers - number of layers
% Q_m - modulation order
% 1 - BPSK
% 2 - QPSK
% 4 - 16QAM
% 6 - 64QAM
% 8 - 256QAM
% rv_id - redundancy version index (0, 1, 2 or 3)
% ctbs - transport block size after encoding
%
% Returns:
% g - vector of concatenated bits


function g = nr_38_212_rate_matching_ldpc(d, base_graph, Z_c, N_layers, Q_m, rv_id, ctbs)
C = size(d,1);
N = size(d,2);

Cp = C;

bits = struct([]);

% FIXME: simplified N_cb calculation assuming I_LBRM = 0
N_cb = N;
G = ctbs;

for r = 0 : C-1
if r <= Cp - mod(G / (N_layers * Q_m), Cp)
bits(r+1).E = N_layers * Q_m * floor(G / (N_layers * Q_m * Cp));
else
bits(r+1).E = N_layers * Q_m * ceil(G / (N_layers * Q_m * Cp));
end
end

if base_graph == 1
switch rv_id
case 0
k_0 = 0;
case 1
k_0 = floor(17 * N_cb / (66 * Z_c)) * Z_c;
case 2
k_0 = floor(33 * N_cb / (66 * Z_c)) * Z_c;
case 3
k_0 = floor(56 * N_cb / (66 * Z_c)) * Z_c;
otherwise
error('rv_id permitted values are in integer range 0:3');
end
elseif base_graph == 2
switch rv_id
case 0
k_0 = 0;
case 1
k_0 = floor(13 * N_cb / (50 * Z_c)) * Z_c;
case 2
k_0 = floor(25 * N_cb / (50 * Z_c)) * Z_c;
case 3
k_0 = floor(43 * N_cb / (50 * Z_c)) * Z_c;
otherwise
error('rv_id permitted values are in integer range 0:3');
end
else
error('base_graph permitted values are 1 or 2');
end

try
for r = 0 : C-1
bits(r+1).f = nr_38_212_circbuff_interleave_mex(d(r+1,:), bits(r+1).E, Q_m, k_0);
end
catch
persistent flag
if isempty(flag)
disp('nr_38_211_rate_matching_ldpc: compile mex file to reduce execution time');
flag = 0;
end

for r = 0 : C-1
bits(r+1).e = zeros(1, bits(r+1).E);
k = 0;
j = 0;
while k < bits(r+1).E
if d(r+1,1+mod(k_0 + j, N_cb)) ~= -1
bits(r+1).e(k+1) = d(r+1,1+mod(k_0 + j, N_cb));
k = k + 1;
end
j = j + 1;
end

bits(r+1).f = zeros(1, bits(r+1).E);
% interleaving
for j = 0 : bits(r+1).E/Q_m - 1
for i = 0 : Q_m - 1
bits(r+1).f(1+i+j*Q_m) = bits(r+1).e(1+i*bits(r+1).E/Q_m+j);
end
end
end
end

% codeblock concatenation
g = zeros(1,G);
k = 1;
for r = 0 : C-1
g(k:k+bits(r+1).E-1) = bits(r+1).f;
k = k + bits(r+1).E;
end
end

做速率匹配有一个细节,很可能会遇到平均到每个码块后导致每个码块的比特数不同,这部分是在这里处理的:

for r = 0 : C-1
if r <= Cp - mod(G / (N_layers * Q_m), Cp)
bits(r+1).E = N_layers * Q_m * floor(G / (N_layers * Q_m * Cp));
else
bits(r+1).E = N_layers * Q_m * ceil(G / (N_layers * Q_m * Cp));
end
end


详细的代码可以私信我,留下邮箱~

欢迎交流~

相关内容