信息论编码实验3~9连载,更多看专栏。
一、香农编码的原理
香农码严格意义上来说不是最佳码,与基于符号概率进行映射的哈夫曼编码不同的地方在于,香农码基于累积概率的二进制数进行编码。
编码步骤:
- 将概率分布列降序排序;
- 求出每一行所对应的累加概率 Pi ;
- 根据累加概率 Pi 计算该符号对应香农码的长度 Li ;
- 将累加概率 Pi 转换成二进制数,取其前 Li 位,即为该符号的香农码。
对于香农码的评价:
香农编码的效率不高,实用性不大,但对其他编码方法有很好的理论指导意义。一般情况下,按照香农编码方法编出来的码,其平均码长不是最短的,即不是紧致码(最佳码)。只有每一个符号的概率都是1/2的整数倍时,编码效率才能达到最高。
二、香农编码实例
以后有空再补充吧~
三、程序及流程图
下面是代码:
%% 实验三:香农编码仿真实验
clear all
clc
% 用户输入符号概率
p = input('请输入离散信源概率分布,例如[0.5,0.5]:\n');
N = length(p);
L = ceil(-log2(p));% 获得码长向量,元素表示每个符号所对应的码长
% 获得累加概率P及对应码字
[p_SortDescend,reflect] = sort(p,'descend');% 将概率从大到小进行排序
%注:reflect所表示的映射关系很重要
P = zeros(1,N); % 初始化累加概率
CODE = strings(1,N); % 初始化对应码字(字符串形式)
for i=1:N % i表示排序后第几个符号
code = zeros(1,L(reflect(i)));% 初始化对应码字(数组形式)
if i==1 % 定义第一个编码为0
P(1)=0;
CODE(reflect(i)) = num2str(code);
else
P(i) = sum(p_SortDescend(1,1:i-1)); % 获得累加概率
end
% 下面计算香农码(计算累加概率的二进制数,并取前Li位)
p_count = P(i)*2; % p_count用于逐步的计算累加概率的二进制数
for m=1:L(reflect(i)) % m表示这个符号里第几个码字
if p_count >= 1
code(m) = 1;
p_count = p_count-1;
else
code(m) = 0;
end
p_count = p_count*2;
end
% 将香农码赋值给对应的符号
CODE(reflect(i)) = num2str(code);
end
H = sum(-p.*log2(p)); % 计算信源信息熵
L_ave = sum(L.*p); % 计算平均码长
yita = H/L_ave; % 计算编码效率
% 展示输出码字、平均码长和编码效率
fprintf('\n运行结果:\n');
disp(['信号符号: ',num2str(1:N)]);
disp(['对应概率: ',num2str(p)]);
fprintf('对应码字:');disp(CODE);
disp(['平均码长:',num2str(L_ave)]);
disp(['编码效率:',num2str(yita)]);
四、程序运行结果
下面假设输入[0.1,0.2,0.3,0.4]
五、程序自评价
怎么说呢,代码原理其实很简单,但是我一直对它的命令行窗口的输出耿耿于怀,这没有达到我理想的输出效果:
- 每一列对应元素都对齐;
- “对应码字”的输出不要加引号,并且可以密集排列;
- “对应码字”下面不要有换行。
经过我对disp、display、fprintf的反复试验,推测大概还是得输出到表格里,再读入才可能会达到理想效果,所以:嗯,就这样吧,挺好了,哈~
代码原创,但因为原理编写参考到了实验课的指导书,假如有什么不对的地方,侵删。