User Manual, Developers Guide and API Documentation

Strategy.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002  * This file is part of openWNS (open Wireless Network Simulator)
00003  * _____________________________________________________________________________
00004  *
00005  * Copyright (C) 2004-2009
00006  * Chair of Communication Networks (ComNets)
00007  * Kopernikusstr. 5, D-52074 Aachen, Germany
00008  * phone: ++49-241-80-27910,
00009  * fax: ++49-241-80-22242
00010  * email: info@openwns.org
00011  * www: http://www.openwns.org
00012  * _____________________________________________________________________________
00013  *
00014  * openWNS is free software; you can redistribute it and/or modify it under the
00015  * terms of the GNU Lesser General Public License version 2 as published by the
00016  * Free Software Foundation;
00017  *
00018  * openWNS is distributed in the hope that it will be useful, but WITHOUT ANY
00019  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
00020  * A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00021  * details.
00022  *
00023  * You should have received a copy of the GNU Lesser General Public License
00024  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00025  *
00026  ******************************************************************************/
00027 
00028 #include <WNS/scheduler/CallBackInterface.hpp>
00029 #include <WNS/scheduler/RegistryProxyInterface.hpp>
00030 #include <WNS/scheduler/strategy/Strategy.hpp>
00031 #include <WNS/scheduler/strategy/StrategyInterface.hpp>
00032 #include <WNS/PowerRatio.hpp>
00033 
00034 using namespace wns::scheduler;
00035 using namespace wns::scheduler::strategy;
00036 
00037 Strategy::Strategy(const wns::pyconfig::View& config)
00038     : colleagues(),
00039       friends(),
00040       pyConfig(config),
00041       logger(config.get("logger"))
00042 {
00043     simTimeType symbolDuration = config.get<double>("symbolDuration");
00044     bool txMode = config.get<bool>("txMode"); // Python parameter
00045     bool excludeTooLowSINR = config.get<bool>("excludeTooLowSINR");
00046     bool powerControlSlave = config.get<bool>("powerControlSlave");
00047     PowerControlType powerControlType;
00048 
00049     MESSAGE_SINGLE(NORMAL, logger,"Strategy=" 
00050         << config.get<std::string>("nameInStrategyFactory"));
00051 
00052     // there are three positions for the scheduler...
00053     if (txMode && !powerControlSlave) 
00054     {
00055         // 1.) BS.Tx (DL) -> power from Python (myself)
00056         powerControlType = PowerControlDLMaster;
00057     } 
00058     else if(!txMode && !powerControlSlave) 
00059     {
00060         // 2.) BS.Rx (UL) -> power from Python (user)
00061         powerControlType = PowerControlULMaster;
00062     } 
00063     else if(txMode && powerControlSlave) 
00064     {
00065         // 3.) UT.Tx (UL) -> power from masterBurst
00066         powerControlType = PowerControlULSlave;
00067     } 
00068     else 
00069     {
00070         assure(0,"invalid case for powerControlType: txMode="
00071             << txMode <<", powerControlSlave=" << powerControlSlave);
00072         throw wns::Exception("invalid case for powerControlType");
00073     }
00074     getNewSchedulerState();
00075     schedulerState->symbolDuration = symbolDuration;
00076     schedulerState->isTx = txMode;
00077     schedulerState->powerControlType = powerControlType;
00078     schedulerState->excludeTooLowSINR = excludeTooLowSINR; 
00079 }
00080 
00081 Strategy::~Strategy()
00082 {
00083     if (colleagues.apcstrategy) 
00084         delete colleagues.apcstrategy;
00085     if (colleagues.dsastrategy) 
00086         delete colleagues.dsastrategy;
00087     if (colleagues.dsafbstrategy) 
00088         delete colleagues.dsafbstrategy;
00089 
00090     // delete SchedulerState:
00091     if (schedulerState) 
00092     {
00093         if (schedulerState->currentState) 
00094         {
00095             schedulerState->clearMap();
00096             if (schedulerState->currentState->strategyInput) 
00097             {
00098                 schedulerState->currentState->strategyInput = NULL;
00099             }
00100             if (schedulerState->currentState->channelQualitiesOfAllUsers) 
00101             {
00102                 schedulerState->currentState->channelQualitiesOfAllUsers = ChannelQualitiesOfAllUsersPtr();
00103             }
00104             if (schedulerState->currentState->schedulingMap) 
00105             {
00106                 schedulerState->currentState->schedulingMap = SchedulingMapPtr(); 
00107             }
00108             if (schedulerState->currentState->bursts) 
00109             {
00110                 schedulerState->currentState->bursts = MapInfoCollectionPtr();
00111             }
00112             schedulerState->currentState->strategyInput = NULL;
00113             schedulerState->currentState = RevolvingStatePtr(); 
00114         }
00115         schedulerState = SchedulerStatePtr(); 
00116     }
00117 }
00118 
00119 void
00120 Strategy::setColleagues(queue::QueueInterface* _queue,
00121                         grouper::GroupingProviderInterface* _grouper,
00122                         RegistryProxyInterface* _registry,
00123                         wns::scheduler::harq::HARQInterface* _harq
00124     )
00125 {
00126     MESSAGE_SINGLE(NORMAL, logger,"Strategy::setColleagues(): creating DSA/APC strategies...");
00127     colleagues.queue = _queue;
00128     colleagues.grouper = _grouper;
00129     colleagues.registry = _registry;
00130     colleagues.harq = _harq; 
00131 
00132     assure(dynamic_cast<queue::QueueInterface*>(colleagues.queue), "Need access to the queue");
00133     assure(dynamic_cast<grouper::GroupingProviderInterface*>(colleagues.grouper), "Need access to the grouper");
00134     assure(dynamic_cast<RegistryProxyInterface*>(colleagues.registry), "Need access to the registry");
00135 
00136     std::string apcstrategyName   = pyConfig.get<std::string>("apcstrategy.nameInAPCStrategyFactory");
00137     std::string dsastrategyName   = pyConfig.get<std::string>("dsastrategy.nameInDSAStrategyFactory");
00138     std::string dsafbstrategyName = pyConfig.get<std::string>("dsafbstrategy.nameInDSAStrategyFactory");
00139 
00140     MESSAGE_SINGLE(NORMAL, logger,"dsastrategy   = "<<dsastrategyName);
00141     MESSAGE_SINGLE(NORMAL, logger,"dsafbstrategy = "<<dsafbstrategyName);
00142     MESSAGE_SINGLE(NORMAL, logger,"apcstrategy   = "<<apcstrategyName);
00143 
00144     // create the scheduling dsastrategy
00145     wns::scheduler::strategy::dsastrategy::DSAStrategyCreator* dsastrategyCreator;
00146     dsastrategyCreator = wns::scheduler::strategy::dsastrategy::DSAStrategyFactory::creator(dsastrategyName);
00147     colleagues.dsastrategy = dsastrategyCreator->create(pyConfig.get<wns::pyconfig::View>("dsastrategy"));
00148     assure(colleagues.dsastrategy, "DSAStrategy module creation failed");
00149 
00150     // create the scheduling dsafallbackstrategy
00151     wns::scheduler::strategy::dsastrategy::DSAStrategyCreator* dsafbstrategyCreator;
00152     dsafbstrategyCreator = wns::scheduler::strategy::dsastrategy::DSAStrategyFactory::creator(dsafbstrategyName);
00153     colleagues.dsafbstrategy = dsafbstrategyCreator->create(pyConfig.get<wns::pyconfig::View>("dsafbstrategy"));
00154     assure(colleagues.dsafbstrategy, "DSAfbStrategy module creation failed");
00155 
00156     // create the scheduling apcstrategy
00157     wns::scheduler::strategy::apcstrategy::APCStrategyCreator* apcstrategyCreator;
00158     apcstrategyCreator = wns::scheduler::strategy::apcstrategy::APCStrategyFactory::creator(apcstrategyName);
00159     colleagues.apcstrategy = apcstrategyCreator->create(pyConfig.get<wns::pyconfig::View>("apcstrategy"));
00160     assure(colleagues.apcstrategy, "APCStrategy module creation failed");
00161 
00162     assure(colleagues.dsastrategy != NULL, "dsastrategy = NULL");
00163     assure(colleagues.dsafbstrategy != NULL, "dsafbstrategy = NULL");
00164     assure(colleagues.apcstrategy != NULL, "apcstrategy = NULL");
00165 
00166     colleagues.dsastrategy->setColleagues(colleagues.registry);
00167     colleagues.dsafbstrategy->setColleagues(colleagues.registry);
00168     colleagues.apcstrategy->setColleagues(colleagues.registry);
00169 
00170     assure(schedulerState!=SchedulerStatePtr(),"schedulerState must be valid");
00171     bool useCQI = colleagues.registry->getCQIAvailable();
00172     schedulerState->useCQI = useCQI;
00173     schedulerState->myUserID = colleagues.registry->getMyUserID();
00174 
00175     assure(!colleagues.dsafbstrategy->requiresCQI(),"dsafbstrategy must never require CQI");
00176     assure(useCQI || !colleagues.dsastrategy->requiresCQI(),"dsastrategy requires CQI");
00177     assure(useCQI || !colleagues.apcstrategy->requiresCQI(),"apcstrategy requires CQI");
00178 
00179     // calls method of derived class for initialization
00180     this->onColleaguesKnown(); 
00181 } // setColleagues
00182 
00183 void
00184 Strategy::onColleaguesKnown()
00185 {
00186     MESSAGE_SINGLE(NORMAL, logger,"Strategy::onColleaguesKnown()");
00187 }
00188 
00189 void
00190 Strategy::setFriends(wns::service::phy::ofdma::BFInterface* _ofdmaProvider)
00191 {
00192     friends.ofdmaProvider = _ofdmaProvider;
00193     assure(friends.ofdmaProvider != NULL, "ofdmaProvider==NULL => eirpLimited undefined");
00194     assure(schedulerState!=SchedulerStatePtr(),"schedulerState must be valid");
00195 
00196     bool eirpLimited = friends.ofdmaProvider->isEIRPLimited();
00197     schedulerState->eirpLimited = eirpLimited;
00198 
00199     assure(colleagues.registry!=NULL,"colleagues.registry==NULL");
00200 
00201     bool isDL = colleagues.registry->getDL(); 
00202     if ((isDL == true) && (schedulerState->isTx == false)) 
00203     {
00204         MESSAGE_SINGLE(NORMAL, logger,"Strategy::setFriends(): misconfiguration: isDL="
00205             << isDL << ", isTx=" << schedulerState->isTx);
00206 
00207         // workaround for WiMAC where registry->getDL() is not implemented
00208         isDL = false; 
00209     }
00210     schedulerState->isDL = isDL;
00211     assure((isDL && (schedulerState->powerControlType == PowerControlDLMaster)) || !isDL,
00212             logger.getLoggerName() << ": invalid: powerControlType="
00213             << schedulerState->powerControlType 
00214             << ",isDL=" << isDL << ",isTx="
00215             << schedulerState->isTx);
00216 
00217     // there are three positions for the scheduler...
00218     wns::scheduler::SchedulerSpotType schedulerSpot;
00219     if (isDL && schedulerState->isTx ) 
00220     {
00221         schedulerSpot = wns::scheduler::SchedulerSpot::DLMaster();
00222         assure(canHandleDL(), "DLMaster");
00223     } 
00224     else if(!isDL && !schedulerState->isTx ) 
00225     {
00226         schedulerSpot = wns::scheduler::SchedulerSpot::ULMaster();
00227         assure(canHandleUL(), "ULMaster");
00228     } 
00229     else if(!isDL && schedulerState->isTx ) 
00230     {
00231         schedulerSpot = wns::scheduler::SchedulerSpot::ULSlave();
00232         assure(canBeSlave(), "ULSlave scheduler needs SlaveAspect of strategy");
00233         assure(!schedulerState->useCQI,"cannot useCQI in slave scheduler");
00234     } 
00235     else 
00236     {
00237         assure(0,"invalid case for schedulerSpot: isDL="<<isDL<<", isTx="<<schedulerState->isTx);
00238         throw wns::Exception("invalid case for schedulerSpot");
00239     }
00240     schedulerState->schedulerSpot = schedulerSpot;
00241 
00242     MESSAGE_SINGLE(NORMAL, logger,"Strategy::setFriends(): isDL="
00243         << isDL <<", isTx=" << schedulerState->isTx
00244         << ", schedulerSpot=" << wns::scheduler::SchedulerSpot::toString(schedulerSpot)
00245         << ", useCQI=" << schedulerState->useCQI);
00246 } // setFriends
00247 
00248 SchedulerStatePtr
00249 Strategy::getNewSchedulerState()
00250 {
00251     MESSAGE_SINGLE(NORMAL, logger,"Strategy::getNewSchedulerState()");
00252 
00253     assure(schedulerState==SchedulerStatePtr(),
00254         "schedulerState must be empty before making a new one");
00255 
00256     schedulerState = SchedulerStatePtr(new SchedulerState(this));
00257 
00258     assure(schedulerState!=SchedulerStatePtr(),"schedulerState must be valid");
00259 
00260     return schedulerState;
00261 }
00262 
00263 SchedulerStatePtr
00264 Strategy::revolveSchedulerState(const StrategyInput& strategyInput)
00265 {
00266     assure(schedulerState != SchedulerStatePtr(),"schedulerState must be valid");
00267     assure(colleagues.registry != NULL,"registry == NULL");
00268     assure(&strategyInput != NULL,"strategyInput == NULL");
00269 
00270     schedulerState->currentState = RevolvingStatePtr(new RevolvingState(&strategyInput));
00271     return schedulerState;
00272 }
00273 
00274 SchedulerStatePtr
00275 Strategy::getSchedulerState()
00276 {
00277     assure(schedulerState != SchedulerStatePtr(),"schedulerState must be valid");
00278     return schedulerState;
00279 }
00280 
00281 MapInfoCollectionPtr
00282 Strategy::getMapInfo() const 
00283 {
00284     // if startScheduling has never been called but mapHandler calls getMapInfo(): return empty
00285     if (schedulerState->currentState==wns::scheduler::strategy::RevolvingStatePtr())
00286         return MapInfoCollectionPtr(new MapInfoCollection);
00287 
00288     MapInfoCollectionPtr bursts = schedulerState->currentState->bursts; 
00289 
00290     assure(bursts!=MapInfoCollectionPtr(),"bursts must not be NULL here");
00291 
00292     return bursts;
00293 }
00294 
00295 wns::scheduler::PowerCapabilities
00296 Strategy::getPowerCapabilities(const UserID user) const
00297 {
00298     /* This method changes the state "schedulerState->powerCapabilities".
00299        This is good and ok if all users are the same (default of all systems),
00300        but if they are different (future), APC must call this function anytime.
00301     */
00302     switch (schedulerState->powerControlType)
00303     {
00304         case PowerControlDLMaster:
00305         {
00306             schedulerState->powerCapabilities = 
00307                 colleagues.registry->getPowerCapabilities(); 
00308             break;
00309         }
00310         case PowerControlULMaster:
00311         {
00312             // peer unknown. Assume peer=UT.
00313             if (!user.isValid()) 
00314             { 
00315                 MESSAGE_SINGLE(NORMAL, logger, "getPowerCapabilities(NULL): asking registry...");
00316                 schedulerState->powerCapabilities = colleagues.registry->getPowerCapabilities(user); 
00317 
00318                 MESSAGE_SINGLE(NORMAL, logger, "getPowerCapabilities(NULL): nominal="
00319                     << schedulerState->powerCapabilities.nominalPerSubband);
00320 
00321                 return schedulerState->powerCapabilities;
00322             }
00323             schedulerState->powerCapabilities = colleagues.registry->getPowerCapabilities(user); 
00324             break;
00325         }
00326         case PowerControlULSlave:
00327         {
00328             if (schedulerState->defaultTxPower!=wns::Power()) 
00329             {
00330                 // don't use powerCapabilities but masterBurst instead
00331                 assure(schedulerState->defaultTxPower!=wns::Power(),"undefined defaultTxPower");
00332                 schedulerState->powerCapabilities.nominalPerSubband = schedulerState->defaultTxPower;
00333                 schedulerState->powerCapabilities.maxPerSubband = schedulerState->defaultTxPower;
00334                 // limit not used for slave
00335                 schedulerState->powerCapabilities.maxOverall = schedulerState->defaultTxPower * 1000.0; 
00336             } 
00337             // not given (by masterBurst) because there is an InputSchedulingMap (new method)
00338             else 
00339             { 
00340                 assure(schedulerState->currentState->strategyInput->inputSchedulingMap != wns::scheduler::SchedulingMapPtr(), 
00341                     "need inputSchedulingMap with txPower information");
00342 
00343             // the power settings in inputSchedulingMap can be overwritten
00344             // if APC strategy is changed to use nominal power. Therefore we need these values:
00345             schedulerState->powerCapabilities = colleagues.registry->getPowerCapabilities(); 
00346             }
00347             break;
00348         }
00349         default:
00350         {
00351             throw wns::Exception("invalid powerControlType");
00352         }
00353     } // switch(powerControlType)
00354     if (user.isValid()) 
00355     {
00356         MESSAGE_SINGLE(NORMAL, logger, "getPowerCapabilities("
00357             << user.getName() << "): nominal="
00358             << schedulerState->powerCapabilities.nominalPerSubband);
00359 
00360     } 
00361     else 
00362     {
00363         MESSAGE_SINGLE(NORMAL, logger, "getPowerCapabilities(NULL): nominal="
00364             << schedulerState->powerCapabilities.nominalPerSubband);
00365     }
00366     assure(schedulerState->powerCapabilities.nominalPerSubband != wns::Power(),
00367         "undefined power nominalPerSubband="<<schedulerState->powerCapabilities.nominalPerSubband);
00368 
00369     return schedulerState->powerCapabilities;
00370 }
00371 
00372 // perform master scheduling
00373 StrategyResult 
00374 Strategy::startScheduling(const StrategyInput& strategyInput)
00375 {
00376     if (strategyInput.fChannels  < 1)          
00377         throw wns::Exception("Need at least one subBand");
00378 
00379     if (strategyInput.slotLength < 0.0)        
00380         throw wns::Exception("Invalid slotLength");
00381 
00382     if (strategyInput.slotLength < schedulerState->symbolDuration)    
00383         throw wns::Exception("Can't schedule on slot shorter than OFDM symbol");
00384 
00385     if (strategyInput.numberOfTimeSlots < 1)   
00386         throw wns::Exception("Need at least one TimeSlot");
00387 
00388     // strategyInput.maxSpatialLayers > 1 means SDMA or MIMO
00389     if (strategyInput.maxSpatialLayers   < 1)          
00390         throw wns::Exception("Need at least one spatialLayer");
00391 
00392     assure(isNewStrategy() || strategyInput.beamforming || strategyInput.maxSpatialLayers == 1,
00393            "beamforming=" << strategyInput.beamforming
00394             << " && maxSpatialLayers="
00395             << strategyInput.maxSpatialLayers
00396             << ": MIMO not supported in old strategies");
00397 
00398     // prepare a new state for this timeFrame:
00399     schedulerState = revolveSchedulerState(strategyInput);
00400 
00401     // master scheduling on freshly created empty resources
00402     // the fresh Scheduling Map (empty and free) is prepared in the RevolvingStatePtr() constructor
00403     if (strategyInput.inputSchedulingMap == wns::scheduler::SchedulingMapPtr()) 
00404     { 
00405         MESSAGE_SINGLE(NORMAL, logger, "inputSchedulingMap is empty");
00406         
00407     } 
00408     // slave scheduling or preallocated SchedulingMap 
00409     else 
00410     { 
00411         MESSAGE_SINGLE(NORMAL, logger, "inputSchedulingMap exists: "
00412             << strategyInput.inputSchedulingMap->toString());
00413 
00414         assure(schedulerState->currentState->schedulingMap != wns::scheduler::SchedulingMapPtr(),
00415             "schedulingMap initialization failed");
00416         assure(schedulerState->currentState->schedulingMap == strategyInput.inputSchedulingMap,
00417             "schedulingMap must be set in revolveSchedulerState()");
00418     }
00419     wns::scheduler::SchedulingMapPtr schedulingMap = schedulerState->currentState->schedulingMap; // alias
00420 
00421     // master scheduling
00422     if (schedulerState->schedulerSpot != wns::scheduler::SchedulerSpot::ULSlave())
00423     { 
00424         assure(strategyInput.mapInfoEntryFromMaster == MapInfoEntryPtr(),"mapInfoEntryFromMaster must be NULL");
00425 
00426         MESSAGE_BEGIN(NORMAL, logger, m, "startScheduling(master): ");
00427         if (strategyInput.frameNrIsValid())
00428             m << "frameNr=" << strategyInput.frameNr << ", ";
00429             m << "fChannels="   << strategyInput.fChannels
00430             << ", maxSpatialLayers="   << strategyInput.maxSpatialLayers
00431             << ", slotLength=" << strategyInput.slotLength;
00432         MESSAGE_END();
00433 
00434         // not necessary but these defaults may be optionally provided by the caller:
00435         // may be undefined (NULL) in most cases
00436         schedulerState->setDefaultPhyMode(strategyInput.defaultPhyModePtr); 
00437         // may be undefined (0.0) in most cases
00438         schedulerState->setDefaultTxPower(strategyInput.defaultTxPower); 
00439 
00440         // only if master and beamforming
00441         // grouping needed for beamforming & its antenna pattern
00442         if (groupingRequired() && !colleagues.queue->isEmpty())
00443         {   
00444             GroupingPtr sdmaGrouping = GroupingPtr(new Grouping());
00445             UserSet allUsers;
00446             allUsers = colleagues.queue->getQueuedUsers();
00447             UserSet activeUsers = colleagues.registry->filterReachable(allUsers, strategyInput.getFrameNr());
00448             if (schedulerState->isTx) // transmitter grouping
00449             {
00450                 MESSAGE_SINGLE(NORMAL, logger, "StartScheduling(): get TxGrouping");
00451                 sdmaGrouping = colleagues.grouper->getTxGroupingPtr(activeUsers, strategyInput.maxSpatialLayers);
00452             } 
00453             // receiver grouping
00454             else 
00455             {
00456                MESSAGE_SINGLE(NORMAL, logger, "StartScheduling(): get RxGrouping");
00457                sdmaGrouping = colleagues.grouper->getRxGroupingPtr(activeUsers, strategyInput.maxSpatialLayers);
00458             }
00459             schedulerState->currentState->setGrouping(sdmaGrouping);
00460 
00461             assure(schedulerState->currentState->getGrouping() == sdmaGrouping,"invalid grouping");
00462 
00463             MESSAGE_SINGLE(NORMAL, logger, "StartScheduling(): Number of Groups = " << sdmaGrouping->groups.size());
00464             MESSAGE_SINGLE(NORMAL, logger, "StartScheduling(): grouping.getDebugOutput = " << sdmaGrouping->getDebugOutput());
00465         } 
00466         else 
00467         {
00468             MESSAGE_SINGLE(VERBOSE, logger, "StartScheduling(): no grouping required.");
00469         }
00470     
00471     } 
00472     // slave scheduling
00473     else 
00474     { 
00475         // two ways of master input:
00476         // 1. old way: mapInfoEntryFromMaster
00477         // 2. new way: inputSchedulingMap
00478         if (strategyInput.mapInfoEntryFromMaster != MapInfoEntryPtr()) 
00479         {
00480             assure(strategyInput.mapInfoEntryFromMaster != MapInfoEntryPtr(),"mapInfoEntryFromMaster must be non-NULL");
00481 
00482             MESSAGE_SINGLE(NORMAL, logger,"startScheduling(slave): fChannels="
00483                 << strategyInput.fChannels
00484                 << ", subBand=" 
00485                 << strategyInput.mapInfoEntryFromMaster->subBand);
00486 
00487             MESSAGE_SINGLE(NORMAL, logger,"PhyMode="
00488                 << *(strategyInput.mapInfoEntryFromMaster->phyModePtr)
00489                 << ", txPower=" << strategyInput.mapInfoEntryFromMaster->txPower);
00490 
00491             schedulerState->setDefaultPhyMode(strategyInput.mapInfoEntryFromMaster->phyModePtr);
00492             schedulerState->setDefaultTxPower(strategyInput.mapInfoEntryFromMaster->txPower);
00493         } 
00494         else 
00495         {
00496             assure(strategyInput.inputSchedulingMap != wns::scheduler::SchedulingMapPtr(), 
00497                 "slave scheduling requires inputSchedulingMap");
00498 
00499             MESSAGE_SINGLE(NORMAL, logger, "SlaveScheduling with given inputSchedulingMap...");
00500 
00501             // all PhyModes and TxPower are written in the inputSchedulingMap
00502             // I may only use those resources (subchannels,slots) where my userID is written into (UTx)
00503             // Before going to UT's PhyUser, take care to use the right userID!
00504             // it must be reverted (to BSx) in the PhyCommand to send to the right peer.
00505 
00506             assure(schedulerState->currentState->schedulingMap == strategyInput.inputSchedulingMap,
00507                 "schedulingMap must be set in revolveSchedulerState()");
00508 
00509             // set empty all resources but keep userID, PhyMode, TxPower
00510             MESSAGE_SINGLE(NORMAL, logger, "inputSchedulingMap->processMasterMap()");
00511             schedulerState->currentState->schedulingMap->processMasterMap();
00512 
00513             MESSAGE_SINGLE(NORMAL, logger, "prepared master schedulingMap="
00514                 << schedulerState->currentState->schedulingMap->toString());
00515         }
00516     }
00517     // empty bursts result datastructure MapInfoCollection (not schedulingMap)
00518     schedulerState->clearMap(); 
00519 
00520     // prepare CQI
00521     if (schedulerState->useCQI)
00522     {
00523         schedulerState->currentState->channelQualitiesOfAllUsers =
00524             ChannelQualitiesOfAllUsersPtr(new ChannelQualitiesOfAllUsers());
00525     }
00526 
00527     // Initialize the "working" datastructures
00528     // new burst result structure (part of the state):
00529     assure(schedulerState->currentState->bursts==MapInfoCollectionPtr(),"bursts must be NULL here");
00530 
00531     MapInfoCollectionPtr bursts = MapInfoCollectionPtr(new wns::scheduler::MapInfoCollection);
00532     schedulerState->currentState->bursts = bursts;
00533 
00534     // initialize helper strategies for DSA,APC:
00535     if (colleagues.dsastrategy != NULL)
00536         colleagues.dsastrategy->initialize(schedulerState, schedulingMap);
00537 
00538     if (colleagues.dsafbstrategy != NULL)
00539         colleagues.dsafbstrategy->initialize(schedulerState, schedulingMap);
00540 
00541     if (colleagues.apcstrategy != NULL)
00542         colleagues.apcstrategy->initialize(schedulerState,schedulingMap);
00543 
00544     // this calls the derived strategies (various algorithms):
00545     StrategyResult strategyResult =
00546         this->doStartScheduling(schedulerState, schedulingMap);
00547 
00548     assure(strategyResult.schedulingMap == schedulingMap,"schedulingMap mismatch");
00549 
00550     if (colleagues.apcstrategy != NULL)
00551         colleagues.apcstrategy->postProcess(schedulerState,schedulingMap);
00552 
00553     return strategyResult;
00554 } // startScheduling
00555 
00556 
00557 MapInfoEntryPtr
00558 Strategy::doAdaptiveResourceScheduling(RequestForResource& request,
00559                                        SchedulingMapPtr schedulingMap)
00560 {
00561     assure(colleagues.dsastrategy !=NULL, "dsastrategy==NULL");
00562     assure(colleagues.dsafbstrategy != NULL, "dsafbstrategy==NULL");
00563     assure(colleagues.apcstrategy != NULL, "apcstrategy==NULL");
00564     assure(schedulerState->currentState != RevolvingStatePtr(),
00565         "currentState must be valid");
00566     assure(schedulerState->currentState->strategyInput != NULL, 
00567         "strategyInput must be valid");
00568 
00569     int frameNr = schedulerState->currentState->strategyInput->getFrameNr();
00570     MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling("<<request.user.getName()<<",cid="<<request.cid<<",bits="<<request.bits<<"): useCQI="<<schedulerState->useCQI);
00571 
00572     // empty means no result. Filled later
00573     MapInfoEntryPtr resultMapInfoEntry; 
00574 
00575     // The slave RS-TX in the UT does not need to and cannot do AdaptiveResourceScheduling:
00576     if (schedulerState->powerControlType == PowerControlULSlave)
00577     {
00578         assure(schedulerState->schedulerSpot==wns::scheduler::SchedulerSpot::ULSlave(),
00579                "PowerControlULSlave requires SchedulerSpot::ULSlave");
00580         assure(schedulerState->currentState->strategyInput!=NULL,"need strategyInput");
00581 
00582         // don't do anything. Just return the known=given masterBurst
00583         if (schedulerState->currentState->strategyInput->mapInfoEntryFromMaster != MapInfoEntryPtr())
00584         { 
00585             assure(schedulerState->currentState->strategyInput->mapInfoEntryFromMaster != MapInfoEntryPtr(),
00586                 "need masterBurst");
00587 
00588             // copy and new SmartPtr to carry the result
00589             MapInfoEntryPtr mapInfoEntry = MapInfoEntryPtr(
00590                 new MapInfoEntry(*(schedulerState->currentState->strategyInput->mapInfoEntryFromMaster))); 
00591 
00592             assure(mapInfoEntry != MapInfoEntryPtr(),"need masterBurst");
00593             assure(mapInfoEntry->user.isValid(),"need user in masterBurst");
00594 
00595             MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling(): using masterBurst in slave mode: user="
00596                 << UserID(mapInfoEntry->user).getName()
00597                 << " -> request.user="
00598                 << request.user.getName()
00599                 << " (destination peer)");
00600 
00601             mapInfoEntry->user = request.user;
00602 
00603             assure(mapInfoEntry->phyModePtr!=wns::service::phy::phymode::PhyModeInterfacePtr(),
00604                 "phyMode must be defined in masterBurst" << mapInfoEntry->toString());
00605 
00606             // needed later
00607             request.phyModePtr=mapInfoEntry->phyModePtr; 
00608 
00609             // no space
00610             if (!schedulingMap->pduFitsInto(request,mapInfoEntry)) 
00611                 return resultMapInfoEntry; 
00612 
00613             return mapInfoEntry;
00614         } 
00615         else 
00616         {
00617             MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling(): using inputSchedulingMap. request.user="
00618                 << request.user.getName()
00619                 << " (destination peer)");
00620 
00621             assure(schedulerState->currentState->strategyInput->inputSchedulingMap != wns::scheduler::SchedulingMapPtr(), +
00622                 "slave scheduling requires inputSchedulingMap");
00623             assure(!colleagues.dsastrategy->requiresCQI(),"SlaveScheduler DSAStrategy must not require CQI");
00624         }
00625     }
00626 
00627     // SmartPtr (allocated in CQI)
00628     ChannelQualitiesOnAllSubBandsPtr cqiForUser; 
00629     wns::CandI estimatedCandI;
00630 
00631     assure(schedulerState->defaultPhyModePtr == wns::service::phy::phymode::PhyModeInterfacePtr(),
00632            "defaultPhyModePtr must not be set at this point (either master scheduler or inputSchedulingMap method)");
00633 
00634     if (schedulerState->useCQI)
00635     {
00636         assure (schedulerState->powerControlType!=PowerControlULSlave,"slave must not use CQI");
00637 
00638         // is the CQI state already available in our state?
00639         // NO -> get current CQI state
00640         if (!schedulerState->currentState->channelQualitiesOfAllUsers->knowsUser(request.user))
00641         { 
00642             // RS-TX (master DL)
00643             if (schedulerState->isTx)
00644             { 
00645                 // TODO: change CQIHandler so that it produces SmartPtr
00646                 cqiForUser = colleagues.registry->getChannelQualities4UserOnDownlink(request.user, frameNr);
00647             } 
00648             // RS-RX (master UL)
00649            else 
00650             { 
00651                 cqiForUser = colleagues.registry->getChannelQualities4UserOnUplink(request.user, frameNr);
00652             }
00653             (*(schedulerState->currentState->channelQualitiesOfAllUsers)).insert(
00654                 std::map<UserID,ChannelQualitiesOnAllSubBandsPtr>::value_type(request.user,cqiForUser));
00655 
00656         } 
00657         else 
00658         {
00659             cqiForUser = schedulerState->currentState->channelQualitiesOfAllUsers->find(request.user)->second;
00660         }
00661     } 
00662 
00663     dsastrategy::DSAResult dsaResult;
00664     int subChannel = dsastrategy::DSAsubChannelNotFound;
00665     int timeSlot = 0; 
00666     int spatialLayer = 0; 
00667     bool CQIrequired = colleagues.dsastrategy->requiresCQI();
00668     bool CQIavailable = (cqiForUser!=ChannelQualitiesOnAllSubBandsPtr())
00669         && (schedulerState->currentState->channelQualitiesOfAllUsers != ChannelQualitiesOfAllUsersPtr())
00670         && ((*(schedulerState->currentState->channelQualitiesOfAllUsers))[request.user]->size() > 0);
00671 
00672     MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling("
00673         << request.user.getName()
00674         << ",cid=" << request.cid
00675         << ",bits=" << request.bits
00676         << "): useCQI=" << schedulerState->useCQI
00677         << ",CQIrequired=" << CQIrequired 
00678         << ",CQIavailable="<<CQIavailable);
00679 
00680     // memory of request structure
00681     ChannelQualityOnOneSubChannel& cqiOnSubChannel
00682         = request.cqiOnSubChannel; 
00683 
00684     // start dynamic subchannel assignment (DSA):
00685     // with or without CQI information?
00686     if (schedulerState->useCQI && CQIrequired && CQIavailable)
00687     {
00688         assure (schedulerState->powerControlType!=PowerControlULSlave,"slave must not use CQI");
00689         MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling("
00690             << request.user.getName()
00691             << ",cid="
00692             << request.cid
00693             << ",bits="
00694             << request.bits
00695             << "): calling dsastrategy");
00696 
00697         // start dynamic subchannel assignment
00698         dsaResult = colleagues.dsastrategy->getSubChannelWithDSA(request, schedulerState, schedulingMap);
00699         subChannel = dsaResult.subChannel;
00700         timeSlot = dsaResult.timeSlot;
00701         spatialLayer = dsaResult.spatialLayer;
00702 
00703         if (subChannel==dsastrategy::DSAsubChannelNotFound)
00704             return resultMapInfoEntry; 
00705 
00706         assure(cqiForUser!=ChannelQualitiesOnAllSubBandsPtr(), "cqiForUser["
00707             << request.user.getName()
00708             << "]==NULL");
00709 
00710         // this writes into request structure:
00711         // copy
00712         cqiOnSubChannel = (*cqiForUser)[subChannel]; 
00713 
00714         assure(&cqiOnSubChannel == &(request.cqiOnSubChannel),"copy failed: addresses don't match");
00715 
00716         MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling("
00717             << request.user.getName()
00718             << ",cid=" << request.cid
00719             << ",bits=" << request.bits
00720             << "): subChannel="<<subChannel);
00721     } 
00722     // no CQI required or available
00723     else 
00724     { 
00725         if (!CQIrequired) 
00726         {
00727             MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling(): calling dsastrategy");
00728             // start dynamic subchannel assignment
00729             dsaResult = colleagues.dsastrategy->getSubChannelWithDSA(request, schedulerState, schedulingMap);
00730         } 
00731         else 
00732         { // no CQI available (principially or temporary)
00733             MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling(): calling dsafbstrategy (fallback)");
00734             dsaResult = colleagues.dsafbstrategy->getSubChannelWithDSA(request, schedulerState, schedulingMap);
00735         }
00736         subChannel = dsaResult.subChannel;
00737         timeSlot = dsaResult.timeSlot;
00738         spatialLayer = dsaResult.spatialLayer;
00739 
00740         if (subChannel==dsastrategy::DSAsubChannelNotFound)
00741             return resultMapInfoEntry; 
00742 
00743         // assume flat channel and nominal TxPower for this case
00744         wns::Power nominalPowerPerSubChannel = getPowerCapabilities(request.user).nominalPerSubband;
00745         cqiOnSubChannel = (schedulerState->isTx)?
00746             (colleagues.registry->estimateTxSINRAt(request.user)) // Tx
00747             :
00748             (colleagues.registry->estimateRxSINROf(request.user)); // Rx
00749     } 
00750 
00751     // Tell result of DSA: subChannel
00752     MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling("
00753         << request.user.getName()
00754         << ",cid="<<request.cid
00755         << ",bits="<<request.bits<<"):"
00756         << " subChannel.tSlot.spatialLayer="
00757         << subChannel<<"."<<timeSlot<<"."<<spatialLayer);
00758 
00759     if (subChannel==dsastrategy::DSAsubChannelNotFound)
00760         return resultMapInfoEntry; 
00761 
00762     // must be replaced by code which copes with that case:
00763     assure(subChannel != dsastrategy::DSAsubChannelNotFound, "DSAsubChannelNotFound");
00764 
00765     // fix the proposed subChannel value:
00766     request.subChannel = subChannel;
00767     request.timeSlot = timeSlot;
00768     request.spatialLayer = spatialLayer;
00769 
00770     wns::Power txPower;
00771     apcstrategy::APCResult apcResult;
00773     // Master
00774     if (schedulerState->powerControlType!=PowerControlULSlave)
00775     { 
00776         // do adaptive power allocation
00777         apcResult = colleagues.apcstrategy->doStartAPC(request, schedulerState, schedulingMap);
00778         // not (yet) possible: 
00779         if (apcResult.txPower == wns::Power())
00780             return resultMapInfoEntry; 
00781 
00782         // fix the proposed phyMode value:
00783         request.phyModePtr = apcResult.phyModePtr;
00784         txPower = apcResult.txPower;
00785 
00786         // process result:
00787         estimatedCandI.I = cqiOnSubChannel.interference;
00788         estimatedCandI.C = apcResult.txPower / cqiOnSubChannel.pathloss.get_factor(); 
00789 
00790         MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling(): txP="
00791             << apcResult.txPower
00792             << ", pl=" << cqiOnSubChannel.pathloss
00793             << ", sinr=" << estimatedCandI.toSINR()
00794             << ", PhyMode=" << *(apcResult.phyModePtr));
00795 
00796         assure(std::fabs(estimatedCandI.C.get_dBm() - apcResult.estimatedCandI.C.get_dBm()) < 1e-6,
00797             "estimatedCandI mismatch: C=" << estimatedCandI.C << " != " << apcResult.estimatedCandI.C);
00798         assure(std::fabs(estimatedCandI.I.get_dBm() - apcResult.estimatedCandI.I.get_dBm()) < 1e-6,
00799             "estimatedCandI mismatch: I=" << estimatedCandI.I << " != " << apcResult.estimatedCandI.I);
00800         assure(std::fabs(estimatedCandI.toSINR().get_dB() - apcResult.sinr.get_dB()) < 1e-6,
00801             "sinr mismatch: sinr=" << estimatedCandI.toSINR() << " != " << apcResult.sinr);
00802 
00803         // estimatedCandI (calculated here) and apcResult.estimatedCandI should be the same
00804         double minSINRforPhyMode = colleagues.registry->getPhyModeMapper()->getMinimumSINR();
00805 
00806         // this could mean "APC failed"
00807         if ((apcResult.sinr.get_dB() < minSINRforPhyMode))
00808         { 
00809             MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling(): too low SINR! sinr="
00810                 << estimatedCandI.toSINR()
00811                 << ", PhyMode="
00812                 << *(apcResult.phyModePtr)
00813                 << " requires " 
00814                 << minSINRforPhyMode << "dB");
00815 
00816             // If the value is extremely low, it is likely that something bad has happened
00817             assure(estimatedCandI.C.get_dBm() > -190,
00818                 "sinr=" << apcResult.sinr.get_dB() 
00819                 << " but minSINRforPhyMode="
00820                 << minSINRforPhyMode << " not reached. Estimation was: C="
00821                 << estimatedCandI.C << ", I="<<estimatedCandI.I<<" (blind)");
00822 
00823             if (schedulerState->excludeTooLowSINR)
00824             {
00825                 return resultMapInfoEntry; 
00826             }
00827         }
00828     } 
00829     // slave scheduling (PowerControlULSlave)
00830     else 
00831     { 
00832         request.phyModePtr = schedulingMap->getPhyModeUsedInResource(subChannel,timeSlot,spatialLayer);
00833         txPower = schedulingMap->getTxPowerUsedInResource(subChannel,timeSlot,spatialLayer);
00834     }
00835 
00836     // This really fixes the proposed values of DSA and APC.
00837     resultMapInfoEntry = MapInfoEntryPtr(new MapInfoEntry());
00838     resultMapInfoEntry->frameNr = frameNr;
00839     resultMapInfoEntry->subBand = subChannel;
00840     resultMapInfoEntry->timeSlot = timeSlot;
00841     resultMapInfoEntry->spatialLayer = spatialLayer;
00842     resultMapInfoEntry->user = request.user;
00843     resultMapInfoEntry->sourceUser = schedulerState->myUserID;
00844     resultMapInfoEntry->txPower = txPower; // apcResult.txPower;
00845     resultMapInfoEntry->phyModePtr = request.phyModePtr; // = apcResult.phyModePtr
00846     resultMapInfoEntry->estimatedCQI = cqiOnSubChannel; 
00847    
00848     // Set antennaPattern etc. according to grouping result
00849     if (groupingRequired()) 
00850     {
00851         assure(schedulerState->currentState->getGrouping() != GroupingPtr(),"invalid grouping");
00852 
00853         wns::service::phy::ofdma::PatternPtr antennaPattern;
00854         antennaPattern = schedulerState->currentState->getGrouping()->patterns[request.user];
00855         int groupIndex = schedulerState->currentState->getGrouping()->userGroupNumber[request.user] - 1;
00856 
00857         assure(groupIndex <= schedulerState->currentState->getGrouping()->groups.size(), "invalid group index");
00858 
00859         Group currentGroup = schedulerState->currentState->getGrouping()->groups[groupIndex];
00860         estimatedCandI = currentGroup[request.user];
00861         resultMapInfoEntry->estimatedCQI.carrier = estimatedCandI.C;
00862         resultMapInfoEntry->estimatedCQI.interference = estimatedCandI.I;
00863         resultMapInfoEntry->estimatedCQI.pathloss = estimatedCandI.PL;
00864         resultMapInfoEntry->estimatedCQI.sdma.iIntra = estimatedCandI.sdma.iIntra;
00865 
00866         assure(antennaPattern != wns::service::phy::ofdma::PatternPtr(),"invalid pattern");
00867 
00868         resultMapInfoEntry->pattern = antennaPattern;
00869     }
00870     resultMapInfoEntry->start = wns::scheduler::undefinedTime;
00871     resultMapInfoEntry->end   = wns::scheduler::undefinedTime;
00872 
00873     return resultMapInfoEntry;
00874 } // doAdaptiveResourceScheduling
00875 
00876 wns::service::phy::phymode::PhyModeInterfacePtr
00877 Strategy::getBestPhyMode(const wns::Ratio& sinr) const
00878 {
00879     if (schedulerState->currentState->strategyInput->defaultPhyModePtr != 
00880         wns::service::phy::phymode::PhyModeInterfacePtr()) 
00881     {
00882         assure(schedulerState->currentState->strategyInput->defaultPhyModePtr->isValid(),
00883             "defaultPhyModePtr is invalid!");
00884 
00885         return schedulerState->currentState->strategyInput->defaultPhyModePtr;
00886     } 
00887     // do link adaptation
00888     else 
00889     {
00890         return colleagues.registry->getBestPhyMode(sinr);
00891     }
00892 }
00893 
00894 wns::scheduler::SchedulerSpotType
00895 Strategy::getSchedulerSpotType() const 
00896 {
00897     assure(schedulerState!=SchedulerStatePtr(),"schedulerState must be valid");
00898     assure(schedulerState->schedulerSpot>0,"uninitialized schedulerSpot="
00899         << schedulerState->schedulerSpot);
00900 
00901     return schedulerState->schedulerSpot;
00902 }
00903 
00904 bool
00905 Strategy::isTx() const
00906 {
00907     // comes from Python. isTx=true for RS-TX (DL,UL) in (BS,UT,RN)
00908     assure(schedulerState!=SchedulerStatePtr(),"schedulerState must be valid");
00909 
00910     return schedulerState->isTx; 
00911 }
00912 
00913 // method only to support the old strategies. Not intended for new schedulers.
00914 wns::Power
00915 Strategy::getTxPower() const
00916 {
00917     wns::Power power;
00918     MESSAGE_SINGLE(NORMAL, logger, "getTxPower()");
00919 
00920     assure(schedulerState != SchedulerStatePtr(),
00921         "schedulerState must be valid");
00922     assure(schedulerState->currentState != RevolvingStatePtr(),
00923         "currentState must be valid");
00924     assure(schedulerState->currentState->strategyInput != NULL,
00925         "need strategyInput");
00926     assure(!isNewStrategy(),
00927         "getTxPower() only allowed for the old obsolete strategies");
00928 
00929     // not yet prepared. Do it now.
00930     if (schedulerState->powerCapabilities.nominalPerSubband==wns::Power())
00931     { 
00932         MESSAGE_SINGLE(NORMAL, logger, "getTxPower: asking getPowerCapabilities(NULL)...");
00933         // NULL because peer unknown
00934         getPowerCapabilities(UserID()); 
00935     }
00936     power = schedulerState->powerCapabilities.nominalPerSubband;
00937 
00938     assure(power != wns::Power(),"undefined power=" << power);
00939 
00940     return power;
00941 }
00942 
00943 float
00944 Strategy::getResourceUsage() const
00945 {
00946     assure(schedulerState!=SchedulerStatePtr(),"schedulerState must be valid");
00947     assure(schedulerState->currentState!=RevolvingStatePtr(),"currentState must be valid");
00948     assure(schedulerState->currentState->schedulingMap!=wns::scheduler::SchedulingMapPtr(),"schedulingMap must be valid");
00949 
00950     // This is the default implementation. Overload in your desired strategy
00951     // if you want information about the resource usage.
00952     // In general it is better to call schedulingMap->getResourceUsage() in the system specific methods after scheduling
00953     if (schedulerState->currentState->schedulingMap!=SchedulingMapPtr()) 
00954     {
00955         return schedulerState->currentState->schedulingMap->getResourceUsage();
00956     } 
00957     else 
00958     {
00959         return 0.0;
00960     }
00961 }
00962 
00963 bool
00964 Strategy::groupingRequired() const
00965 {
00966     assure(schedulerState != SchedulerStatePtr(),
00967         "schedulerState must be valid");
00968     assure(schedulerState->currentState != RevolvingStatePtr(),
00969         "currentState must be valid");
00970     assure(schedulerState->currentState->strategyInput != NULL,
00971         "schedulerState->currentState->strategyInput must be valid");
00972 
00973     bool isMaster = (schedulerState->schedulerSpot == wns::scheduler::SchedulerSpot::DLMaster() 
00974         || schedulerState->schedulerSpot == wns::scheduler::SchedulerSpot::ULMaster());
00975 
00976     return (schedulerState->currentState->strategyInput->beamforming && isMaster);
00977 }

Generated on Sat May 26 03:31:51 2012 for openWNS by  doxygen 1.5.5