-
Notifications
You must be signed in to change notification settings - Fork 31
/
NRLDPCDecoder.m
359 lines (301 loc) · 14.1 KB
/
NRLDPCDecoder.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
%NRLDPCDECODER Decoder for 3GPP New Radio LDPC code
% LDPCDEC = NRLDPCDECODER creates a 3GPP New Radio LDPC decoder system
% object, LDPCDEC. Default values are assumed for all properties, which
% are inherited from the NRLDPC base class.
%
% LDPCDEC = NRLDPCDECODER(Name,Value) creates a 3GPP New Radio LDPC
% decoder system object, LDPCDEC, with the specified property Name set to
% the specified Value. You can specify additional name-value pair
% arguments in any order as (Name1,Value1,...,NameN,ValueN).
%
% Copyright © 2018 Robert G. Maunder. This program is free software: you
% can redistribute it and/or modify it under the terms of the GNU General
% Public License as published by the Free Software Foundation, either
% version 3 of the License, or (at your option) any later version. This
% program is distributed in the hope that it will be useful, but WITHOUT
% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
% FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
% for more details.
classdef NRLDPCDecoder < NRLDPC
properties(Nontunable)
%I_HARQ Enable Hybrid Automatic Repeat reQuest (HARQ)
% Specifies whether or not successive blocks of input LLRs are assumed to
% be retransmissions of the same information block. When I_HARQ = 0, it
% is assumed that successive blocks of input LLRs correspond to different
% information blocks. In this case, the blocks of input LLRs are decoded
% independently. When I_HARQ ~= 0, the successive blocks of input LLRs
% are assumed to be retransmissions of the same information block. In
% this case the successive blocks of input LLRs are accumulated in an
% internal d_tilde_buffer, before they are processed by the LDPC decoder core.
% The internal d_tilde_buffer may be reset using the reset method, when the
% retransmission of a particular information block is completed, allowing
% the transmission of another information block.
I_HARQ = 0; % Default value
end
properties
%ITERATIONS Number of decoding iterations
% Specifies the number of flooding decoding iterations performed during
% LDPC decoding.
iterations = 50; % Default value
end
properties(Access = private, Hidden)
%HTBCRCDETECTOR Cyclic Redundancy Check (CRC) detector
% A COMM.CRCDETECTOR used to check the transport block CRC.
%
% See also COMM.CRCDETECTOR
hTBCRCDetector
%HCBCRCDETECTOR Cyclic Redundancy Check (CRC) detector
% A COMM.CRCDETECTOR used to check the code block CRC.
%
% See also COMM.CRCDETECTOR
hCBCRCDetector
%HLDPCDECODER Low Density Parity Check (LDPC) decoder
% A COMM.LDPCDECODER used to perform the LDPC decoding.
%
% See also COMM.LDPCDECODER
hLDPCDecoder
end
properties(DiscreteState)
%D_TILDE_BUFFER Internal buffer used to accumulate input LLRs during HARQ
% When I_HARQ ~= 0, successive blocks of input LLRs are assumed to be
% retransmissions of the same information block. In this case, the
% successive blocks of input LLRs are accumulated in this internal
% buffer, before they are processed by the LDPC decoder core. The
% internal buffer may be reset using the reset method, when the
% retransmission of a particular information block is completed, allowing
% the transmission of another information block.
d_tilde_buffer
%B_HAT_BUFFER Internal buffer used to collect successfully decoded bits during HARQ
% When I_HARQ ~= 0, successive blocks of input LLRs are assumed
% to be retransmissions of the same information block. However,
% some retransmissions may not contain all code blocks. In this
% case, the successfully decoded code blocks are collected in
% this internal buffer, after they are processed by the LDPC
% decoder core. The internal buffer may be reset using the reset
% method, when the retransmission of a particular information
% block is completed, allowing the transmission of another
% information block.
b_hat_buffer
%CODE_BLOCK_CRC_PASSED Vector of binary flags which indicates whether the
%CRC check has been passed for each code block
% The vector of binary flags may be reset using the reset
% method, when the retransmission of a particular information
% block is completed, allowing the transmission of another
% information block.
code_block_CRC_passed
end
methods
% Constructor allowing properties to be set according to e.g.
% a = NRLDPCDecoder('BG',1,'A',20,'G',132);
function obj = NRLDPCDecoder(varargin)
setProperties(obj,nargin,varargin{:});
end
end
methods(Access = protected)
function setupImpl(obj)
B_ = obj.B;
C_ = obj.C;
N_cb_ = obj.N_cb;
code_block_L_ = obj.code_block_L;
obj.hTBCRCDetector = comm.CRCDetector('Polynomial',obj.transport_block_CRC_polynomial);
if code_block_L_ > 0
obj.hCBCRCDetector = comm.CRCDetector('Polynomial',obj.code_block_CRC_polynomial);
end
% try
% obj.hLDPCDecoder = comm.gpu.LDPCDecoder('ParityCheckMatrix',obj.H,'MaximumIterationCount',obj.iterations,'IterationTerminationCondition','Parity check satisfied');
% catch
obj.hLDPCDecoder = comm.LDPCDecoder('ParityCheckMatrix',obj.H,'MaximumIterationCount',obj.iterations,'IterationTerminationCondition','Parity check satisfied');
% end
d_tilde_buffer_ = cell(C_,1);
for r=0:C_-1
d_tilde_buffer_{r+1} = zeros(N_cb_,1);
end
obj.d_tilde_buffer = d_tilde_buffer_;
obj.b_hat_buffer = zeros(B_,1);
obj.code_block_CRC_passed = zeros(C_,1);
end
function a_hat = stepImpl(obj, g_tilde)
f_tilde = code_block_concatenation(obj, g_tilde);
e_tilde = bit_interleaving(obj, f_tilde);
d_tilde = bit_selection(obj, e_tilde);
c_hat = LDPC_coding(obj, d_tilde);
b_hat = code_block_segmentation(obj, c_hat);
a_hat = crc_calculation(obj, b_hat);
end
% Implements Section 5.5 of TS38.212
function f_tilde = code_block_concatenation(obj, g_tilde)
G_ = obj.G;
C_ = obj.C;
E_r_ = obj.E_r;
if size(g_tilde,1) ~= G_ || size(g_tilde,2) ~= 1
error('ldpc_3gpp_matlab:Error','g_tilde should be a column vector of length G.');
end
f_tilde = cell(C_,1);
for r = 0:C_-1
f_tilde{r+1} = zeros(E_r_(r+1), 1);
end
k = 0;
r = 0;
while r < C_
j = 0;
while j < E_r_(r+1)
f_tilde{r+1}(j+1) = g_tilde(k+1);
k = k + 1;
j = j + 1;
end
r = r + 1;
end
end
% Implements Section 5.4.2.2 of TS38.212
function e_tilde = bit_interleaving(obj, f_tilde)
C_ = obj.C;
E_r_ = obj.E_r;
Q_m_ = obj.Q_m;
if size(f_tilde,1) ~= C_ || size(f_tilde,2) ~= 1
error('ldpc_3gpp_matlab:Error','f_tilde should be a column cell array of length C.');
end
e_tilde = cell(C_,1);
for r = 0:C_-1
if size(f_tilde{r+1},1) ~= E_r_(r+1) || size(f_tilde{r+1},2) ~= 1
error('ldpc_3gpp_matlab:Error','f_tilde{r+1} should be a column vector of length E_r(r+1).');
end
e_tilde{r+1} = zeros(E_r_(r+1),1);
for j = 0:E_r_(r+1)/Q_m_-1
for i = 0:Q_m_-1
e_tilde{r+1}(i*E_r_(r+1)/Q_m_+j+1) = f_tilde{r+1}(i+j*Q_m_+1);
end
end
end
end
% Implements Section 5.4.2.1 of TS38.212
function d_tilde = bit_selection(obj, e_tilde)
C_ = obj.C;
E_r_ = obj.E_r;
N_ = obj.N;
K_prime_ = obj.K_prime;
Z_c_ = obj.Z_c;
K_ = obj.K;
k_0_ = obj.k_0;
N_cb_ = obj.N_cb;
I_HARQ_ = obj.I_HARQ;
d_tilde_buffer_ = obj.d_tilde_buffer;
if size(e_tilde,1) ~= C_ || size(e_tilde,2) ~= 1
error('ldpc_3gpp_matlab:Error','e_tilde should be a column cell array of length C.');
end
d_tilde = cell(C_,1);
for r=0:C_-1
if size(e_tilde{r+1},1) ~= E_r_(r+1) || size(e_tilde{r+1},2) ~= 1
error('ldpc_3gpp_matlab:Error','e_tilde{r+1} should be a column vector of length E_r(r+1).');
end
d_tilde{r+1} = zeros(N_,1);
d_tilde{r+1}(max(K_prime_-2*Z_c_+1,1):K_-2*Z_c_) = NaN;
k = 0;
j = 0;
while k < E_r_(r+1)
if ~isnan(d_tilde{r+1}(mod(k_0_ + j, N_cb_)+1))
d_tilde{r+1}(mod(k_0_ + j, N_cb_)+1) = d_tilde{r+1}(mod(k_0_ + j, N_cb_)+1) + e_tilde{r+1}(k+1);
k = k+1;
end
j = j+1;
end
if I_HARQ_ ~= 0
d_tilde{r+1}(1:N_cb_) = d_tilde{r+1}(1:N_cb_) + d_tilde_buffer_{r+1};
d_tilde_buffer_{r+1} = d_tilde{r+1}(1:N_cb_);
end
end
obj.d_tilde_buffer = d_tilde_buffer_;
end
% Implements Section 5.3.2 of TS38.212
function c_hat = LDPC_coding(obj, d_tilde)
C_ = obj.C;
N_ = obj.N;
Z_c_ = obj.Z_c;
K_ = obj.K;
if size(d_tilde,1) ~= C_ || size(d_tilde,2) ~= 1
error('ldpc_3gpp_matlab:Error','d_tilde should be a column cell array of length C.');
end
c_hat = cell(C_,1);
for r=0:C_-1
if size(d_tilde{r+1},1) ~= N_ || size(d_tilde{r+1},2) ~= 1
error('ldpc_3gpp_matlab:Error','d_tilde{r+1} should be a column vector of length N.');
end
cw_tilde = [zeros(2*Z_c_,1); d_tilde{r+1}];
c_tilde = cw_tilde(1:K_);
cw_tilde(isnan(cw_tilde)) = inf;
c_hat{r+1} = double(step(obj.hLDPCDecoder, cw_tilde));
c_hat{r+1}(isnan(c_tilde)) = NaN;
end
end
% Implements Section 5.2.2 of TS38.212
function b_hat = code_block_segmentation(obj, c_hat)
C_ = obj.C;
I_HARQ_ = obj.I_HARQ;
b_hat_buffer_ = obj.b_hat_buffer;
B_ = obj.B;
K_ = obj.K;
K_prime_ = obj.K_prime;
code_block_L_ = obj.code_block_L;
CBGTI_flags_ = obj.CBGTI_flags;
code_block_CRC_passed_ = obj.code_block_CRC_passed;
if size(c_hat,1) ~= C_ || size(c_hat,2) ~= 1
error('ldpc_3gpp_matlab:Error','c_hat should be a column cell array of length C.');
end
if I_HARQ_ ~= 0
b_hat = b_hat_buffer_;
else
b_hat = zeros(B_,1);
end
s = 0;
for r = 0:C_-1
if size(c_hat{r+1},1) ~= K_ || size(c_hat,2) ~= 1
error('ldpc_3gpp_matlab:Error','c_hat should be a column vector of length K.');
end
code_block_CRC_failed = false;
if C_ > 1
[~,code_block_CRC_failed] = step(obj.hCBCRCDetector,c_hat{r+1}(1:K_prime_));
end
for k = 0:K_prime_-code_block_L_-1
if ~code_block_CRC_failed && CBGTI_flags_(r+1) == 1
b_hat(s+1) = c_hat{r+1}(k+1);
code_block_CRC_passed_(r+1) = 1;
end
s = s + 1;
end
end
if I_HARQ_ ~= 0
b_hat_buffer_ = b_hat;
end
obj.code_block_CRC_passed = code_block_CRC_passed_;
obj.b_hat_buffer = b_hat_buffer_;
end
% Implements Section 5.1 of TS38.212
function a_hat = crc_calculation(obj, b_hat)
B_ = obj.B;
A_ = obj.A;
code_block_CRC_passed_ = obj.code_block_CRC_passed;
if size(b_hat,1) ~= B_ || size(b_hat,2) ~= 1
error('ldpc_3gpp_matlab:Error','b_hat should be a column vector of length B.');
end
a_hat = zeros(A_,1);
for k = 0:A_-1
a_hat(k+1) = b_hat(k+1);
end
[~,transport_block_CRC_failed] = step(obj.hTBCRCDetector,b_hat);
if transport_block_CRC_failed || any(~code_block_CRC_passed_)
a_hat = [];
end
end
function resetImpl(obj)
C_ = obj.C;
B_ = obj.B;
N_cb_ = obj.N_cb;
d_tilde_buffer_ = cell(C_,1);
for r=0:C_-1
d_tilde_buffer_{r+1} = zeros(N_cb_,1);
end
obj.d_tilde_buffer = d_tilde_buffer_;
obj.b_hat_buffer = zeros(B_,1);
obj.code_block_CRC_passed = zeros(C_,1);
end
end
end