一、速率匹配介绍

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,行数为  rowTcSb = \left \lceil D/ colTcSb \right \rceil ,为上去整。一般情况下,码块长度不是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序列生成,输出序列定义为两个序列的异或操作的输出。伪随机序列定义如下:

                 p_1(x)=x^{31}+x^3+1            p_2(x)=x^{31}+x^3+x^2+x+1

    第一个序列的初始值定义为长度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

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