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

📄 cdatams.cpp

📁 这是cdma2000的一个分组调度算法实例
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	if (fabs(fdifference)>1e-6) bFlag=true;
	int iSGNumber=0;						//当前Subpacket中的SG个数,为整数
	if(bFlag)							//fSGNumber is not a integer
	{
		if(fdifference>0.5) iSGNumber=int(fSGNumber)+2;
		else iSGNumber=int(fSGNumber)-1;
	}									//加2和减1都是通过观察数据表后得出的合理值	
	else iSGNumber=int(fSGNumber);
	if(iSGNumber==6) iSGNumber=4;
	
	int iSGNumberPerSubslot=0;
	iSGNumberPerSubslot=iSGNumber/SubslotNumber;

	float* pTempSGEsNt=new float[iSGNumber];					//临时存放Symbol Group的EsNt的数组指针  

	for(int j2=0 ; j2<SubslotNumber ; j2++)
	{
		for(int j3=0 ; j3<iSGNumberPerSubslot ; j3++)
		{
			pTempSGEsNt[j2*iSGNumberPerSubslot+j3]=fEsNt[j2];						
		}
	}

//根据情况向当前EP的SG_Es/Nt数组填充数据并实现最大比值合并
	for(int j3=0 ; j3<iSGNumber ; j3++)
	{
		int i;
		i=(m_iSgNumber+j3)%(m_iLengthOfArrayEsNt);
		m_pfSymbolEsNt[i]+=pTempSGEsNt[j3];
	}
	int iSgEsNtNumber=m_iSgNumber+iSGNumber;
	if(iSgEsNtNumber>(m_iLengthOfArrayEsNt)) m_bIsSGEsNtArrayfull=true;
	//true表示SGEsNtArray已被有效数据填满
	m_iSgNumber=(m_iSgNumber+iSGNumber)%(m_iLengthOfArrayEsNt);
	delete [] pTempSGEsNt; 
//递减当前SubPacket的时隙数
	m_iSlotNumRemained--;
	m_iSlotCounter++;

}


bool CDataMs::IsSubPacketEnd()
//Sub-packet传输完毕的判断函数: 判断当前sub-packet是否传输完毕                                                                      
{
    if (m_iSlotNumRemained<=0)
	{
		m_bIsTransmitingNow=false;	//是否传输标志复位
		m_iSlotNumRemained=0;		//当前子包的剩余slot数置零
		return true;
	}
	else return false;
} 

void CDataMs::InsertEffectiveCodeRate()
//Sub-packet传输完毕,把当前的编码速率插入编码速率链表。
{
	float ftempEffectiveCodeRate;
	ftempEffectiveCodeRate=m_pstRatePrediction->fEffectiveCodeRate;
	m_EffectiveCodeRateList.AddTail(ftempEffectiveCodeRate);	//将当前的编码速率m_fCurrentEffectiveCodeRate插入编码速率链表
}
			
bool CDataMs::IsPacketGood()
//EP分组质量判决:	根据PER判决当前EP分组是否正确接收,true为正确。考虑ACK/NAK的差错。                                                                                                
{
    float r1,r2,r3;
	r1=xUniform();
	if (r1<m_fEPErrorRate)
	{
		r2=xUniform();
		if (r2<m_pMsManager->m_fErrorRateOfFeedBack)
		{
			m_bIsEPGood=true;
		}
		else
		{
			m_bIsEPGood=false;
		}
	}
	else
	{
		r3=xUniform();
		if (r3<m_pMsManager->m_fErrorRateOfFeedBack) 
		{
			m_bIsEPGood=false;
		}	
		else
		{
			m_bIsEPGood=true;
		}		
	}
	return m_bIsEPGood;
} 
			
                                        
//几个分量较重的函数                    
void CDataMs::PERPrediction()
//质量估计函数	功能:根据SNR链表计算SNR的均值和标准差,以及平均编码速率。
//调用LinkPrediction的差表函数,得到当前的EP分组差错概率。                                                
{
//计算SNR的均值和标准差
//SNR的均值和标准差改为根据Symbol Group的等效Es/Nt计算
//SNR的链表改为存储SG的等效Es/Nt的数组
//改为计算Es/Nt的平均值和标准差
//The mean and std of Es/Nt value are real values(not in dB)!!
	//判断SGEsNt数组中用于计算均值和方差的有效数据的数量
	if(m_bIsSPDCCHOverEstimation)
	{
		m_fEPErrorRate=1.;
		return;
	}
	int iSGEsNtNumber;		//用于计算均值和方差的有效数据的数量
	if(m_bIsSGEsNtArrayfull) iSGEsNtNumber=m_iLengthOfArrayEsNt;
	else iSGEsNtNumber=m_iSgNumber;
	
	float fSNR=0.0;
	float fSNRReal=0.0;			//the real mean value of real EsNt values 
	for(int j=0 ; j<iSGEsNtNumber ; j++)
	{
		if (m_pfSymbolEsNt[j]<=0)
			cerr<<"Error!"<<endl;
		fSNR+=m_pfSymbolEsNt[j];	//the accumulation of the real EsNt values 
	}
	fSNRReal=fSNR/iSGEsNtNumber;
	m_fMeanSNR=float(10*log10(fSNRReal));	//the mean value in dB
	
	float fSymbolEsNt_dB=0.0;
	double dMiddleVariableOfStd=0.0;
	for(int k=0 ; k<iSGEsNtNumber ; k++)
	{
		fSymbolEsNt_dB=float(10*log10(m_pfSymbolEsNt[k]));
		dMiddleVariableOfStd+=pow(double(fSymbolEsNt_dB-m_fMeanSNR),double(2.0));
	}
	m_fStdOfSNR=float(dMiddleVariableOfStd/iSGEsNtNumber);	//the std value of EsNt values in dB
	
//计算平均等效编码速率    各个等效编码速率的倒数之和的倒数 
	POSITION pos;
	pos=m_EffectiveCodeRateList.GetHeadPosition();
	float fMiddleVariableCodeRate;
	fMiddleVariableCodeRate=0.0;
	while(pos!=NULL)
	{
		fMiddleVariableCodeRate+=(1/m_EffectiveCodeRateList.GetNext(pos));
	}
	m_fCurrentEffectiveCodeRate=float (1/fMiddleVariableCodeRate)>=float(1/5.0)?float (1/fMiddleVariableCodeRate):float(1/5.0);

//调用LinkPrediction的差表函数,得到当前的分组差错概率
	m_fEPErrorRate=m_LinkPredictionPointer->GetBLER(m_iCurrentPacketSize,m_fMeanSNR,m_fStdOfSNR,m_fCurrentEffectiveCodeRate);
} 
			
void CDataMs::ReTransmissionControl()
//重传控制函数	首先判断重传次数是否达到门限,若达到门限则从数据队列中减去packet的长度,同时错误EP分组数加1。若未达到门限,设置重传标志,重传次数加1。                                    
{
	if(m_iTransmissionNum<MaxTransmissionNum)
   {
	   m_bIsReTransmission=true;	//置重传标志:
	   m_iTransmissionNum++;		//传输次数加1:
   }
   else
   {
	   if(m_iLabelOfDataTraffic==2||m_iLabelOfDataTraffic==0)
		   m_lDataQueueSize-=(long)m_iCurrentPacketSize;	//从数据队列中减去EncoderPacket的长度
	   else
		   HandlePacket();									//处理packet
	   m_iErrorEPNum++;							//记录EP分组差错数
	   m_iCurrentPacketSize=0;							//当前EP大小清零
	   delete [] m_pfSymbolEsNt;							//释放存放SymbolEsNt的数组空间
	   m_pfSymbolEsNt=NULL;
  	   m_bIsSGEsNtArrayfull=false;				//清除标志_用于指示SGEsNtArray是否已被有效数据填满
//复位相关变量
	   m_iTransmissionNum=0;			//传输次数清零 
	   m_bIsTransmitingNow=false;			//复位是否传输标志 
	   m_bIsReTransmission=false;	    		//复位重传标志
	   m_iSlotNumRemained=0;			//当前子包的剩余slot数清零 
//清空CodeRate链表
	   
	   POSITION pos;
	   pos=m_EffectiveCodeRateList.GetTailPosition();
	   while (pos!=NULL)
	   {
		   m_EffectiveCodeRateList.RemoveTail();
		   pos=m_EffectiveCodeRateList.GetTailPosition();
	   }
	   //以上操作清除了链表的内容,但是有关内存的释放还未解决
     }
} 
                                                                                                                                         
void CDataMs::NewPacketSetup()
//设置新的传输EP分组  EP分组成功传输后,从数据队列中减去EP分组长度,成功EP分组数加1,清空SNR和编码速率链表,调用Encoder Packet生成函数,生成新的分组。同时,向传输扇区中加入传输数据量。
{
	m_lDataQueueSize-=(long) m_iCurrentPacketSize;		//从数据队列中减去EncoderPacket的长度:
	if(m_iLabelOfDataTraffic==1)
		HandlePacket();
	m_iSuccessfulEPNum++;							//记录成功传输的EP分组数:
	if(m_lDataQueueSize<0) 
	{
		m_lTotalGoodBitsNum+=(long(m_iCurrentPacketSize)+m_lDataQueueSize);
		//成功传输的数据量累加,去除EP中的冗余比特
		m_lDataQueueSize=0;
	}
	else
		m_lTotalGoodBitsNum+=(long) m_iCurrentPacketSize;	//记录传输的数据量:
	//复位相关变量
	m_iCurrentPacketSize=0;						//当前EP大小清零
	delete [] m_pfSymbolEsNt;					//释放存放SymbolEsNt的数组空间
	m_pfSymbolEsNt=NULL;
	m_bIsSGEsNtArrayfull=false;					//清除标志_用于指示SGEsNtArray是否已被有效数据填满
	m_iTransmissionNum=0;						//传输次数清零 
	m_bIsTransmitingNow=false;					//复位是否传输标志 
	m_bIsReTransmission=false;					//复位重传标志
	m_iSlotNumRemained=0;						//当前子包的剩余slot数清零 
//清空CodeRate链表

	POSITION pos;
	pos=m_EffectiveCodeRateList.GetTailPosition();
	while (pos!=NULL)
	{
		m_EffectiveCodeRateList.RemoveTail();
        pos=m_EffectiveCodeRateList.GetTailPosition();
	}
} 

			
void CDataMs::HandlePacket()
//处理Packet链表,完成Packet的传输,进行Packet和PC的时延和传输的个数的统计
{
	CSector* pSector=m_pServiceArea->GetSector(m_stCurrentSector);
	CDataMs* pDataMs=pSector->GetCurrentDataMs();
//HTTP的用户进行如下处理
	PACKETARRIVALMESSAGE_TYPE * pPacketHead=NULL, * pPacketSecond=NULL;	//pPacketHead指向表头元素,pPacketSecond指向第二个元素
	POSITION pos;
//	if(m_PacketArrivalMessageList.IsEmpty()||m_PacketCallArrivalMessageList.IsEmpty()) return;

	pos=m_PacketArrivalMessageList.GetHeadPosition();
	pPacketHead=m_PacketArrivalMessageList.GetNext(pos);

	PACKETCALLARRIVALMESSAGE_TYPE * pPacketCallHead=NULL;//pPacketHead指向表头元素
	pPacketCallHead=m_PacketCallArrivalMessageList.GetHead();

	if(m_bIsEPGood)
	{
		pPacketHead->iPacketSize-=m_iCurrentPacketSize;				//根据EP递减packet的链表头元素的数据量的大小
		m_lPacketCallDataBits+=m_iCurrentPacketSize;

		if(pPacketHead->iPacketSize<=0)
		{

				m_bIsCurrentPacketOver=true;
			//当前的Packet传输完毕

				if(pos!=NULL)
				{
					pPacketSecond=m_PacketArrivalMessageList.GetAt(pos);
					pPacketSecond->iPacketSize+=pPacketHead->iPacketSize;
				}//表头结点的数据大小减为负数之后表示第二个结点的数据也开始了传输


				int iPDelay;
				iPDelay=m_pMsManager->m_iSlotCurrentNum-pPacketHead->iTimeOfGeneratePacket;
				m_iCurrentPacketDelay=iPDelay;  //记录当前的packet分组时延
				m_fPacketDelay+=(float)iPDelay;		//计算此packet的时延,进行Packet的时延累加
				m_iSuccessfulPacketNum++;		//成功传输的packet数目加一
				if(pPacketHead->bIsPacketCallEnd)
				{
					int iPCDelay;
		
					PACKETCALLARRIVALMESSAGE_TYPE * pPacketCallHead=NULL;
					pPacketCallHead=m_PacketCallArrivalMessageList.GetHead();

					iPCDelay=m_pMsManager->m_iSlotCurrentNum-pPacketCallHead->iTimeOfPCArrival;
					m_fPacketCallDelay+=(float)iPCDelay;	//计算此PC的时延,进行PC的时延累加
					m_iPacketCallNum++;	

					delete m_PacketCallArrivalMessageList.GetHead();
					m_PacketCallArrivalMessageList.RemoveHead();
				//传输PC的数目加一
				}
		}
		else return;
	}
	else
	{
		m_lDataQueueSize-=long(pPacketHead->iPacketSize);//根据表头结点数据量的大小从数据队列中递减数据
		m_iErrorPacketNum++;					//错误传输的packet数目加一
		if(pPacketHead->bIsPacketCallEnd)
		{
			delete m_PacketCallArrivalMessageList.GetHead();
			m_PacketCallArrivalMessageList.RemoveHead();

		}

	}

///删除链表的头元素所指的内存空间
//		if ( m_PacketArrivalMessageList.IsEmpty() ) 	return; 
		delete m_PacketArrivalMessageList.GetHead();
		m_PacketArrivalMessageList.RemoveHead();
}

//先不考虑小区交换
/*
void CDataMs::CSMsgGenerator()
//小区交换消息生成函数  候选集信息更新后,扫描候选集信息数组,
//若有扇区的导频信噪比高于当前传输扇区一定门限且超过一定时间,则发出小区交换消息,加入消息链表。                    
{
//设置临时变量
    float fBestPilotSNR=0.0;	//临时变量,存放当前候选扇区数组中不同于传输扇区的、满足小区交换条件的最好的导频SNR
	int iBestCandidateIndex=0;	//临时变量,存放相应的扇区在数组中的下标
	int iLogicTxCandidateIndex;	//指示‘逻辑传输扇区’在候选扇区数组中的下标
								//所谓逻辑传输扇区是指最近一次数据MS将要进行小区交换的目标扇区

//初始化iLogicTxCandidateIndex
//当CSMsg队列为空时,它就等于当前传输扇区m_iCurrentSectorIndex;
//当CSMsg队列非空时,它应当等于队列中最新的节点所对应的候选扇区下标
	if(m_CellSwitchMessageList.IsEmpty()) iLogicTxCandidateIndex=m_iCurrentSectorIndex;
	else  iLogicTxCandidateIndex=m_CellSwitchMessageList.GetTail()->iCandidateIndex;
	
//对候选集中扇区结构体进行循环(跳过逻辑传输扇区扇区对应的结构体)
	for (int i=0 ; i<6+SectorNumber  ; i++)
	{
		if(i!=iLogicTxCandidateIndex)
		{
			if(10*log10(m_aCandidateSector[i].fPilotSNR/m_aCandidateSector[iLogicTxCandidateIndex].fPilotSNR)>3)
			{
				m_aCandidateSector[i].iStatusTimer++;
				if (m_aCandidateSector[i].iStatusTimer>8)//8为临时设置的时间门限值,还需确定!!!
				{
					if (m_aCandidateSector[i].fPilotSNR>fBestPilotSNR*pow(10,0.1))
					{
						fBestPilotSNR=m_aCandidateSector[i].fPilotSNR;
						iBestCandidateIndex=i;
					}
				}
			}
			else m_aCandidateSector[i].iStatusTimer=0;
		}
	}
	if(fBestPilotSNR>0)
	{
		for (int j=0 ; j<6+SectorNumber ; j++)
		//对候选集中iStatusTimer到时的扇区结构体进行循环(跳过逻辑传输扇区扇区对应的结构体)
		//8为临时设置的时间门限值,还需确定!!!
		{
			if((j!=iLogicTxCandidateIndex) && (m_aCandidateSector[j].iStatusTimer>8)) 
			{
				if(m_aCandidateSector[j].fPilotSNR==fBestPilotSNR)
				//生成扇区交换消息插入CSMsg链表,目标扇区为当前循环的扇区,相应的iStatusTimer=0;
				{
					CELLSWITCHMESSAGE_TYPE* pNewCellSwitchMessage=new CELLSWITCHMESSAGE_TYPE; 
					pNewCellSwitchMessage->iCandidateIndex=j;
					pNewCellSwitchMessage->iWaitTime=m_pMsManager->m_iCellSwitchDelay;
					pNewCellSwitchMessage->stTargetSector=m_aCandidateSector[j].stSectorID;
					m_CellSwitchMessageList.AddTail(pNewCellSwitchMessage);
					m_iCSMsgNum=m_CellSwitchMessageList.GetCount();
					m_aCandidateSector[j].iStatusTimer=0;
				}
				else m_aCandidateSector[j].iStatusTimer--;
			}
		}
	}
} 
			
                                        
bool CDataMs::CSMsgProcess()
//小区交换消息处理函数	扫描消息队列,完成等待时间的递减,同时判断是否有消息到时,到时返回TRUE。                                                                                
	{
    bool bIsTimeOut=false;	//指示是否有到时的CSMsg临时bool变量bIsTimeOut初始化为false
	POSITION pos;
	pos=m_CellSwitchMessageList.GetHeadPosition();
	while(pos!=NULL)
	{
		CELLSWITCHMESSAGE_TYPE* pCMS=m_CellSwitchMessageList.GetNext(pos);
		pCMS->iWaitTime--;
		if(pCMS->iWaitTime<=0)
		{
			pCMS->iWaitTime=0;
			bIsTimeOut=true;
		}
	}
	return bIsTimeOut;
} 
			
void CDataMs::CellSwitch()
//小区交换函数	更新当前传输小区。实际意义是扇区交换SectorSwitch    
{
//找出消息队列队尾中已经到时的CSMsg消息,为队列中对应元素的指针pCMS
//即找出最近到时的小区交换事件
	bool bFlagOfTimeOut=false;			//是否有小区交换事件到时的标志
	CELLSWITCHMESSAGE_TYPE* pCMS;
	POSITION pos;
	pos=m_CellSwitchMessageList.GetTailPosition();
	while(pos!=NULL)
	{
		pCMS=m_CellSwitchMessageList.GetPrev(pos);
		if(pCMS->iWaitTime<=0) 
		{
			bFlagOfTimeOut=true;
			break;
		}
		else continue;
	}

	if(!bFlagOfTimeOut) return;		//如果没有事件到时,则直接退出。

⌨️ 快捷键说明

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