MATLAB (n,k,m)卷积码原理及仿真代码(你值得拥有)

小小低头哥
• 阅读 389

卷积码原理介绍

1.基本概念

首先卷积码是一种纠错码,让我们先从大格局出发,去认识卷积码。如图1所示

MATLAB (n,k,m)卷积码原理及仿真代码(你值得拥有)

我是先从通信原理书上了解了卷积码的概念,再结合网上部分资料,勉强搞懂,感觉主要需要掌握卷积码编码器状态图网状图。基本概念太多,要叙述起来需要花挺多时间的,不过网上这部分资料挺多的,这里就不在全部叙述,仅就部分知识点说一下我的看法。

1.1 编码器状态

以(2,1,2)卷积码例,此时编码器对应的状态共有2^2=4种,如图2所示。MATLAB (n,k,m)卷积码原理及仿真代码(你值得拥有)

由于输入只有0或者1,故每一种状态对应的下一种状态都只有两种情况。值得一提的是,这两种情况对应的输出相互取反,如果一个输入为01,则另一种输入为10,即码距最大。后面我也去理解了一下Viterbi译码,由这个译码原理,我进一步发现 编码时一个状态对应不同的输出互相取反的情况是有必要的,是有特殊规定的。因为这样的规定可以使得最大似然译码(MLD) 算法可以在Viterbi译码中成功应用。(由于本篇只论述编码,我还没开始译码的仿真,所以此处不再继续叙述译码。后面了解译码并仿真成功后再进一步叙述我对译码的理解)。

2.(n,1,m)卷积编码及仿真

本实验以(2,1,2)为例。必须知道如何通过生成多项式画出编码器结构,或者从编码器结构写出生成多项式,这部分内容B上面很多讲的挺详细的视频。本次实验的生成多项式为

%一般用八进制表示,为了方便,我用的是二进制。 m = [1 0 0;1 1 1]; %第n行元素分别表示每个编码器(从左至右)与第n个输出码元的连接情况,即行数代表输出码元数 列数代表编码器个数 即m+1

此代码模仿自这位大佬的作品实验七-卷积编码的MATLAB实现如有侵权,告知后立马删!

%% 测试主函数
clear all
clc
G = [1,0,1;1,1,1]; %%生成多项式
M = [1 1 0 0 1 0 1 1]; %%信息
C = ZW_conv_encode(M,G);
%% 本函数实现卷积编码
function C = ZW_conv_encode(m,G)
%{
输入:
    原始序列m
    生成矢量G  每一行代表一个输出的连接结构
输出:
    卷积码结果C 
特点:
    适用于所有的[n,1,N]卷积编码
%}
len = length(m);    %记录输入信息长度
k=1;                %每次输入一个码元
[n,N] =  size(G);   %n表示一次有几个码元输出 N表示一次有几个监督码元(包括当前输入)
C = zeros(1,n*len); %储存输出卷积码
% 在头尾补0,方便卷积输出和寄存器清洗
m_add0 = [zeros(1,N-1),m,0]; %初始m个状态均假设为0,补N-1个0 当作新的信息流
%fliplr将矩阵倒序 因为编码器输出的计算是对应的 [输入-m个状态].*G 而m_add0中与所需相反
C_reg = fliplr(m_add0(1,1:N));  %C_reg[输入-m个状态] 因为每次监督的码元为N个,故寄存器中也储存N个码元

