目录
一、前言
branch里存储了路径的所有信息,包括寄存器状态、编码输入状态、编码结果、汉明距离,理解起来很方便。
二、matlab代码
%% [2,1,7]卷积码的编码与维特比译码
% 卷积码(n,k,L) *还有一种叫法(n,k,m)感觉容易混淆?以生成式为准。
% 其中n表示输出码字长度,
% k表示输入信息比特长度,
% L表示卷积码中的约束长度(L=m+1,m为卷积码中寄存器个数)
%%
%****************编码******************************
clear all
close all
clc
%%生成多项式,八进制表示[133 171]
G = [
1,0,1,1,0,1,1;
1,1,1,1,0,0,1
];
%%输入比特流,这里可以随便更改
M = [1 0 0 1 1 0 0 0 1 1 1 1 0 0 1 1 1 1 1 0];
%%编码
k=1; %输入信息比特长度=1,每次输入一个码元
[n,L] = size(G); %n表示输出码字长度,L表示卷积码中的约束长度
len = length(M);
coded_output = zeros(1,n*len); %编码结果输出,初始化
inputs = zeros(k,L);%参与编码的输入状态共7b,1b新输入拼上6b寄存器
for i = 1:len
%状态更新(输入更新,寄存器右移)
inputs = [M(i),inputs(1:end-1)];
%编码过程一条语句完成,即横矩阵(输入)*竖矩阵(多项式)
coded_output(n*i-(n-1):n*i) = mod(inputs*G',2);
end
coded_output1 = coded_output.'; %加了很多转置,方便观察
%%
% 使用matlab自带函数进行对比
ConstraintLength = 7;
CodeGenerator = [133 171];%2列表示n=2;1行表示k=1?
trellis = poly2trellis(ConstraintLength,CodeGenerator);
coded_matlab = convenc(M,trellis);
coded_matlab1 = coded_matlab.';
decode_matlab = vitdec(coded_matlab,trellis,7,'trunc','hard');
decode_matlab1 = decode_matlab.';
%%
%****************解码******************************
%列出所有输入状态对应的输出,2^L*n的矩阵,供后面直接按输入状态查找输出
states_val=0:2^L-1;
states_str=dec2bin(states_val);
[x,y]=size(states_str);
states_all=zeros(x,y);
for i=1:x
for j=1:y
states_all(i,j)=str2num(states_str(i,j));
end
end
output_all=mod(states_all*G',2);
%初始化分支(路径)容器branch,branch存储了每条路径的6项关键信息:
% isuse, 此条路径是否已使用
% regs, 6b寄存器
% state, 7b输入状态,等于1b新输入拼上6b寄存器
% output, 7b的输入对应的编码输出
% weight, 编码输出与读取的数据间的汉明重量(距离)
% bits, 从t0时刻开始此条路径所有的输入记录,也就是可回溯每条路径对应的译码结果
%最终在branch里找到weight最小的那条路径,取出bits就是最终译码结果。
branch=cell(2^L,6);
branch{1,1}=1;
branch{1,2}=zeros(1,L-1);
branch{1,5}=0;
for i=2:2^L
branch{i,1}=0;
end
%开始读取已编码数据
code_in=coded_output;
n_bits=length(code_in)/n;%n位数据对应1位原始未编码比特流
for n_bits_i=1:n_bits
%每次读取1bit原始数据对应的编码
code_in_1bit=code_in(1:n);code_in=[code_in(n+1:end),zeros(1,n)];
branch_used=find([branch{:,1}]==1);
branch_free=find([branch{:,1}]==0);
%每条现有路径branch_used都会分裂为2条(输入0or1),所以遍历branch_used
%第1条使用原来的路径容器,第2条使用新的路径容器
for branch_used_i=1:length(branch_used)
%当前待分裂路径(老的)
branch1=branch_used(branch_used_i);
%当前待填充路径(新的)
branch2=branch_free(branch_used_i);
%先缓存此路径在分裂前的值,分裂时要使用
regs = branch{branch1,2};
weight = branch{branch1,5};
bits = branch{branch1,6};
%开始分裂
state1=[0,regs];
state1_index=vector2val(state1)+1;
state1_output=output_all(state1_index,:);%按输入状态查找输出
state1_weight=sum(xor(code_in_1bit,state1_output));
state2=[1,regs];
state2_index=vector2val(state2)+1;
state2_output=output_all(state2_index,:);
state2_weight=sum(xor(code_in_1bit,state2_output));
%计算完毕,把分裂后的数据填到两条路径容器里
branch{branch1,1}=1;
branch{branch1,2}=state1(1:end-1);
branch{branch1,3}=state1;
branch{branch1,4}=state1_output;
branch{branch1,5}=state1_weight+weight;
branch{branch1,6}=[bits,0];
branch{branch2,1}=1;
branch{branch2,2}=state2(1:end-1);
branch{branch2,3}=state2;
branch{branch2,4}=state2_output;
branch{branch2,5}=state2_weight+weight;
branch{branch2,6}=[bits,1];
%打断点用
breakpoint=1;
end
% 剪枝 分裂到所有路径填满时,要开始修去一半被淘汰的路径,释放空间以供下次迭代
if(length(branch_used)==2^(L-1))
for(i=1:2^(L-1))
index1=i*2-1;
index2=i*2;
if(branch{index1,5}>branch{index2,5})
branch{index1,1}=0;
else
branch{index2,1}=0;
end
end
%打断点用
breakpoint=1;
end
%打断点用
breakpoint=1;
end
%到此,其实直接观察branch就能找到重量最短的那条路径了
weight_all=[branch{:,5}];
[weight_sorted,weight_index]=sort(weight_all);
%几个数据转置一下,方便观察
weight_all1=weight_all.';
weight_sorted1=weight_sorted.';
weight_index1=weight_index.';
%最终译码结果
decode_output=branch{weight_index(1),6};
decode_output1=decode_output.';
%% 函数
function val = vector2val(Q) %数列表示的二进制转为数值,高位在左
len = length(Q);
val=0;
for i=1:len
val = Q(i) * 2^(len-i)+val;
end
end
三、总结
熟悉了之后,branch里可以作一些精简。