Multi-rate MAC in ns-2

[ Back to Network Simulator 2 for Wireless Home Page ]


First, an introduction on "how ns-2 handle the 802.11 rate":

There is a file ns-mac.tcl in ./tcl/lib directory, in this file the MAC/802-11 set datarate_ as 1Mb, and basicRate_ as 1Mb. change these two values could change rate.

We have to consider following questions:

Atomic operations:

  1. The sender determine the rate (how??). calculate NAV, assuming ACK use the same rate( or basic rate??). Send DATA
  2. How to let the receiver know the rate? We have to use PLCP header. The SIGNAL field in PLCP header is used for this purpose.
  3. Why the receiver needs to know the rate? because it wants to correct receive it and might send ACK with same rate.
  4. Using Short PLCP? Two major changes, PLCP preamble is 72 instead of 144 bits (still sent with 1Mbps) The PLCP header is sent with 2Mbps.

Control & Feedback for auto-rate

  1. Receiver-based Autorate (RBAR). RTS/CTS is necessary, RTS send with lowest rate (1Mbps), the receiver put something in the CTS to tell the sender use which rate (CTS is still sent with lowest rate)
  2. ARF (auto-rate fallback), for every 2nd ACK miss( transmission failure) following good transmission, fallback to lower rate and set a timer. Whenever the consecutive 10  good transmission or timer expired, upgrade to higher rate. Then, if miss ACK, fallback to lower rate.
  3. Fixed Rate. Assume every node is not moving, the benefits of adaptive autorate is very small. So, for every node pair, we set a fixed rate to follow, either 1,2,5.5,11

Rate .vs. Range

  1. Each rate corresponding to a different transmission range. This is to be reflected.
  2. Carrier-Sense threshold does not change for different rate. So this is a fixed vaue.


  1. set rate
  2. short preamble
  3. receive threshold
  4. AutoRate Scheme 1: ARF

baisc multirate codes (only Implement Feature 1 & 2) (download zip file)
And also, there is 8db SNR difference from the 1Mbps and 11Mbps rate. It means that the 1Mbps frames will be decoded in a distance more than 250 meters.
it is a baisc multirate setting with rate info attached as Pxtinfo txinfo
there is no auto rate selection.

Advanced multirate code:
Implement Feature 1,2 3

Auto multi-rate codes:  (Implement Feature 1,2 3 and a feasible Autorate Scheme)
in addition to basic multirate, auto rate and channel access estimation.
The design is integrated with a new cross-layer MAC design entity which a new structure of Node_Info is involved. (Link to Design of Cross-layer MAC).

For both versions, 6 files need to modified:

in ~/mac directoty:

in ~/common directory

Note that whenever switch from versions of multi-rate to non-mulitrate ns codes, make clean & make due to problems with packet-stamp.h otherwise, "segmentation fault" occurs.
Based on the feature, Modifications are described in detail

Set Rate in TCL for each node:

rate is given in tcl code, and no matter what happens, the node has to use this rate as a fixed value. No matter a received DATA is another rate or not, datarate_ does not change. Only if an auto-rate scheme is in effect.............
getTxrate helps to get the rate info and calculate the timeouts,
setTxrate is only used for autorate..............


#include "wireless-phy.h"
#include "mac-802_11.h"

Mac802_11* macptr;
//Zhibin - To have an access to change rate!

else if (strcmp(argv[1], "change_rate") == 0) {
macptr = (Mac802_11*) ifhead_.lh_first->uptarget();
if (macptr) {
// Keep attention: supposes only 1
// interface present!
fprintf(stderr, "Rate changed to: %d\n\n",\
return TCL_OK;
} else {
fprintf(stderr, "Error.. Mac not found..\n");
return TCL_OK;



Actually, this change might not useful if u don't set it dynamically from tcl file.

in mac-802_11.h

inline double setRate(double newvalue){ return dataRate_ = newvalue;};

Short Preamble header & different rate for ACK/RTS/CTS/DATA

in mac-802_11.h

       // Zhibin- To introduce the short preamble, variables will be bind from ns-default.tcl
u_int32_t ShortPreambleLength;
double ShortPLCPDataRate;
double ShortPLCPHeaderThreshold; // we keep this parameter as part of MIB

inline double getEIFS(double r) {
// see (802.11-1999, 9.2.10)
return(SIFSTime + getDIFS()
+ (8 * getACKlen(r))/PLCPDataRate);
inline double getShortPLCPHeaderThreshold() { return ShortPLCPHeaderThreshold ; }

inline u_int32_t getShortPreambleLength() { return(ShortPreambleLength); }
inline double getShortPLCPDataRate() { return(ShortPLCPDataRate); }
inline u_int32_t getPLCPHeaderLength() { return(PLCPHeaderLength); }

inline u_int32_t getPLCPhdrLen(double r) {
return ((r>ShortPLCPHeaderThreshold )
?((ShortPreambleLength >> 3)+(PLCPHeaderLength >> 3))
:((PreambleLength >> 3)+(PLCPHeaderLength >> 3)));

inline u_int32_t getHdrLen11(double r) {
return(getPLCPhdrLen(r) + sizeof(struct hdr_mac802_11)

inline u_int32_t getRTSlen(double r) {
return(getPLCPhdrLen(r) + sizeof(struct rts_frame));

inline u_int32_t getCTSlen(double r) {
return(getPLCPhdrLen(r) + sizeof(struct cts_frame));

inline u_int32_t getACKlen(double r) {
return(getPLCPhdrLen(r) + sizeof(struct ack_frame));

in ns-default.tcl
Mac/802_11 set ShortPreambleLength_ 72 ;
# DataRate of Short PLCP Header. PLCP preample is always sent at DSSS_PLCPDataRate
Mac/802_11 set ShortPLCPDataRate_ 2.0e6 ;
#-------zhibinwu ----------------
Mac/802_11 set ShortPLCPHeaderThreshold_ 1.0e6;


parent->bind("ShortPreambleLength_", &ShortPreambleLength);
parent->bind("ShortPLCPHeaderThreshold_", &ShortPLCPHeaderThreshold);
parent->bind_bw("ShortPLCPDataRate_", &ShortPLCPDataRate);

Has to assume all ACK and RTS/CTS are in basic rate. Thus, probablay 1mbps,
Change :

 getCTSlen() ----> getRTSlen(basicRate_);
 getRTSlen() ----> getCTSlen(basicRate_);
 getACKlen() ----> getACKlen(basicRate_);
 getEIFS ----> getEIFS(basicRate_);
 getHdrlen11()  ----->getHdrlen11(p->txinfo_.getTxRate())

Mac802_11::txtime(double psz, double drt)

// change wrt Mike's code
// double dsz = psz - PLCP_HDR_LEN;
// int plcp_hdr = PLCP_HDR_LEN << 3;
// double dsz = psz - phymib_.getPLCPhdrLen();
// int plcp_hdr = phymib_.getPLCPhdrLen() << 3;

double dsz = psz - phymib_.getPLCPhdrLen(drt);
int plcp_hdr = phymib_.getPLCPhdrLen(drt) << 3;

int datalen = (int)dsz << 3;
// change wrt Mike's code
// double t = (((double)plcp_hdr)/phymib_->PLCPDataRate) + (((double)datalen)/drt);

// double t = (((double)plcp_hdr)/phymib_.getPLCPDataRate())
// + (((double)datalen)/drt);
double t = 0;
if ( drt >phymib_.getShortPLCPHeaderThreshold() ) {
/* Zhibin - In this case the are sent at 1 Mbps while
* ShortPLCPHeader at 2Mbps and the rest at dataRate_
t = (((double)phymib_.getShortPreambleLength())/(phymib_.getPLCPDataRate())) +
(((double)phymib_.getPLCPHeaderLength())/(phymib_.getShortPLCPDataRate())) +
} else {
t = (((double)plcp_hdr)/phymib_.getPLCPDataRate()) + (((double)datalen)/drt);


Attach and Read Rate information with DATA frame

in packet-stamp.h
 inline double getTxRate() {return txRate;}
inline void setTxRate(double r) {txRate = r;}


Mac802_11::sendDATA(Packet *p)
if((u_int32_t)ETHER_ADDR(dh->dh_ra) != MAC_BROADCAST) {


if((u_int32_t)ETHER_ADDR(dh->dh_ra) != MAC_BROADCAST) {
ch->size() += phymib_.getHdrLen11(dataRate_);
// GgX - Broadcast packets are always sent at basicRate_
ch->size() += phymib_.getHdrLen11(basicRate_);


SNR of different Rates ( Drop packets of higher rate if SNR is low)


IN sendup fucntion, first get the rate information of the packet. ( The default rate is 1M,if unset in MAC layer)

    double rate = p->txinfo_.getTxRate();
int rate_index;
//zhibinwu, find the rate index in rate table
for ( int rate_index=0; rate_index< NUM_RATE_80211b; i++)
if ( rate == RXRate_[rate_index]) break;
if (rate_index==4) printf ("ERROR! RATE NOT FOUND!\N");

if (Pr < RXThresh_[rate_index]) {
* We can detect, but not successfully receive
* this packet.
hdr_cmn *hdr = HDR_CMN(p);
hdr->error() = 1;
#if DEBUG > 3
printf("SM %f.9 _%d_ drop pkt from %d low POWER %e/%e\n",
Scheduler::instance().clock(), node()->index(),

	RXRate_[0]= 1000000;
RXrate_[1]= 2000000;
RxRate_[2]= 5500000;
RxRate_[3]= 11000000;
RXThresh_[0] = 0.1; // receive power threshold (W) for each rate
RXThresh_[1] = 0.2; // receive power threshold (W) for each rate
RXThresh_[2] = 0.3; // receive power threshold (W) for each rate
RXThresh_[3] = 0.4; // receive power threshold (W) for each rate

in wireless-phy.h

#define NUM_RATE_80211b 4;

double RXRate_[NUM_RATE_80211b];
double RXThresh_[NUM_RATE_80211b]; // receive power threshold (W) for each rate


ARF relies on MAC retransmission (set retry limit as 7 will be good)
  1. Define rate array in MAC;
  2. set a varible in MAC to flag miss ACK event.
  3. Set a conunter to counter consecutive transmissions
  4. In retransmit data, downgrade-rate, reset ch->size() and ch->txtime();
  5. In recvACK, prepare upgrade-rate
optRate_[0] = 1000000;
optRate_[1] = 2000000;
optRate_[2] = 5500000;
optRate_[3] = 11000000;

missACK = false;
ACKcounter = 0;

Mac802_11::recvACK(Packet *p)
//zhibinwu ----------ARF----
missACK_ = false;
if ( ACKcounter_ >10 )
//upgrade datarate
int m;
for (m=0;m<4;m++)
if ( optRate_[m] == dataRate_ && m!=3)
dataRate_ = optRate_[m+1];
//printf(" the new datarate is %f\n", dataRate_);
ACKcounter_ = 0;




//zhibinwu's code to do ARF (AutoRate Fallback)
ACKcounter_ = 0; // no successive ACKs
if (missACK_ == false))
missACK_ = true; //first missed ACK does not trigger fallback
else if ( dataRate_ == basicRate_)
//already fallback to lowest
//previous rate is datarate_ as same as getTxRate
ch->size() -= phymib_.getHdrLen11(pktTx_->txinfo_.getTxRate());
// assert pktTx and change size
int m;
for (m=0;m<4;m++)
if ( optRate_[m] == dataRate_ && m!=0)
dataRate_ = optRate_[m-1];
//calculate new size
ch->size() += phymib_.getHdrLen11(dataRate_);
ch->txtime() = txtime(ch->size(), dataRate_);

// =============ARF---end=========



Appendix: PHY Model

In ns-2, the model is TwoRayground. It is for long range. Basically it means the attenuation factor 4 is used instead of 2.

Pr =   PtGtGrht2hr2 / (Ld4)

The original setting is:

Tx Power
0.2818W  (24.5dbm)

1.559e-11 W (-102.5db) 
3.652e-10 W (-91.1db) 250m
((3.652/1.559)*10)^0.25 =2.2
2.2*250 = 550

Modified model for 802.11b
0.031622777 W (15dbm) Rate
 -100dbm (1e-13 W)

-94dbm    3.9811e-13 W 
RxThreshold[1] -91dbm   7.9433e-13W
RxThreshold[2] -87dbm   1.9953e-12  W
RxThreshold[3] -82dbm   6.3096e-12  W