一:卷积码编译码原理
1.卷积码编码原理
(1)实验指导书原文部分:
信道编码采用卷积码进行编码。以(n,k,m)来描述卷积码,其中k为每次输入到卷积编码器的bit数,n为每个k元组码字对应的卷积码输出n元组码字,码率为k/n。编码器在任何一段规定时间内产生的n个码元,不仅和当前的k比特信息段有关,而且还同前面的m-1个信息段有关。一个码组中的监督码元监督着m个信息段,nm称为编码约束长度。
如图3.3.2所示是一个卷积码的编码器(2,1,6)。编码器的输入信息位,一方面可以直接通过1级移位寄存器直接输出,另一方面还可以暂存于6级移位寄存器中。每当进入编码器一个信息位,就立即计算出一监督位,并且此监督位紧跟此信息位之后发送出去。这种卷积码的参量为:k=1,n=2,m=6,约束长度等于nm,即12,码率为1/2。编码器输出与输入的关系如图3.4.3所示。
图3.3.2卷积编码器
图3.3.3 编码器的输入输出关系
在OFDM系统实验中,卷积码使用码率为1/2的卷积码或1/3的卷积码,编码器输入输出对应的生成多项式为9位,可表示为:
1/2卷积码:[561,753],
1/3卷积码:[557, 663, 711]
其中1/2卷积码的编码器框图如图3.3.4所示。
图3.3.4 1/2卷积码, [561,753]
第1个多项式中的系数为101 110 001,从右边起每3比特进行分段,转化为8进制为[561]。
第2个多项式中的系数为111 101 011,从右边起每3比特进行分段,转化为8进制为[753]。
编码时需要注意添加尾比特,在输入数据后面添加8个0,再进行卷积编码。
(2)我们如何描述一个编(译)码器
综合上文以及通信原理课程我们知道有六种的方法描述一个(n,k,m)的编(译)码器
1.编码器框图
2.生成多项式
3.(matlab常用)八进制矩阵组(对应二进制穿孔向量puncture vector)
4.转移状态图
5.转移网格图
6.转移码树图
后三种实验内不做要求所以略过。
如无意外一般我们看到的编(译)码器的形如【561】,【753】的都是八进制矩阵上文讲了如何把八进制矩阵组化成生成多项式和框图。每个输出位比特对应一个多项式和八进制矩阵,共n个。
我们知道k/n对应的是码率,k代表每组进入移位寄存器的码元数,n代表每组输出的码元数。但是指导书中的m与其他常用的指代有所区别。一般来讲指导书中的m(常用l)就是所谓的约束长度。n*m或是n*l代表的是内存大小,即编码器可能的状态数。在此强调以免造成混乱。
我们使用迭代算法如Viterbi(维特比)算法译码时所用的回溯深度应满足以下关系:回溯深度≥约束长度
(3)回溯深度和约束长度
下面我们讲如何计算回溯深度和约束长度
(不做要求仅作了解)
来源:信道编码:MATLAB使用卷积编译码函数_vitdec函数-CSDN博客
gpt翻译:一般估计一个典型的回溯深度值大约是(约束长度 - 1)/ (1 - 码率) 的两到三倍。编码器的约束长度由公式 (log2(trellis.numStates) + 1) 确定。码率等于 (K/N) × (puncturePattern 的长度 / puncturePattern 的总和)。其中,K 是输入符号的数量,N 是输出符号的数量,puncturePattern 是穿孔模式向量。例如,应用这一一般估计,可以得到以下近似的回溯深度值。 一个码率为 1/2 的码具有回溯深度为 5*(约束长度 - 1)。 一个码率为 2/3 的码具有回溯深度为 7.5*(约束长度 - 1)。 一个码率为 3/4 的码具有回溯深度为 10*(约束长度 - 1)。 一个码率为 5/6 的码具有回溯深度为 15*(约束长度 - 1)。
上例中:取回溯深度=2.5*(约束长度-1)/(1-码率)(2~3之间皆可,此处取2.5)
*给出的约束长度的计算为约束长度=(log2(转移状态总数)+1)
码率=(k/n)*(穿孔向量长度/穿孔向量和)
穿孔向量即八进制转出的二进制向量组
【561,753】对应的【101110001,111101011】
穿孔向量的长度=编码器约束长度,穿孔向量和=穿孔向量中为1的量的数量
另:原文中【171】转二进制应为【1111001】而非【1111111】
2.主要函数使用
信道编码:MATLAB使用卷积编译码函数_vitdec函数-CSDN博客
还是这篇文章,我们要用的就是这三个函数,下面是省流版
(1)poly2trellis
直接定义一个卷积码编(译)码器的结构,服务于接下来要用的函数
trellis = poly2trellis(ConstraintLength,CodeGenerator)
ConstraintLength即约束长度,CodeGenerator要求我们输入设定的八进制穿孔向量矩阵
OFDM实验中要求的是1/2码率的[561,753]和1/3的[557, 663, 711]
(2)convenc
codedout = convenc(msg,trellis)
codedout = convenc(msg,trellis,puncpat)
msg即输入的待编码码元
trellis就是我们上面定义的编码器
(3)vitdec(译码部分)
decodedout = vitdec(codedin,trellis,tbdepth,opmode,dectype)
decodedout = vitdec(codedin,trellis,tbdepth,opmode,'soft',nsdec)
decodedout = vitdec(codedin,trellis,tbdepth,opmode,dectype,puncpat)
codein编码部分生成的卷积码
trellis略
由于实验要求添加8个尾比特0,
故:tbdepth回溯深度取8
opmode选用cont即可
dectype选用hard即可。
关于opmode和dectype其他参数下异同见引用文章
信道编码:MATLAB使用卷积编译码函数_vitdec函数-CSDN博客
下面我们试验下尾比特数对编译码的影响
我们实验发现,基于链接文档中的代码当尾比特达到30时,主体码组1000比特时仍无错误
n = 2;
k = 1;
rate = k/n; % rate为 1/2
L = 7;
tblen = 5*(L-1); % 回溯深度
trellis = poly2trellis(L,[171 133]);
code_data = convenc(msg_source,trellis);
d = vitdec(code_data,trellis,tblen,'cont','hard');
figure(1);
stairs(msg_source(1:end-30),':*r');
hold on;
stairs(d(31:end),':+b');
ylim([-0.1,1.1]);
grid on;
legend('原始信息','恢复信息');
此时得到的msg_source有30个尾比特,d有30个首比特
msg_source的30个尾比特是我们添加的,以保证码段大于回溯深度30以免引起错误.若取更多的尾比特数,则可以改变回溯深度使之相等或者直接用下文的方法删除等量的首比特0
d的30个首比特0等于回溯深度
假设你有一个向量或矩阵 A
,你想去除从第 i 项到第 j 项之间的元素。你可以这样做:
% 假设 A 是你的向量或矩阵
i = 3; % 开始索引
j = 5; % 结束索引
% 创建一个逻辑索引,将第 i 到第 j 项之间的元素标记为 0,其他元素标记为 1
index = true(size(A)); % 创建一个与 A 大小相同的逻辑索引
index(i:j) = false; % 将第 i 到第 j 项之间的元素标记为 false
% 使用逻辑索引去除元素
A = A(index);
这样就会将矩阵或向量 A
中从第 i 项到第 j 项之间的元素去除掉,并返回去除后的结果。
我们可以先去除msg_source和d的多余位,然后用isequal函数验证
index=true(size(d));
index(1:30)=false;
d=d(index);
index=true(size(msg_source));
index(1001:1030)=false;
msg_source=msg_source(index);
然后再命令行使用
isequal(d,msg_source);
结果如下
译码与原码相同,验证成功
3.卷积码编码器函数OFDM_TXTrchCoder
function [out_data] = OFDM_TxTrchCoder(input_data, coder_type)
input_num=length(input_data);
%% 功能实现
switch coder_type
case 0 %% 不编码
out_data = zeros(1, input_num); %#ok
out_data = input_data;
case 1 %% 1/2卷积码
CodeGenerator = [561, 753];
%第一步添加尾比特(在输入数据后添加8个0)
%第二步卷积编码
case 2 %% 1/3卷积码
CodeGenerator = [557, 663, 711];
%第一步添加尾比特(在输入数据后添加8个0)
%第二步卷积编码
otherwise
fprintf('error \n');
end
我们将给定的程序补齐
4.卷积码译码器函数OFDM_RxTrchDecoder
function [out_data] = OFDM_RxTrchDecoder(input_data, coder_type)
input_num=length(input_data);
%% 功能实现
switch coder_type
case 0 %% 不编码
out_data = zeros(1, input_num); %#ok
out_data = input_data;
case 1 %% 1/2卷积码
%第一步卷积译码
%第二步去掉尾比特
case 2 %% 1/3卷积码
%第一步卷积译码
%第二步去掉尾比特
otherwise
fprintf('error\n');
end
将它补齐
function [out_data] = OFDM_TxTrchCoder(input_data, coder_type)
input_num=length(input_data);
%% 功能实现
switch coder_type
case 0 %% 不编码
out_data = zeros(1, input_num); %#ok
out_data = input_data;
case 1 %% 1/2卷积码
CodeGenerator = [561,753];
tail_bits=zeros(1,8);%插入尾比特
input_data=[input_data,tail_bits];
trellis=poly2trellis(9,CodeGenerator);%定义寄存器
out_data=convenc(input_data,trellis);%生成卷积码
case 2 %% 1/3卷积码
CodeGenerator = [557,663,711];
tail_bits=zeros(1,8);%插入尾比特
input_data=[input_data,tail_bits];
trellis=poly2trellis(9,CodeGenerator);%定义寄存器
out_data=convenc(input_data,trellis);%生成卷积码
otherwise
fprintf('error \n');
end
function [out_data] = OFDM_RxTrchDecoder(input_data, coder_type)
input_num=length(input_data);
%% 功能实现
switch coder_type
case 0 %% 不编码
out_data = zeros(1, input_num); %#ok
out_data = input_data;
case 1
trellis = poly2trellis(9, [561, 753]);%定义解码器
decoded_data = vitdec(input_data, trellis, 8, 'cont', 'hard');%维特比译码
out_data = decoded_data(9:end); % 去除添加的8个尾比特
case 2
trellis = poly2trellis(9, [557,663,711]);%定义解码器
decoded_data = vitdec(input_data, trellis, 8, 'cont', 'hard');%维特比译码
out_data = decoded_data(9:end); %去除添加的8个尾比特
otherwise
fprintf('error\n');
end
5实验验证
clear all
msg_source = [randi([0 1],1,1000),zeros([1,8])];
a=OFDM_TxTrchCoder(msg_source,1);
b=OFDM_RxTrchDecoder(a,1);
clear all
msg_source = [randi([0 1],1,1000),zeros([1,8])];
a=OFDM_TxTrchCoder(msg_source,2);
b=OFDM_RxTrchDecoder(a,2);
代码部分验证成功