前言


由于这一专栏算是我本科通信专业知识的总结,构建一个完备的通信系统是我的目标,且信源编码又是其中非常重要的一节,所以必须总结一下。但又由于不同的信源系统对应的信源编码是大相径庭的。所以这篇文章就作类似科普一般的文章,并且会附上基于MATLAB实现的Huffman Coding,希望通信小白可从这篇文章构建信源编码的知识网并实现Huffman Coding。

目录

前言

一、信源编码

二、Huffman Coding - 按步骤直接实现

2.1 Huffman Coding步骤

2.2 MATLAB 代码

三、Huffman Coding 二叉树思想实现

3.1 二叉树思想

3.1.1 Huffman Tree 结构

3.1.2 Huffman Tree 构造方法

3.1.3 Huffman Tree的特点

3.2 MATLAB 实现

四、Huffman Coding的解码(译码)

4.1 Huffman 译码器的原理

4.2 完整的Huffman Coding编码译码MATLAB实现


一、信源编码


正如在本专栏量化一篇中讲到,信源编码是高度关系到信源的,不同的信源可能对应完全不同的信源编码方案。信源编码的首要目的如 移动通信原理与系统 一书中所表述的一样: “通常,对于一个数字通信系统而言,信源编码位于从信源到信宿的整个传输链路中的第一个环节,其首要目的就是通过压缩信源产生的冗余信息,降低传递这些不必要信息的开销,从而提高整个传输链路的有效性。”  打个比方,你想要的从你的电脑上发送 Game of Thrones 给你的另一台设备,假设一个字母一个字节(8bits),想想你得传多少个bits。但是我们知道,小说里字母出现的概率是很不一样的,通常来说e出现的次数最多,z出现次数最少,而出现次数最多的e理论上最好用更少的比特数去表示,这样就有可能减少传输的比特数。这就是一个简单的信源编码思想。

而目前非常广为流传的编码技术主要有以下三种:

1. Huffman Coding

2. 算数编码

3. LZ 编码(注意,LZ编码是一系列编码,常见的如LZ-78)

还是如上所说,不同信源可能对应完全不同的方案,如3G系统中视频信源编码主要是H.264,2G/3G 系统中的话音信源编码有CELP,AMR等。它们根据信源的特点设计了更行之有效的编码技术。但是这不代表上三种没有学习必要,他们能用于非常广泛的领域,比如我们今天MATLAB实现的Huffman Coding会用于zip压缩技术中。

二、Huffman Coding - 按步骤直接实现


2.1 Huffman Coding步骤

首先我们来按直觉实现一次Huffman Coding,然后再介绍如何用二叉树思想实现,你会发现二叉树思想实现地会更方便简单。

Huffman Coding是一种Prefix-free Coding,若要从数学上深度学习Source Coding可以看下面这个MIT的网课:

麻省理工 数字通信原理 I (MIT 6.450, Principles of Digital Communications I)【英】_哔哩哔哩_bilibilihttps://www.youtube.com/playlist?list=PL2AD004D035C24F21讲师:Prof. Lizhong Zheng, Prof. Robert Gallager课程地址:https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-450-principles-of-dihttps://www.bilibili.com/video/BV1Qt411Y7BA在Chapter2 和 Chapter3章节,有足够的数学细节。而且是全英文的可以锻炼自己的听力(好像有中英字幕版)。在此推荐一下。而这篇文章就不涉及更多的数学细节了。

Huffman Coding的主要流程非常简单,就以下三步:

1. 计算出你要编码的所有符号的出现概率,并按从大到小(从小到大也可以)降序排列。

[MATLAB] 对应MATLAB可以使用以下函数:

sort(A,dim,mode);    A 是矩阵,dim=1则按列,dim=2则按行,mode可为'ascend' ,‘descend’

sortrows(A,mode);  和上面不同的是,sort会每一列/行都排序,而sortrows只排序第一列/行,其他列/行会像随从一样跟着动。

 2.把最小的两个概率相加,形成新的一个合并概率,并将这个合并概率与原来的除最小两个概率的其他概率进行相同的排序方式。(注意,若合并概率和原来的概率有数值相同的,则将合并概率放在上面,原来的概率放下面)

[MATLAB] 算法

一般正常的方法是,等全部概率操作完,也即合并概率变为1时,再从最远处开始编码。但是我在MATLAB实现中,每两个概率相加就进行编码,这时候分四种情况和应对手段:

