如题,代码终于跑动啦,记录一下,写了很多注释,可以自行观看。
%%卷积码(n,k,N)=(2,1,7) 约束长度为7
%生成多项式(171,133)
% = G[1 1 1 1 0 0 1
% 1 0 1 1 0 1 1]
clc;clear all;close all;
data = randi([0,1],1,100);
% data = [1 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 ];
G_matrix = [1 1 1 1 0 0 1;1 0 1 1 0 1 1];
trellis = poly2trellis(7,[171,133]); %生成网格图
% code_data = convenc(data,trellis);
code_data = conv_encode(data,G_matrix); %卷积编码 比convenc长N
%% bpsk
data_bio = 1 - 2*code_data; %1- -1 0- 1
fs = 2e6;
rs = 1e6;
rolloff = 0.35;
EbN0 = 20;
SNR = EbN0 +10 * log10(2) - 10 * log10(fs/rs);
data_noise = awgn(data_bio,SNR,'measured');
data_decision = (sign(data_noise)-1 )/-2; %判决
%%
hui_len = 35; %回溯长度
% data_out = vitdec(data_decision,trellis,hui_len,'trunc','hard'); %解码 截断到数据发送完,硬判决
data_out = conv_decode(data_decision,G_matrix);
error_bits = sum(data_out(hui_len+1:end-7)~=data(hui_len+1:end)); % 计算错误比特
% 计算误码率
BER = error_bits/length(data); % 误码率
disp(BER);
%% 编码函数
%% 本函数实现卷积编码 适用于所有的[n,1,N]卷积编码
%{
输入:
原始序列m
生成矢量G
输出:
卷积码结果C
特点:
适用于所有的[n,1,N]卷积编码
%}
function C = conv_encode(m,G)
len = length(m);
k=1; % 表示每次对k个码元进行编码
[n,N] = size(G);% n表示一个输入码元拥有几个输出,N表示每次监督的输入码元数
C = zeros(1,n*len); %%一共输出的个数
% 在头尾补0,方便卷积输出和寄存器清洗
m_add0 = [zeros(1,N-1),m,zeros(1,N+1)];
% 循环每一位输入符号,获得输出矩阵
C_reg = fliplr(m_add0(1,1:N)); %如果是1:N,c_reg开头是m第一个数
for i =1:len+N
%生成每一位输入符号的n位输出
C(n*i-(n-1):n*i) = mod(C_reg*G.',2);
%更新寄存器序列+待输出符号(共N个符号)
C_reg = [m_add0(i+N),C_reg];% 添加新符号
C_reg(end) = [];% 挤掉旧符号
end
end
%% 译码函数
%% 本函数实现卷积码译码
function V = conv_decode(m,G)
%{
输入:
接收到的卷积码 m
生成矢量G 每一行代表一个输出的连接结构 与发送机编码器结构相同
输出:
卷积码译码结果C
特点:
适用于所有的[n,1,N]卷积译码
%}
len = length(m); %记录输入信息长度
K=1; %每次输入一个码元
%通过 n和len的值来判断总共需要几个解码循环
[n,N] = size(G); %n表示发送端一次有几个码元输出 N表示一次有几个监督码元(包括当前输入)
times = len/n; %解码循环总次数 即原信息的长度
%states = ZW_B_Comb(N-1); %共有N-1种状态 states存储了每一种状态
%状态寄存器 由于有N-1个编码器(不包含输入) 所以共有种状态 最多时候每种状态有两种路径 所以共有2^N种情况
%每种状态又有累计路径值、累计输入、以及当前状态三种情况
C_regs = cell(2^(N),4); %每一列代表一个状态 同一列中每一行分别表示当前状态的不同情况
C_regs_reg = cell(2^(N-1),3);
%初始时从网格图中第一个状态开始出发 为0
C_regs{1,1} = 0; %第一行代表此时这个状态累计路径值 初始为零
C_regs{1,2} = []; %第二行存储输入的信息 一开始没有输入
C_regs{1,3} = zeros(1,N-1); %第三行存储该寄存器此时存储的状态是什么 共2^(N-1)可能
C_regs{1,4} = 1; %第四行代表是否被征用 1代表这个寄存器被征用了 0代表空闲
for i=2:1:2^(N) %将初始累计值均设置为0 且初始时除1外全为空闲
C_regs{i,1}=0;
C_regs{i,4}=0;
end
for i=1:times
code_buffer=m(1,(i-1)*n+1:i*n); %第一次输出时对应的码元 共n个
a_b=find([C_regs{:,4}]==0); %返回为0的序号 看哪个没有被使用
n_b=2^N-length(a_b); %说明有n_b个征用的状态等待去进入下两个状态
%第i个元素储存了编码器对应状态的前两条输入对应的寄存器序号 此状态二进制换成十进制正好等于i-1
states = cell(1,2^(N-1));
for j=1:n_b
in_0 = j; %第j个与此时是序号最靠前的第一个为空闲的状态C_regs的 将是上一个第j个输入分别为0、1后
in_1 = a_b(j); %对应的状态
put_0 = mod( [0 C_regs{j,3}] *G.',2); %求出输入为0时,此状态对应的输出
put_1 = mod( [1 C_regs{j,3}] *G.',2); %求出输入为1时,此状态对应的输出
C_regs1_in_0 = C_regs{j,1} + sum(xor(put_0,code_buffer)); %计算输入为0时的路径累计值(汉明距离)
C_regs1_in_1 = C_regs{j,1} + sum(xor(put_1,code_buffer)); %计算输入为0时的路径累计值
C_regs2_in_0 = [C_regs{j,2} 0]; %得到这条路径的累积输入信息码
C_regs2_in_1 = [C_regs{j,2} 1]; %得到这条路径的累积输入信息码
C_regs_in_0 = [0 C_regs{j,3}]; %计算输入为0时的下一个状态的情况
C_regs_in_0(end) = []; %删除多余单元
C_regs{in_0,4} = 1; %代表被征用
states{1,B_T(C_regs_in_0)+1} = [states{1,B_T(C_regs_in_0)+1} in_0];%储存相同状态的两条路径
C_regs_in_1 = [1 C_regs{j,3}]; %计算输入为1时的下一个状态的情况
C_regs_in_1(end) = []; %删除多余单元
C_regs{in_1,4} = 1; %代表被征用
states{1,B_T(C_regs_in_1)+1} = [states{1,B_T(C_regs_in_1)+1} in_1];%储存相同状态的两条路径
% 计算完毕后再一并赋值 不能就算一个就赋值一个 因为in_1也要用到in_0原来的值
C_regs{in_0,1} = C_regs1_in_0;
C_regs{in_1,1} = C_regs1_in_1;
C_regs{in_0,2} = C_regs2_in_0;
C_regs{in_1,2} = C_regs2_in_1;
C_regs{in_0,3} = C_regs_in_0;
C_regs{in_1,3} = C_regs_in_1;
end
if n_b == 2^(N-1) %说明现在每个状态都有两个输入 该将每个状态的最小累计路径取出来并删除最大累计路径了
for k=1:2^(N-1)
%Len = length(states{1,k}); %计算每个状态对应来源路径的累计路径数
if C_regs{states{1,k}(1),1} > C_regs{states{1,k}(2),1} %选出最近的路径所在的寄存器序号
i_tmw = states{1,k}(2);
else
i_tmw = states{1,k}(1);
end
%weight_list=[C_regs{states{1,k},1}]; %找出当前状态对应来源路径的累计路径值
%[~,i_tmw]=sort(weight_list); %从小到大排列 并返回此时序列对应排列前的序号
C_regs_reg{k,1}=C_regs{i_tmw,1};%只找出每个状态最短的累计路径
C_regs_reg{k,2}=C_regs{i_tmw,2};%并重新存储在序号前2^(N-1)的状态寄存器中
C_regs_reg{k,3}=C_regs{i_tmw,3};
end
for k=1:2^(N-1) %将挑选出来的2^(N-1)个状态重新从小到大赋给原寄存器
C_regs{k,1}=C_regs_reg{k,1};%只找出每个状态最短的累计路径
C_regs{k,2}=C_regs_reg{k,2};%并重新存储在序号前2^(N-1)的状态寄存器中
C_regs{k,3}=C_regs_reg{k,3};
end
for L=2^(N-1)+1:2^N %将后2^(N-1)个寄存器释放
C_regs{L,4}=0;
end
end
end
n_survival_branch=length(find([C_regs{:,4}]==1)); %找出被征用(存储了状态的寄存器序号) 一般为前2^(N-1)
w_survival_branch=[C_regs{1:n_survival_branch,1}];%找出被征用(存储了状态的寄存器序号)的累计路径值
[~,i_weight]=sort(w_survival_branch); %把各状态的累计路径值从小到大排列 并返回对应从前所在序列的序号值
i_minimum_weight=i_weight(1); %i_weight(1)最后所有状态中累计路径值最小的状态序号
V=C_regs{i_minimum_weight,2}; %输出最有可能的输入情况
end
%%
%% 本递归函数实现由二进制得出十进制
function C = B_T(Q)
len = length(Q);
C=0;
for i=1:len
C = Q(i) * 2^(i-1)+C;
end
end