⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 convcode.c

📁 卷积码编码器
💻 C
字号:
//程序:卷积码编码、维特比硬判译码器
//作者:Anfysky
//日期:2004-12


#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <malloc.h>
#include <windows.h>
//extern("c");

//卷积码参数结构体
typedef struct
{
	int *G;					//生成多项式
	int **pStateTable;		//状态表
	int nOutc;				//输出校验位个数
	int nDelayNum;			//延时窗个数
}CONV_PARM;

//二维指针分配函数
void ** malloc2(int r, int l, int typesize)
{
	int i=0;
	void **p=(void **)malloc(r*typesize);
	for(i=0; i<r; i++)
		p[i]=(void *)malloc(l*typesize);
	return p;
}

//二维指针释放函数
void free2(void **p, int r, int l)
{
	int i=0;
	for(i=0; i<r; i++)
	{
		free(p[i]);
	}
	free(p);
}

//二维指针内存清零函数
void ** memset2(void **p, char c, int r, int l)
{
	int i=0;
	for(i=0; i<r; i++)
	{
		memset(p[i],c,l);
	}
	return p;
}

//产生随机数
int randB_vec(double* pOut, int nOut)
{
	int i=0;
	printf("Source Generating ...");
	for(i=0; i<nOut; i++)
	{
		*(pOut+i)=(rand()>(RAND_MAX/2));
	}
	printf(" Done\n");
	return i;
}

//根据当前状态和生成多项式,产生下一个状态
static int Gen_C_Int(int nStates, int nWindow, int G)
{
	int i=0; 
	int nAns=0;
	int nAnd=nStates&G;
	for(i=0; i<=nWindow; i++)
	{
		nAns+=nAnd%2;
		nAnd>>=1;
	}
	return nAns%2;
}

//产生状态转移表
static double Gen_Conv_Table(CONV_PARM* conv_parm)
{
	int nStateNumWI=1<<(conv_parm->nDelayNum+1);
	int i=0;
	int j=0;
	int nOut=0;
	for(i=0; i<nStateNumWI; i++)
	{
		//第一个数纪录下一状态
		conv_parm->pStateTable[i][0]=i>>1;
		//第二个数纪录输出
		nOut=0;
		for(j=0; j<conv_parm->nOutc; j++)
		{
			nOut<<=1;
			nOut+=Gen_C_Int(i,conv_parm->nDelayNum,conv_parm->G[j]);
		}
		conv_parm->pStateTable[i][1]=nOut;
	}
	return 0;
}

//编码器
int Conv_Encode(double *pSrc, int nSrcLen, double *pCoded, CONV_PARM conv_parm)
{
	int nWindow=0;
	int i=0,j=0;
	printf("Conv Encoding ... ");
	for(i=0; i<nSrcLen+conv_parm.nDelayNum; i++)
	{
		if(i<nSrcLen)
			nWindow+=(int)(*(pSrc+i))<<conv_parm.nDelayNum;
		for(j=0; j<conv_parm.nOutc; j++)
		{
			*(pCoded+i*conv_parm.nOutc+j)=Gen_C_Int(nWindow,conv_parm.nDelayNum,conv_parm.G[j]);
		}
		nWindow>>=1;
	}
	printf("Done\n");
	return (nSrcLen+conv_parm.nDelayNum)*conv_parm.nOutc;
}

//比较低8位的不同数字位数
int Get_Distance_Char(int n1, int n2)
{
	int nXor=n1^n2;
	int ans=0;
	int i=0;
	for(i=0; i<8; i++)
	{
		ans+=nXor%2;
		nXor>>=1;
	}
	return ans;
}

