umts-phy.cc

00001 /*
00002  * Copyright (c) 2007 Regents of the SIGNET lab, University of Padova.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University of Padova (SIGNET lab) nor the 
00014  *    names of its contributors may be used to endorse or promote products 
00015  *    derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
00018  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
00019  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
00020  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
00021  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00022  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
00023  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
00024  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
00025  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
00026  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
00027  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00030 #include"umts-phy.h"
00031 #include"umts-headers.h"
00032 #include<rng.h>
00033 #include<iostream>
00034 #include<math.h>
00035 #include<ip.h>
00036 
00037 
00038 static class UmtsPhyClass : public TclClass {
00039 public:
00040   UmtsPhyClass() : TclClass("Module/MPhy/UMTS") {}
00041   TclObject* create(int, const char*const*) {
00042     return (new UmtsPhy());
00043   }
00044 } class_UmtsPhy;
00045 
00046 
00047 static class MEUmtsPhyClass : public TclClass {
00048 public:
00049   MEUmtsPhyClass() : TclClass("Module/MPhy/UMTS/ME") {}
00050   TclObject* create(int, const char*const*) {
00051     return (new UmtsPhyME());
00052   }
00053 } class_UmtsPhyME;
00054 
00055 
00056 static class BSUmtsPhyClass : public TclClass {
00057 public:
00058   BSUmtsPhyClass() : TclClass("Module/MPhy/UMTS/BS") {}
00059   TclObject* create(int, const char*const*) {
00060     return (new UmtsPhyBS());
00061   }
00062 } class_UmtsPhyBS;
00063 
00064 
00065 
00066 bool UmtsPhy::mod_initialized = false;
00067 int UmtsPhy::modid = -1;
00068 
00069 int UmtsPhy::code_id_counter = 0;
00070 
00071 
00072 
00073 UmtsPhy::UmtsPhy()
00074   : dl_smask_(0), ul_smask_(0), pcTable_(NULL)
00075 {
00076   bind("chip_rate_",&chip_rate_);
00077   bind("spreading_factor_",&spreading_factor_);
00078   bind("bits_per_symbol_",&bits_per_symbol_);
00079   bind("coding_rate_",&coding_rate_);
00080   bind("coding_type_",&coding_type_);
00081   bind("slot_duration_",&slot_duration_);
00082   bind("code_id_",&code_id_);
00083   bind("PERtarget_",&PERtarget_);
00084   bind("SIRtarget_",&SIRtarget_);
00085   bind("maxTxPower_",&maxTxPower_);
00086   bind("minTxPower_",&minTxPower_);
00087   bind("pcStep_",&pcStep_);
00088   bind("alpha_",&alpha_);
00089   bind("PowerCtrlUpdateCmdAtStartRx_",&PowerCtrlUpdateCmdAtStartRx_);
00090   bind("PowerCtrlReadCmdAtStartRx_",&PowerCtrlReadCmdAtStartRx_);
00091 //   bind("",&);
00092 
00093 
00094   if (!mod_initialized) 
00095     {
00096       modid = MPhy::registerModulationType(UMTS_MODNAME);
00097       mod_initialized = true;
00098     }
00099 
00100   // Get a new code id for this BS/ME
00101   code_id_counter++;
00102   code_id_ = code_id_counter;  
00103 }
00104 
00105 
00106 UmtsPhyBS::UmtsPhyBS()
00107 {
00108   bind("iuccorr_",&iuccorr_);  
00109 }
00110 
00111 
00112 int UmtsPhy::command(int argc, const char*const* argv)
00113 {
00114   //  printf("UmtsPhy::command -- %s (%d)\n", argv[1], argc);
00115   Tcl& tcl = Tcl::instance();
00116 
00117   if(argc == 2)
00118     {  
00119       if(strcasecmp(argv[1], "getDataRate")==0)
00120         {
00121           tcl.resultf("%f",getDataRate());
00122           return TCL_OK;
00123         }
00124       if(strcasecmp(argv[1], "printPktHeaderInfo")==0)
00125         {
00126           std::cout << "PacketHeader/MPhy "
00127                     << sizeof(hdr_MPhy) << " bytes at "
00128                     << hdr_MPhy::offset_ << std::endl;
00129           std::cout << "PacketHeader/UMTSPHY "
00130                     << sizeof(hdr_umtsphy) << " bytes at "
00131                     << hdr_umtsphy::offset_ << std::endl;
00132           std::cout << "PacketHeader/RLC "
00133                     << sizeof(hdr_rlc) << " bytes at "
00134                     << hdr_rlc::offset_ << std::endl;
00135           std::cout << "PacketHeader/CMN "
00136                     << sizeof(hdr_cmn) << " bytes at "
00137                     << hdr_cmn::offset_ << std::endl;
00138           std::cout << "PacketHeader/IP "
00139                     << sizeof(hdr_ip) << " bytes at "
00140                     << hdr_ip::offset_ << std::endl;
00141           std::cout << "size of packet = "
00142                     << Packet::hdrlen_ << " bytes"
00143                     << std::endl;
00144           return TCL_OK;
00145         }
00146     }
00147 
00148   if(argc == 3)
00149     {  
00150       if(strcasecmp(argv[1], "setDownlinkSpectralMask")==0)
00151         {
00152           // dynamic cast returns NULL if object is not of the correct type
00153           dl_smask_ = dynamic_cast<MSpectralMask*> (TclObject::lookup(argv[2]));
00154           if(!dl_smask_)
00155             return TCL_ERROR;
00156           return TCL_OK;
00157         }
00158 
00159       if(strcasecmp(argv[1], "setUplinkSpectralMask")==0)
00160         {
00161           // dynamic cast returns NULL if object is not of the correct type
00162           ul_smask_ = dynamic_cast<MSpectralMask*> (TclObject::lookup(argv[2]));
00163           if(!ul_smask_)
00164             return TCL_ERROR;
00165           return TCL_OK;
00166         }
00167       if(strcasecmp(argv[1], "computeSIRtarget")==0)
00168         {
00169                 int payload = atoi(argv[2]);
00170                 if (payload<=0)
00171                 {
00172                         printf("Error UmtsPhy::command(%s), payload must be greater than 0, not %d\n", argv[1], payload);
00173                         return TCL_ERROR;
00174                 }
00175                 double sinr = 0;
00176                 double ber = sinr2ber(sinr);
00177                 double per = (1 - (pow(1-ber, payload * 8)));
00178                 while(per>PERtarget_)
00179                 {
00180                         sinr = sinr + 0.1;
00181                         ber = sinr2ber(sinr);
00182                         per = (1 - (pow(1-ber, payload * 8)));
00183                 }
00184                 SIRtarget_ = sinr;
00185                 if (debug_>10) 
00186                         printf("UMTS Power Control Algorithm: PERtarget %f -> SIRtarget %f (payload %d)\n", PERtarget_, SIRtarget_, payload);
00187                 return TCL_OK;
00188         }
00189       if(strcasecmp(argv[1], "monitor")==0)
00190         {
00191           int rlcId = atoi(argv[2]);
00192           if (rlcId<0)
00193             {
00194               fprintf(stderr,"UmtsPhy::command(%s), RLC identifier (%d) must be greater than zero\n", argv[1], rlcId);
00195               return TCL_ERROR;
00196             }
00197           addPcEntry(rlcId);
00198           return TCL_OK;
00199         }  
00200   
00201     }
00202 
00203   return MPhy::command(argc, argv);
00204 }
00205 
00206 
00207 void UmtsPhy::addPcEntry(int id)
00208 {
00209   if (debug_>50)
00210     printf("UMTS-PHY: monitor id %d\n", id);
00211 
00212   pcEntry *p = new pcEntry;
00213 
00214   p->id = id;
00215   p->TxPower_ = maxTxPower_;
00216   p->powerUp_ = TRUE;
00217 
00218   p->next_ = NULL;
00219   if (pcTable_==NULL)
00220     {
00221       pcTable_ = p;
00222       return;
00223     }
00224 
00225   // insert in order
00226   pcEntry *q = pcTable_;
00227   pcEntry *last = pcTable_;
00228   while(q!=NULL)
00229     {
00230       if (q->id > id) 
00231         break;
00232       last = q;
00233       q = q->next_;
00234     }
00235   if ((last==q)&&(q==pcTable_))
00236     {
00237       // insert in head
00238       p->next_ = pcTable_;
00239       pcTable_ = p;
00240     }
00241   else
00242     {
00243       last->next_ = p;
00244       p->next_ = q;
00245     }
00246   q = pcTable_;
00247 }
00248 
00249 
00250 pcEntry* UmtsPhy::getPcEntry(int id)
00251 {
00252   pcEntry *q = pcTable_;
00253   while(q!=NULL)
00254     {
00255       if (q->id == id)
00256         {
00257           return q;
00258         }
00259       q = q->next_;
00260     }
00261 
00262   if (debug_)
00263     std::cerr << "ID " << id << " not found in PC table" << endl;
00264   return NULL;
00265 }
00266 
00267 
00268 
00269 void UmtsPhy::pcUpdatePi(Packet* p)
00270 {
00271   hdr_rlc *rh = HDR_RLC(p);
00272   hdr_MPhy* ph = HDR_MPHY(p);
00273 
00274   pcEntry *q = getPcEntry(rh->src_rlc_id_);
00275   q->Pi = ph->Pi;
00276 }
00277 
00278 
00279 void UmtsPhy::pcUpdateCmd(Packet* p)
00280 {
00281   hdr_rlc *rh = HDR_RLC(p);
00282   hdr_MPhy* ph = HDR_MPHY(p);
00283 
00284   pcEntry *q = getPcEntry(rh->src_rlc_id_);
00285   if (q==NULL)
00286     {
00287       if (debug_>2)
00288         fprintf(stderr,"UmtsPhy::pcUpdateCmd() ignoring NULL pcEntry, rlc_id=%d, this_code_id_=%d\n",
00289                 rh->src_rlc_id_,
00290                 code_id_);
00291       return;
00292     }
00293 
00294 
00295   double sinr;
00296 
00297   if (PowerCtrlUpdateCmdAtStartRx_)
00298     { 
00299 
00300 
00301 
00302       sinr =  getPrAfterDeSpreading(p) / (ph->Pn + (q->Pi));
00303     }
00304   else
00305     { 
00306 
00307 
00308       sinr =  ph->Pr / (ph->Pn + (ph->Pi));
00309     }
00310 
00311   if (sinr < SIRtarget_ * pcStep_)
00312     q->powerUp_ = true;
00313   else
00314     q->powerUp_ = false;
00315 
00316   if (debug_>20)
00317     {
00318       printf("UMTS-PHY connection %2d -> %2d has sinr %6.2f SIRtarget %6.2f (Ptx %5.2e) -> %s\n",
00319              rh->src_rlc_id_, 
00320              rh->dst_rlc_id_, 
00321              sinr, 
00322              SIRtarget_, 
00323              ph->Pt,
00324              q->powerUp_ ? "UP" : "DOWN");
00325     }
00326 
00327 }
00328 
00329 
00330 void UmtsPhy::pcReadCmd(Packet* p)
00331 {
00332   hdr_rlc *rh = HDR_RLC(p);
00333   hdr_MPhy* ph = HDR_MPHY(p);
00334   hdr_umtsphy* uh = HDR_UMTSPHY(p);
00335 
00336   pcEntry *q = getPcEntry(rh->src_rlc_id_);
00337   if (q == NULL)
00338     return;  
00339 
00340   double oldTxPower = q->TxPower_;
00341 
00342   // get power control command 
00343   // (before error check since we suppose control channel is more reliable than the data one)
00344   if ((uh->powerUp==TRUE)&&((q->TxPower_*pcStep_)<maxTxPower_))
00345     q->TxPower_ = q->TxPower_ * pcStep_;
00346   if ((uh->powerUp==FALSE)&&((q->TxPower_/pcStep_)>minTxPower_))
00347     q->TxPower_ = q->TxPower_ / pcStep_;
00348 
00349 
00350   if (debug_==-1)
00351     {
00352       printf("UMTS-MAC %d rx pkt at %.6f: PC command %s %s (%e->%e))", 
00353              rh->src_rlc_id_, 
00354              Scheduler::instance().clock(),
00355              uh->data == true ? "DATA" : "CTRL" ,
00356              uh->powerUp == true ? "UP" : "DOWN",
00357              oldTxPower,
00358              q->TxPower_);
00359     }
00360 
00361 }
00362 
00363 
00364 int UmtsPhyME::command(int argc, const char*const* argv)
00365 {
00366   //  printf("UmtsPhy::command -- %s (%d)\n", argv[1], argc);
00367   Tcl& tcl = Tcl::instance();
00368 
00369   if(argc == 2)
00370     {  
00371     //   if(strcasecmp(argv[1], "getSNR")==0)
00372 //      {
00373 //        tcl.resultf("%f",getSNR());
00374 //        return TCL_OK;
00375 //      }
00376 //       if(strcasecmp(argv[1], "getSINR")==0)
00377 //      {
00378 //        tcl.resultf("%f",getSINR());
00379 //        return TCL_OK;
00380 //      }
00381     }
00382 
00383   return UmtsPhy::command(argc, argv);
00384 }
00385 
00386 
00387 
00388 int UmtsPhy::getModulationType(Packet*)
00389 {
00390   assert(mod_initialized);
00391   return modid;
00392 }
00393 
00394 
00395 double  UmtsPhy::getTxDuration(Packet* p)
00396 {
00397   return (slot_duration_);
00398 }
00399 
00400 
00401 
00402 
00403 double UmtsPhy::getTxPower(Packet* p)
00404 {
00405         // read the power level from the power control table
00406         hdr_rlc *rh = HDR_RLC(p);
00407         hdr_MPhy* ph = HDR_MPHY(p);
00408 
00409         pcEntry *q = getPcEntry(rh->dst_rlc_id_);
00410         assert(q);
00411 
00412         if (q == NULL)
00413           {
00414             printf("Error UmtsPhy::getTxPower does not find any entry for RLC id %d\n", rh->src_rlc_id_);
00415             exit(1);
00416           }
00417 
00418         return(q->TxPower_);
00419 }
00420 
00421 
00422 
00423 void UmtsPhyBS::startTx(Packet* p)
00424 {
00425   hdr_umtsphy* uh = HDR_UMTSPHY(p);
00426 
00427   uh->bs_code_id  = code_id_;
00428   uh->direction = DIRECTION_DOWNLINK;
00429 
00430   UmtsPhy::startTx(p);
00431 }
00432 
00433 
00434 void UmtsPhyME::startTx(Packet* p)
00435 {
00436   hdr_umtsphy* uh = HDR_UMTSPHY(p);
00437 
00438   uh->me_code_id  = code_id_;
00439   uh->bs_code_id  = bs_code_id_;
00440   uh->direction = DIRECTION_UPLINK;
00441 
00442   UmtsPhy::startTx(p);
00443 }
00444 
00445 
00446 void UmtsPhy::startTx(Packet* p)
00447 {
00448 
00449   hdr_umtsphy* uh = HDR_UMTSPHY(p);
00450   uh->coding_type  = coding_type_;
00451   uh->coding_rate = coding_rate_;
00452   uh->spreading_factor  = spreading_factor_;
00453   uh->bits_per_symbol = bits_per_symbol_;
00454   // put the power control command
00455   hdr_rlc *rh = HDR_RLC(p);
00456   
00457   pcEntry *q = getPcEntry(rh->dst_rlc_id_);
00458   assert(q);
00459   uh->powerUp = q->powerUp_;
00460 
00461   sendDown(p);
00462 }
00463 
00464 void UmtsPhy::endTx(Packet* p)
00465 {
00466 
00467 }
00468 
00469 
00470 // void UmtsPhyBS::startRx(Packet* p)
00471 // {  
00472 //   /// BS tries to receive packet from all users
00473 
00474 //   hdr_MPhy* ph = HDR_MPHY(p);
00475 //   hdr_umtsphy* uh = HDR_UMTSPHY(p);
00476 
00477 //   assert(uh->direction == DIRECTION_UPLINK);
00478 
00479 //   // need to account for inter-user spreading code correlation
00480 //   ph->Pr = uh->spreading_factor * ph->Pr ;
00481  
00482 //   UmtsPhy::startRx(p);
00483 // }
00484 
00485 
00486 
00487 
00488 
00489 
00490 void UmtsPhy::startRx(Packet* p)
00491 {
00492 
00493   if (PowerCtrlUpdateCmdAtStartRx_)
00494     pcUpdateCmd(p);
00495 
00496   
00497   if (PowerCtrlReadCmdAtStartRx_)
00498     pcReadCmd(p);
00499     
00500 }
00501 
00502 
00503 
00504 void UmtsPhyBS::endRx(Packet* p)
00505 {
00506   hdr_MPhy* ph = HDR_MPHY(p);
00507   hdr_umtsphy* uh = HDR_UMTSPHY(p);
00508 
00509   assert(uh->direction == DIRECTION_UPLINK);
00510 
00511   // need to account for inter-user spreading code correlation
00512   ph->Pr = getPrAfterDeSpreading(p);
00513   ph->Pi = ph->Pi * iuccorr_;
00514   
00515   UmtsPhy::endRx(p);
00516 }
00517 
00518 
00519 
00520 void UmtsPhyME::endRx(Packet* p)
00521 { 
00522   hdr_umtsphy* uh = HDR_UMTSPHY(p); 
00523   hdr_MPhy* ph = HDR_MPHY(p);
00524  
00525   assert(uh->direction == DIRECTION_DOWNLINK);
00526 
00527   if (uh->me_code_id != code_id_)
00528     {
00529       // This packet is not for me
00530         Packet::free(p);
00531         return;
00532     }
00533   else
00534     {
00535       // Packet is for me
00536       // Non-orthogonality of intra-cell interferers and correlation
00537       // of inter-cell codes for Downlink Transmissions should have
00538       // been accounted for by the UmtsCorrelation module      
00539       ph->Pr = getPrAfterDeSpreading(p);
00540 
00541       UmtsPhy::endRx(p);
00542     }
00543 }
00544 
00545 
00546 
00547 void UmtsPhy::endRx(Packet* p)
00548 {
00549   // Note: this method is to be called AT THE END of the endRx() method of each
00550   // derived classes (UmtsPhyBS, UmtsPhyME) 
00551   
00552   if (! PowerCtrlReadCmdAtStartRx_)
00553     pcReadCmd(p);
00554   
00555   if (! PowerCtrlUpdateCmdAtStartRx_)
00556     pcUpdateCmd(p);
00557   
00558   pcUpdatePi(p);
00559   
00560   calculateErrors(p);
00561   
00562   sendUp(p);
00563   
00564 }
00565 
00566 
00567 double UmtsPhyME::getPrAfterDeSpreading(Packet* p)
00568 {
00569   hdr_umtsphy* uh = HDR_UMTSPHY(p); 
00570   hdr_MPhy* ph = HDR_MPHY(p);
00571 
00572   return (uh->spreading_factor * ph->Pr * (1.0/(1.0+alpha_)));
00573 }
00574 
00575 
00576 
00577 double UmtsPhyBS::getPrAfterDeSpreading(Packet* p)
00578 {
00579   hdr_umtsphy* uh = HDR_UMTSPHY(p); 
00580   hdr_MPhy* ph = HDR_MPHY(p);
00581 
00582   return (uh->spreading_factor * ph->Pr);
00583 }
00584 
00585 
00586 
00587 
00588 void UmtsPhy::calculateErrors(Packet* p)
00589 {
00590   hdr_MPhy* ph = HDR_MPHY(p);
00591   hdr_cmn* ch = HDR_CMN(p);
00592 
00593   double sinr = ph->Pr / (ph->Pn + (ph->Pi));
00594   double per = getPacketErrorRate(p, sinr);
00595   double rnd =  RNG::defaultrng()->uniform_double();
00596   ch->error() = rnd <= per;
00597   
00598   if (debug_)     std::cerr << NOW 
00599                             << " PER=" << per 
00600                             << " RND=" << rnd 
00601                             << " ERR=" << ch->error()
00602                             << std::endl;
00603   
00604   
00605 }
00606 
00607 
00608 
00609 double UmtsPhy::getPacketErrorRate(Packet* p, double sinr)
00610 {
00611   hdr_umtsphy* uh = HDR_UMTSPHY(p);
00612   hdr_MPhy* ph = HDR_MPHY(p);
00613 
00614   /* This is the only coding currently supported */
00615   assert(uh->coding_type = CODE_CONVOLUTIONAL);
00616   assert(fabs(uh->coding_rate - 0.5) < 1e-5);
00617 
00618   double ber = sinr2ber(sinr);
00619   int nbits =  getNumBits(p);
00620   double per = (1 - (pow(1-ber, nbits)));
00621 
00622   if (debug_)
00623     std::cerr << NOW
00624               << " SINR=" << sinr 
00625               << " NBITS=" << nbits 
00626               << " BER=" << ber 
00627               << " PER=" << per 
00628               << std::endl;
00629   
00630   return per;
00631 
00632 }
00633 
00634 
00635 double UmtsPhy::sinr2ber(double sinr)
00636 {
00637         return (0.5*erfc(sqrt(pow(sinr, ZETA_CONVOLUTIONAL_ONEHALF))));
00638 }
00639 
00640 
00641 int UmtsPhy::getNumBits(Packet* p)
00642 {
00643   hdr_umtsphy* uh = HDR_UMTSPHY(p);
00644   hdr_MPhy* ph = HDR_MPHY(p);
00645   hdr_cmn* ch = HDR_CMN(p);
00646   return (int)(ch->size()*8);
00647 //   return (int)((chip_rate_  / 
00648 //              (uh->bits_per_symbol * uh->spreading_factor * ph->duration))
00649 //             * uh->coding_rate);
00650 }
00651 
00652 
00653 
00654 double UmtsPhyME::getDataRate()
00655 {
00656   // 
00657   // Result agrees with bit rates for uplink DPDCH 
00658   // as reported in Holma and Toskala, "WCDMA for UMTS", p. 90
00659   assert(spreading_factor_ > 0);
00660   return (chip_rate_ * bits_per_symbol_ * coding_rate_/ spreading_factor_ );
00661 }
00662 
00663 
00664 double UmtsPhyBS::getDataRate()
00665 {
00666   // Maximum bit rate for downlink DPDCH 
00667   // Source: Holma and Toskala, "WCDMA for UMTS", p. 96
00668 
00669   assert(chip_rate_ == 3840000);
00670   assert(bits_per_symbol_ == 2);
00671 
00672   switch (spreading_factor_)
00673     {
00674     case 4:     return (1872000 * coding_rate_);
00675     case 8:     return (912000 * coding_rate_);
00676     case 16:    return (432000 * coding_rate_); 
00677     case 32:    return (210000 * coding_rate_); 
00678     case 64:    return (90000 * coding_rate_);  
00679     case 128:   return (51000 * coding_rate_);  
00680     case 256:   return (24000 * coding_rate_);
00681     case 512:   return (6000 * coding_rate_);
00682     default:    assert(0);
00683     }
00684 }
00685 
00686 // double UmtsPhyME::getSNR()
00687 // {
00688 //   return SNR;
00689 // }
00690 
00691 
00692 // double UmtsPhyME::getSINR()
00693 // {
00694 //   return SINR;
00695 // }

Generated on Wed Nov 26 15:47:29 2008 for NS-MIRACLE library by  doxygen 1.5.2