信道编码:MATLAB 使用Conv函数
1. 相关函数
在进行卷积编码的过程中,使用的函数是convenc()
函数和vitdec()
函数,同时需要poly2trellis()
函数。
1.1 poly2trellis()
函数
先看poly2trellis()
函数,用来生成卷积编码所需要的网表。
trellis = poly2trellis(ConstraintLength,CodeGenerator)
这个函数相当于定义了编码器中寄存器的结构,一般来说,在查看卷积编码的相关资料中都是类似于(2,1,3)这种结构,但是这这个函数只需要两个参数:
ConstraintLength
参数代表约束长度CodeGenerator
代码生成器,指定为八进制数的K
乘N
矩阵、多项式字符向量的K
乘N
单元阵列或K
乘N
字符串阵列。CodeGenerator
为编码器的K
个输入比特流中的每一个指定N
个输出连接。
通俗理解这两个参数的含义和作用,首先约束长度决定了再译码时候的回溯深度的大小,根据不同的编码速率有不同的关系,技术文档中对此有介绍:
根据设定的n
,k
,和L
值来确定,如对于(2,1,3)
结构类型的卷积编码器,其中rate = k/n = 1/2
,对应第一种计算方式,那么回溯深度为5*(L-1)
,结果为10,在进行译码的时候利用这个值对齐或者截断,这个在下面使用过程中会有。
回到函数本身,如设计(2,1,7)
类型的编码器,可以用:
L = 7;
trellis = poly2trellis(L,[171 133]);
其中的第二个参数是8进制数据的表现形式,对应二进制为[111_1111, 101_1011]
。可以理解为进入1bit
数据,输出2bit
数据,所以这个是2维的,同时这个7bit
每一位代表寄存器的抽头,可以根据这个画出编码器的连接形式。
有了这些概念就可以使用这个函数了。
1.2 convenc()
函数
再看convenc()
函数
codedout = convenc(msg,trellis)
codedout = convenc(msg,trellis,puncpat)
简单使用卷积编码就用这个第1种调用方式就可以了,其中
msg
参数是需要编码的信息,这个需要输入0,1二进制数据。trellis
参数就是上面函数生成的结果,传输到这里。
在使用时,需要注意的是 msg
数据的长度要是k
的整数倍,同时利用上面的约束长度,计算回溯深度,利用回溯深度在信息后面添加0
。
1.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)
译码函数的参数相对校多,主要是需要设置模式:
codedin
参数是需要译码的结果,模式选择硬判决的时候必须输入是整数,模式选择软判决的时候可以输入小数。trellis
参数也编码函数的一致。tbdepth
这个参数参数就是回溯深度,前面利用约束长度计算的结果。opmode
这个参数有三个不同的选项,分别为cont
,term
和trunc
。dectype
参数用来设置是硬解码hard
还是软解码soft
,硬解码输入的数据都是0
和1
,软解码可以说输入小数。
有一点需要注意的是,对于term
和trunk
模式,回溯深度tbdepth
必须是一个正整数,并且小于或等于输入编码中的输入符号数,说白了就是在编码前的信息msg
长度就得大于等于回溯深度,要不然不够译码的。
这三个参数的差别,term
模式下没有延时,就是译码的第一个数据就是编码的第一个数据。trunc
参数也没有延时,cont
参数有延时,是回溯深度。还有差别就是连续编码的区别。
下面用程序看具体的区别。
2.使用方法
利用(2,1,7)结构的形式进行卷积编译码,如下是测试代码,首先选择cont
和hard
模式。
close all;
clear;
clc;
msg_source = [randi([0 1],1,50),zeros([1,30])]; % 一共10e4个点
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('原始信息','恢复信息');
得到的实验结果为:
当译码函数在使用term
模式的时候
close all;
clear;
clc;
msg_source = [randi([0 1],1,50),zeros([1,30])]; % 一共10e4个点
% msg_source2 = [randi([0 1],1,50),zeros([1,30])]; % 一共10e4个点
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,'term','hard');
figure(1);
stairs(msg_source(1:end),':*r');
hold on;
stairs(d(1:end),':+b');
ylim([-0.1,1.1]);
grid on;
legend('原始信息','恢复信息');
此时的到的结果为:
从上图中可以看出来,译码之后的信息直接从第一位开始,不需要利用回溯深度来截断之后对比数据,但是这种模式适用的情况是需要编码的信息后面存在足够的多的0数据才可以,当把上一段的代码中的原始数据msg_source
后面的30个0,改为20个1时
msg_source = [randi([0 1],1,50),ones([1,30])];
得到的试验结果为:
可以发现虽然译码的结果可以从与原始数据从第1位对齐,但是最后的数据会出现错误。
在测试连续编码的情况:对两段信息分别编码,然后把编码后的信息拼接在一起进行解码,采用的模式为trunc
和hard
,程序代码如下:
close all;
clear;
clc;
msg_source1 = [randi([0 1],1,50)]; % 一共10e4个点
msg_source2 = [randi([0 1],1,50),zeros([1,30])]; % 一共10e4个点
msg_source = [msg_source1,msg_source2];
n = 2;
k = 1;
rate = k/n; % rate为 1/2
L = 7;
tblen = 5*(L-1); % 回溯深度
trellis = poly2trellis(L,[171 133]);
code_data1 = convenc(msg_source1,trellis);
code_data2 = convenc(msg_source2,trellis);
code_data = [code_data1, code_data2];
d = vitdec(code_data,trellis,tblen,'trunc','hard');
figure(1);
stairs(msg_source(1:end),':*r');
hold on;
stairs(d(1:end),':+b');
ylim([-0.1,1.1]);
grid on;
legend('原始信息','恢复信息');
得到的结果为:
从结果中可以看出来译码是存在错误的。
可以对上面的msg_source1
进行更改,改为
msg_source1 = [randi([0 1],1,50),zeros([1,30])];
在后面添加回溯深度个0
,再次运行,可以得到结果
可以得到正确的结果,总结起来方便操作就是在信息的末尾添加回溯深度个0
。