User Manual, Developers Guide and API Documentation

PhyUser.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002  * WiFiMac                                                                    *
00003  * This file is part of openWNS (open Wireless Network Simulator)
00004  * _____________________________________________________________________________
00005  *
00006  * Copyright (C) 2004-2007
00007  * Chair of Communication Networks (ComNets)
00008  * Kopernikusstr. 16, D-52074 Aachen, Germany
00009  * phone: ++49-241-80-27910,
00010  * fax: ++49-241-80-22242
00011  * email: info@openwns.org
00012  * www: http://www.openwns.org
00013  * _____________________________________________________________________________
00014  *
00015  * openWNS is free software; you can redistribute it and/or modify it under the
00016  * terms of the GNU Lesser General Public License version 2 as published by the
00017  * Free Software Foundation;
00018  *
00019  * openWNS is distributed in the hope that it will be useful, but WITHOUT ANY
00020  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
00021  * A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00022  * details.
00023  *
00024  * You should have received a copy of the GNU Lesser General Public License
00025  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00026  *
00027  ******************************************************************************/
00028 
00029 #include <WIFIMAC/convergence/PhyUser.hpp>
00030 #include <WIFIMAC/convergence/TxDurationSetter.hpp>
00031 #include <WIFIMAC/helper/CholeskyDecomposition.hpp>
00032 
00033 #include <DLL/StationManager.hpp>
00034 
00035 #include <WNS/ldk/fun/FUN.hpp>
00036 #include <WNS/pyconfig/View.hpp>
00037 #include <WNS/logger/Logger.hpp>
00038 #include <WNS/module/Base.hpp>
00039 #include <WNS/ldk/concatenation/Concatenation.hpp>
00040 
00041 #include <boost/numeric/ublas/matrix.hpp>
00042 #include <boost/bind.hpp>
00043 
00044 using namespace wifimac::convergence;
00045 
00046 STATIC_FACTORY_REGISTER_WITH_CREATOR(
00047     wifimac::convergence::PhyUser,
00048     wns::ldk::FunctionalUnit,
00049     "wifimac.convergence.PhyUser",
00050     wns::ldk::FUNConfigCreator);
00051 
00052 PhyUser::PhyUser(wns::ldk::fun::FUN* fun, const wns::pyconfig::View& _config) :
00053     wns::ldk::fu::Plain<PhyUser, PhyUserCommand>(fun),
00054     config(_config),
00055     logger(config.get<wns::pyconfig::View>("logger")),
00056     tune(),
00057     dataTransmission(NULL),
00058     notificationService(NULL),
00059     phyModes(config.getView("myConfig.phyModesDeliverer")),
00060     managerName(config.get<std::string>("managerName")),
00061     txDurationProviderCommandName(config.get<std::string>("txDurationProviderCommandName")),
00062     txrxTurnaroundDelay(config.get<wns::simulator::Time>("myConfig.txrxTurnaroundDelay")),
00063     bfEnabled(config.get<bool>("myConfig.bfEnabled")),
00064     phyUserStatus(receiving),
00065     currentTxCompound(),
00066     lastTxRxTurnaround(0.0)
00067 {
00068     tune.frequency = config.get<double>("myConfig.initFrequency");
00069     tune.bandwidth = config.get<double>("myConfig.initBandwidthMHz");
00070     tune.numberOfSubCarrier = 1;
00071 }
00072 // PhyUser
00073 
00074 
00075 PhyUser::~PhyUser()
00076 {
00077 }
00078 
00079 void PhyUser::onFUNCreated()
00080 {
00081     friends.manager = getFUN()->findFriend<wifimac::lowerMAC::Manager*>(managerName);
00082 } // onFUNCreated
00083 
00084 bool PhyUser::doIsAccepting(const wns::ldk::CompoundPtr& /* compound */) const
00085 {
00086     // we only accept if we are not currently transmitting
00087     return (phyUserStatus != transmitting);
00088 } // isAccepting
00089 
00090 void PhyUser::doSendData(const wns::ldk::CompoundPtr& compound)
00091 {
00092     assure(compound, "sendData called with an invalid compound.");
00093     assure(phyUserStatus != transmitting, "Cannot send data during transmission");
00094 
00095     if(friends.manager->getFrameType(compound->getCommandPool()) != PREAMBLE)
00096     {
00097         // signal tx start to the MAC
00098         this->wns::Subject<ITxStartEnd>::forEachObserver(OnTxStartEnd(compound, start));
00099     }
00100 
00101     wns::simulator::Time frameTxDuration = getFUN()->getCommandReader(txDurationProviderCommandName)->
00102         readCommand<wifimac::convergence::TxDurationProviderCommand>(compound->getCommandPool())->getDuration();
00103 
00104     PhyUserCommand* command = activateCommand(compound->getCommandPool());
00105 
00106     wns::Power defaultTxPower = getDataTransmissionService()->getMaxPowerPerSubband();
00107 
00108     // to schedule the startBroadcast function, we have to indicate to
00109     // boost::bind the correct function, as startBroadcast has two different
00110     // signatures (with number of streams and phyMode). Therefore, we first
00111     // create a variable of the desired function signature type and assign using
00112     // desired member function.  This will resolve the correct function thanks
00113     // to the signature including the argument types.
00114     if(bfEnabled and friends.manager->getReceiverAddress(compound->getCommandPool()).isValid())
00115     {
00116         void (wns::service::phy::ofdma::NonBFTransmission::*fn)(wns::osi::PDUPtr, wns::node::Interface*, int, wns::Power, int) =
00117             &wns::service::phy::ofdma::NonBFTransmission::startUnicast;
00118 
00119         wns::service::dll::UnicastAddress destination = friends.manager->getReceiverAddress(compound->getCommandPool());
00120         wns::node::Interface* n = this->getFUN()->getLayer<dll::ILayer2*>()->getStationManager()->getStationByMAC(destination)->getNode();
00121 
00122         // Now boost::bind can be used to schedue the start of the transmission
00123         wns::simulator::getEventScheduler()->scheduleDelay(
00124             boost::bind(fn,
00125                         this->getDataTransmissionService(),
00126                         compound,
00127                         n,
00128                         0,
00129                         defaultTxPower,
00130                         friends.manager->getPhyMode(compound->getCommandPool()).getNumberOfSpatialStreams()),
00131             0.0);
00132     }
00133     else
00134     {
00135         void (wns::service::phy::ofdma::NonBFTransmission::*fn)(wns::osi::PDUPtr, int, wns::Power, int) =
00136             &wns::service::phy::ofdma::NonBFTransmission::startBroadcast;
00137 
00138         // Now boost::bind can be used to schedue the start of the transmission
00139         wns::simulator::getEventScheduler()->scheduleDelay(
00140             boost::bind(fn,
00141                         this->getDataTransmissionService(),
00142                         compound,
00143                         0,
00144                         defaultTxPower,
00145                         friends.manager->getPhyMode(compound->getCommandPool()).getNumberOfSpatialStreams()),
00146             0.0);
00147     }
00148     // schedule end of transmission similarly
00149     wns::simulator::getEventScheduler()->scheduleDelay(
00150         boost::bind(&wns::service::phy::ofdma::DataTransmission::stopTransmission,
00151                     this->getDataTransmissionService(),
00152                     compound,
00153                     0),
00154         frameTxDuration);
00155 
00156     MESSAGE_SINGLE(NORMAL, logger, "Transmission, rx disabled for " << frameTxDuration);
00157     if(phyUserStatus == txrxTurnaround)
00158     {
00159         setNewTimeout(frameTxDuration);
00160     }
00161     else
00162     {
00163         setTimeout(frameTxDuration);
00164     }
00165     // we are transmitting!
00166     phyUserStatus = transmitting;
00167 
00168     this->currentTxCompound = compound;
00169 
00170 } // doSendData
00171 
00172 void PhyUser::doOnData(const wns::ldk::CompoundPtr& compound)
00173 {
00174     assure(compound, "onData called with an invalid compound.");
00175 
00176     getDeliverer()->getAcceptor(compound)->onData(compound);
00177 } // doOnData
00178 
00179 void PhyUser::doWakeup()
00180 {
00181     assure(false, "PhyUser doWakeup will never be called -- nobody is below");
00182 } // doWakeup
00183 
00184 void PhyUser::onData(wns::osi::PDUPtr pdu, wns::service::phy::power::PowerMeasurementPtr rxPowerMeasurement)
00185 {
00186     assure(wns::dynamicCast<wns::ldk::Compound>(pdu), "not a CompoundPtr");
00187 
00188     if(phyUserStatus != receiving)
00189     {
00190         // During transmission, the receiver is off
00191         return;
00192     }
00193     // FIRST: create a copy instead of working on the real compound
00194     wns::ldk::CompoundPtr compound = wns::staticCast<wns::ldk::Compound>(pdu)->copy();
00195 
00196     if(not getFUN()->getProxy()->commandIsActivated(compound->getCommandPool(), this))
00197     {
00198         // if the phyUserCommand is not activated, the compound was not send
00199         // from a WIFIMAC node!
00200         return;
00201     }
00202 
00203     wns::simulator::Time frameRxDuration = getFUN()->getCommandReader(txDurationProviderCommandName)->
00204         readCommand<wifimac::convergence::TxDurationProviderCommand>(compound->getCommandPool())->getDuration();
00205 
00206     if(lastTxRxTurnaround > (wns::simulator::getEventScheduler()->getTime() - frameRxDuration))
00207     {
00208         // The received frame started BEFORE the last txrxTurnaround -> not readable!
00209         return;
00210     }
00211 
00212     // check if we have enough antennas to receive all streams
00213     unsigned int nss = friends.manager->getPhyMode(compound->getCommandPool()).getNumberOfSpatialStreams();
00214     if(nss > friends.manager->getNumAntennas())
00215     {
00216         MESSAGE_BEGIN(NORMAL, logger, m, "Transmission ");
00217         m << "from " << friends.manager->getTransmitterAddress(compound->getCommandPool());
00218         m << " has " << nss;
00219         m << " spatial streams, but receiver has only " << friends.manager->getNumAntennas() << " antennas -> drop";
00220         MESSAGE_END();
00221         return;
00222     }
00223     else
00224     {
00225         MESSAGE_BEGIN(NORMAL, logger, m, "Transmission ");
00226         m << "from " << friends.manager->getTransmitterAddress(compound->getCommandPool());
00227         m << " has " << nss;
00228         m << " spatial streams, receiver has " << friends.manager->getNumAntennas() << " antennas";
00229         MESSAGE_END();
00230     }
00231 
00232     PhyUserCommand* phyCommand = getCommand(compound->getCommandPool());
00233 
00234     // store measured signal into Command
00235     phyCommand->local.rxPower      = rxPowerMeasurement->getRxPower();
00236     phyCommand->local.interference = rxPowerMeasurement->getInterferencePower();
00237     phyCommand->local.postSINRFactor = rxPowerMeasurement->getPostProcessingSINRFactor();
00238 
00239     this->wns::ldk::FunctionalUnit::onData(compound);
00240 } // onData
00241 
00242 wns::Ratio PhyUser::getExpectedPostSINRFactor(unsigned int nss, unsigned int numRx)
00243 {
00244     assure(numRx >= nss, "Nss must be smaller or equal to numRx");
00245 
00246     double cF = 1.0;
00247 
00248     double mimoCorrelation = 1.0;
00249     if(mimoCorrelation > 0.0)
00250     {
00251         // there is a correlation among the MIMO channels, thus we have a
00252         // correlation factor < 1.0
00253 
00254         // generate covariance matrix
00255         boost::numeric::ublas::matrix<double> m(nss, nss);
00256         for(unsigned int i = 0; i < nss; ++i)
00257         {
00258             for(unsigned int j = 0; j < nss; ++j)
00259             {
00260                 if(i == j)
00261                 {
00262                     m(i,j) = 1;
00263                 }
00264                 else
00265                 {
00266                     m(i,j) = mimoCorrelation;
00267                 }
00268             }
00269         }
00270 
00271         // compute correlation matrix & correlation factor
00272         choleskyDecompose< boost::numeric::ublas::matrix<double> >(m);
00273         cF = m(nss-1, nss-1)*m(nss-1, nss-1);
00274     }
00275 
00276     return( wns::Ratio::from_factor(cF * (static_cast<double>(numRx - nss + 1)) / (static_cast<double>(nss))));
00277 }
00278 
00279 void PhyUser::onTimeout()
00280 {
00281     assure(phyUserStatus != receiving, "Timeout although not transmitting");
00282     if(phyUserStatus == transmitting)
00283     {
00284         // finished transmission, start turnaround
00285         MESSAGE_SINGLE(NORMAL, logger, "Timout, finished transmission");
00286         phyUserStatus = txrxTurnaround;
00287         setTimeout(txrxTurnaroundDelay);
00288 
00289         assure(this->currentTxCompound, "currentTxCompound is NULL");
00290         if(friends.manager->getFrameType(this->currentTxCompound->getCommandPool()) != PREAMBLE)
00291         {
00292             // signal tx end to MAC
00293             MESSAGE_SINGLE(NORMAL, logger, "No preamble -> signal tx end");
00294             this->wns::Subject<ITxStartEnd>::forEachObserver(OnTxStartEnd(this->currentTxCompound, end));
00295         }
00296 
00297         this->currentTxCompound = wns::ldk::CompoundPtr();
00298 
00299         // wakeup: we are ready to transmit another compound
00300         this->getReceptor()->wakeup();
00301         return;
00302     }
00303 
00304     if(phyUserStatus == txrxTurnaround)
00305     {
00306         // finished turnaround, ready to receive
00307         phyUserStatus = receiving;
00308         lastTxRxTurnaround = wns::simulator::getEventScheduler()->getTime();
00309         return;
00310     }
00311 
00312     assure(false, "Unknown phyUserStatus");
00313 }
00314 
00315 void PhyUser::setDataTransmissionService(wns::service::Service* phy)
00316 {
00317     assure(phy, "must be non-NULL");
00318     assureType(phy, wns::service::phy::ofdma::DataTransmission*);
00319     dataTransmission = dynamic_cast<wns::service::phy::ofdma::DataTransmission*>(phy);
00320     dataTransmission->setRxTune(tune);
00321     dataTransmission->setTxTune(tune);
00322 } // setDataTransmissionService
00323 
00324 wns::service::phy::ofdma::DataTransmission* PhyUser::getDataTransmissionService() const
00325 {
00326     assure(dataTransmission, "no ofdma::DataTransmission set. Did you call setDataTransmission()?");
00327     return dataTransmission;
00328 } // getDataTransmissionService
00329 
00330 void PhyUser::setNotificationService(wns::service::Service* phy)
00331 {
00332     assure(phy, "must be non-NULL");
00333     assureType(phy, wns::service::phy::ofdma::Notification*);
00334     notificationService = dynamic_cast<wns::service::phy::ofdma::Notification*>(phy);
00335 
00336     // attach handler (there can be only one)
00337     notificationService->registerHandler(this);
00338 
00339 } // setNotificationService
00340 
00341 wns::service::phy::ofdma::Notification* PhyUser::getNotificationService() const
00342 {
00343     assure(notificationService, "no ofdma::Notification set. Did you call setNotificationService()?");
00344     return notificationService;
00345 } // getNotificationService
00346 
00347 void PhyUser::setFrequency(double frequency)
00348 {
00349     if(dataTransmission == NULL)
00350     {
00351         MESSAGE_SINGLE(NORMAL, logger, "cannot yet set RxFrequency, save for after inialisation");
00352         tune.frequency = frequency;
00353     }
00354     else
00355     {
00356         MESSAGE_SINGLE(NORMAL, logger, "setRxFrequency to f: " << frequency << " MHz");
00357         tune.frequency = frequency;
00358         dataTransmission->setRxTune(tune);
00359         dataTransmission->setTxTune(tune);
00360     }
00361 }
00362 
00363 PhyModeProvider* PhyUser::getPhyModeProvider()
00364 {
00365     return &phyModes;
00366 }
00367 
00368 

Generated on Sun May 27 03:32:05 2012 for openWNS by  doxygen 1.5.5