项目简述
交织多么好听的名字,第一次听见这个名字是在移动通信的课程中,当时就对这个名字一亮。交织其实就是把原有的码元顺序打乱进行发送,说白了就是矩阵变换。至于为什么要把原有的码元顺序打乱,是因为现实中传送的码元每一段都有固定的校验位,通过该校验位可以在码元错误较少的情况下进行纠错。而实际中受环境影响的码元是突发性错误,那么我们先经过交织之后传送的码元产生的突发性错误,经过解交织之后就会把原有的突发性错误转变成离散性错误,那么就可以有效的利用校验位进行纠错。这也是交织在通信系统中起到的主要作用,即变突发性错误为随机性错误。
数学模型
从上面我们可以知道交织就是把原有的码元顺序打乱。一般的码组分为信息位和校验位,在交织的过程中,我们一般分为两步:
1、进行校验位的交织操作
2、对整个码组进行交织操作
上面两步的交织的原理并不一样,接下来分别介绍常见的交织操作。
校验位交织
校验位交织的数学公式如下:
d i = u i f o r 0 < = i < = K 1 d_i=u_i\ \ \ \ for\ \ \ 0<=i<=K1 di=ui for 0<=i<=K1
d K 1 + 360 t + s = u K 1 + Q l d p c s + t f o r 0 < = s < 360 , 0 < = t < = Q l d p c d_{K1+360t+s}=u_{K1+Q_{ldpc}s+t}\ \ \ \ \ for \ \ \ \ 0<=s<360,0<=t<=Q_{ldpc} dK1+360t+s=uK1+Qldpcs+t for 0<=s<360,0<=t<=Qldpc
其中 i i i是码组中第几个码元, K 1 K1 K1是信息位的个数, u i u_i ui是交织前的码元, d i d_i di是交织后的输出码元, Q l d p c = 校 验 位 个 数 / 360 Q_{ldpc}=校验位个数/360 Qldpc=校验位个数/360。
依据校验位交织地址生成公式可知,校验位交织本质是行进列出,若校验位数据向量重新构成矩阵形式,交织前矩阵为Qldpc*360,即依次将向量数据每行写入 360 个数,第 361 个数为第 2 行第 1 列数,依次类推。存入 Rom 地址如图所示,
我们矩阵的时候都是一行一行的看,这里虽然本质上是列进行出,但是我们读地址是一行一行读的,所以这个就相当于矩阵的转置操作。即取数据依次以如下地址取数据,重新生成新读出矩阵。
这里隐含一个非常重要的FPGA技巧,FPGA中矩阵的转置如何使用硬件语言来描述。 等进行讲解Verilog代码的时候,可以着重注意矩阵转置对应的Verilog代码。
码组的列旋转交织
上面我们已经进行了检验位交织,将校验位交织与原来的信息位组合成的输入 d i d_{i} di 按列顺序依次写入列旋转交织器,然后按行依次读出完成列旋转交织,每列写入的起始位置由 t c tc tc 决定 ,整个列旋转交织器:
这里解释一下与校验位交织的不同点:
1、校验位交织只有码组的校验位参与交织操作,而列旋转交织是整个码组进行交织操作
2、校验位交织的行是固定的360个元素,而列旋转交织则不是固定值
3、列旋转交织在转置的基础上,每一行均有一个tc的偏移,这也使得在书写FPGA代码的时候要比校验位交织难一点
以16QAM为例,上面的列旋交织主要有2025行8列,其中每一列的tc的值如下:
tc | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|---|
16QAM | 0 | 0 | 0 | 1 | 7 | 20 | 20 | 21 |
列旋转交织器的输入为 d i , 0 < = i < = N d_i,0<=i<=N di,0<=i<=N(其中N是整个码组的长度,在16QAM中N的长度是16200),写入列旋转交织器的 c m c_m cm 列, r n r_n rn 行,则行和列需要满足下面的情况(以16QAM为例):
c m = i / 2025 c_m=i/2025 cm=i/2025
r n = ( i − t c ) % 2025 r_n=(i-tc)\%2025 rn=(i−tc)%2025
由上面的的公式,我们可以写出列旋交织器的输入矩阵与输出矩阵之间的关系,这里同样是按照按照行的顺序写入读出。交织前的地址是:
进行列旋交织之后的地址如下:
这里注意,FPGA的语言叫做硬件描述语言,那么要想才能成功描述上面矩阵的变化,就必须找到上面矩阵的规律,上面的公式规律已经标红,大家可以最终结合相应的FPGA代码进行学习。大家阅读下面的FPGA代码的时候,可以发现一共2025行数据,只有前21行数据是乱的,后面的2000多行数据的计算都是有规律的,这也是FPGA代码中有一个很笨重状态机的原因。大家阅读FPGA代码的时候,一定要联系上面的矩阵,可以便于理解。
交织的MATLAB实现
经过上面的原理介绍,相信大家对交织的操作有了一定的了解,那么接下来我们给出相应的MATLAB代码供大家更深入的了解。这里说明一下,代码不是博主编写,博主只是在原有的代码上进行了一些更改,可以更方便的理解代码,代码的来源是发烧友学院,在文章的最后,会附上参考网址,需要的同学可以关注一下。
sim_options = struct(...
'CRATE_DATA', '3/5', ... %业务编码码率1/2 3/5 2/3 3/4 4/5 5/6
'CONSTELLATION', '16-QAM' ...
);
tx_nFrame =1;
fid1 = fopen('bint_data_in.txt','r');
DataIn = fscanf(fid1,'%d');
switch sim_options.CRATE_DATA
case '1/2',
Q = 25;
CR=4/9;
case '3/5',
Q = 18;
CR=3/5;
case '2/3',
Q = 15;
CR=2/3;
case '3/4',
Q = 12;
CR=11/15;
case '4/5',
Q = 10;
CR=7/9;
case '5/6',
Q = 8;
CR=37/45;
otherwise
error('sim_options UNKNOWN CODING RATE');
end
%------------------------------------------------------------------------------
% PLP-specific Parameters Definition
%------------------------------------------------------------------------------
CONSTEL = sim_options.CONSTELLATION; % modulation constellation
COD_RATE = CR;
S = 360; % The S of the code
CRATE = sim_options.CRATE_DATA; % The code rate
%------------------------------------------------------------------------------
% Procedure
%---------------------------------------
data = DataIn';
nbint_len = 16200 ; % block size, need to pass this in
int_type = 2;
parity_only = false;
Nc = 8;
switch CONSTEL
case 'QPSK'
int_type = 0;
case '16-QAM'
Tc = [0 0 0 1 7 20 20 21];
end
Nr = nbint_len / Nc;
numIntlvBlocks = floor(length(data)/nbint_len); % Number of interleaving blocks
data = data(1:numIntlvBlocks*nbint_len); %clip the length of the input data
bitIntlvOut = zeros(1,length(data),'single'); %mem preallocation
if int_type == 0
%do no interleaving
bitIntlvOut = data;
elseif int_type == 2
%the type B interleaver
plen = round(nbint_len * (1 - COD_RATE));
%make the parity interleaving table
parity_table = zeros(1,plen);
count = 1;
for scount = 0:S-1
for t = 0:Q-1
parity_table(count) = S * t + scount + 1;
count = count + 1;
end
end
%compare data
fid1 = fopen('mb_parity_addr.txt','w');
fprintf(fid1,'%d\n',parity_table);
%make the Sony interleaving table
if ~parity_only;
code_table =