1.若这两个概率都不是合并概率,则给这两个概率所表示的字符编码'0'或'1'(比如概率大的为1小的为0,反之亦可),并且将这两个概率所表示的字符存储起来。(为什么存储起来后面就知道了)【比如下面我将全部以概率大的编码'1',小的编码'0'来操作】

2.若这两个概率都是合并概率,意味着它们一定来源于先前编码的字符的加和,所以分别给这两个合并概率的来源字符编码'0'或'1'。所以在第一步会有存储字符的操作,因为到时候我们要给来源编码,我们得知道来源。

3.一个是合并概率一个不是合并概率的情况有两种,也即合并概率数值较大或者较小,应对方法就是对合并概率的来源进行'0'或'1'的编码,并对另一个概率代表的字符编码'0‘或'1‘。

 3. 计算到合并概率为1时,停止编码。(意味着到头了)

2.2 MATLAB 代码

以下是MATLAB的Huffman Coding实现,已经全部英文注释完毕,如果需要验证别的符号集,只需更改symbol和probabilities这两个向量里的信息即可。这里举例使用的是{'a' : 0.05,'b' : 0.06,'c' : 0.09,'d' : 0.1,'e' : 0.15,'f' : 0.15,'g' : 0.4}。

%%
% Construction of the Test table
probabilities=[0.05 0.06 0.09 0.1 0.15 0.15 0.4]'; % The probability of each symbol
symbol={'a','b','c','d','e','f','g'}; % Symbol list
symbols_index=linspace(1,length(symbol),length(symbol))'; % The index for each symbol, for example 1 represent 'a', '2' represent 'b'
table=[probabilities,symbols_index]; % This is an table containing information of upper two matrixs
max=length(probabilities); % Here we have 7 probabilities%%
% Huffman Coding
sym_freq_sorted=sortrows(table,'descend'); % The sorted frequency table of all symbols
pro_com=0; % The combined probability [Used in step 2]
huffman_table=cell(max,1); % A table storing Huffman Code% Initialization of the table above
for j=1:1:size(huffman_table,1)huffman_table{j}=[];
endlist_psym=cell(max,1); % pre-allocate the 'list of previous symbols' [Used in step 2]
i=0; % A helpful parameter to locate the branchwhile(pro_com<1)  % As long as the combined probability equal to 1, The coding stops% Draw the last two symbols outupper=sym_freq_sorted(end,1);upper_index=sym_freq_sorted(end,2);lower=sym_freq_sorted(end-1,1);lower_index=sym_freq_sorted(end-1,2);% Coding Part% If these two probabilities are not combined probabilityif (upper_index<max+2)&&(lower_index<max+2)huffman_table{upper_index}=[huffman_table{upper_index},'0'];huffman_table{lower_index}=[huffman_table{lower_index},'1'];i=i+1;list_psym{i}=[upper_index,lower_index];end% If the upper one is combined probabilityif (upper_index>max+2)&&(lower_index<max+2)for index=list_psym{upper_index-500}huffman_table{index}=[huffman_table{index},'0'];endhuffman_table{lower_index}=[huffman_table{lower_index},'1'];i=i+1;list_psym{i}=[list_psym{upper_index-500},lower_index];end% If the lower one is combined probabilityif (upper_index<max+2)&&(lower_index>max+2)for index=list_psym{lower_index-500}huffman_table{index}=[huffman_table{index},'1'];endhuffman_table{upper_index}=[huffman_table{upper_index},'0'];i=i+1;list_psym{i}=[list_psym{lower_index-500},upper_index];end% If both of these probabilities are combined probabilityif (upper_index>max+2)&&(lower_index>max+2)for index=list_psym{upper_index-500}huffman_table{index}=[huffman_table{index},'0'];endfor index=list_psym{lower_index-500}huffman_table{index}=[huffman_table{index},'1'];endi=i+1;list_psym{i}=[list_psym{upper_index-500},list_psym{lower_index-500}];end% Combine two probabilities & extend it to symbol table & sort againpro_com=upper+lower;sym_freq_sorted=sym_freq_sorted(1:end-2,:);sym_freq_sorted=[[pro_com,500+i];sym_freq_sorted];sym_freq_sorted=sortrows(sym_freq_sorted,'descend');end%%
% Demonstrate the Huffman Coding
for i=1:1:length(symbol)disp(['The Code of symbol: ',symbol{i},' is ',huffman_table{i}]);
end

手写验证:

三、Huffman Coding 二叉树思想实现


3.1 二叉树思想

3.1.1 Huffman Tree 结构

Huffman Coding 的二叉树思想实现关键是Huffman Tree的构建。先看看二叉树的构造:

1.父枝(parent)

2. 左孩子/左枝(Left child/ Left branch)和 右孩子/右枝 (Right child/ Right branch)

3. 权重(weight) 在Huffman Coding中就是每个枝的概率

4. 编码(Coding)在Huffman Coding中就是0或1,这里采用左枝为0,右枝为1

3.1.2 Huffman Tree 构造方法

回忆上面的Huffman Coding的顺序,就是不断地将概率数值最小的两个概率相加形成一个新的概率,现在我们将概率换成带有权重的树枝。那么就是不断将权重最小的树枝合并形成新的父枝,然后再将父枝加入其他的树枝之间排序,再相加,直到加到一个权重为1的树枝。拆解下来就是这样:(仍然沿用第二节的例题)

Step 1. 把全部要编码的符号和概率变成树枝

 Step 2. 将最小的两个枝相加,并且记得重新排序

 Step 3. 不断重复第二步

这样就可以从权重为1的枝开始,向下编码,权值大的为左孩子,编码为0,权值小的为右孩子,编码为1.上面的图我因为是手绘的没有注意左右之分,读者自己要注意

3.1.3 Huffman Tree的特点

在此有几个注意点,也是算法的源泉,但是此文章不会进行数学的证明,想看证明可以看上面推荐的MIT网课,几个注意点是:

1. Huffman Tree的枝的个数一定是,n是要编码的符号的数量。数学原理是“它是无前缀码”

2.从最小权重的枝开始,相加形成新的枝,直到新枝权重为1

3. Huffman Coding得到的码是无前缀码(prefix free code)。啥是prefix free code呢?打比方说一组码是{'a': 0 'b': 011 'c': 101},你会发现0是011的前缀,那么这样的时候解码就会出现疑惑,比如接收端收到010,0出现的时候我要继续往下译码吗?但是无前缀码就没有这种疑惑,比如{‘’a': 0 'b': 101 'c': 110}。

3.2 MATLAB 实现

%%
% Test table of symbolsclear;clc;
table={'a',0.05;'b',0.06;'c',0.09;'d',0.10;'e',0.15;'f',0.15;'g',0.40};
nos=size(table,1); % The amount of symbols
weight_list=zeros(nos,1);
for i=1:1:nosweight_list(i)=table{i,2};
end%%
%The construction of Huffman tree% A table of Huffman tree with four columns
Huffman_Tree=zeros(2*nos-1,4); % weights parent left_child right_childfor i=1:nosHuffman_Tree(i,1)=weight_list(i);
endbuffer2=weight_list;
for i=1:nos-1buffer1=buffer2(:,1);  % A buffer for sorting[probabilities,index]=sort(buffer1,'descend');sum=probabilities(nos-i+1)+probabilities(nos-i); % sum of the two smallest probabilities(Pay attention to 0)buffer2(nos+i,1)=sum;buffer2(index(nos-i+1),1)=0; % delete the smallest value in order to go onbuffer2(index(nos-i),1)=0;Huffman_Tree(nos+i,1)=sum;  % weight of new branchHuffman_Tree(index(nos-i+1),2)=nos+i; % update the index of parent of left child Huffman_Tree(index(nos-i),2)=nos+i; % update the index of parent of right childHuffman_Tree(nos+i,3)=index(nos-i+1); % store the index of left childHuffman_Tree(nos+i,4)=index(nos-i);  % store the index of right child
endfigure('name','Huffman Tree');
treeplot(Huffman_Tree(:,2)');title('Huffman Tree');
%%
% Huffman Encoding
Huffman_table=cell(nos,2);
Huffman_table(:,1)=table(:,1);for i=1:1:noschild=i; parent=Huffman_Tree(i,2);while(parent~=0)if Huffman_Tree(parent,3)==childHuffman_table{i,2}=[0,Huffman_table{i,2}]; % left is 0elseHuffman_table{i,2}=[1,Huffman_table{i,2}]; % right is 1endchild=parent;parent=Huffman_Tree(parent,2);end
end

四、Huffman Coding的解码(译码)


4.1 Huffman 译码器的原理

要译码必须对原理有足够的了解。Huffman 译码器的关键在于,他需要接收到来自发送端的 各个符号的出现次数和总符号数,然后根据接收到的信息计算出各个符号的出现频率,也就是说,接收端需要知道你在发送端进行Huffman Coding的东西。具体的步骤如下:

1.根据得到的信息计算各个符号出现频率

2.通过上面的符号频率重构Huffman Tree

3.通过Huffman Tree进行译码

而译码过程非常简单。由于是无前缀码,所以一翻译到没有左孩子和右孩子的结点就代表是一个符号。(自己画一下就发现了)

步骤是:

1. 从重构的Huffman Tree的权重为1的结点开始。根据接收到的比特流,一位一位地翻译。

2. 若此刻比特流是0,则往左侧走一个枝,并且读取这个结点的子节点

3. 若这个结点没有子节点,则表示到了一个符号

4. 不断翻译直到比特流结束。

4.2 完整的Huffman Coding编码译码MATLAB实现

%%
% Test table of symbolsclear;clc;
table={'a',0.05;'b',0.06;'c',0.09;'d',0.10;'e',0.15;'f',0.15;'g',0.40};
nos=size(table,1); % The amount of symbols
weight_list=zeros(nos,1);
for i=1:1:nosweight_list(i)=table{i,2};
end%%
%The construction of Huffman tree% A table of Huffman tree with four columns
Huffman_Tree=zeros(2*nos-1,4); % weights parent left_child right_childfor i=1:nosHuffman_Tree(i,1)=weight_list(i);
endbuffer2=weight_list;
for i=1:nos-1buffer1=buffer2(:,1);  % A buffer for sorting[probabilities,index]=sort(buffer1,'descend');sum=probabilities(nos-i+1)+probabilities(nos-i); % sum of the two smallest probabilities(Pay attention to 0)buffer2(nos+i,1)=sum;buffer2(index(nos-i+1),1)=0; % delete the smallest value in order to go onbuffer2(index(nos-i),1)=0;Huffman_Tree(nos+i,1)=sum;  % weight of new branchHuffman_Tree(index(nos-i+1),2)=nos+i; % update the index of parent of left child Huffman_Tree(index(nos-i),2)=nos+i; % update the index of parent of right childHuffman_Tree(nos+i,3)=index(nos-i+1); % store the index of left childHuffman_Tree(nos+i,4)=index(nos-i);  % store the index of right child
endfigure('name','Huffman Tree');
treeplot(Huffman_Tree(:,2)');title('Huffman Tree');
%%
% Huffman Encoding
Huffman_table=cell(nos,2);
Huffman_table(:,1)=table(:,1);for i=1:1:noschild=i; parent=Huffman_Tree(i,2);while(parent~=0)if Huffman_Tree(parent,3)==childHuffman_table{i,2}=[0,Huffman_table{i,2}]; % left is 0elseHuffman_table{i,2}=[1,Huffman_table{i,2}]; % right is 1endchild=parent;parent=Huffman_Tree(parent,2);end
end%%
% Huffman Decoding
bit_stream=[1 1 0 1 0 1];
len_of_bit_stream=size(bit_stream,2);
flag=2*nos-1;
i=1;
message_index=[];while(i<=len_of_bit_stream) % Once read the end of bits stream, then stopif(bit_stream(i)==0) % Start from the root, if 0 then go left, else go right flag=Huffman_Tree(flag,3);elseflag=Huffman_Tree(flag,4);endi=i+1; % Next bitif Huffman_Tree(flag,3)==0message_index(end+1)=flag;flag=2*nos-1;end
endmessage='';
len=length(message_index); % Length of message
for i=1:1:lenmessage=[message,table{message_index(i),1}];
enddisp(['The text is: ',message]); % Display the message

【信源编码】Huffman Coding原理以及MATLAB实现相关推荐

  1. huffman编码——原理与实现

    哈夫曼算法原理 Wikipedia上面说的非常清楚了,这里我就不再赘述,直接贴过来了. 1952年, David A. Huffman提出了一个不同的算法,这个算法能够为不论什么的可能性提供出一个理想 ...

  2. Huffman编码原理详解

    转载自这里 1.概述      huffman编码是一种可变长编码(  VLC:variable length coding))方式,于1952年由huffman提出.依据字符在需要编码文件中出现的概 ...

  3. 硬件huffman解码器(一):huffman编码原理

    计算机系统在存储或传输数据时通常有对数据进行压缩的需求.数据压缩可以减小存储介质的占用量(或用有限的存储介质存储更多的数据),也可以减小数据传输时需要的带宽(或用有限的位宽和频率实现更高的数据传输速率 ...

  4. Huffman 编码原理详解(代码示例)

    1.概述 huffman编码是一种可变长编码(  VLC:variable length coding))方式,于1952年由huffman提出.依据字符在需要编码文件中出现的概率提供对字符的唯一编码 ...

  5. 2022黄文嵩商盛兰张阳徐铭信息论课程作业 哈夫曼编码(Huffman Coding)简介

    目录 5G,华为,土耳其--我花了两个月,搞懂了5G背后的秘密_哔哩哔哩_bilibili 一.什么是编码? 二.哈夫曼编码 1.编码过程 2.码方差 3.编码特点 4.人无完人,码无完码 三.总结 ...

  6. matlab 投票法_SVM算法原理及其Matlab应用

    <SVM算法原理及其Matlab应用>由会员分享,可在线阅读,更多相关<SVM算法原理及其Matlab应用(18页珍藏版)>请在人人文库网上搜索. 1.SVM 算法及其 Mat ...

  7. 量子遗传算法原理与MATLAB仿真程序

    写在前面: 1.其实这些智能算法的思想都差不多,只不过是各自搜寻方式.编码方式.种群更新方式等不一样而已. 量子遗传算法是在遗传算法的基础上使用了一种新的编码方式. 2.直接看前面介绍可能会觉得较难, ...

  8. 赫夫曼编码-译码器(Huffman Coding)

    基本概念 哈夫曼编码(Huffman Coding):又称霍夫曼编码.赫夫曼编码-,是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种.Huffman于1952年提出一种编码方法,该方法完全依据 ...

  9. JAVA——赫夫曼编码-译码器(Huffman Coding)

    基本概念 哈夫曼编码(Huffman Coding):又称霍夫曼编码.赫夫曼编码-,是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种.Huffman于1952年提出一种编码方法,该方法完全依据 ...

  10. C++——赫夫曼编码-译码器(Huffman Coding)

    基本概念 哈夫曼编码(Huffman Coding):又称霍夫曼编码.赫夫曼编码-,是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种.Huffman于1952年提出一种编码方法,该方法完全依据 ...

最新文章

  1. 单例模式中,你不知道的事~~
  2. 记一些暂未找到解决方案的问题 -- 持续更新
  3. UnityShader之Shader分类篇【Shader资料2】
  4. 『C#基础』调用CMD的一个小工具
  5. 【自定义标签开发】01-标签简介和开发第一个标签
  6. 通过Source insight查看内核源码
  7. java取模多位数_JAVA大数类—基础操作(加减乘除、取模、四舍五入、设置保留位数)...
  8. 【JAVA SE】第十四章 集合框架、语法糖和泛型
  9. 智能行业热点速览(2019.7.15)
  10. 属性动画中同一个动画改变多个属性
  11. 【习惯】是学习最好的坚持方式
  12. 分享:EditText默认不弹出软件键盘
  13. plsql 64连接32oracle,32位plsql developer连接64位oracle的方法
  14. 安卓开发3d模型展示源码_Android(安卓)全套开发资料视频+源码
  15. 数据库服务器的打开方式
  16. 中古调式(调式音阶)
  17. 云智慧智能研究院:2022年智能运维发展八大趋势
  18. android usb触摸屏idc实现触摸唤醒
  19. 《信息安全技术 关键信息基础设施安全保护要求》国家标准在京发布
  20. 华擎主板简直在开玩笑

热门文章

  1. Linux下 cmatrix的安装和使用(黑客屏保)
  2. 边做边记中航信酒店接口开发
  3. 时间序列分类实践介绍(使用Python代码)
  4. 禁止Solaris系统不必要的网络服务
  5. Oracle 分组求和(特殊处理)
  6. stm32f030移植到stm32f072
  7. 通信模块整理(一)JDY-31
  8. 初中七年级上计算机试题答案,初中信息技术考试试题(含答案).docx
  9. linux 统计文件字节和行数,Linux命令-统计文件中的字节数、字数、行数:wc
  10. Typora下载加速