%开始循环 将每一个输入都得到对应的输出
for i=1:len
    %生成每一位输入符号的n位输出
    C(n*i-(n-1):n*i) =  mod(C_reg*G',2);
    %载入新的输入并更新寄存器状态 
    C_reg = [m_add0(i+N),C_reg];%此时(1,N+1)
    C_reg(end) = [];% 挤掉旧符号 最后一个元素直接没有 回到(1,N)
end

经过验证,此函数的卷积编码输出与在MATLAB中直接调用poly2trellisconvenc函数卷积编码后的输出一致。

3.(n,k,m)卷积编码及仿真

做完(n,1,m)的卷积编码还不能罢休,我的任务是完成(n,k,m)的编码与译码,所以首先我还得把(n,k,m)码给仿真出来,这样才算真正理解了。但是网上这部分资料比较少,好在被我发现了一个宝藏文章,自取。poly2trellis(matlab) 在搜索怎么使用MATLAB的时候发现了这个宝藏,让我受益匪浅。从这篇文章可以看出来,实际k个输入就有点类似于k个(n,1,m)卷积码的相叠加,就是把最后结果取异或而已。于是抱着试一试的态度,我又继续尝试了,在于BUG一番斗争后,功夫不负有心人,我成功了!!!! 以(3,2,[2 2])为例,生成多项式为

G1{1} = [1 0;0 1;1 1];每个元组中对应一个信息码所在编码器的结构 G1{2} = [0 1;1 1;1 1];

%% 测试主函数
clear all
clc
M = [1 1 0 0 1 0 1 1];
%G1{1} = [1 1 1;0 0 1;1 0 0];
%G1{2} = [0 1 0;1 0 1;1 1 1];
G1{1} = [1 0;0 1;1 1];
G1{2} = [0 1;1 1;1 1];
C2 = ZW_conv_K_encode(M,G1);

%C3 = [1 1 0 0 0 1 0 0 0 0 1 0];
C3 = [1 1 0 1 0 0 1 0 1 1 0 1];  %调用MATLAB内部函数得到的编码情况
C2 - C3 %如输出全为零则此函数编码正确
%% 本函数实现卷积编码
function C = ZW_conv_K_encode(m,G)
%{
输入:
    原始序列m
    生成矢量G  元组 每一个细胞对应一个输入的生成式 输入(1,k)
输出:
    卷积码结果C 
特点:
    适用于所有的[n,k,N]卷积编码
%}
len = length(m);    %记录输入信息长度
[~,k] = size(G);    %k表示每次输入的信息码元数
if (mod(len,k)~=0)  %说明最后一次输入的时候信息玛不够 
    times = len/k + 1; %time 为循环次数
else
    times =len/k;
end

%times

m = [m,zeros(1,k)];    %这样总可以让最后一次输入时有k个信息码输入 防止最后一次循环没有输入报错

%预先分配内存 加快运行速度
n = zeros(1,k);     %共有k个 每一个表示一个输入对应的编码器结构
N = zeros(1,k);     %不过每个码元对应的输出码元数肯定相同 所以n(i)均相同 
for i=1:k           %求每次输入码元对应的编码器结构
    [n(i),N(i)] = size(G{i}); %n表示一次有几个码元输出 N表示一次有几个监督码元(包括当前输入)
end

C = zeros(1,n(1)*floor(times));%每次循环输入n个码元 
%C1 = zeros(1,n(1));%暂时存储每个输入码元对应的输出码元
C_regs = cell(1,k);  %k个输入 对应k个编码器结构
%初始化每个输入对应的寄存器状态 并送入新的输入
for i=1:k 
    C_regs{i} = [m(i),zeros(1,N(i)-1)]; %对应[输入,m个初始为零的状态] 
end

for i=1:floor(times)    %开始循环 将每一次的k个输入都得到其对应的输出
    for j=1:k       %对每个输入进行循环 得到C的值
        C1 = mod(C_regs{j}*G{j}',2); %得到第i次输入时第j个码元的输入结果
        %上一个输入码元对应的输出加上此时码元对应的输入码元异或(对2取余),则为此时全部输入对应的输入码元
        C((i-1)*n(j)+1:n(j)*i) = mod(C1+C((i-1)*n(j)+1:n(j)*i),2);
        %载入新的输入并更新寄存器状态 为下一次的大循环的第j个码元的编码器做准备
        C_regs{j} = [m(j+i*k),C_regs{j}];%此时(1,k+1)
        C_regs{j}(end) = [];% 挤掉旧符号 最后一个元素直接没有 回到(1,k)
    end
end

中途由于马虎出了一些问题,最终终于成功实现。后面还进行了另一组实验,仍然正确。

4.总结

总的来说,卷积码相对分组码来说更难理解。这次很幸运地理解了卷积码的编码过程并成功仿真出来,还是很自豪的。不过编码要比译码更简单,后面的译码才更是一块硬骨头,目前已经有一定的了解了,打算继续进一步了解,并尝试去仿真,希望下一次译码仿真不会太久! (内容如有侵权,我知道后立马删除

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Easter79 Easter79
2年前
sql注入
反引号是个比较特别的字符,下面记录下怎么利用0x00SQL注入反引号可利用在分隔符及注释作用,不过使用范围只于表名、数据库名、字段名、起别名这些场景,下面具体说下1)表名payload:select\from\users\whereuser\_id1limit0,1;!(https://o
Stella981 Stella981
2年前
SILC超像素分割算法详解(附Python代码)
SILC算法详解一、原理介绍SLIC算法是simplelineariterativecluster的简称,该算法用来生成超像素(superpixel)算法步骤: 已知一副图像大小M\N,可以从RGB空间转换为LAB空间,LAB颜色空间表现的颜色更全面假如预定义参数K,K为预生成的超像素数量,即预计将M\N大小的图
Wesley13 Wesley13
2年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
2年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
2年前
MySQL数据库InnoDB存储引擎Log漫游(1)
作者:宋利兵来源:MySQL代码研究(mysqlcode)0、导读本文介绍了InnoDB引擎如何利用UndoLog和RedoLog来保证事务的原子性、持久性原理,以及InnoDB引擎实现UndoLog和RedoLog的基本思路。00–UndoLogUndoLog是为了实现事务的原子性,
Wesley13 Wesley13
2年前
Java面试总结(排序算法)
1.冒泡排序算法描述:两两比较,大的放后面2.选择排序算法描述:在m元数组中找到最小值的位置,然后将最小值的位置和第n(n0,1,2,....m1)位的值对调,排序k次则m元数组中前k(k<m)位的值已经排序好,m元数组中前k位的值不需要再进行排序,此时需要排序的元素只有mk个3.插入排序算
Wesley13 Wesley13
2年前
Java编程的逻辑 (17)
第15节我们介绍了继承和多态的基本概念,而上节我们进一步介绍了继承的一些细节,本节我们通过一个例子,来介绍继承实现的基本原理。需要说明的是,本节主要从概念上来介绍原理,实际实现细节可能与此不同。例子这是基类代码:!复制代码(https://oscimg.oschina.net/oscnet/8c3c06c1286af01feb0c05
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
胖大海 胖大海
1年前
Redis 原理
架构原理Redis组件的系统架构如图所示,主要包括事件处理、数据存储及管理、用于系统扩展的主从复制/集群管理,以及为插件化功能扩展的ModuleSystem模块。!(https://imgblog.csdnimg.cn/i
小小低头哥
小小低头哥
Lv1
帘卷西风,人比黄花瘦。
文章
1
粉丝
0
获赞
0
热门文章

暂无数据