香农编码基于C语言上的实现

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

香农编码基于C语言上的实现
摘要
编码是指为了达到某种目的而对信号进行的一种变换。

根据编码的目的不同,编码理论有三个分支:①信源编码。

对信源输出的信号进行变换,包括连续信号的离散化,即将模拟信号通过采样和量化变成数字信号,以及对数据进行压缩,提高数字信号传输的有效性而进行的编码。

②信道编码。

对信源编码器输出的信号进行再变换,包括区分通路、适应信道条件和提高通信可靠性而进行的编码。

③保密编码。

对信道编码器输出的信号进行再变换,即为了使信息在传输过程中不易被人窃取而进行的编码。

编码理论在数字化遥测遥控系统、电气通信、数字通信、图像通信、卫星通信、深空通信、计算技术、数据处理、图像处理、自动控制、人工智能和模式识别等方面都有广泛的应用。

其中信源编码又分为三种,包括香农编码、哈夫曼编码和算术编码。

本文主要介绍香农编码。

关键词:累加概率、排序、熵、码长、编码效率
第1章前言
1948年,美国科学家香农(Shannon)发表了一篇题为“通信的数学理论”的学术论文,这篇划时代论文的问世,宣告了信息论的诞生。

信息论的研究领域从自然科学扩展到经济、管理科学甚至人文社会科学,从狭义信息论发展到如今的广义信息论,成为涉及面极广的信息科学。

1951年美国电信工程师D.A.霍夫曼提出更有效的霍夫曼编码。

此后又出现了传真编码、图像编码和话音编码,对数据压缩进行了深入的研究,解决了数字通信中提出的许多实际问题。

在信源编码方面,1951年香农证明,当信源输出有冗余的消息时可通过编码改变信源的
输出,使信息传输速率接近信道容量。

1948年香农就提出能使信源与信道匹配的香农编码。

编码分为信源编码与信道编码,其中信源编码又分为无失真和限失真。

由于信源符号之间存在分布不均匀和相关性,使得信源存在冗余度,信源编码的主要任务就是减少冗余,提高编码效率。

信源编码的基本途径有两个,一是解除相关性;二是概率均匀化。

信源编码的编码定理有两个,无失真编码定理和限失真编码定理。

信源编码定理出现后,编码方法就趋于合理化。

其中以香浓码、费诺码和哈夫曼码为无失真编码的最佳码。

[1]
第2章 香农编码原理
2.1 信源编码原理
信源编码就是从信源符号到码符号的一种映射f ,它把信源输出的符号u i 变换成码元序列w i 。

f :u i ——>w i ,i =1,2,…,q 信源编码定义如图2.1:
凡是能载荷一定的信息量,且码字的平均长度最短,可分离的变长码的码字集合都可以称为最佳码。

为此必须将概率大的信息符号编以短的码字,概率小的符号编以长的码字,使得平均码字长度最短。

能获得最佳码的编码方法主要有:香农(Shannon )、费诺(Fano )、哈夫曼(Huffman )编码等。

[2]
2.2 香农编码原理
香农第一定理指出了平均码长与信源之间的关系,同时也指出了可以通过编
码使平均码长达到极限值,这是一个很重要的极限定理。

如何构造这种码?香农
X
{ x 1,…,x R }
W {w 1,w 2,…,w K }
U
{u 1,u 2,…,u L }
信源编码器
图2.1信源编码器
第一定理指出,选择每个码字的长度K i 满足下式 I(x i )≤K ﹤I (x i )+1, i ∀ 就可以得到这种码。

这种编码方法就是香农编码。

2.3 编码步骤
香农编码法冗余度稍大,实用性不大,但有重要的理论意义。

编码步骤如下: (1) 将信源消息符号按其出现的概率大小依次排列 p (x 1)≥p (x 2)≥…≥p (x n ) (2) 确定满足下列不等式整数码长K i :
-log 2p(x i )≤K i <-log 2p(x i )+1 (3) 为了编成唯一可译码,计算第i 个消息的累加概率 P i =∑-+1
1i k p(x k )
(4) 将累加概率P i 变成二进制数。

(5) 取P i 二进制数的小数点后K i 位即为该消息符号的二进制码字。

第3章 香农编码的算法介绍
3.1 C 语言算法介绍
C 语言是目前世界上流行,使用最广泛的高级程序设计语言。

C 是结构式语
言,结构式语言的显著特点是代码及数据的分隔化,即程序的各个部分除了必要的信息交流外彼此独立.这种结构化方式可使程序层次清晰, 便于使用,维护以及调试.C 语言是以函数形式提供给用户的,这些函数可方便的调用,并具有多种循环,条件语句控制程序流向,从而使程序完全结构化.[3]
3.2 C 语言算法举例
程序中要先定义代码长度的最大值及输入序列的个数,即 #include <stdio.h> #include <math.h> #include <stdlib.h> #define max_CL 10
#define max_PN 6
typedef float datatype;
typedef struct SHNODE
{
datatype pb; /*第i个消息符号出现的概率*/
datatype p_sum; /*第i个消息符号累加概率*/
int kl; /*第i个消息符号对应的码长*/
int code[max_CL]; /*第i个消息符号的码字*/
struct SHNODE *next;
}
shnolist;
datatype sym_arry[max_PN]; /*序列的概率*/
void pb_scan(); /*得到序列概率*/
void pb_sort(); /*序列概率排序*/
由程序可以看出代码长度的最大值为10,序列个数位6。

