基于MATLAB的信源、信道编码与译码仿真
基于MATLAB的信源、信道编码与译码仿真
在信息通信领域,信源编码和信道编码是提高通信效率和可靠性的关键技术。本文将通过MATLAB和Simulink工具,详细演示信源编码和信道编码的仿真过程,并通过可视化误码率曲线,直观展示编码技术的效果。
哈夫曼编码原理与实现
信源编码的主要目标是提高通信的有效性,而信道编码则侧重于提高通信的可靠性。本节将借助MATLAB实现哈夫曼编码的仿真。
编码基本步骤
- 统计信源字符中各符号出现的概率,将各字符出现的概率由大到小的顺序排列;将最小的两个概率相加,合并成新的概率,与其他概率重新按由大到小的顺序排列;
- 重新排列后将两个最小概率合并相加合并为新的概率,即重复步骤①,直到最后两个概率之和为 1;
- 将每个相加的组合中,概率大的指定为 0,概率小的指定为 1,相等则任意指定找出由每一个信源字符到达概率为 1.0 处的路径,顺序记录路径的每一个1 和 0 的数字编码。反向写出编码,即为该信源字符的哈夫曼编码。
MATLAB函数实现
本文利用了三个MATLAB函数来实现哈夫曼编码:
huffmandict
函数:生成哈夫曼字典[dict, avglen] = huffmandict(symbols, p)
该函数表示按照
symbols
中的字符和p
中的概率生成一个字典dict
,并将字典中的字符串的平均长度返回到avglen
。huffmanenco
函数:进行哈夫曼编码comp = huffmanenco(actualsig, dict)
表示将
actualsig
序列按照dict
字典进行哈夫曼编码。huffmandeco
函数:进行哈夫曼解码dsig = huffmandeco(comp, dict)
表示将
comp
码字按照dict
字典进行哈夫曼解码。
实现步骤
- 用 MATLAB 编写一个信源,信源符号数为 10,符号的概率分布服从高斯分布。对生成的序列进行霍夫曼编码,输出符号的码字。
首先用 normrnd
生成一个遵循高斯分布的0-1随机序列,然后对其归一化得到信源。然后就对信源序列作 Huffman 编码以及译码,分别打印未编码的概率分布和归一化之后的概率分布,可以得到信源的概率空间。
% P0 :产生范围为(0,1)的高斯随机数
% P1:P0归一化后得到的符号概率
% symbols:信源符号
% dict:译码本
% inputSig:模拟信源输出的信源符号
% code:霍夫曼编码的结果
% Sig:译码结果
P0 = normrnd(0.5,0.1666666666667,[1 10]); %产生0-1分布的高斯随机数
disp('P0=')
disp(P0)
sum0 = sum(P0(:)); %求和,以便归一化
P = P0/sum0; %归一化
disp('P(归一化之后的概率分布)=')
disp(P);
symbols = 1:1:10;%信源符号1-10
dict = huffmandict(symbols,P);%2个参数:信源符号组+服从的概率分布
%dict是译码本
inputSig = randsrc(10,1,[symbols,;P]);
code = huffmanenco(inputSig,dict);%针对名为”inputSig”的输入信源序列,产生对应的霍夫曼编码
code1=code';
Sig = huffmandeco(code,dict);%针对名为”code”的霍夫曼码进行解码,还原对应的信源符号。
通过 code1
和 Sig
,可以直接得到编码后输出序列与译码后输出序列。理论上有译码本的存在,inputSig
与 Sig
一致。
最后得到编码后的输出为:101100100001000101110101100001101,这和根据概率分布自己编码的结果是一致的。如果对实验结果感兴趣可以亲自手动编码。
利用Simulink模拟线性分组码
Simulink是MATLAB中的一个重要组成部分,它提供了一个可视化的仿真环境,允许用户通过拖拽模块和设置参数来构建动态系统模型。Simulink广泛应用于线性系统、非线性系统、数字控制和数字信号处理等领域的建模和仿真。
仿真设计电路
总体的仿真设计电路如下:
信源选择伯努利信源,仿真运行方式选择Interpreted execution,方便后续编写调试代码绘制误码率图像。
伯努利分布中产生符号0的概率p(相应地产生符号1的概率为1-p)
- Source of initial seed-Parameter: 用户指定产生随机数的种子
- Source of initial seed-Auto:由系统在后台指定随机种子
- Sample time:表示输出信号的每个采样之间的间隔,单位是秒。一般取正数,也可以取-1(系统根据模型里的其他组件设置,为信源自动设置采样时间)。本次实验取1/100000。
- Sample per frame:输出信号的通道中每帧的采样数,取正整数,在本实验中设定为每帧采4个点。
仿真运行方式:
- Code generation:
使用生成的C代码来模拟模型。第一次运行仿真时,Simulink会为模块生成C代码。如果模型没有发生变化,C代码将重复用于后续仿真。此方式需要额外的启动时间,但后续模拟的速度比较快。 - Interpreted execution:
使用MATLAB解释器模拟模型。与前者相比,此选项的启动时间更短,但后续仿真的速度较慢。在此模式下,用户可以调试模块的源代码。
线型编码器与线性解码器保持默认即可,MATLAB已经为我们生成好了对应的生成矩阵。
选择二元对称信道BSC对信号进行传输。
- 错误概率:输入信号发生错误的概率,取值为[0,1]范围内的正数。信号中每一位独立地发生错误。
- BSC信道除了默认输出外,还有可选的“Err”输出,用于指示发生错误的信号位置。如果要使用此输出,需要将“Output error vector”勾选上。在这里我就先不做勾选,不过后续也会做一次勾选Err的实验。
接着就是选择误码率计算器并设置其参数。
- 接收时延:Rx端的数据滞后于Tx端的数据的样本数。(如果Tx或Rx端的数据是向量,则每个向量就是一个样本)。
- 计算时延:误码率计算模块在开始比较前应忽略的样本数。
- 计算模式:“Entire frame”:两路输入信号都是标量,直接比较计算误码率。
- 输出数据:“Workspace”:模块计算得到的误码率发送至MATLAB的工作空间中,并以“Variable name”中的名字命名。
- 重置端口:如果选择了重置端口,则会出现一个附加输入端口,标记为”Rst”。此端口仅接收标量信号,同时具有与Tx和Rx相同的采样时间。当这一端口输入非零时,模块会清零并重新统计错误信息。
- 停止仿真:如果选择了此项,模块就会在检测到指定数量的错误或者执行了指定数量的比较后停止仿真。
在实际仿真电路中,设置直接未经编码的输出数据命名为BER1,经过线型编码后的输出数据命名为BER2。
在完成仿真电路的设计连接之后,在上方设置仿真运行时间,设置的是5秒。
接着需要编写一个控制仿真的脚本文件。
clear all;
EB = 0 : 0.005 : 0.05;
for i = 1 : length(EB)
errB = EB(i); %errB为BSC参数设置中变量 错误概率
sim('test3_1'); %运行所设置的模型
ber1(i) = BER1(1);%ER1得到的误码率赋给数组ber1的第i个元素
ber2(i) = BER2(1);%BER2得到的误码率赋给数组ber2的第i个元素
end
%绘制曲线
plot(EB,ber1,'ro-',EB,ber2,'b--+','LineWidth',2,'markersize',4);%定义曲线图标
grid on;
set(gca,'Fontsize',16);%设置字体大小
legend('Uncoding','Linear coding');%设置图例
title('未编码和线性分组码在BSC下的性能');
xlabel('信道差错概率');
ylabel('误码率');
选择运行10轮,但是真正运行起来时间还是比较长的,这一点问题没有想明白。最后得到设置0.05和0.1两种情况下的误码率曲线。
第一幅图为0.05时情况。
第二幅图为0.1时情况。
对比之后不难发现,有效的编码确实可以降低在信道传输过程中导致的误码率,这也是为什么信源、信道编码至关重要的原因。