# include "stdio.h" # include "time.h" # include "stdlib.h" # define A 4000 # define M 4 # define N 7 /*****************************************************************************************************************/ // 该函数是初始化函数 // 作用:随机产生信源,并将信源存放到数组b中,初始化数组e,使它的初值是0 // 入口参数:bb(信源),ee(陪首集) // 出口参数:k1(代表信源个数) /*****************************************************************************************************************/ int init(int bb[A/M][M],int ee[A/M][N]) { int i=0,j,k1; printf("\n 随机产生%d个二元(%d,%d)汉明码的信源:",A/4,N,M); srand( (unsigned)time( NULL ) ); for( i = 0; i < A/4; i++ ) for( j = 0; j < M; j++ ) { bb[i][j]=rand()%2; } for(i=0;i<A/M;i++) for(j=0;j<N;j++) ee[i][j]=0; k1=A/4; return k1; } /*****************************************************************************************************************/ // 该函数是输出函数 // 作用:输出生成矩阵 // 入口参数:g(生成矩阵) // 出口参数:没有 /*****************************************************************************************************************/ void print1(int g[M][N]) { int i,j; printf("\n 生成矩阵是:\n "); for(i=0;i<M;i++) { for(j=0;j<N;j++) printf("%d ",g[i][j]); printf("\n "); } } /*****************************************************************************************************************/ // 该函数是输出函数 // 输出校验矩阵 // 入口参数:h(校验矩阵) // 出口参数:没有 /*****************************************************************************************************************/ void print2(int h[N-M][N]) { int i,j; printf("\n 校验矩阵是:\n "); for(i=0;i<N-M;i++) { for(j=0;j<N;j++) printf("%d ",h[i][j]); printf("\n "); } } /*****************************************************************************************************************/ // 该函数是求码字函数 // 作用:求出要传输的的码字 // 入口参数:n(信源个数),gg(生成矩阵),cc(信源生成的码字),bb(信源) // 出口参数:没有 /*****************************************************************************************************************/ void SYard(int n,int gg[M][N],int cc[M][N],int bb[A/M][M]) { int i,j,k,t; for(i=0;i<n;i++) { for(j=0;j<N;j++) // 码字cc[][]=信源bb[][]*生成矩阵gg[][],用for循环实现 { t=0; for(k=0;k<M;k++) t+=bb[i][k]*gg[k][j]; cc[i][j]=t%2; // %2是为了让它们之和小于2 } } } /*****************************************************************************************************************/ // 该函数是模拟信道函数 // 作用:改变要传输的码字, // 咐:码字经过该信道后,不产生错误的概率是70%,产生一位错误的概率是21%,两位错误的概率是6%,三位错误的概率是3% // 入口参数:n(信源个数),rr(接收到的码字),cc(发送的码字) // 出口参数:q(产生一位随机错误的码字个数) /*****************************************************************************************************************/ int Channel(int n,int rr[A/M][N],int cc[A/M][N]) { int a,i,j,k,a1,a2,a3,q=0; // k代表经过信道后码字会错几位,a1,a2,a3表示具体的错误位置 srand( (unsigned)time( NULL ) ); for(i=0;i<n;i++) { a=rand()%100; // a表示小于100的一个随机数 if(a<70) k=0; // 该判断语句控制没有产生错误的概率是70% else { if(a<91) k=1; // 该判断语句控制产生一位错误的概率是21%,在出错概率中占70% else { if(a<97)k=2; // 该判断语句控制产生两位错误的概率是6%,在出错概率中占20% else k=3; // 该判断语句控制产生三位错误的概率是3%,在出错概率中占10% } } switch (k) // 该语句判断出现几位错误,并作出相应的处理 { case 0: for(j=0;j<N;j++) // k=0表示没有产生错误,接收到的码字r跟发送的码字c相等 rr[i][j]=cc[i][j]; break; case 1: a1=rand()%7; // k=1表示产生一位错误,a1是随机产生的一个小于7的数,作为码字的错误位置 for(j=0;j<N;j++) { if(j==a1) rr[i][j]=(cc[i][j]+1)%2; // (c[i]+1)%2 是为了把对应位置上的c[i]值由0变1或者由1变0 else rr[i][j]=cc[i][j]; } q++; // 统计产生一位随机错误的码字 break; case 2: a1=rand()%7; // k=2表示产生两位错误,a1和a2代表两个不同的错误位置 a2=rand()%7; while(a2==a1) // 该循环防止a1和a2相等 a2=rand()%7; for(j=0;j<N;j++) { if(j==a1||j==a2) rr[i][j]=(cc[i][j]+1)%2; // (c[i]+1)%2 是为了把对应位置上的c[i]由0变1或者由1变0 else rr[i][j]=cc[i][j]; } break; case 3: a1=rand()%7; // k=3表示产生三位错误 a2=rand()%7; while(a2==a1) // a1和a2代表两个不同的错误位置,该循环防止a1和a2相等 a2=rand()%7; a3=rand()%7; while(a3==a2||a3==a1) // a1,a2,a3分别代表三个不同的错误位置,该循环防止a1,a2,a3相等 a3=rand()%7; for(j=0;j<N;j++) { if(j==a1||j==a2||j==a3) rr[i][j]=(cc[i][j]+1)%2; // (c[i]+1)%2 是为了把对应位置上的c[i]由0变1或者由1变0 else rr[i][j]=cc[i][j]; } break; default: printf("error\n"); } } return q; } /*****************************************************************************************************************/ // 该函数是获得错位函数 // 作用:求出伴随式p和陪首集e // 入口参数:hh(校验矩阵),n(信源个数),rr(接收到的码字),ss(伴随式),ee(陪首集) // 出口参数:没有 /*****************************************************************************************************************/ void Erbit(int hh[N-M][N],int n,int rr[A/M][N],int ss[A/M][N-M],int ee[A/M][N]) { int i,j,k,t,k1; for(i=0;i<n;i++) { for(j=0;j<N-M;j++) { t=0; for(k=0;k<N;k++) t+=rr[i][k]*hh[j][k]; // r[i][k]*h[j][h]相当于r*h的转置矩阵 ss[i][j]=t%2; } } for(i=0;i<n;i++) { for(j=0;j<N;j++) { k1=0; // k1是伴随式和校验矩阵某一列是否相等的标志 for(k=0;k<N-M;k++) //该循环判断伴随式和校验矩阵的哪一列相等 { if(ss[i][k]!=hh[k][j]) { k1=1;break; // 若不相等则k1=1,若相等则k1=0 } } if (k1==0) // k1=0 时,e[i][j]对应位置1 { ee[i][j]=1; break; } } } } /*****************************************************************************************************************/ // 该函数是求码字函数 // 作用:求得纠正后的码字t // 入口参数:n(信源个数),ee(陪首集),tt(纠正后的码字),rr(接收到的码字) // 出口参数:没有 /*****************************************************************************************************************/ void TYard(int n,int ee[A/M][N],int tt[A/M][N],int rr[A/M][N]) { int i,j; for(i=0;i<n;i++) { for(j=0;j<N;j++) { if(ee[i][j]) tt[i][j]=(rr[i][j]+1)%2; else tt[i][j]=rr[i][j]; } } } /*****************************************************************************************************************/ // 该函数是输出函数 // 作用:输出要传输的码字,接收到的码字,伴随式,陪首集,纠正后的码字 // 入口参数:n(信源个数),cc(发送的码字),rr(接收的码字),ss(伴随式),ee(陪首集),tt(纠正后的码字) // 出口参数:没有 /*****************************************************************************************************************/ void output(int n,int cc[A/M][N],int rr[A/M][N],int ss[A/M][N-M],int ee[A/M][N],int tt[A/M][N]) { int i,j; for(i=0;i<n;i++) { printf("\n 要传输的码字 接收到的码字 伴随式 陪首集 纠正后的码字\n\n"); printf(" "); for(j=0;j<N;j++) printf("%d",cc[i][j]);printf(" "); for(j=0;j<N;j++) printf("%d",rr[i][j]);printf(" "); for(j=0;j<N-M;j++) printf("%d",ss[i][j]);printf(" "); for(j=0;j<N;j++) printf("%d",ee[i][j]);printf(" "); for(j=0;j<N;j++) printf("%d",tt[i][j]); printf("\n"); } } /*****************************************************************************************************************/ // 该函数是性能分析函数 // 作用:计算信源经过汉明编译码前后通过模拟信道的误码率,并计算出一位随机错误的误码率。 // 入口参数:n(信源个数),q(一位随机错误码字个数),cc(发送的码字),rr(接收的码字),tt(纠正后的码字) // 出口参数:没有 /*****************************************************************************************************************/ void PAnalysis(int n,int q,int cc[A/M][N],int rr[A/M][N],int tt[A/M][N]) { int i,j,m1,m2,m3=0,m4=0; for(i=0;i<n;i++) { m1=0,m2=0; for(j=0;j<N;j++) { if(cc[i][j]==rr[i][j]) m1++; if(cc[i][j]==tt[i][j]) m2++; } if(m1!=7) m3++; if(m2!=7) m4++; } printf("\n 随机产生的%d个二元(%d,%d)汉明码的信源通过模拟信道后的性能分析:\n",A/4,N,M); printf("\n 编译码前的误码率是:%.3f%%\n",(float)m3*100/(A/4)); printf("\n 编译码后的误码率是:%.3f%%\n",(float)m4*100/(A/4)); printf("\n 一位随机错误码率是:%.3f%%\n",(float)q*100/(A/4)); printf("\n 经过汉明编译码后的信源经过模拟信道后降低的误码率正是一位随机错误码率,所以证明\n\n 汉明码只能纠正一位随机错误"); } /*****************************************************************************************************************/ // 该函数是主函数 // 作用:调用其他函数,实现其功能,并固定屏幕 /*****************************************************************************************************************/ void main() { int k,k0, G[M][N]={{1,0,0,0,1,0,1},{0,1,0,0,1,1,1},{0,0,1,0,1,1,0},{0,0,0,1,0,1,1}}, // 生成矩阵 H[N-M][N]={{1,1,1,0,1,0,0},{0,1,1,1,0,1,0},{1,1,0,1,0,0,1}}, // 校验矩阵 // 数组b存放信源,数组c存放要发送的码字,数组r存放接收到的码字, // 数组p存放伴随式,数组e存放陪首集,数组t存放纠正后的码字 b[A/M][M],c[A/M][N],r[A/M][N],p[A/M][N-M],e[A/M][N],t[A/M][N]; k=init(b,e); // 初始化函数 print1(G); // 输出生成矩阵 print2(H); // 输出校验矩阵 SYard(k,G,c,b); // 求出要传输的的码字 k0=Channel(k,r,c); // 模拟信道 Erbit(H,k,r,p,e); // 求伴随式和陪首集 TYard(k,e,t,r); // 求纠正后的码字 output(k,c,r,p,e,t); // 输出函数 PAnalysis(k,k0,c,r,t); //误码率分析 getchar(); // 固定屏幕 }