其中还定义了消息符号出现的概率,累加概率等计算香农编码时所必须的数值。

计算编码时,需要计算的几个符号的出现概率总和应为1,当大于或小于1时,则是错误的,不能进行香农编码,所以,程序应可以对概率总和是否等于1进行判断。

即如下程序:
if(sum>1.0001||sum<0.99)
{ printf("sum=%f,sum must (<0.999<sum<1.0001)",sum);
pb_scan();
}
在VC中运行整个程序,在没有错误出现的情况下,输入要编码的符号的概率,再运行,就可出现运行结果,即编码结果、平均码长、熵、信息传输速率。

第4章具体例题解析
结论
在用C语言编写的香农编码程序中,对于计算编码时用到的各种概率值要有具体的定义,由于进行香农编码时,首先要进行从大到下的概率排序,所以,程序中编辑的降序的部分是必须的,运行结果不仅要求有编码结果,还要有信源熵,平均码长,所以在程序中也应定义这两个值。

通过运用香农编码方法进行计算和对香农编码C程序的运行,可知,香农编码方法多余度稍大,相较于其他编码方法实用性不大,但香农编码法有重要的理论意义。

附录
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define max_CL 10 /*maxsize of length of code*/
#define max_PN 6 /*输入序列的个数*/
typedef float datatype;
typedef struct SHNODE {
datatype pb; /*第i个消息符号出现的概率*/
datatype p_sum; /*第i个消息符号累加概率*/
int kl; /*第i个消息符号对应的码长*/
int code[max_CL]; /*第i个消息符号的码字*/
struct SHNODE *next;
}shnolist;
datatype sym_arry[max_PN]; /*序列的概率*/
void pb_scan(); /*得到序列概率*/
void pb_sort(); /*序列概率排序*/
void valuelist(shnolist *L); /*计算累加概率,码长,码字*/
void codedisp(shnolist *L);
void pb_scan()
{
int i;
datatype sum=0;
printf("input %d possible!\n",max_PN);
for(i=0;i<max_PN;i++)
{ printf(">>");
scanf("%f",&sym_arry[i]);
sum=sum+sym_arry[i];
}
/*判断序列的概率之和是否等于1,在实现这块模块时,scanf()对float数的缺陷,故只要满足0.99<sum<1.0001出现的误差是允许的*/
if(sum>1.0001||sum<0.99)
{ printf("sum=%f,sum must (<0.999<sum<1.0001)",sum);
pb_scan();
}
}
/*选择法排序*/
void pb_sort()
{
int i,j,pos;
datatype max;
for(i=0;i<max_PN-1;i++)
{
max=sym_arry[i];
pos=i;
for(j=i+1;j<max_PN;j++)
if(sym_arry[j]>max)
{
max=sym_arry[j];
pos=j;
}
sym_arry[pos]=sym_arry[i];
sym_arry[i]=max;
}
}
void codedisp(shnolist *L)
{
int i,j;
shnolist *p;
datatype hx=0,KL=0; /*hx存放序列的熵的结果,KL存放序列编码后的平均码字的结果*/
p=L->next;
printf("num\tgailv\tsum\t-lb(p(ai))\tlenth\tcode\n");
printf("\n");
for(i=0;i<max_PN;i++)
{
printf("a%d\t%1.3f\t%1.3f\t%f\t%d\t",i,p->pb,p->p_sum,-3.332*log10(p->pb),p->kl);
j=0;
for(j=0;j<p->kl;j++)
printf("%d",p->code[j]);
printf("\n");
hx=hx-p->pb*3.332*log10(p->pb); /*计算消息序列的熵*/
KL=KL+p->kl*p->pb; /*计算平均码字*/
p=p->next;
}
printf("H(x)=%f\tKL=%f\nR=%fbit/code",hx,KL,hx/KL); /*计算编码效率*/
}
shnolist *setnull()
{ shnolist *head;
head=(shnolist *)malloc(sizeof(shnolist));
head->next=NULL;
return(head);
}
shnolist *my_creat(datatype a[],int n)
{
shnolist *head,*p,*r;
head=setnull();
r=head;
for(i=0;i<n;i++)
{ p=(shnolist *)malloc(sizeof(shnolist));
p->pb=a[i];
p->next=NULL;
r->next=p;
r=p;
}
return(head);
}
void valuelist(shnolist *L)
{
shnolist *head,*p;
int j=0;
int i;
datatype temp,s;
head=L;
p=head->next;
temp=0;
while(j<max_PN)
{
p->p_sum=temp;
temp=temp+p->pb;
p->kl=-3.322*log10(p->pb)+1;
/*编码,*/
{
s=p->p_sum;
for(i=0;i<p->kl;i++)
p->code[i]=0;
for(i=0;i<p->kl;i++)
{
p->code[i]=2*s;
if(2*s>=1)
s=2*s-1;
else if(2*s==0)
break;
else s=2*s;
}
}
j++;
p=p->next;
}
int main(void)
{
shnolist *head;
pb_scan();
pb_sort();
head=my_creat(sym_arry,max_PN); valuelist(head);
codedisp(head);
}。

相关文档
最新文档