LTE物理层概述(8)-- LTE之Turbo编译码及其matlab仿真2--速率匹配、码块分段、扰码介绍
一、速率匹配介绍1、原理概述LTE在实际使用中,并非使用1/3 Turbo编码,更多的采用 1/2 Turbo编码,即所谓的 “打孔码”。在每个子块(CB)内,为了实现各种需要的码率,我们需要进行速率匹配。一般,速率匹配包含以下3个部分:子块交织器 (Sub - block Interleaver);比特收集(Bit - Collection);比特选择与修剪(Bit Selection and
一、速率匹配介绍
1、原理概述
LTE在实际使用中,并非使用1/3 Turbo编码,更多的采用 1/2 Turbo编码,即所谓的 “打孔码”。
在每个子块(CB)内,为了实现各种需要的码率,我们需要进行速率匹配。一般,速率匹配包含以下3个部分:
- 子块交织器 (Sub - block Interleaver);
- 比特收集(Bit - Collection);
- 比特选择与修剪(Bit Selection and Pruning);
如图1所示为 Turbo码速率匹配过程,在 TS 36.212(复用和信道编码协议)中,对其有详细规定。后续我们会具体说明。
图1 Turbo码的速率匹配
1.1 子块交织器
对Turbo码的三组比特流 —— 1个系统比特流(Infomation bit)和 2 个校验比特流(Parity bit)中的比特排序进行调整,改进 Turbo码打孔(Puncture)后的性能。子块交织器采用交织深度 32 的 “ 行入列出 ” 块交织器。
Matlab程序实现解读:
function y = lte_RateMatcher(in, Kplus, Rate)
% Rate matching per coded block
D = Kplus + 4;
if numel(in) ~= 3*D
error('Kplus (2nd argument) times 3 must be size of input 1.');
end
% Parameters
colTcSb = 32;
rowTcSb = ceil(D/colTcSb);
Kpi = colTcSb * rowTcSb;
Nd = Kpi - D;
% Bit streams
d0 = in(1:3:end); % systematic
d1 = in(2:3:end); % parity 1st
d2 = in(3:3:end); % parity 2nd
1)程序实现时,列数 ColTcSb = 32,行数为 ,为上去整。一般情况下,码块长度不是32的整倍数,于是有:
Nd = colTcSb * rowTcSb - D
这里的 Nd 即表示加入的虚比特数量 (dummy bits),matlab里每一个虚比特值为 NaN。在码块头部,即码块开始部分添加 Nd 个虚比特,构成:
y = [NaN * ones(Nd,1); d];
2) 将 y 逐行逐列写入矩阵,完成矩阵排列。图2节选的是TS 36.212列出的矩阵排列方式:
3) 将矩阵按照下表,完成列置换:
具体实现为:
function v = indexGenerator(d, colTcSb, rowTcSb, Nd)
% Sub-block interleaving for d0 and d1 streams only
colPermPat = [ 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, ...
1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31];
% For 1 and 2nd streams only
y = [NaN * ones(Nd,1); d];
inpMat = reshape(y, colTcSb, rowTcSb).';
permlnpMat = inpMat(:, colPermPat+1);
v = permlnpMat(:);
end
4)进行块交织:
乍看这个公式比较复杂,其实是由于36. 212协议中 参数命名的问题,用matlab翻译过来:
pi = zeros(colTcSb * rowTcSb,1);
for i = 1:length(pi)
pi(i) = colPermPat(floor((i-1) / rowTcSb)+1) + colTcSb * (mod(i-1, rowTcSb)) + 1;
end% 由于i 的序列长度为 0 ~ (colTcSb * rowTcSb -1),不可能大于K_pi,因此实际实现时可省略公式最后 “ mod K_pi ” 操作;
%说明:公式中k取值为 0 ~ (colTcSb * rowTcSb -1),但 matlab中下标序列需从 1开始,因此有了 (floor((i-1) / rowTcSb)+1) 这样的复杂操作;
完整的块交织代码如下所示:
function v = indexGenerator2(d, colTcSb, rowTcSb, Nd)
% Sub-block interleaving for d0 and d1 streams only
colPermPat = [ 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, ...
1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31];
pi = zeros(colTcSb * rowTcSb,1);
for i = 1:length(pi)
pi(i) = colPermPat(floor((i-1) / rowTcSb)+1) + colTcSb * (mod(i-1, rowTcSb)) + 1;
end
% For 1 and 2nd streams only
y = [NaN * ones(Nd,1); d];
inpMat = reshape(y, colTcSb, rowTcSb).';
ytemp = inpMat.';
y = ytemp(:);
v = y(pi);
end
1.2 比特收集
对交织后的3个比特流按序排列,寄存在一个虚拟循环与缓存( Virtual Circular Buffer)。首先收集系统比特流,然后交替收集第1和第2校验比特流。按照块交织索引值,对 d0 ~ d2进行重新排列。其中,d0、d1使用子块内列交织方式进行重排,d2使用子块交织方式排列。循环缓存器按如下方式进行排列(36.212协议):
Matlab实现时主要调用 subBlkInterl 函数:
% Sub - block interleaving - per stream
v0 = subBlkInterl(d0, index);
v1 = subBlkInterl(d1, index);
v2 = subBlkInterl(d2, index2);
subBlkInterl 函数如下所示:
function out = subBlkInterl(d0, index)
out = zeros(size(index));
IndexG = find(~isnan(index)==1);
IndexB = find(isnan(index)==1);
out(IndexG) = d0(index(IndexG));
%Nd = sum(IndexB);
Nd = numel(IndexB);
out(IndexB) = nan*ones(Nd, 1);
end
1.3 比特选择与修剪
从虚拟缓存中循环读取指定长度的比特流,完成速率匹配。
function y = lte_RateMatcher(in, Kplus, Rate)
% Rate matching per coded block
D = Kplus + 4;
if numel(in) ~= 3*D
error('Kplus (2nd argument) times 3 must be size of input 1.');
end
% Parameters -- 按照32bit对码块进行交织,列号为32,行号为分组数
colTcSb = 32;
rowTcSb = ceil(D/colTcSb);
Kpi = colTcSb * rowTcSb;
Nd = Kpi - D;
% Bit streams
d0 = in(1:3:end); % systematic
d1 = in(2:3:end); % parity 1st
d2 = in(3:3:end); % parity 2nd
i0 = (1:D)';
index = indexGenerator(i0, colTcSb, rowTcSb, Nd);
index2 = indexGenerator2(i0, colTcSb, rowTcSb, Nd);
% Sub - block interleaving - per stream
v0 = subBlkInterl(d0, index);
v1 = subBlkInterl(d1, index);
v2 = subBlkInterl(d2, index2);
vpre=[v1,v2].';
v12 = vpre(:);
% Concat 0, interleave 1, 2 sub-blk streams
% Bit collection
wk = zeros(numel(in), 1);
wk(1:D) = remove_dummy_bits(v0);
wk(D+1:end) = remove_dummy_bits(v12);
% apply rate matching
N = ceil(D/Rate);
y = wk(1:N);
end
1.4 Turbo卷尾比特处理
根据 36.212 协议,5.1.3.2.2 小节规定了对 Turbo码的破零处理,即卷尾处理:
协议解释如下:
原有输出顺序为:
经过重新排列后,排列顺序为:
【1 5 7 11 4 3 10 9 2 6 8 12】
二、绕码介绍
2.1、绕码定义
在LTE下行链路中,信道编码生成的码字序列由比特级绕码序列绕码。相邻小区使用不同的绕码序列以保证干扰随机,且来自不同小区传输在解码之前被分开。为达到这些目前,各个小区序列绕码的数据比特是唯一的,小区的绕码序列由PHY小区识别码生成。
比特级绕码应用于所有 LTE TrCH 和下行链路控制信道。
绕码由两部分构成:伪随机序列生成和比特相乘。伪随机序列由长度31的Gold序列生成,输出序列定义为两个序列的异或操作的输出。伪随机序列定义如下:
第一个序列的初始值定义为长度31的单位冲击函数,第二个序列的初始值则取决于小区识别码、码字数量和子帧索引。最终输出是对输入比特和Gold多项式比特进行异或运算。
在接收端,去绕操作为绕码器的反向过程。但是,要分两种情况判断:
1)若先于去绕操作进行硬判决译码,绕码器输入为比特。这种情况下,输入比特和 Gold序列异或运算将会直接生成去绕序列输出;
2)去绕之前进行软判决译码,输入信号不为比特而是LLR。这种情况下,去绕为输入对数似然值与Gold序列比特变换系数值的乘积。0值Gold序列映射为1,1值Gold序列映射为-1;
绕码MATLAB实现如下所示:
function y = lte_Scrambler(u, nS)
% Downlink scarmbler
persistent hSeqGen hInt2Bit
% p1(x) = x^31 + x^3 + 1
% p2(x) = x^31 + x^3 + x^2 + x + 1
if isempty(hSeqGen)
maxG = 43200;
hSeqGen = comm.GoldSequence('FirstPolynomial',[1 zeros(1,27) 1 0 0 1], ...
'FirstInitialConditions', [zeros(1,30) 1], 'SecondPolynomial', [ 1 zeros(1,27) 1 1 1 1], ...
'SecondInitialConditionsSource','Input port', 'Shift', 1600, 'VariableSizeOutput', true, ...
'MaximumOutputSize', [maxG 1]);
hInt2Bit = comm.IntegerToBit('BitsPerInteger',31);
end
% Parameters to compute initial condition
RNTI = 1;
NcelllD = 0;
q = 0;
% Initial conditions
c_init = RNTI * (2^14) + q * (2^13) + floor(nS/2) * (2^9) + NcelllD;
% Convert Initial conditon to binary vector
iniStates = step(hInt2Bit, c_init);
% Generate the scrambling sequence
nSamp = size(u,1);
seq = step(hSeqGen, iniStates, nSamp);
seq2 = zeros(size(u));
seq2(:) = seq(1:numel(u),1);
% Scramble input with the Scrambling sequence
y = xor(u, seq2);
解绕MATLAB实现如下所示:
% 第一种实现方式:硬比特译码下去绕
function y = lte_DescramblerHard(u, nS)
% Downlink scarmbler
persistent hSeqGen hInt2Bit
% p1(x) = x^31 + x^3 + 1
% p2(x) = x^31 + x^3 + x^2 + x + 1
if isempty(hSeqGen)
maxG = 43200;
hSeqGen = comm.GoldSequence('FirstPolynomial',[1 zeros(1,27) 1 0 0 1], ...
'FirstInitialConditions', [zeros(1,30) 1], 'SecondPolynomial', ...
[ 1 zeros(1,27) 1 1 1 1], 'SecondInitialConditionsSource', ...
'Input port', 'Shift', 1600, 'VariableSizeOutput', true, ...
'MaximumOutputSize', [maxG 1]);
hInt2Bit = comm.IntergerToBit('BitsPerInteger',31);
end
% Parameters to compute initial condition
RNTI = 1;
NcelllD = 0;
q = 0;
% Initial conditions
c_init = RNTI * (2^14) + q * (2^13) + floor(nS/2) * (2^9) + NcelllD;
% Convert Initial conditon to binary vector
iniStates = step(hInt2Bit, c_init);
% Generate the scrambling sequence
nSamp = size(u,1);
seq = step(hSeqGen, iniStates, nSamp);
% Descramble
y = xor(u(:,1), seq2(:,1));
end
% -----------------------------------------------------------------------------
% 第二种实现方式:软译码LLR下去绕
% 从seq = step(hSeqGen, iniStates, nSamp)后面开始不同
seq2 = zeros(size(u));
seq2(:) = seq(1:numel(u),1);
% Scramble input with the Scrambling sequence
seq2 = 1- 2 * seq2;
% Descramble
y = u .* seq2;
代码完整运行可自行下载:
LTE Turbo编译码综合仿真https://download.csdn.net/download/snowman898/85391832
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)