📄 cvoicems.cpp
字号:
//////////////////////////////////////////////////////////////////////////
// for Evaluation Project //
// Mobile User Team //
// BUPT Radio Research Center //
//////////////////////////////////////////////////////////////////////////
// //
// CVoiceMs.CPP //
// //
//////////////////////////////////////////////////////////////////////////
// //
// 话音移动台类CVoiceMs的成员函数的声明 //
// //
// //
// Ref. documents: //
// "1xEV-DV仿真程序类的初步定义" //
// //
// Written by: CAI Qi-ming //
// //
// Rev. date: 20010320 (yyyymmdd) //
// //
// What's NEW: //
// //
//////////////////////////////////////////////////////////////////////////
#include "CVoiceMs.h"
#include "systemsim.h"
#include "iostream.h"
#include "sys_random.h"
#include "CMsManager.h"
//////////////////////////////////////////////////////////////////////////
// 构造函数, //
// 将各属性赋予初始值 //
//////////////////////////////////////////////////////////////////////////
CVoiceMs::CVoiceMs()
{
}
//end of CVoiceMs()
//////////////////////////////////////////////////////////////////////////
// 析构函数 //
// 释放内存空间 //
//////////////////////////////////////////////////////////////////////////
CVoiceMs::~CVoiceMs()
{
Clean();
}
//end of ~CVoiceMs()
//////////////////////////////////////////////////////////////////////////
// 话音MS初始化函数 //
// 初始化m_iServiceLength、m_bIsServiceActive //
// 并调用最佳扇区选择函数,计算出最佳扇区, //
// 调用激活集初始化函数,设定激活集 //
// 随机初始化激活集的业务信道功率 //
//////////////////////////////////////////////////////////////////////////
void CVoiceMs::VoiceInitialization()
{
Random R;
float fRand;
fRand=R.Next();
m_fVoiceActiveFactor=m_pMsManager->m_fVoiceActiveFactor;
//话音激活因子初始化
m_iSHOMsgNum=0; //当前软切换消息队列长度初始化
m_iDropTimer=0; //掉话计时器赋初值
m_iUnsatisfiedTimer=0; //不满意计时器赋初值
// m_bIsServiceActive=true; //设置话音激活标志为true
m_iServiceTime=(int)(xExponent(MeanCallLength)*1000/(1.25*16));
//服务时长一直不变(以帧为单位)
m_iServiceLength=480000+INITIALSLOT;//m_iServiceTime*16;
//参数为平均呼叫时长120s(用slot数表示)
m_fMeanC2I=0;
// m_iFwdFrameRate=FULL_RATE; //前向信道帧速率初始化为全速率
m_cFwdMarkovState.initRan(m_iMsID); //Markov状态初始化(入口参数为移动台标号)
// m_fFwdCurrentActiveFactor=1.0; //本slot话音激活因子为1
// m_fFwdLastActiveFactor=1.0; //上一slot话音激活因子为1
if(fRand<0.2921)
{
m_fFwdCurrentActiveFactor=1.0; //本slot话音激活因子为1
m_fFwdLastActiveFactor=1.0; //上一slot话音激活因子为1
m_iFwdFrameRate=FULL_RATE;
}
else if((0.2921<=fRand)&&(fRand<0.3303))
{
m_fFwdCurrentActiveFactor=0.5; //本slot话音激活因子为0.5
m_fFwdLastActiveFactor=0.5; //上一slot话音激活因子为0.5
m_iFwdFrameRate=HALF_RATE;
}
else if((0.3303<=fRand)&&(fRand<0.4029))
{
m_fFwdCurrentActiveFactor=0.25; //本slot话音激活因子为0.25
m_fFwdLastActiveFactor=0.25; //上一slot话音激活因子为0.25
m_iFwdFrameRate=QUARTER_RATE;
}
else
{
m_fFwdCurrentActiveFactor=0.125; //本slot话音激活因子为0.125
m_fFwdLastActiveFactor=0.125; //上一slot话音激活因子为0.125
m_iFwdFrameRate=EIGHTH_RATE;
}
m_bIsSHOOut=false;
//...... added by cqm, Apr.9 .......//
m_fMeanC2IofLastFrame=0;
m_iBadFrameCounter=0;
m_bIsFrameCorrect=true;
bsFrameErrorFlagSet.set(); //初始化为帧全部正确
m_iFERIndicator=0;
m_pfC2IIndex=&(m_pMsManager->m_fC2IIndex[0]); //前向链路C/I指针
switch(int(m_fMsVelocity+1e-6)) //确定功控的目标
{
case 0 :
m_fC2ITarget=-(float)17.4;
m_pfFER=&(m_pMsManager->m_fFER_0[0]); //前向链路FER指针
break;
case 3 :
m_fC2ITarget=-(float)16.45;
m_pfFER=&(m_pMsManager->m_fFER_3[0]);
break;
case 10 :
m_fC2ITarget=-(float)16.8;
m_pfFER=&(m_pMsManager->m_fFER_30[0]);
break;
case 30 :
m_fC2ITarget=-(float)16.8;
m_pfFER=&(m_pMsManager->m_fFER_30[0]);
break;
case 120 :
m_fC2ITarget=-(float)17.;
m_pfFER=&(m_pMsManager->m_fFER_100[0]);
break;
}
//..................................//
ObtainBestSector(); //找出最佳扇区
InitActiveSet(); //初始化激活集
ObtainC2I(); //获得当前时隙的C/I
}
//end of VoiceInitialization()
//////////////////////////////////////////////////////////////////////////
// 激活集初始化函数 //
// 根据最佳基站的导频信噪比,扫描候选集中其他扇区的导频信噪比 //
// 确定激活集扇区、业务信道功率和信噪比 //
//////////////////////////////////////////////////////////////////////////
void CVoiceMs::InitActiveSet()
{ //定义必要的变量
int i,j; //循环所需变量
// int iVoiceNumInSys; //系统中的用户数,单位:个
int iBestSectorIndex; //激活集中最佳基站
float fOrthogonalFactor; //正交因子
float fFastFading;
// float fTempTxPower; //临时发射功率,单位:mw
float fOtherChannelPower; //本扇区其他信道的干扰,单位:mw
float fMaxTrafficPower; //最大业务信道功率,单位:mw
float fMinTrafficPower; //业务信道功率动态范围(最小值)
float fC2ITarget; //目标C/I
//...... added by cqm, Apr.9 ......//
bool bFlag=false;
//.................................//
ACTIVESECTOR_TYPE* pTempActiveSector=NULL; //临时激活扇区指针
m_iActiveSetSize=0; //激活集链表初值是零
//test by cqm
if(m_fBestPilotSNR<-16)
{
m_iServiceLength=16;//等效为服务到时,重新初始化一个(即认为软切换出去了)
m_bIsSHOOut=true;
}
switch(m_iFwdFrameRate)
{
case FULL_RATE : fC2ITarget=/*m_pMsManager->*/m_fC2ITarget;
break;
case HALF_RATE : fC2ITarget=/*m_pMsManager->*/m_fC2ITarget-(float)3.0;
break;
case QUARTER_RATE : fC2ITarget=/*m_pMsManager->*/m_fC2ITarget-(float)6.0;
break;
case EIGHTH_RATE : fC2ITarget=/*m_pMsManager->*/m_fC2ITarget-(float)9.0;
break;
}
// if(m_iMsID==10)
// cout<<"wait"<<endl;
//...... added by cqm, May.22 ......//
for(i=0;i<6+SectorNumber;i++) //对候选扇区进行循环(共九个)
{
if(m_fBestPilotSNR-m_aCandidateSector[i].fPilotSNR==0)
//最佳扇区的导频信噪比和当前扇区的导频信噪比之差小于门限3dB?
{
iBestSectorIndex=i;
if(m_iActiveSetSize<m_pMsManager->m_iActiveSetMaxSize)
//如果激活集未满
{
pTempActiveSector=new ACTIVESECTOR_TYPE;
//产生一个新的激活集结构体
pTempActiveSector->stSectorID=
m_aCandidateSector[i].stSectorID; //扇区标号赋初值
pTempActiveSector->iIndexInCandidate=i;
//在候选集中的标号赋初值
fMaxTrafficPower=
m_pMsManager->m_fMaxFractionOfTrafficPower
*m_pServiceArea->
GetSector(pTempActiveSector->stSectorID)->
GetMaxPower(); //业务信道最大发射功率
for(j=0;j<19*SectorNumber;j++)
if((m_aNeighborSector[j].stSectorID.stCellID.m
==m_aCandidateSector[i].stSectorID.stCellID.m)
&&(m_aNeighborSector[j].stSectorID.stCellID.n
==m_aCandidateSector[i].stSectorID.stCellID.n)
&&(m_aNeighborSector[j].stSectorID.s
==m_aCandidateSector[i].stSectorID.s))
//找到当前候选扇区在相邻集中的位置
{
fC2ITarget=
(float)pow(10,(/*m_pMsManager->*/fC2ITarget/10));
//转化为倍数
fOrthogonalFactor=
m_pServiceArea->GetOrthogonalFactor();
fFastFading=(m_aNeighborSector[j].fFastFading[0]
+m_aNeighborSector[j].fFastFading[1]
+m_aNeighborSector[j].fFastFading[2]
+m_aNeighborSector[j].fFastFading[3])/(float)4;
fOtherChannelPower=
m_pServiceArea->
GetSector(pTempActiveSector->stSectorID)->
GetTxPower()
*m_aNeighborSector[j].fPropagationLoss*fFastFading;
pTempActiveSector->fTrafficPower=
(float)(fC2ITarget*
(m_aCandidateSector[i].fInterferenceFromOtherSector
+fOtherChannelPower*fOrthogonalFactor
+NoisePower)/(m_aNeighborSector[j].fPropagationLoss*fFastFading));
//业务信道发射功率赋初值,公式参考UpAndDown里的公式
if(pTempActiveSector->fTrafficPower>fMaxTrafficPower)
//如果算出来的功率大于功率最大值
pTempActiveSector->fTrafficPower=fMaxTrafficPower;
//则将业务信道功率赋最大值
fMinTrafficPower=
(float)(fMaxTrafficPower
/pow(10,(m_pMsManager->m_fDynamicRangeOfTrafficPower/10)));
//将dB转化为mw
if(pTempActiveSector->fTrafficPower<fMinTrafficPower)
//如果业务信道功率小于最小值
pTempActiveSector->fTrafficPower=fMinTrafficPower;
//就将业务信道功率置为最小值
m_pServiceArea->
GetSector(m_aCandidateSector[i].stSectorID)->
VoicePowerCumulate(pTempActiveSector->fTrafficPower);
//将功率累加进去
break; //计算完后跳出循环
}
pTempActiveSector->fTrafficC2I=/*m_pMsManager->*/10*log10(fC2ITarget);///////////
//下行业务信道C/I赋初值,单位:dB
//(等执行UpdateActiveSet时再计算C/I)
m_ActiveSetList.AddTail(pTempActiveSector);
//将该扇区加入激活集链表
m_aCandidateSector[i].bIsInActive=true;
//该候选扇区是在激活集中
m_iActiveSetSize++;
//更新激活集链表长度
if((pTempActiveSector->stSectorID.stCellID.m!=3)||(pTempActiveSector->stSectorID.stCellID.n!=3))
bFlag=true;
}
else //如果激活集已满
break; //结束循环
}
}
//................................//
for(i=0;i<6+SectorNumber;i++) //对候选扇区进行循环(共九个)
{
if((m_fBestPilotSNR-m_aCandidateSector[i].fPilotSNR<6)&&(iBestSectorIndex!=i)&&(m_aCandidateSector[i].fPilotSNR>-16))
//最佳扇区的导频信噪比和当前扇区的导频信噪比之差小于门限3dB?
{
if(m_iActiveSetSize<m_pMsManager->m_iActiveSetMaxSize)
//如果激活集未满
{
pTempActiveSector=new ACTIVESECTOR_TYPE;
//产生一个新的激活集结构体
pTempActiveSector->stSectorID=
m_aCandidateSector[i].stSectorID; //扇区标号赋初值
pTempActiveSector->iIndexInCandidate=i;
//在候选集中的标号赋初值
fMaxTrafficPower=
m_pMsManager->m_fMaxFractionOfTrafficPower
*m_pServiceArea->
GetSector(pTempActiveSector->stSectorID)->
GetMaxPower(); //业务信道最大发射功率
for(j=0;j<19*SectorNumber;j++)
if((m_aNeighborSector[j].stSectorID.stCellID.m
==m_aCandidateSector[i].stSectorID.stCellID.m)
&&(m_aNeighborSector[j].stSectorID.stCellID.n
==m_aCandidateSector[i].stSectorID.stCellID.n)
&&(m_aNeighborSector[j].stSectorID.s
==m_aCandidateSector[i].stSectorID.s))
//找到当前候选扇区在相邻集中的位置
{
// fC2ITarget=
// (float)pow(10,(/*m_pMsManager->*/m_fC2ITarget/10));
//转化为倍数
fOrthogonalFactor=
m_pServiceArea->GetOrthogonalFactor();
fFastFading=(m_aNeighborSector[j].fFastFading[0]
+m_aNeighborSector[j].fFastFading[1]
+m_aNeighborSector[j].fFastFading[2]
+m_aNeighborSector[j].fFastFading[3])/(float)4;
fOtherChannelPower=
m_pServiceArea->
GetSector(pTempActiveSector->stSectorID)->
GetTxPower()
*m_aNeighborSector[j].fPropagationLoss*fFastFading;
pTempActiveSector->fTrafficPower=
(float)(fC2ITarget*
(m_aCandidateSector[i].fInterferenceFromOtherSector
+fOtherChannelPower*fOrthogonalFactor
+NoisePower)/(m_aNeighborSector[j].fPropagationLoss*fFastFading));
//业务信道发射功率赋初值,公式参考UpAndDown里的公式
if(pTempActiveSector->fTrafficPower>fMaxTrafficPower)
//如果算出来的功率大于功率最大值
pTempActiveSector->fTrafficPower=fMaxTrafficPower;
//则将业务信道功率赋最大值
fMinTrafficPower=
(float)(fMaxTrafficPower
/pow(10,(m_pMsManager->m_fDynamicRangeOfTrafficPower/10)));
//将dB转化为mw
if(pTempActiveSector->fTrafficPower<fMinTrafficPower)
//如果业务信道功率小于最小值
pTempActiveSector->fTrafficPower=fMinTrafficPower;
//就将业务信道功率置为最小值
m_pServiceArea->
GetSector(m_aCandidateSector[i].stSectorID)->
VoicePowerCumulate(pTempActiveSector->fTrafficPower);
//将功率累加进去
break; //计算完后跳出循环
}
pTempActiveSector->fTrafficC2I=/*m_pMsManager->*/10*log10(fC2ITarget);/////////////
//下行业务信道C/I赋初值,单位:dB
//(等执行UpdateActiveSet时再计算C/I)
m_ActiveSetList.AddTail(pTempActiveSector);
//将该扇区加入激活集链表
m_aCandidateSector[i].bIsInActive=true;
//该候选扇区是在激活集中
m_iActiveSetSize++;
//更新激活集链表长度
//...... added by cqm, Apr.9 ......//
if((pTempActiveSector->stSectorID.stCellID.m!=3)||(pTempActiveSector->stSectorID.stCellID.n!=3))
bFlag=true;
//.................................//
}
else //如果激活集已满
break; //结束循环
}
}
//...... added by cqm, Apr.9 ......//
if((bFlag==true)&&(m_iActiveSetSize==1))//如果激活集里面只有一个扇区而且不是(3,3)扇区
{
m_iServiceLength=16;//等效为服务到时,重新初始化一个(即认为软切换出去了)
m_bIsSHOOut=true;
}
//.................................//
// UpdateActiveSet(); //更新激活集(计算C/I)
//由于函数UpdateActiveSet()考虑了话音激活的影响,
//在这里调用会引起程序的错误,而程序现在也引入了初始化的一段时间
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -