参考文献
[1] 802.11 Wireless Networks: The Definitive Guide, Mattbew S. Gast
[2] Overhaul of IEEE 802.11 Modeling and Simulation in NS-2, Qi Chen, Felix Schmidt-Eisenlohr.
[3] C++ Source codes of NS-2
[4] IEEE Std-2007
[5] 无线局域网(WLAN)——原理,技术与应用,刘乃安
[6] supplement-IEEE Std 802.11b-1999
The CS/CCA procedure is executed while the receiver is turned on and the STA is not currently receiving or transmitting a packet. The CS/CCA procedure is used for two purposes: to detect the start of a network signal that can be received (CS) and to determine whether the channel is clear prior to transmitting a packet (CCA).当当前工作站不处于正在接收或者发送数据包并且接收机打开时,CS/CCA过程会被执行。CS/CCA过程的启动有两个目的:探测网络信号是否可以被开始接收以及当前信道是否空闲从而可以发送数据包。
在IEEE Std 802.11-2007中提到,“ The method of determining CS/CCA is unspecified”,也就是说CS/CCA的方式并没有指定,仅仅给出了它应该实现那些功能。所以下面所给出五种CS/CCA的实现方式是在某些协议(supplement-IEEE Std 802.11b-1999,802.11 Wireless Networks: The Definitive Guide, Mattbew S. Gast)的补充文件里定义的。
一共有五种CS/CCA实现方式,在直接序列物理层中(DSSS PHY):
Mode1,当能量超过能量检测(energy detection, ED)阀值时。它会汇报媒介处于忙碌状态,ED阀值因功率而异。
Mode2,采用这种模式的实现产品必须搜寻真正的DSSS信号,如果检测到,计算信号能量低于检测阀值ED,也会汇报该信道处于忙碌状态。
Mode3,结合了Mode1和Mode2,所检测到的信号必须具备足够的能量,才会向上一层汇报信道处于忙碌状态。
Mode4,实现时Mode4是用来寻找真是信号。一旦被触发,实现Mode4 CCA的产品会开启一个月3.65ms的定时器,如果在定时器结束时还没有发现有效的HR/DSSS信号,媒介就被视为处于闲置状态。3.65ms相当于5.5Mps传送最大可能帧所需时间。
Mode5,结合了Mode4和Mode1,所检测到的信号还必须有相当能量,才能向上层汇报信道处于忙碌状态。
这里注意到,Mode1,Mode2,Mode3用于DSSS PHY,而Mode1,Mode4,Mode5用于HR/DSSS PHY。而在FH PHY,OFDM PHY相关文献中并没有指定,兼容了1和2Mps的DSSS调制(802.11)和5.5与11Mps的CCK调制(802.11b)以及6,12与24Mps的OFDM调制的802.11g只定义了一种CCA模式:除了检测能量的最低阀值,也用了解读信号。在传输时隙开始时,若接收到的功率高于-76dBm的信号,则视为有效信号。CCA与PLCP级的虚拟载波监听(virtual carrier sense)机制整合在一起。接收到PLCP标头时,其后会包括length字段,显示媒介将忙碌多长时间。这段时间内,物理层将持续汇报媒介处于忙碌状态。
物理层数据的接收
物理层 包括两个部分:物理层汇聚过程(Physical Layer Convergence Procedure)子层:直接与MAC接触。起到承上启下的功能。
物理媒体依赖(Phsical Medium Dependent)子层:直接与无线信道接触。将数据通过天线传输以及接收。当然上述的CCA功能显然位于物理层中。
每一次数据的发送都会选择一个特定的调制方式和编码速率,对于一个接收机来说,它必须知道探测到的信号到底是信号还是噪声,这个数据帧到底持续多长这些信息,它才能够成功的接收一个数据帧。
物理层的帧通常会以一个训练序列也作为PLCP前导(Preamble),这个前导码会告知接收机帧的到来。这个前导码之后是PLCP帧头,这个帧头包含调制方式,编码速率,帧长度等等关于数据帧的信息,通常情况下,一个工作站是无法同时进行收发功能的,所以一个工作站只会处于一下三个状态之一:监听信道,发送从MAC层传来的数据帧,或者接收一个数据帧。
当站点监测信道时,它通过使用特定的检波(解调)方式检出已知模式前导码,如果监测出来,接收机就试图对PLCP头进行解码,如果成功解码将随后对PLCP头里duration时间内所到来的射频波进行解调,在这个过程结束之前,接收机将把所有到来的信号看作是属于当前的数据帧,并对他们进行解调。最后将所解调出来的bits传送到MAC层进行CRC校验看数据帧是否已经成功接收。
网络仿真软件对物理层的仿真能力比较弱,下面是我通过阅读ns2的相关源代码所总结的关于802.11 物理层在ns2中是如何实现的。
听说在ns2.23之前是ns2对802.11的物理层的支持比较弱。从2.33开始,NS2正式添加了几个新的802.11模块,其中一个便是由Mercedes-Benz研发部门和Karlsruhe大学联合开发的802.11Ext模块。该模块的主要特点包括:模块化的设计、累计SINR计算、MAC帧捕获能力、支持多种调制机制、物理层跟踪和Nakagami衰减模型等。主要包括ns/mac/mac-802_11Ext.[h, cc]、ns/mac/wireless-phyExt.[h,cc]、ns/mobile/nakagami.[h, cc]和ns/apps/pbc.[h, cc]等。
#ifndef ns_WirelessPhyExt_h
#define ns_WirelessPhyExt_h
#include "phy.h"
#include "propagation.h"
#include "modulation.h"
#include "omni-antenna.h"
#include "mobilenode.h"
#include "timer-handler.h"
#include
#include
enum PhyState {SEARCHING = 0, PreRXing = 1, RXing = 2, TXing = 3};
typedef struct ModulationParam {
int schemeIndex;
char schemeName[10];
double SINR_dB;
double SINR_ratio;
int NDBPS; //Data Bits Per Symbol
} ModulationParam;
const struct ModulationParam modulation_table[4] = {
// mod name SINRdB SINR NDBPS bit
{ 0, "BPSK", 5, 3.1623, 24 }, { 1, "QPSK", 8, 6.3096, 48 }, { 2,
"QAM16", 15, 31.6228, 96 }, { 3, "QAM64", 25, 316.2278, 192 } };
让我们慢慢的来阅读这段代码。
首先是对物理层状态的定义:
enum PhyState {SEARCHING = 0, PreRXing = 1, RXing = 2, TXing = 3};分为搜索,预接收,接收和发送四种状态。
然后是对调制参数的定义:
const struct ModulationParam modulation_table[4] = {
{ 0, "BPSK", 5, 3.1623, 24 },
{ 1, "QPSK", 8, 6.3096, 48 },
{ 2, "QAM16", 15, 31.6228, 96 },
{ 3, "QAM64", 25,316.2278,192 } };
总共这里提供了四种调制方式及其参数。
当物理层处于搜索状态时,物理层检测每一个无线信到上传输的数据帧,如果该数据帧达到一定的信号能量,比如SINR>BPSK threshold,也就说达到了某种调制方式的门限,那么物理层就进入预接收状态。
当物理层处于预接收状态时,实际上这段时间是接收前导码和PLCP头,如果在整个这段时间内,信号的SINR值 都满足门限要求,那么就物理层就进接收状态。如果在这段时间内从信道到来的信号有足够的能量破坏对当前的接收,那么物理层就装入到搜索状态,但是如果后来 的帧有足够的信号强度让物理层更能监听到自己的前导码,那么物理层就会继续处于预接收状态并且重置计数器开始新的数据帧的接收。
当物理层处于接收状态时,物理层接收的是数据帧,物理层会时刻检测到达帧的SINR在整个duration时间内,如果有某个时刻SINR小于调制解调或者编码的要求门限,那么物理层就会在这个地方标记错误。等待接收计数器结束。数据帧就会传递给MAC层,而错误标记的地方直接有CRC校验决定。
上述是在body capture 功能没有打开的时候,这个body capture的开启与否表明的是物理层在接收数据帧的时候能否被后续的帧所打扰从而触发物理层回到预接收状态进行新的前导码和PLCP头的接收。
当物理层收到MAC层的发送命令时,物理层就会转到发送状态,无论此时物理层处于什么状态。当物理层处于发送状态时,从信道中到来的帧都会被丢弃,只是被能力检测模块当作干扰。根据载波监听机制,通常情况下MAC层不会在预接收和接收状态非物理层发出传送命令。MAC层永远不会在物理层处于发送状态的时候发出发送命令。
具体的代码实现如下(节选自 ns2.34wireless-phyExt.cc ):
int WirelessPhyExt::sendUp(Packet *p) {
。。。。。。
。。。。。。
switch (state) {
case TXing:
//物理层正处于发送状态,不能执行接收功能。直接丢弃。
pkt_recvd = discard(p, Pr, "TXB");
setState(TXing);
break;
case SEARCHING:
//物理层处于搜索状态。先通过能力检测模块检测SNR是否达到相关门限,如果达到,那
//么接收前导码,重置物理层状态。开启计时器。
if ((powerMonitor->SINR(Pr)
>= modulation_table[BasicModulationScheme_].SINR_ratio)) {
power_RX = Pr;
pkt_RX=p->copy();
setState(PreRXing);
preRX_Timer.sched(HeaderDuration_); // preamble and PCLP header
break;
} else {
//能量达不到,丢弃该帧
//pkt_recvd =discard(p,Pr,"");
pkt_recvd =discard(p, Pr, "SXB");
setState(SEARCHING);
break;
}
case PreRXing:
//如果物理层处于预接收状态,能量检测模块检测当前接收的帧的SINR是否能够破坏当//前接收,如果不是,忽略带来
if (powerMonitor->SINR(power_RX)
>= modulation_table[BasicModulationScheme_].SINR_ratio) {
//case 4
pkt_recvd = discard(p, Pr, "PXB");
if (PHY_DBG)
log("PCAP 1st SUCC", "");
setState(PreRXing);
break;
} else {
// 否则就重置计时器,开始新帧的接收。
// case 2
pkt_recvd = discard(pkt_RX, power_RX, "PXB");
Packet::free(pkt_RX);
power_RX=0;
preRX_Timer.cancel();
pkt_RX=0;
if (PHY_DBG)
log("PCAP 1st FAIL", "");
if (PreambleCaptureSwitch_) {
//此处描述是否开启了Preamble Capture
if (powerMonitor->SINR(Pr) >= SINR_PreambleCapture_) {
pkt_RX=p->copy();
power_RX =Pr;
if (PHY_DBG)
log("PCAP 2nd SUCC", "");
setState(PreRXing);
preRX_Timer.sched(HeaderDuration_);
break;
} else {
//case 3
pkt_recvd = discard(p, Pr, "PXB");
if (PHY_DBG)
log("PCAP 2nd FAIL", "");
setState(SEARCHING);
break;
}
} else {
pkt_recvd = discard(p, Pr, "PXB");
if (PHY_DBG)
log("PCAP 2nd FAIL N/A", "");
setState(SEARCHING);
break;
}
}
case Rxing:
//同PreRxing
if (powerMonitor->SINR(power_RX) >= SINR_Th_RX) {
//case 8
pkt_recvd = discard(p, Pr, "RXB");
if (PHY_DBG)
log("DCAP 1st SUCC", "");
setState(RXing);
break;
} else {
if (PHY_DBG)
log("DCAP 1st FAIL", "");
HDR_CMN(pkt_RX)->error()=1;
if (DataCaptureSwitch_) {
if (powerMonitor->SINR(Pr) >= SINR_DataCapture_) {
// case 9
rX_Timer.cancel();
discard(pkt_RX, power_RX, "RXB");
pkt_RX=0;
//------ start the prerx of this new packet p---//
pkt_RX=p->copy();
power_RX =Pr;
if (PHY_DBG)
log("DCAP 2nd SUCC", "");
setState(PreRXing);
preRX_Timer.sched(HeaderDuration_);
} else {
// case 10
pkt_recvd = discard(p, Pr, "RXB");
if (PHY_DBG)
log("DCAP 2nd FAIL", "");
setState(RXing);
}
} else {
// case 11
pkt_recvd = discard(p, Pr, "RXB");
if (PHY_DBG)
log("DCAP 2nd FAIL N/A", "");
setState(RXing);
}
break;
}
default:
cout<<"packet arrive from chanel at invalid PHY state"<
exit(-1);
}
}
return 0; // the incoming MAC frame will be freed by phy.cc.
}
需要注意的是,在所有ns2的仿真代码里,up和down直接代表这个函数是接收还是发送,比如针对物理层的函数来说,如果是up的话,那么说明数据帧从信道来,也就是接收。如果是down的话,那么说明数据帧从MAC层来,也就发送。
能量检测模块
现面我们来看看过于上面所提到的能量检测模块。
enum PowerMonitorState {IDLE = 0, BUSY = 1};
struct interf {
double Pt;
double end;
};
class PowerMonitor : public TimerHandler {
public:
PowerMonitor(WirelessPhyExt *);
void recordPowerLevel(double power, double duration);
double getPowerLevel();
void setPowerLevel(double);
double SINR(double Pr);
void expire(Event *); //virtual function, which must be implemented
private:
double CS_Thresh;
double monitor_Thresh;//packet with power > monitor_thresh will be recorded in the monitor
double powerLevel;
WirelessPhyExt * wirelessPhyExt;
list interfList_;
};
能量检测模块对应的是物理层的物理媒体相关(Physical Media Dependent, PMD)子层。PMD是唯一直接与信道中的模拟射频信号相交互的子层。所以接收信号的所有信息都会在这个模块进行处理。能量检测模块跟踪节点所有的噪声和干扰,无论什么时候,如果积累的噪声和干扰达到载波监听的门限,它就会让MAC层改变载波监听状态。应该注意到的是,节点自己的传输也会使节点的载波监听状态是处于忙碌的。
下面我们来仔细解读它的代码实现(节选自ns2.34的wireless-phyExt.cc):
PowerMonitor::PowerMonitor(WirelessPhyExt * phy) {
wirelessPhyExt = phy;
CS_Thresh = wirelessPhyExt->CSThresh_; // monitor_Thresh = CS_Thresh;
monitor_Thresh = wirelessPhyExt->PowerMonitorThresh_;
powerLevel = wirelessPhyExt->noise_floor_; // noise floor is -99dbm
}
这个是构造函数,完成初始化。
void PowerMonitor::recordPowerLevel(double signalPower, double duration) {
// to reduce the number of entries recorded in the interfList
if (signalPower < monitor_Thresh )
return;
interf timerEntry;
timerEntry.Pt = signalPower;
timerEntry.end = Scheduler::instance().clock() + duration;
list:: iterator i;
for (i=interfList_.begin(); i != interfList_.end() && i->end <= timerEntry.end; i++) { }
interfList_.insert(i, timerEntry);
resched((interfList_.begin())->end - Scheduler::instance().clock());
powerLevel += signalPower; // update the powerLevel
if (wirelessPhyExt->getState() == SEARCHING && powerLevel >= CS_Thresh) {
wirelessPhyExt->sendCSBusyIndication();
}
}
double PowerMonitor::getPowerLevel() {
if (powerLevel > wirelessPhyExt->noise_floor_)
return powerLevel;
else
return wirelessPhyExt->noise_floor_;
}
void PowerMonitor::setPowerLevel(double power) {
powerLevel = power;
}
double PowerMonitor::SINR(double Pr) {
if (getPowerLevel()-Pr<=0) {
//cout<<"PowerLevel lower than Pr"<
//char msg[1000];
//sprintf(msg,"PowerLevel %f lower than Pr %f = %f",getPowerLevel()*1e9,Pr*1e9,(getPowerLevel()-Pr));
//wirelessPhyExt->log("PMX",msg);
//exit(-1);
return 0.0; //internal event contention, new msg arrives betweeen the expire of two timers.
}
return Pr/(getPowerLevel()-Pr);
}
void PowerMonitor::expire(Event *) {
double pre_power = powerLevel;
double time = Scheduler::instance().clock();
list:: iterator i;
i=interfList_.begin();
while(i != interfList_.end() && i->end <= time) {
powerLevel -= i->Pt;
interfList_.erase(i++);
}
if (!interfList_.empty())
resched((interfList_.begin())->end - Scheduler::instance().clock());
char msg[1000];
sprintf(msg, "Power: %f -> %f", pre_power*1e9, powerLevel*1e9);
wirelessPhyExt->log("PMX", msg);
// check if the channel becomes idle ( busy -> idle )
if (wirelessPhyExt->getState() == SEARCHING && powerLevel < CS_Thresh) {
wirelessPhyExt->sendCSIdleIndication();
}
}
上述成员函数完成信道的扫描并且向MAC层指示。