//译码器
int Conv_Decode(double* pCoded, int nCodedLen, double* pDecoded, CONV_PARM conv_parm)
{
	int i=0, j=0;
	int nDecodedCounter=0;
	int nStateCounterWI=0;
	int nStateCounter=0;
	int nReceiveC=0;
	int nDistance=0;
	int nNextState=0;
	int nStateNumWI=1<<(conv_parm.nDelayNum+1);
	int nStateNum=1<<conv_parm.nDelayNum;
	int nDecodedNum=(nCodedLen/conv_parm.nOutc)+conv_parm.nDelayNum*2;
	int nRealDecodedNum=0;
	int nMinDistanceState=0;
	int nMinDistance=0;
	int nNewDistance=0;
	int nTempAddress=0;
	//定义pDecodedPath[信源点数][状态数×3],每个点的每个状态上记录
	//1、距离,2、输入,3、来自的前一状态
	//经过比较之后选择最短距离并放到每个点每个状态的记录头部。
	//由于8bit状态已经是非常复杂的状态机了,所以使用2字节存储转移状态是合理的。
	//所以可以这样按位处理:第1个4字节为距离,第2个4字节的头部1字节为输入
	//第2个4字节的低3字节为下一个最短路径状态。(显然足够了)


	int** pDecodedPath=(int **)malloc2(nDecodedNum,nStateNum*2,sizeof(int));
	//为了节省内存,定义pTempDecodedStates[状态数×4],
	//存放生成的下一个状态的两个路径。
	int* pTempDecodedStates=(int *)malloc(nStateNum*4*sizeof(int));

	printf("Conv Decoding .");

	memset2(pDecodedPath,-1,nDecodedNum,nStateNum*2*sizeof(int));

	//将第一个点的前6个值赋0。这里是循环的起点。
	for(i=0; i<2; i++)
		pDecodedPath[0][i]=0;
	
	for(i=0; i<nCodedLen; i+=conv_parm.nOutc)
	{
		nReceiveC=0;
		for(j=0; j<conv_parm.nOutc; j++)
		{
			nReceiveC<<=1;
			nReceiveC+=(int)(pCoded[i+j]);
		}

		memset(pTempDecodedStates,-1,nStateNum*4*sizeof(int));
		for(nStateCounterWI=0; nStateCounterWI<nStateNumWI; nStateCounterWI++)
		{
			nStateCounter=nStateCounterWI%nStateNum;
			//如果当前状态所处的位置上,误差距离全是负数,就是不可到达当前状态,
			//则不做新的目标误差距离的生成。
			if(pDecodedPath[nDecodedCounter][nStateCounter*2]==-1)
			{
				continue;
			}
			else
			{
				nNextState=nStateCounterWI>>1;
				//conv_parm.pStateTable[nStateCounterWI][1]是输出
				//比较接收与conv_parm.pStateTable[nStateCounterWI][1],得到下一状态上的距离。
				nDistance=Get_Distance_Char(conv_parm.pStateTable[nStateCounterWI][1],	nReceiveC);

				//写下一状态的几个值:距离,输入,来自的状态

				//距离写在2整数倍的位置上。
				nNewDistance=pDecodedPath[nDecodedCounter][nStateCounter*2]+nDistance;
				pTempDecodedStates[nNextState*4+2*(nStateCounterWI%2)]=nNewDistance;
				//输入和来自的状态合并之后写在2n+1的位置上。
				pTempDecodedStates[nNextState*4+2*(nStateCounterWI%2)+1]=(nStateCounterWI/nStateNum)<<24;
				//来自的状态
				pTempDecodedStates[nNextState*4+2*(nStateCounterWI%2)+1]+=nStateCounter;
			}

			//判断最小距离,把最小距离点的参数覆盖到最短路径上。
			if((pTempDecodedStates[nNextState*4+2]>=0) &&
				(pTempDecodedStates[nNextState*4+2]<pTempDecodedStates[nNextState*4]))
			{
				pDecodedPath[nDecodedCounter+1][nNextState*2]=
					pTempDecodedStates[nNextState*4+2];
				pDecodedPath[nDecodedCounter+1][nNextState*2+1]=
					pTempDecodedStates[nNextState*4+3];
			}
			else
			{
				pDecodedPath[nDecodedCounter+1][nNextState*2]=
					pTempDecodedStates[nNextState*4];
				pDecodedPath[nDecodedCounter+1][nNextState*2+1]=
					pTempDecodedStates[nNextState*4+1];
			}
		}
		nDecodedCounter++;
		if(nDecodedCounter%20000==0)
			printf(".");
	}
	nRealDecodedNum=nDecodedCounter;
	//从最后一个点的状态开始,选择最小距离
	nMinDistance=pDecodedPath[nDecodedCounter][0];
	nMinDistanceState=0;
	for(nStateCounter=0; nStateCounter<nStateNum; nStateCounter++)
	{
		nDistance=pDecodedPath[nDecodedCounter][nStateCounter*2];
		if((nDistance>0) && (nMinDistance>nDistance))
		{
			nMinDistance=nDistance;
			nMinDistanceState=nStateCounter;
		}
	}
	//选出最小距离之后,根据路径,倒推整个输入
	for(i=nRealDecodedNum; i>0; i--)
	{
		pDecoded[i-1]=(pDecodedPath[i][nMinDistanceState*2+1])>>24;
		nMinDistanceState=pDecodedPath[i][nMinDistanceState*2+1]%0x1000000;
	}
	printf(" Done\n");
	free2(pDecodedPath,nDecodedNum,nStateNum*2);
	free(pTempDecodedStates);
	return nRealDecodedNum;
}
//private
//本私有方法仅用于简化main函数,不可被外部函数调用
static void Initate_Conv_Parm(CONV_PARM* conv_parm)
{
	conv_parm[0].nOutc=2;
	conv_parm[0].nDelayNum=8;
	conv_parm[0].G=(int*)malloc(conv_parm[0].nOutc*sizeof(double));
	conv_parm[0].pStateTable=(int**)malloc2(1<<(conv_parm[0].nDelayNum+1),3,sizeof(double));
	conv_parm[0].G[0]=0561;
	conv_parm[0].G[1]=0753;
	Gen_Conv_Table(conv_parm);

	conv_parm[1].nOutc=3;
	conv_parm[1].nDelayNum=8;
	conv_parm[1].G=(int*)malloc(conv_parm[1].nOutc*sizeof(double));
	conv_parm[1].pStateTable=(int**)malloc2(1<<(conv_parm[1].nDelayNum+1),3,sizeof(double));
	conv_parm[1].G[0]=0557;
	conv_parm[1].G[1]=0663;
	conv_parm[1].G[2]=0711;
	Gen_Conv_Table(conv_parm+1);
}

void main()
{
	int i=0;
	int nSrc=15;
	CONV_PARM conv_parm[2];
	double *pSrc=NULL;
	double *pOut=NULL;
	double *pDecoded=NULL;
	DWORD  time=0;

	int nOut=0;
	int nDecoded=0;
	int nBitError=0;

	time=GetTickCount();

	//内部私有方法:初始化卷积码编码器参数
	Initate_Conv_Parm(conv_parm);

	//目前使用的都是conv_parm[0];
	pSrc=(double*)malloc(nSrc*sizeof(double));
	pOut=(double*)malloc(((nSrc+20)*conv_parm[0].nOutc)*sizeof(double));
	pDecoded=(double*)malloc((nSrc+20)*sizeof(double));
	
	printf("Source Number:\t%d \n",nSrc);
	//产生信源
	randB_vec(pSrc,nSrc);

	//卷积码编码
	nOut=Conv_Encode(pSrc, nSrc, pOut, conv_parm[0]);

	for (i=0; i<nSrc; i++)
	{
		printf("%d,%d,%d\n",(int)pSrc[i],(int)pOut[i*2+1],(int)pOut[i*2]);//输出高位在前
	}

	//卷积码硬判解码
	nDecoded=Conv_Decode(pOut, nOut, pDecoded, conv_parm[0]);

	//错误检查
	for(i=0; i<nSrc; i++)
	{
		if((int)pSrc[i]!=(int)pDecoded[i])
			nBitError++;
	}

	time=GetTickCount()-time;
	printf("\nTime Used:\t%.3f s\nErrors:\t\t%d bits\n",time*0.001,nBitError);

	free(pSrc);
	free(pOut);
	free(pDecoded);

	free(conv_parm[0].G);
	free(conv_parm[1].G);

	free2(conv_parm[0].pStateTable,(1<<(conv_parm[0].nDelayNum+1)),3);
	free2(conv_parm[1].pStateTable,(1<<(conv_parm[1].nDelayNum+1)),3);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -