User Manual, Developers Guide and API Documentation

SchedulingMap.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/SchedulerTypes.hpp>
00029 #include <WNS/scheduler/SchedulingMap.hpp>
00030 #include <WNS/scheduler/strategy/SchedulerState.hpp> // for RequestForResource
00031 #include <WNS/ldk/Compound.hpp>
00032 #include <WNS/SmartPtr.hpp>
00033 #include <WNS/service/phy/phymode/PhyModeInterface.hpp>
00034 #include <iostream>
00035 #include <fstream>
00036 
00037 using namespace wns::scheduler;
00038 
00039 SchedulingCompound::SchedulingCompound()
00040   : subChannel(0),
00041     timeSlot(0),
00042     spatialLayer(0),
00043     startTime(0.0),
00044     endTime(0.0),
00045     connectionID(-1),
00046     userID(NULL),
00047     sourceUserID(NULL),
00048     compoundPtr(),
00049     phyModePtr(),
00050     txPower(),
00051     estimatedCQI(),
00052     harqEnabled(false)
00053 {
00054 };
00055 
00056 SchedulingCompound::SchedulingCompound(const SchedulingCompound& other):
00057     subChannel(other.subChannel),
00058     timeSlot(other.timeSlot),
00059     spatialLayer(other.spatialLayer),
00060     startTime(other.startTime),
00061     endTime(other.endTime),
00062     connectionID(other.connectionID),
00063     userID(other.userID),
00064     sourceUserID(other.sourceUserID),
00065     compoundPtr(),
00066     phyModePtr(other.phyModePtr),
00067     txPower(other.txPower),
00068     pattern(other.pattern),
00069     estimatedCQI(other.estimatedCQI),
00070     harqEnabled(other.harqEnabled)
00071 {
00072     if(other.compoundPtr != NULL)
00073     {
00074         compoundPtr = wns::ldk::CompoundPtr(other.compoundPtr->clone());
00075     }
00076 };
00077 
00078 SchedulingCompound::SchedulingCompound(int _subChannel,
00079                                        int _timeSlot,
00080                                        int _spatialLayer,
00081                                        simTimeType _startTime,
00082                                        simTimeType _endTime,
00083                                        wns::scheduler::ConnectionID _connectionID,
00084                                        wns::scheduler::UserID _userID,
00085                                        wns::scheduler::UserID _sourceUserID,
00086                                        wns::ldk::CompoundPtr _compoundPtr,
00087                                        wns::service::phy::phymode::PhyModeInterfacePtr _phyModePtr,
00088                                        wns::Power _txPower,
00089                                        wns::service::phy::ofdma::PatternPtr _pattern,
00090                                        ChannelQualityOnOneSubChannel _estimatedCQI,
00091                                        bool _harqEnabled
00092     )
00093     : subChannel(_subChannel),
00094       timeSlot(_timeSlot),
00095       spatialLayer(_spatialLayer),
00096       startTime(_startTime),
00097       endTime(_endTime),
00098       connectionID(_connectionID),
00099       userID(_userID),
00100       sourceUserID(_sourceUserID),
00101       compoundPtr(_compoundPtr),
00102       phyModePtr(_phyModePtr),
00103       txPower(_txPower),
00104       pattern(_pattern),
00105       estimatedCQI(_estimatedCQI),
00106       harqEnabled(_harqEnabled)
00107 {
00108 }
00109 
00110 SchedulingCompound::~SchedulingCompound()
00111 {
00112 }
00113 
00114 std::string
00115 SchedulingCompound::toString() const
00116 {
00117     std::stringstream s;
00118     s.setf(std::ios::fixed,std::ios::floatfield);   // floatfield set to fixed
00119     s.precision(1);
00120     s << "SchedulingCompound(";
00121     if (harqEnabled) s << " H ";
00122     s << "cid="<<connectionID;
00123     s << ", user="<<userID.getName();
00124     if (compoundPtr != wns::ldk::CompoundPtr()) {
00125         s << ", bits="<< compoundPtr->getLengthInBits();
00126     }
00127     s << ", T=[" << startTime*1e6 << "-" << endTime*1e6 << "]us";
00128     s << ", d=" << (endTime-startTime)*1e6 << "us";
00129     s << ", estI=" << estimatedCQI.interference.get_dBm() << "dBm";
00130     s << ", estC=" << estimatedCQI.carrier.get_dBm() << "dBm";
00131     s << ", estPL=" << estimatedCQI.pathloss.get_dB() << "dB";
00132     s << ")";
00133     return s.str();
00134 }
00135 
00136 /**************************************************************/
00137 PhysicalResourceBlock::PhysicalResourceBlock()
00138     : subChannelIndex(0),
00139       timeSlotIndex(0),
00140       spatialIndex(0),
00141       slotLength(0.0),
00142       freeTime(0.0),
00143       nextPosition(0.0),
00144       scheduledCompounds(),
00145       phyModePtr(),
00146       txPower(),
00147       estimatedCQI(),
00148       antennaPattern()
00149 {
00150 }
00151 
00152 PhysicalResourceBlock::PhysicalResourceBlock(int _subChannelIndex, int _timeSlotIndex, int _spatialLayer, simTimeType _slotLength)
00153     : subChannelIndex(_subChannelIndex),
00154       timeSlotIndex(_timeSlotIndex),
00155       spatialIndex(_spatialLayer),
00156       slotLength(_slotLength),
00157       freeTime(_slotLength),
00158       nextPosition(0.0),
00159       scheduledCompounds(),
00160       userID(NULL),
00161       sourceUserID(NULL),
00162       phyModePtr(),
00163       txPower(),
00164       estimatedCQI(),
00165       antennaPattern()
00166 {
00167 }
00168 
00169 PhysicalResourceBlock::PhysicalResourceBlock(const PhysicalResourceBlock& other):
00170     subChannelIndex(other.subChannelIndex),
00171     timeSlotIndex(other.timeSlotIndex),
00172     spatialIndex(other.spatialIndex),
00173     slotLength(other.slotLength),
00174     freeTime(other.freeTime),
00175     nextPosition(other.nextPosition),
00176     scheduledCompounds(),
00177     userID(other.userID),
00178     sourceUserID(other.sourceUserID),
00179     phyModePtr(other.phyModePtr),
00180     txPower(other.txPower),
00181     estimatedCQI(other.estimatedCQI),
00182     antennaPattern(other.antennaPattern)
00183 {
00184     for (ScheduledCompoundsList::const_iterator it=other.scheduledCompounds.begin();
00185          it != other.scheduledCompounds.end();
00186          ++it)
00187     {
00188         scheduledCompounds.push_back(SchedulingCompound(*it));
00189     }
00190 }
00191 
00192 PhysicalResourceBlock::~PhysicalResourceBlock()
00193 {
00194 }
00195 
00196 simTimeType
00197 PhysicalResourceBlock::getUsedTime() const
00198 {
00199     assure(slotLength-freeTime-nextPosition<wns::scheduler::slotLengthRoundingTolerance,"slotLength mismatch");
00200     return slotLength-freeTime;
00201 }
00202 
00203 simTimeType
00204 PhysicalResourceBlock::getFreeTime() const
00205 {
00206     assure(slotLength-freeTime-nextPosition<wns::scheduler::slotLengthRoundingTolerance,"slotLength mismatch");
00207     return freeTime;
00208 }
00209 
00210 simTimeType
00211 PhysicalResourceBlock::getNextPosition() const
00212 {
00213     return nextPosition;
00214 }
00215 
00216 bool
00217 PhysicalResourceBlock::pduFitsInto(strategy::RequestForResource& request,
00218                                    MapInfoEntryPtr mapInfoEntry // <- must not contain compounds yet
00219     ) const
00220 {
00221     // mapInfoEntry can contain compounds when in while loop:
00222     //assure(mapInfoEntry->compounds.empty(),"mapInfoEntry->compounds must be empty here");
00223     wns::service::phy::phymode::PhyModeInterfacePtr mapPhyModePtr = mapInfoEntry->phyModePtr;
00224     assure(mapPhyModePtr!=wns::service::phy::phymode::PhyModeInterfacePtr(),"phyModePtr==NULL");
00225     assure(scheduledCompounds.empty()
00226            || (*mapPhyModePtr == *phyModePtr),
00227            "all PhyModes must match on a (used) PhysicalResourceBlock: "<<*phyModePtr<<" != "<<*mapPhyModePtr);
00228     double dataRate = mapPhyModePtr->getDataRate();
00229     simTimeType compoundDuration = request.bits / dataRate;
00230     simTimeType startTime = this->nextPosition;
00231     simTimeType endTime = startTime + compoundDuration;
00232     return (endTime <= slotLength+wns::scheduler::slotLengthRoundingTolerance);
00233 } // pduFitsInto (PhysicalResourceBlock)
00234 
00235 int
00236 PhysicalResourceBlock::getFreeBitsOnPhysicalResourceBlock(MapInfoEntryPtr mapInfoEntry) const
00237 {
00238     wns::service::phy::phymode::PhyModeInterfacePtr mapPhyModePtr = mapInfoEntry->phyModePtr;
00239     assure(mapPhyModePtr!=wns::service::phy::phymode::PhyModeInterfacePtr(),"phyModePtr==NULL");
00240     assure(scheduledCompounds.empty()
00241            || (*mapPhyModePtr == *phyModePtr),
00242            "all PhyModes must match on a (used) PhysicalResourceBlock: "<<*phyModePtr<<" != "<<*mapPhyModePtr);
00243     double dataRate = mapPhyModePtr->getDataRate();
00244     return (freeTime+wns::scheduler::slotLengthRoundingTolerance) * dataRate;
00245 } // getFreeBitsOnPhysicalResourceBlock
00246 
00247 bool
00248 PhysicalResourceBlock::addCompound(simTimeType compoundDuration,
00249                                    wns::scheduler::ConnectionID connectionID,
00250                                    wns::scheduler::UserID _userID,
00251                                    wns::scheduler::UserID _sourceUserID,
00252                                    wns::ldk::CompoundPtr compoundPtr,
00253                                    wns::service::phy::phymode::PhyModeInterfacePtr _phyModePtr,
00254                                    wns::Power _txPower,
00255                                    wns::service::phy::ofdma::PatternPtr _pattern,
00256                                    ChannelQualityOnOneSubChannel _estimatedCQI,
00257                                    bool _useHARQ
00258     )
00259 {
00260     simTimeType startTime = this->nextPosition;
00261     simTimeType endTime = startTime + compoundDuration;
00262     if (endTime > slotLength+wns::scheduler::slotLengthRoundingTolerance) return false; // not successful
00263     assure(endTime <= slotLength+wns::scheduler::slotLengthRoundingTolerance,
00264            "end time of the compound="<<endTime<<" exceeds slotLength="<<slotLength);
00265     int predecessors = scheduledCompounds.size();
00266     // this can happen if DSAStrategy.oneUserOnOneSubChannel=False: no implementation yet
00267     assure((predecessors==0)||(txPower == _txPower),
00268            "mismatch: txPower="<<txPower<<"!="<<_txPower<<" please use DSAStrategy.oneUserOnOneSubChannel=True");
00269     txPower = _txPower; // all compounds must have the same power
00270     // check if users match (need oneUserOnOneSubChannel for that)
00271     // we cannot do this here, because in the UL SchedulingMap done by UT.RS-TX the userID is myself
00272     //if (userID!=NULL) { // && oneUserOnOneSubChannel) {
00273     //    assure(_userID==userID,
00274     //           "user mismatch: "<<_userID->getName()<<" != "<<userID->getName());
00275     //}
00276     if (predecessors>0) { // && oneUserOnOneSubChannel) {
00277         wns::scheduler::UserID otherUserID = scheduledCompounds.begin()->userID;
00278         assure(_userID==otherUserID,
00279                "user mismatch: "<<_userID.getName()<<" != "<<userID.getName());
00280     }
00281     if (!userID.isValid())
00282     { // master schedulers set this; slave schedulers get this already set.
00283         userID = _userID; // all compounds must have the same user; oneUserOnOneSubChannel = True ?
00284     }
00285 
00286     if (predecessors>0) { // && oneUserOnOneSubChannel) {
00287         wns::scheduler::UserID otherUserID = scheduledCompounds.begin()->sourceUserID;
00288         assure(_sourceUserID==otherUserID,
00289                "source user mismatch: "<<_sourceUserID.getName()<<" != "<<sourceUserID.getName());
00290     }
00291     if (!sourceUserID.isValid())
00292     { // master schedulers set this; slave schedulers get this already set.
00293         sourceUserID = _sourceUserID; // all compounds must have the same user; oneUserOnOneSubChannel = True ?
00294     }
00295 
00296     assure((predecessors==0)||(phyModePtr == _phyModePtr),
00297            "phyModePtr mismatch: "<<*phyModePtr<<"!="<<*_phyModePtr);
00298     phyModePtr = _phyModePtr; // all compounds should have the same phyMode
00299     antennaPattern = _pattern; // all compounds should have the same antenna pattern
00300     estimatedCQI = _estimatedCQI;
00301     SchedulingCompound newScheduledCompound(this->subChannelIndex,
00302                                             this->timeSlotIndex,
00303                                             this->spatialIndex,
00304                                             startTime,
00305                                             endTime,
00306                                             connectionID,
00307                                             _userID,
00308                                             _sourceUserID,
00309                                             compoundPtr,
00310                                             phyModePtr,
00311                                             txPower,
00312                                             _pattern,
00313                                             _estimatedCQI,
00314                                             _useHARQ
00315         );
00316     this->scheduledCompounds.push_back(newScheduledCompound);
00317     this->nextPosition += compoundDuration;
00318     assure(fabs(nextPosition-endTime)<wns::scheduler::slotLengthRoundingTolerance,"nextPosition!=endTime");
00319     this->freeTime     -= compoundDuration;
00320     assure(freeTime>=-wns::scheduler::slotLengthRoundingTolerance,"freeTime="<<freeTime);
00321     // assure(freeTime>=0.0,"freeTime="<<freeTime); // fails due to double inaccuracies
00322     // this method cannot count SchedulingMap::numberOfCompounds itself
00323     return true;
00324 } // PhysicalResourceBlock::addCompound
00325 
00326 bool
00327 PhysicalResourceBlock::addCompound(strategy::RequestForResource& request,
00328                                    MapInfoEntryPtr mapInfoEntry, // <- must not contain compounds yet
00329                                    wns::ldk::CompoundPtr compoundPtr,
00330                                    bool _useHARQ
00331     )
00332 {
00333     // mapInfoEntry can contain compounds when in while loop:
00334     //assure(mapInfoEntry->compounds.empty(),"mapInfoEntry->compounds must be empty here");
00335     //assure(compoundPtr!=wns::ldk::CompoundPtr(),"compoundPtr==NULL"); // empty is allowed for uplink master scheduling
00336     //int compoundBits = compoundPtr->getLengthInBits();
00337     //assure(compoundBits==request.bits, "bits mismatch: "<<compoundBits<<" != "<<request.bits);
00338     // ^ in the UL the real bits may be less than the requested bits.
00339     //assure(compoundBits<=request.bits, "bits mismatch: "<<compoundBits<<" != "<<request.bits);
00340     wns::service::phy::phymode::PhyModeInterfacePtr mapPhyModePtr = mapInfoEntry->phyModePtr;
00341     double dataRate = mapPhyModePtr->getDataRate();
00342     simTimeType compoundDuration = request.bits / dataRate;
00343 
00344     // check if users match (need oneUserOnOneSubChannel for that)
00345     // we cannot do this here, because in the UL SchedulingMap done by UT.RS-TX the userID is myself
00346     //if (userID!=NULL) { // && oneUserOnOneSubChannel) {
00347     //    assure(compoundUserID==userID,
00348     //           "user mismatch: "<<compoundUserID->getName()<<" != "<<userID->getName());
00349     //}
00350     // assure(compoundUserID==request.user) sometimes fails even with RN2 != RN2
00351     // Reason: user mismatch: RN2 != RN2, 7 != 5
00352     // in this case make a string comparison :-(
00353     //assure(compoundUserID->isEqual(request.user) || compoundUserID->getName().compare(mapInfoEntry->user->getName())==0,
00354     //       "user mismatch: "<<compoundUserID->getName()<<" != "<<mapInfoEntry->user->getName()<<", "<<compoundUserID->getNodeID()<<" != "<<request.user->getNodeID());
00355     wns::Power txPowerInMap = mapInfoEntry->txPower;
00356     wns::scheduler::ConnectionID connectionID = request.cid;
00357     wns::service::phy::ofdma::PatternPtr patternInMap = mapInfoEntry->pattern; // antenna pattern (grouping)
00358     ChannelQualityOnOneSubChannel estimatedCQI = mapInfoEntry->estimatedCQI;
00359 
00360     return addCompound(compoundDuration,
00361                        connectionID,
00362                        mapInfoEntry->user,
00363                        mapInfoEntry->sourceUser,
00364                        compoundPtr,
00365                        mapPhyModePtr,
00366                        txPowerInMap,
00367                        patternInMap,
00368                        estimatedCQI,
00369                        _useHARQ
00370         );
00371 } // addCompound
00372 
00373 // dumpContents(): machine-readable format (table for Matlab,Gnuplot,etc)
00374 std::string
00375 PhysicalResourceBlock::dumpContents(const std::string& prefix) const
00376 {
00377     std::stringstream s;
00378     s.setf(std::ios::fixed,std::ios::floatfield);   // floatfield set to fixed
00379     s.precision(4);
00380     //s << prefix << subChannelIndex << "\t" << spatialIndex;
00381     s << prefix;
00382     if (phyModePtr != PhyModePtr())
00383     {
00384         s << phyModePtr->getBitsPerSymbol() << "\t";
00385     }
00386     else
00387     {
00388         s << "?" << "\t";
00389     }
00390 
00391     s  << txPower.get_dBm() << "\t"
00392        << nextPosition/slotLength << "\t";
00393     if ( nextPosition>0.0 ) // not empty
00394     {
00395         s << scheduledCompounds.size() << "\t";
00396         if (scheduledCompounds.size() > 0)
00397         {
00398             int totalbits = 0;
00399 
00400             s << scheduledCompounds.begin()->userID.getName() << "\t";
00401             for ( ScheduledCompoundsList::const_iterator iter = scheduledCompounds.begin(); iter != scheduledCompounds.end(); ++iter )
00402             {
00403                 s << iter->connectionID << "(" << iter->compoundPtr->getLengthInBits() << "),";
00404                 totalbits += iter->compoundPtr->getLengthInBits();
00405             }
00406             s << "total (" << totalbits << ")";
00407         }
00408     } else {
00409         s << "0\t0";
00410     }
00411     s << std::endl;
00412     return s.str();
00413 } // dumpContents
00414 
00415 // doToString(): human-readable format
00416 std::string
00417 PhysicalResourceBlock::toString() const
00418 {
00419     std::stringstream s;
00420     s.setf(std::ios::fixed,std::ios::floatfield);   // floatfield set to fixed
00421     s.precision(1);
00422     s << "PhysicalResourceBlock(";
00423     s << "#"<<subChannelIndex<<"."<<timeSlotIndex<<"."<<spatialIndex;
00424     if ( nextPosition>0.0 ) { // not empty
00425         s << ", user="<<userID.getName();
00426         s << ", free=" << freeTime*1e6 << "us";
00427         s << ", next=" << nextPosition*1e6 << "us";
00428         s << ", used=" << 100.0*nextPosition/slotLength << "%";
00429         s << ", compounds=" << scheduledCompounds.size();
00430         s << ")";
00431         if (scheduledCompounds.size()>0)
00432         {
00433             s << ":"<<std::endl;
00434             for ( ScheduledCompoundsList::const_iterator iter = scheduledCompounds.begin(); iter != scheduledCompounds.end(); ++iter )
00435             {
00436                 s << "  " << iter->toString();
00437                 if (iter!=scheduledCompounds.end()) s << std::endl;
00438             }
00439         }
00440     } else if (phyModePtr!=wns::service::phy::phymode::PhyModeInterfacePtr()) {
00441         // this is a master schedulingMap (from BS to UT). Compounds have been deleted, values reset
00442         s << ", user="<<userID.getName();
00443         s << ", phyMode="<<*phyModePtr;
00444         s << ", txPower="<<txPower;
00445         s << ")";
00446     } else {
00447         s << ", unused)";
00448     }
00449     s << std::endl;
00450     return s.str();
00451 } // toString
00452 
00453 int
00454 PhysicalResourceBlock::countScheduledCompounds() const
00455 {
00456     return scheduledCompounds.size();
00457 }
00458 
00459 bool
00460 PhysicalResourceBlock::isEmpty() const
00461 {
00462     // nextPosition can be 0.0 in a master schedulingMap, although phyMode and user is set
00463     // so this && check is necessary in the master schedulers
00464     // For the uplink the master map entries have isEmpty==false because nextPosition>0 and PhyMode set.
00465     return ((nextPosition==0.0) &&
00466             (phyModePtr==wns::service::phy::phymode::PhyModeInterfacePtr()));
00467 }
00468 
00469 wns::scheduler::UserID
00470 PhysicalResourceBlock::getUserID() const
00471 {
00472     // In UL slave scheduler, the userIDs are different! (UT vs BS)
00473     //assure(userID==NULL || scheduledCompounds.size()==0 || (scheduledCompounds.begin()->userID == userID),
00474     //       "userID mismatch: userID="<<userID->getName());
00475     return userID;
00476     //return scheduledCompounds.begin()->userID;
00477 }
00478 
00479 wns::scheduler::UserID
00480 PhysicalResourceBlock::getSourceUserID() const
00481 {
00482     return sourceUserID;
00483 }
00484 
00485 wns::Power
00486 PhysicalResourceBlock::getTxPower() const
00487 {
00488     return txPower;
00489 }
00490 
00491 void
00492 PhysicalResourceBlock::setTxPower(wns::Power power)
00493 {
00494     txPower=power;
00495     // adjust contents
00496     if (scheduledCompounds.size() > 0)
00497     {
00498         for ( ScheduledCompoundsList::iterator iter = scheduledCompounds.begin(); iter != scheduledCompounds.end(); ++iter )
00499         {
00500             SchedulingCompound& schedulingCompound = *iter;
00501             schedulingCompound.txPower = power;
00502             // can we and do we have to adjust something inside the compound?
00503             // we cannot access the command here.
00504             // So the PhyUser is responsible for setting the power of the compounds.
00505             //schedulingCompound.compoundPtr->...;
00506         }
00507     }
00508 }
00509 
00510 void
00511 PhysicalResourceBlock::deleteCompounds()
00512 {
00513     scheduledCompounds.clear();
00514 } // deleteCompounds
00515 
00516 void
00517 PhysicalResourceBlock::grantFullResources()
00518 {
00519     // Used in MasterMap: extend UL resource size to full length, so that UT can make use of it.
00520     if (!isEmpty())
00521     {
00522         // with these values the resourceUsage statistics counts the full resource:
00523         nextPosition = slotLength;
00524         freeTime = 0.0;
00525     }
00526 }
00527 
00528 void
00529 PhysicalResourceBlock::processMasterMap()
00530 {
00531     // Used in MasterMap: Extend UL resource size to full length, so that UT can make use of it.
00532     if (!isEmpty())
00533     {
00534         scheduledCompounds.clear();
00535         // with these values the DSASlave strategy can put new UL packets into it:
00536         nextPosition = 0.0;
00537         freeTime = slotLength;
00538     }
00539     assure(scheduledCompounds.size() == 0,"scheduledCompounds is not empty but must be");
00540 }
00541 
00542 bool
00543 PhysicalResourceBlock::hasResourcesForUser(wns::scheduler::UserID user) const
00544 {
00545     return (user == userID);
00546 }
00547 
00548 void
00549 PhysicalResourceBlock::consistencyCheck()
00550 {
00551     for ( ScheduledCompoundsList::const_iterator iter = scheduledCompounds.begin(); iter != scheduledCompounds.end(); ++iter )
00552     {
00553         assure(iter->compoundPtr != wns::ldk::CompoundPtr(), "No compound here");
00554     }
00555 }
00556 
00557 int
00558 PhysicalResourceBlock::getNetBlockSizeInBits() const
00559 {
00560     if ( nextPosition>0.0 ) // not empty
00561     {
00562         if (scheduledCompounds.size() > 0)
00563         {
00564             int totalbits = 0;
00565             for ( ScheduledCompoundsList::const_iterator iter = scheduledCompounds.begin(); iter != scheduledCompounds.end(); ++iter )
00566             {
00567                 assure(iter->compoundPtr != wns::ldk::CompoundPtr(), "No compound here");
00568                 totalbits += iter->compoundPtr->getLengthInBits();
00569             }
00570             return totalbits;
00571         }
00572     }
00573     return 0;
00574 }
00575 
00576 bool
00577 PhysicalResourceBlock::isHARQEnabled() const
00578 {
00579     for ( ScheduledCompoundsList::const_iterator iter = scheduledCompounds.begin(); iter != scheduledCompounds.end(); ++iter )
00580     {
00581         if(iter->harqEnabled)
00582         {
00583             return true;
00584         }
00585     }
00586     return false;
00587 }
00588 
00589 /**************************************************************/
00590 SchedulingTimeSlot::SchedulingTimeSlot()
00591     : subChannelIndex(0),
00592       timeSlotIndex(0),
00593       numSpatialLayers(0),
00594       slotLength(0.0),
00595       timeSlotStartTime(0.0)
00596 {
00597 }
00598 
00599 SchedulingTimeSlot::SchedulingTimeSlot(int _subChannel,
00600                                        int _timeSlot,
00601                                        int _numSpatialLayers,
00602                                        simTimeType _slotLength
00603     )
00604     : subChannelIndex(_subChannel),
00605       timeSlotIndex(_timeSlot),
00606       numSpatialLayers(_numSpatialLayers),
00607       slotLength(_slotLength),
00608       timeSlotStartTime(_slotLength*_timeSlot),
00609       timeSlotIsUsable(true)
00610 {
00611     for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00612     {
00613         // create one PhysicalResourceBlock object per spatialLayer (MIMO channel)
00614         PhysicalResourceBlock emptyPRB(subChannelIndex,timeSlotIndex,spatialIndex,slotLength);
00615         // available as physicalResources[spatialIndex]
00616         physicalResources.push_back(emptyPRB); // object copied
00617     }
00618 }
00619 
00620 SchedulingTimeSlot::SchedulingTimeSlot(const SchedulingTimeSlot& other):
00621     subChannelIndex(other.subChannelIndex),
00622     timeSlotIndex(other.timeSlotIndex),
00623     numSpatialLayers(other.numSpatialLayers),
00624     slotLength(other.slotLength),
00625     timeSlotStartTime(other.timeSlotStartTime),
00626     timeSlotIsUsable(other.timeSlotIsUsable),
00627     harq(other.harq)
00628 {
00629     for (PhysicalResourceBlockVector::const_iterator it = other.physicalResources.begin();
00630          it != other.physicalResources.end();
00631          ++it)
00632     {
00633         physicalResources.push_back(PhysicalResourceBlock(*it));
00634     }
00635 }
00636 
00637 SchedulingTimeSlot::~SchedulingTimeSlot()
00638 {
00639 }
00640 
00641 void
00642 SchedulingTimeSlot::consistencyCheck()
00643 {
00644     for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00645     {
00646         physicalResources[spatialIndex].consistencyCheck();
00647     }
00648 }
00649 
00650 simTimeType
00651 SchedulingTimeSlot::getUsedTime() const
00652 {
00653     //if (!IsUsable) return 0.0; // must be different result than getFreeTime()
00654     simTimeType usedTime = 0.0;
00655     for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00656     {
00657         usedTime += physicalResources[spatialIndex].getUsedTime();
00658     }
00659     return usedTime;
00660 }
00661 
00662 simTimeType
00663 SchedulingTimeSlot::getFreeTime() const
00664 {
00665     //if (!IsUsable) return 0.0; // must be different result than getUsedTime()
00666     simTimeType freeTime = 0.0;
00667     for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00668     {
00669         freeTime += physicalResources[spatialIndex].getFreeTime();
00670     }
00671     return freeTime;
00672 }
00673 
00674 int
00675 SchedulingTimeSlot::countScheduledCompounds() const
00676 {
00677     int count=0;
00678     for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00679     {
00680         count += physicalResources[spatialIndex].countScheduledCompounds();
00681     }
00682     return count;
00683 }
00684 
00685 bool
00686 SchedulingTimeSlot::isEmpty() const
00687 {
00688     for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00689     {
00690         if (!physicalResources[spatialIndex].isEmpty()) return false;
00691     }
00692     return true;
00693 }
00694 
00695 bool
00696 SchedulingTimeSlot::pduFitsInto(strategy::RequestForResource& request,
00697                                 MapInfoEntryPtr mapInfoEntry // <- must not contain compounds yet
00698     ) const
00699 {
00700     //if (!IsUsable) return false;
00701     // is it correct to ask like this?
00702     // or do we have to loop over all spatialLayers?
00703     int spatialLayer = mapInfoEntry->spatialLayer;
00704     assure(spatialLayer>=0 && spatialLayer<numSpatialLayers,"spatialLayer="<<spatialLayer<<" is out of bounds");
00705     return physicalResources[spatialLayer].pduFitsInto(request,mapInfoEntry);
00706 } // pduFitsInto (ResourceBlock)
00707 
00708 wns::scheduler::UserID
00709 SchedulingTimeSlot::getUserID() const
00710 {
00711     for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00712     {
00713         wns::scheduler::UserID userID = physicalResources[spatialIndex].getUserID();
00714         if (userID.isValid())
00715             return userID;
00716     }
00717     return UserID();
00718 }
00719 
00720 wns::scheduler::UserID
00721 SchedulingTimeSlot::getSourceUserID() const
00722 {
00723     for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00724     {
00725         wns::scheduler::UserID userID = physicalResources[spatialIndex].getSourceUserID();
00726     if (userID.isValid())
00727       return userID;
00728     }
00729     return UserID();
00730 }
00731 
00732 wns::Power
00733 SchedulingTimeSlot::getTxPower() const
00734 {
00735     wns::Power txPower;
00736     for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00737     {
00738         txPower = physicalResources[spatialIndex].getTxPower();
00739         if (txPower!=wns::Power())
00740             return txPower;
00741     }
00742     return txPower;
00743 }
00744 
00745 void
00746 SchedulingTimeSlot::setTxPower(wns::Power power)
00747 {
00748     // adjust contents
00749     for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00750     {
00751         physicalResources[spatialIndex].setTxPower(power);
00752     }
00753 }
00754 
00755 // dumpContents(): machine-readable format (table for Matlab,Gnuplot,etc)
00756 std::string
00757 SchedulingTimeSlot::dumpContents(const std::string& prefix) const
00758 {
00759     std::stringstream s;
00760     for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00761     {
00762         std::stringstream p;
00763         p << prefix << spatialIndex << "\t";
00764         if (timeSlotIsUsable) {
00765             s << physicalResources[spatialIndex].dumpContents(p.str());
00766         } else {
00767             s << prefix << spatialIndex << "\t" << "LOCKED" << std::endl;
00768         }
00769     }
00770     return s.str();
00771 }
00772 
00773 // doToString(): human-readable format
00774 std::string
00775 SchedulingTimeSlot::toString() const
00776 {
00777     std::stringstream s;
00778     if (timeSlotIsUsable) {
00779         for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00780         {
00781             s << physicalResources[spatialIndex].toString();
00782         }
00783     } else {
00784         s << "TimeSlot(#"<<timeSlotIndex<<"): locked/unusable" << std::endl;
00785     }
00786     return s.str();
00787 }
00788 
00789 void
00790 SchedulingTimeSlot::deleteCompounds()
00791 {
00792     for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00793     {
00794         physicalResources[spatialIndex].deleteCompounds();
00795     }
00796 }
00797 
00798 void
00799 SchedulingTimeSlot::grantFullResources()
00800 {
00801     for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00802     {
00803         physicalResources[spatialIndex].grantFullResources();
00804     }
00805 }
00806 
00807 void
00808 SchedulingTimeSlot::processMasterMap()
00809 {
00810     for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00811     {
00812         physicalResources[spatialIndex].processMasterMap();
00813     }
00814 }
00815 
00816 bool
00817 SchedulingTimeSlot::hasResourcesForUser(wns::scheduler::UserID user) const
00818 {
00819     for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00820     {
00821         if (physicalResources[spatialIndex].hasResourcesForUser(user))
00822             return true;
00823     }
00824     return false;
00825 }
00826 
00827 wns::scheduler::ChannelQualityOnOneSubChannel
00828 SchedulingTimeSlot::getEstimatedCQI(wns::scheduler::UserID user) const
00829 {
00830     assure(hasResourcesForUser(user),"TimeSlot has not resources for user");
00831     for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00832     {
00833         if (physicalResources[spatialIndex].hasResourcesForUser(user))
00834             return physicalResources[spatialIndex].getEstimatedCQI();
00835     }
00836 }
00837 
00838 int
00839 SchedulingTimeSlot::getNetBlockSizeInBits() const
00840 {
00841     int netBits = 0;
00842     for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00843     {
00844         netBits += physicalResources[spatialIndex].getNetBlockSizeInBits();
00845     }
00846     return netBits;
00847 }
00848 
00849 bool
00850 SchedulingTimeSlot::isHARQEnabled() const
00851 {
00852     for(int spatialIndex=0; spatialIndex<numSpatialLayers; spatialIndex++)
00853     {
00854         if (physicalResources[spatialIndex].isHARQEnabled())
00855         {
00856             return true;
00857         }
00858     }
00859     return false;
00860 }
00861 
00862 /**************************************************************/
00863 
00864 SchedulingSubChannel::SchedulingSubChannel()
00865     : subChannelIndex(0),
00866       numSpatialLayers(0),
00867       slotLength(0.0),
00868       subChannelIsUsable(true)
00869 {
00870 }
00871 
00872 SchedulingSubChannel::SchedulingSubChannel(int _subChannelIndex, int _numberOfTimeSlots, int _numSpatialLayers, simTimeType _slotLength)
00873     : subChannelIndex(_subChannelIndex),
00874       numberOfTimeSlots(_numberOfTimeSlots),
00875       numSpatialLayers(_numSpatialLayers),
00876       slotLength(_slotLength),
00877       subChannelIsUsable(true)
00878 {
00879     for ( int timeSlotIndex = 0; timeSlotIndex < numberOfTimeSlots; ++timeSlotIndex )
00880     {
00881         SchedulingTimeSlotPtr emptyTimeSlotPtr // SmartPtr...
00882             = SchedulingTimeSlotPtr(new SchedulingTimeSlot(subChannelIndex,timeSlotIndex,numSpatialLayers,slotLength));
00883         temporalResources.push_back(emptyTimeSlotPtr); // SmartPtr copied
00884     }
00885 }
00886 
00887 SchedulingSubChannel::~SchedulingSubChannel()
00888 {
00889     temporalResources.clear();
00890 }
00891 
00892 // dumpContents(): machine-readable format (table for Matlab,Gnuplot,etc)
00893 std::string
00894 SchedulingSubChannel::dumpContents(const std::string& prefix) const
00895 {
00896     std::stringstream s;
00897     for ( int timeSlotIndex = 0; timeSlotIndex < numberOfTimeSlots; ++timeSlotIndex )
00898     {
00899         std::stringstream p;
00900         p << prefix << timeSlotIndex << "\t";
00901         if (subChannelIsUsable) {
00902             s << temporalResources[timeSlotIndex]->dumpContents(p.str());
00903         } else {
00904             s << prefix << timeSlotIndex << "\t" << "LOCKED" << std::endl;
00905         }
00906     }
00907     return s.str();
00908 }
00909 
00910 // doToString(): human-readable format
00911 std::string
00912 SchedulingSubChannel::toString() const
00913 {
00914     std::stringstream s;
00915     if (subChannelIsUsable) {
00916         for ( int timeSlotIndex = 0; timeSlotIndex < numberOfTimeSlots; ++timeSlotIndex )
00917         {
00918             s << temporalResources[timeSlotIndex]->toString();
00919         }
00920     } else {
00921         s << "SubChannel(#"<<subChannelIndex<<"): locked/unusable" << std::endl;
00922     }
00923     return s.str();
00924 }
00925 
00926 simTimeType
00927 SchedulingSubChannel::getUsedTime() const
00928 {
00929     if (!subChannelIsUsable) return 0.0; // must be different result than getFreeTime()
00930     simTimeType usedTime = 0.0;
00931     for ( int timeSlotIndex = 0; timeSlotIndex < numberOfTimeSlots; ++timeSlotIndex )
00932     {
00933         usedTime += temporalResources[timeSlotIndex]->getUsedTime();
00934     }
00935     return usedTime;
00936 }
00937 
00938 simTimeType
00939 SchedulingSubChannel::getFreeTime() const
00940 {
00941     if (!subChannelIsUsable) return 0.0; // must be different result than getUsedTime()
00942     simTimeType freeTime = 0.0;
00943     for ( int timeSlotIndex = 0; timeSlotIndex < numberOfTimeSlots; ++timeSlotIndex )
00944     {
00945         freeTime += temporalResources[timeSlotIndex]->getFreeTime();
00946     }
00947     return freeTime;
00948 }
00949 
00950 bool
00951 SchedulingSubChannel::pduFitsInto(strategy::RequestForResource& request,
00952                                   MapInfoEntryPtr mapInfoEntry // <- must not contain compounds yet
00953     ) const
00954 {
00955     if (!subChannelIsUsable) return false;
00956     int timeSlot = mapInfoEntry->timeSlot;
00957     assure(timeSlot>=0 && timeSlot<numberOfTimeSlots,"timeSlot="<<timeSlot<<" is out of bounds");
00958     // is it correct to ask like this?
00959     // or do we have to loop over all spatialLayers?
00960     int spatialLayer = mapInfoEntry->spatialLayer;
00961     assure(spatialLayer>=0 && spatialLayer<numSpatialLayers,"spatialLayer="<<spatialLayer<<" is out of bounds");
00962     return temporalResources[timeSlot]->pduFitsInto(request,mapInfoEntry);
00963 } // pduFitsInto (SubChannel)
00964 
00965 int
00966 SchedulingSubChannel::getFreeBitsOnSubChannel(MapInfoEntryPtr mapInfoEntry) const
00967 {
00968     if (!subChannelIsUsable) return 0;
00969     int timeSlot = mapInfoEntry->timeSlot;
00970     assure(timeSlot>=0 && timeSlot<numberOfTimeSlots,"timeSlot="<<timeSlot<<" is out of bounds");
00971     // is it correct to ask like this?
00972     // or do we have to loop over all spatialLayers?
00973     int spatialLayer = mapInfoEntry->spatialLayer;
00974     assure(spatialLayer>=0 && spatialLayer<numSpatialLayers,"spatialLayer="<<spatialLayer<<" is out of bounds");
00975     return temporalResources[timeSlot]->physicalResources[spatialLayer].getFreeBitsOnPhysicalResourceBlock(mapInfoEntry);
00976 } // getFreeBitsOnSubChannel
00977 
00978 bool
00979 SchedulingSubChannel::isEmpty() const
00980 {
00981     for (int timeSlotIndex = 0; timeSlotIndex < numberOfTimeSlots; ++timeSlotIndex)
00982     {
00983         if (!temporalResources[timeSlotIndex]->isEmpty()) return false;
00984     }
00985     return true;
00986 }
00987 
00988 void
00989 SchedulingSubChannel::deleteCompounds()
00990 {
00991     for ( int timeSlotIndex = 0; timeSlotIndex < numberOfTimeSlots; ++timeSlotIndex )
00992     {
00993         temporalResources[timeSlotIndex]->deleteCompounds();
00994     }
00995 }
00996 
00997 void
00998 SchedulingSubChannel::grantFullResources()
00999 {
01000     for ( int timeSlotIndex = 0; timeSlotIndex < numberOfTimeSlots; ++timeSlotIndex )
01001     {
01002         temporalResources[timeSlotIndex]->grantFullResources();
01003     }
01004 }
01005 
01006 void
01007 SchedulingSubChannel::processMasterMap()
01008 {
01009     for ( int timeSlotIndex = 0; timeSlotIndex < numberOfTimeSlots; ++timeSlotIndex )
01010     {
01011         temporalResources[timeSlotIndex]->processMasterMap();
01012     }
01013 }
01014 
01015 bool SchedulingSubChannel::hasResourcesForUser(wns::scheduler::UserID user) const
01016 {
01017     for ( int timeSlotIndex = 0; timeSlotIndex < numberOfTimeSlots; ++timeSlotIndex )
01018     {
01019         if (temporalResources[timeSlotIndex]->hasResourcesForUser(user))
01020         return true;
01021     }
01022     return false;
01023 }
01024 
01025 wns::scheduler::ChannelQualityOnOneSubChannel
01026 SchedulingSubChannel::getEstimatedCQI(wns::scheduler::UserID user) const
01027 {
01028     assure(hasResourcesForUser(user), "SubChannel has not resources for this user");
01029     for ( int timeSlotIndex = 0; timeSlotIndex < numberOfTimeSlots; ++timeSlotIndex )
01030     {
01031         if (temporalResources[timeSlotIndex]->hasResourcesForUser(user))
01032             return temporalResources[timeSlotIndex]->getEstimatedCQI(user);
01033     }
01034 }
01035 /**************************************************************/
01036 
01037 SchedulingMap::SchedulingMap( simTimeType _slotLength, int _numberOfSubChannels, int _numberOfTimeSlots, int _numSpatialLayers, int _frameNr )
01038     : frameNr(_frameNr),
01039       slotLength(_slotLength),
01040       numberOfSubChannels(_numberOfSubChannels),
01041       numberOfTimeSlots(_numberOfTimeSlots),
01042       numSpatialLayers(_numSpatialLayers),
01043       numberOfCompounds(0),
01044       resourceUsage(0.0)
01045 {
01046     assure(numberOfSubChannels>0,"numberOfSubChannels="<<numberOfSubChannels);
01047     assure(slotLength>0.0,"slotLength="<<slotLength);
01048     for ( int subChannelIndex = 0; subChannelIndex < numberOfSubChannels; ++subChannelIndex )
01049     {
01050         SchedulingSubChannel subChannel(subChannelIndex,numberOfTimeSlots,numSpatialLayers,slotLength);
01051         subChannels.push_back(subChannel); // object copied
01052     }
01053     //#include <WNS/logger/Logger.hpp>
01054     //wns::logger::Logger logger("WNS", "SchedulingMap");
01055 } // SchedulingMap::SchedulingMap
01056 
01057 SchedulingMap::~SchedulingMap()
01058 {
01059     subChannels.clear();
01060 }
01061 
01062 bool
01063 SchedulingMap::pduFitsInto(strategy::RequestForResource& request,
01064                            MapInfoEntryPtr mapInfoEntry // <- must not contain compounds yet
01065     ) const
01066 {
01067     // mapInfoEntry can contain compounds when in while loop:
01068     //assure(mapInfoEntry->compounds.empty(),"mapInfoEntry->compounds must be empty here");
01069     int subChannelIndex = mapInfoEntry->subBand;
01070     //int timeSlot = mapInfoEntry->timeSlot;
01071     //int spatialLayer = mapInfoEntry->spatialLayer;
01072     return subChannels[subChannelIndex].pduFitsInto(request,mapInfoEntry);
01073     //return subChannels[subChannelIndex].temporalResources[timeSlot]->physicalResources[spatialLayer].pduFitsInto(request,mapInfoEntry);
01074 } // pduFitsInto (SubChannel)
01075 
01076 int
01077 SchedulingMap::getFreeBitsOnSubChannel(MapInfoEntryPtr mapInfoEntry) const
01078 {
01079     // mapInfoEntry can contain compounds when in while loop:
01080     //assure(mapInfoEntry->compounds.empty(),"mapInfoEntry->compounds must be empty here");
01081     int subChannelIndex = mapInfoEntry->subBand;
01082     //int timeSlot = mapInfoEntry->timeSlot;
01083     //int spatialLayer = mapInfoEntry->spatialLayer;
01084     return subChannels[subChannelIndex].getFreeBitsOnSubChannel(mapInfoEntry);
01085 }
01086 
01087 bool
01088 SchedulingMap::addCompound(int subChannelIndex,
01089                            int timeSlot,
01090                            int spatialLayer,
01091                            simTimeType compoundDuration,
01092                            wns::scheduler::ConnectionID connectionID,
01093                            wns::scheduler::UserID userID,
01094                            wns::scheduler::UserID sourceUserID,
01095                            wns::ldk::CompoundPtr compoundPtr,
01096                            wns::service::phy::phymode::PhyModeInterfacePtr phyModePtr,
01097                            wns::Power txPower,
01098                            wns::service::phy::ofdma::PatternPtr pattern,
01099                            ChannelQualityOnOneSubChannel estimatedCQI,
01100                            bool useHARQ
01101     )
01102 {
01103     bool ok =
01104         subChannels[subChannelIndex].temporalResources[timeSlot]->physicalResources[spatialLayer].addCompound(
01105             compoundDuration,
01106             connectionID,
01107             userID,
01108             sourceUserID,
01109             compoundPtr,
01110             phyModePtr,
01111             txPower,
01112             pattern,
01113             estimatedCQI,
01114             useHARQ
01115             );
01116     if (ok) {
01117         numberOfCompounds++;
01118     }
01119     return ok;
01120 } // addCompound
01121 
01122 bool
01123 SchedulingMap::addCompound(strategy::RequestForResource& request,
01124                            MapInfoEntryPtr mapInfoEntry, // <- must not contain compounds yet
01125                            wns::ldk::CompoundPtr compoundPtr,
01126                            bool useHARQ
01127     )
01128 {
01129     // mapInfoEntry can contain compounds when in while loop:
01130     //assure(mapInfoEntry->compounds.empty(),"mapInfoEntry->compounds must be empty here");
01131     int subChannelIndex = mapInfoEntry->subBand;
01132     int timeSlot = mapInfoEntry->timeSlot;
01133     int spatialLayer = mapInfoEntry->spatialLayer;
01134     bool ok =
01135         subChannels[subChannelIndex].temporalResources[timeSlot]->physicalResources[spatialLayer].addCompound(
01136             request,
01137             mapInfoEntry,
01138             compoundPtr,
01139             useHARQ
01140             );
01141     if (ok) {
01142         numberOfCompounds++;
01143     }
01144     return ok;
01145 } // addCompound
01146 
01147 simTimeType
01148 SchedulingMap::getNextPosition(int subChannel, int timeSlot, int spatialLayer) const
01149 {
01150     assure(subChannel<numberOfSubChannels,"subChannel="<<subChannel<<" >= numberOfSubChannels="<<numberOfSubChannels);
01151     assure(timeSlot>=0 && timeSlot<numberOfTimeSlots,"timeSlot="<<timeSlot<<" >= numberOfTimeSlots="<<numberOfTimeSlots);
01152     assure(spatialLayer<numSpatialLayers,"spatialLayer="<<spatialLayer<<" >= numSpatialLayers="<<numSpatialLayers);
01153     return subChannels[subChannel].temporalResources[timeSlot]->physicalResources[spatialLayer].getNextPosition();
01154 }
01155 
01156 bool
01157 SchedulingMap::isEmpty() const
01158 {
01159     for ( unsigned int subChannelIndex = 0; subChannelIndex < subChannels.size(); ++subChannelIndex )
01160     {
01161         if (!subChannels[subChannelIndex].isEmpty()) return false;
01162     }
01163     return true;
01164 }
01165 
01166 int
01167 SchedulingMap::getFrameNr() const
01168 {
01169     return this->frameNr;
01170 }
01171 
01172 double
01173 SchedulingMap::getResourceUsage()
01174 {
01175     simTimeType totalUsedTime = getUsedTime();
01176     simTimeType totalTimeResources = slotLength * numberOfSubChannels * numSpatialLayers * numberOfTimeSlots;
01177     double result = totalUsedTime / totalTimeResources;
01178     assure(numberOfSubChannels==subChannels.size(),"mismatch in numberOfSubChannels: "<<numberOfSubChannels<<" != "<<subChannels.size());
01179     assure((result >= -0.01)/*tolerance*/
01180            &&(result <= 1.01)
01181            , "Percentage of used resources="<<result<<" must be within [0..1] !"
01182            <<" totalUsedTime="<<totalUsedTime
01183            <<", totalTime="<<totalTimeResources
01184            <<", subChannels.size="<<subChannels.size());
01185     if (result<0.0) result=0.0;
01186     if (result>1.0) result=1.0;
01187     resourceUsage = result; // store result in member
01188     return result;
01189 } // getResourceUsage
01190 
01191 simTimeType
01192 SchedulingMap::getUsedTime() const
01193 {
01194     simTimeType usedTime = 0;
01195     assure(numberOfSubChannels==subChannels.size(),"mismatch in numberOfSubChannels: "<<numberOfSubChannels<<" != "<<subChannels.size());
01196     for ( unsigned int subChannelIndex = 0; subChannelIndex < subChannels.size(); ++subChannelIndex )
01197     {
01198         usedTime += subChannels[subChannelIndex].getUsedTime();
01199     }
01200     return usedTime;
01201 } // getUsedTime
01202 
01203 simTimeType
01204 SchedulingMap::getFreeTime() const
01205 {
01206     simTimeType leftoverTime = 0;
01207     assure(numberOfSubChannels==subChannels.size(),"mismatch in numberOfSubChannels: "<<numberOfSubChannels<<" != "<<subChannels.size());
01208     for ( unsigned int subChannelIndex = 0; subChannelIndex < subChannels.size(); ++subChannelIndex )
01209     {
01210         leftoverTime += subChannels[subChannelIndex].getFreeTime();
01211     }
01212     return leftoverTime;
01213 } // getFreeTime
01214 
01215 wns::Power
01216 SchedulingMap::getUsedPower(int timeSlot) const
01217 {
01218     assure(timeSlot>=0 && timeSlot<numberOfTimeSlots,"timeSlot="<<timeSlot<<" >= numberOfTimeSlots="<<numberOfTimeSlots);
01219     wns::Power usedPower; // = 0W
01220     for(unsigned int subChannelIndex=0; subChannelIndex<numberOfSubChannels; subChannelIndex++)
01221     {
01222         // what is the right handling of MIMO? Do we count=add txPower per spatialLayer or do we assume this is all "one" power?
01223         //wns::Power usedTxPowerOnThisChannel = subChannels[subChannelIndex].txPower;
01224         // we assume that txPower is the same on all PRBs, so reading the first is sufficient:
01225         wns::Power usedTxPowerOnThisChannel = subChannels[subChannelIndex].temporalResources[timeSlot]->physicalResources[0/*first beam*/].getTxPower();
01226         // if we have no PDU allocated on this channel, just skip it.
01227         if (usedTxPowerOnThisChannel == wns::Power())
01228             continue;
01229         usedPower += usedTxPowerOnThisChannel;
01230     }
01231     return usedPower;
01232 } // getUsedPower
01233 
01234 wns::Power
01235 SchedulingMap::getRemainingPower(wns::Power totalPower, int timeSlot) const
01236 {
01237     assure(timeSlot>=0 && timeSlot<numberOfTimeSlots,"timeSlot="<<timeSlot<<" >= numberOfTimeSlots="<<numberOfTimeSlots);
01238     wns::Power remainingPower = totalPower;
01239     for(unsigned int subChannelIndex=0; subChannelIndex<numberOfSubChannels; subChannelIndex++)
01240     {
01241         // what is the right handling of MIMO? Do we count=add txPower per spatialLayer or do we assume this is all "one" power?
01242         //wns::Power usedTxPowerOnThisChannel = subChannels[subChannelIndex].txPower;
01243         // we assume that txPower is the same on all PRBs, so reading the first is sufficient:
01244         wns::Power usedTxPowerOnThisChannel = subChannels[subChannelIndex].temporalResources[timeSlot]->physicalResources[0/*first spatialLayer*/].getTxPower();
01245         // if we have no PDU allocated on this channel, just skip it.
01246         if (usedTxPowerOnThisChannel == wns::Power())
01247             continue;
01248         if (remainingPower<usedTxPowerOnThisChannel)
01249             return wns::Power(); // zero Watts;
01250         remainingPower -= usedTxPowerOnThisChannel;
01251     }
01252     // the counter totalRemainingPower should be used in the future:
01253     //assure(remainingPower == totalRemainingPower,"remainingPower="<<remainingPower<<" != totalRemainingPower="<<totalRemainingPower);
01254     return remainingPower;
01255 } // getRemainingPower
01256 
01257 wns::service::phy::phymode::PhyModeInterfacePtr
01258 SchedulingMap::getPhyModeUsedInResource(int subChannelIndex, int timeSlot, int spatialLayer) const
01259 {
01260     assure(subChannelIndex>=0 && subChannelIndex<numberOfSubChannels,"subChannelIndex="<<subChannelIndex);
01261     assure(timeSlot>=0 && timeSlot<numberOfTimeSlots,"timeSlot="<<timeSlot<<" >= numberOfTimeSlots="<<numberOfTimeSlots);
01262     assure(spatialLayer>=0 && spatialLayer < numSpatialLayers,"spatialLayer="<<spatialLayer);
01263     return subChannels[subChannelIndex].temporalResources[timeSlot]->physicalResources[spatialLayer].getPhyMode();
01264 }
01265 
01266 wns::Power
01267 SchedulingMap::getTxPowerUsedInResource(int subChannelIndex, int timeSlot, int spatialLayer) const
01268 {
01269     assure(subChannelIndex>=0 && subChannelIndex<numberOfSubChannels,"subChannelIndex="<<subChannelIndex);
01270     assure(timeSlot>=0 && timeSlot<numberOfTimeSlots,"timeSlot="<<timeSlot<<" >= numberOfTimeSlots="<<numberOfTimeSlots);
01271     assure(spatialLayer>=0 && spatialLayer < numSpatialLayers,"spatialLayer="<<spatialLayer);
01272     
01273     wns::Power powerInResource = subChannels[subChannelIndex].temporalResources[timeSlot]->getTxPower();
01274     assure(fabs(subChannels[subChannelIndex].temporalResources[timeSlot]->physicalResources[spatialLayer].getTxPower().get_mW() - powerInResource.get_mW())<1e-3,
01275            "mismatch in powerInResource="<<powerInResource);
01276     return powerInResource;
01277 }
01278 
01279 void
01280 SchedulingMap::maskOutSubChannels(const UsableSubChannelVector& usableSubChannels)
01281 {
01282     //std::cout <<"maskOutSubChannels(#="<<usableSubChannels.size()<<"): usable="<<printBoolVector(usableSubChannels)<<std::endl;
01283     assure(usableSubChannels.size()>=numberOfSubChannels,"#usableSubChannels="<<usableSubChannels.size());
01284     for ( int subChannelIndex = 0; subChannelIndex < numberOfSubChannels; ++subChannelIndex )
01285     {
01286         bool before = subChannels[subChannelIndex].subChannelIsUsable;
01287         bool mask   = usableSubChannels[subChannelIndex];
01288         bool after  = before & mask; // 0&1=0
01289         subChannels[subChannelIndex].subChannelIsUsable = after;
01290     }
01291 } // maskOutSubChannels
01292 
01293 // void
01294 // SchedulingMap::convertToMapInfoCollection(MapInfoCollectionPtr collection /*return value*/)
01295 // {
01296 //     // translate result into currentBurst to allow bursts.push_back(currentBurst)
01297 //     for ( SubChannelVector::iterator iterSubChannel = subChannels.begin();
01298 //           iterSubChannel != subChannels.end(); ++iterSubChannel)
01299 //     {
01300 //         SchedulingSubChannel& subChannel = *iterSubChannel;
01301 //         for ( SchedulingTimeSlotPtrVector::iterator iterTimeSlot = subChannel.temporalResources.begin();
01302 //               iterTimeSlot != subChannel.temporalResources.end(); ++iterTimeSlot)
01303 //         {
01304 //             SchedulingTimeSlotPtr timeSlotPtr = *iterTimeSlot;
01305 //             for ( PhysicalResourceBlockVector::iterator iterPRB = timeSlotPtr->physicalResources.begin();
01306 //                   iterPRB != timeSlotPtr->physicalResources.end(); ++iterPRB)
01307 //             {
01308 //                 UserID lastScheduledUserID;
01309 //                 MapInfoEntryPtr currentBurst;
01310 //                 double currentBurstStartTime = 0.0;
01311 //                 while ( !iterPRB->scheduledCompounds.empty() )
01312 //                 {
01313 //                     SchedulingCompound compound = iterPRB->scheduledCompounds.front(); // .front()
01314 //                     iterPRB->scheduledCompounds.pop_front(); // pop_front()
01315 //                     if ( compound.userID != lastScheduledUserID ) // new User, starts new Burst
01316 //                     {
01317 //                         //MESSAGE_SINGLE(NORMAL, logger, "New compund of cid=" << iterCompound.userID->getName());
01318 //                         // new user -> new newburst=new map entry
01319 //                         currentBurst = MapInfoEntryPtr(new MapInfoEntry());
01320 //                         currentBurst->start          = compound.startTime;
01321 //                         currentBurst->end            = compound.startTime; // intentionally not endTime;
01322 //                         currentBurst->user           = compound.userID;
01323 //                         currentBurst->subBand        = compound.subChannel;
01324 //                         currentBurst->timeSlot       = compound.timeSlot;
01325 //                         currentBurst->beam           = compound.beam;
01326 //                         currentBurst->txPower        = compound.txPower;
01327 //                         currentBurst->phyModePtr     = compound.phyModePtr;
01328 //                         //currentBurst->estimatedCandI = ? how to get it here?
01329 //                         collection->push_back(currentBurst);
01330 //                     }
01331 //                     //bursts.back()->end += iterCompound.compoundDuration;
01332 //                     simTimeType compoundDuration = compound.getCompoundDuration();
01333 //                     currentBurst->end     += compoundDuration;
01334 //                     currentBurstStartTime += compoundDuration;
01335 //                     //compound gehort zum selben connection fuege hinten ein
01336 //                     collection->back()->compounds.push_back(compound.compoundPtr);
01337 
01338 //                     // inherited from Strategy.cpp; calls callback():
01339 //                     // compoundReady() // cannot do this here.
01340 //                     lastScheduledUserID = compound.userID;
01341 //                 } // end while ( !iterSubChannel->scheduledCompounds.empty() )
01342 //             } // end for ( beams )
01343 //         } // end for ( timeSlots )
01344 //     } // end for ( SubChannels )
01345 // } // convertToMapInfoCollection
01346 
01347 
01348 // this is called by the UL master scheduler, because there are no "real" compounds (just fakes).
01349 void
01350 SchedulingMap::deleteCompounds()
01351 {
01352     for ( int subChannelIndex = 0; subChannelIndex < numberOfSubChannels; ++subChannelIndex )
01353     {
01354         subChannels[subChannelIndex].deleteCompounds();
01355     }
01356     numberOfCompounds = 0;
01357 }
01358 
01359 void
01360 SchedulingMap::grantFullResources()
01361 {
01362     for ( int subChannelIndex = 0; subChannelIndex < numberOfSubChannels; ++subChannelIndex )
01363     {
01364         subChannels[subChannelIndex].grantFullResources();
01365     }
01366 }
01367 
01368 void
01369 SchedulingMap::processMasterMap()
01370 {
01371     for ( int subChannelIndex = 0; subChannelIndex < numberOfSubChannels; ++subChannelIndex )
01372     {
01373         subChannels[subChannelIndex].processMasterMap();
01374     }
01375 }
01376 
01377 bool
01378 SchedulingMap::hasResourcesForUser(wns::scheduler::UserID user) const
01379 {
01380     for ( int subChannelIndex = 0; subChannelIndex < numberOfSubChannels; ++subChannelIndex )
01381     {
01382         if (subChannels[subChannelIndex].hasResourcesForUser(user))
01383             return true;
01384     }
01385     return false;
01386 }
01387 
01388 wns::scheduler::ChannelQualityOnOneSubChannel
01389 SchedulingMap::getEstimatedCQI(wns::scheduler::UserID user) const
01390 {
01391     assure(hasResourcesForUser(user), "SchedulingMap has not resources for user");
01392     for ( int subChannelIndex = 0; subChannelIndex < numberOfSubChannels; ++subChannelIndex )
01393     {
01394         if (subChannels[subChannelIndex].hasResourcesForUser(user))
01395             return subChannels[subChannelIndex].getEstimatedCQI(user);
01396     }
01397 
01398 }
01399 
01400 // toString(): human-readable format (incuding resourceUsage)
01401 std::string
01402 SchedulingMap::toString()
01403 {
01404     std::stringstream s;
01405     s.setf(std::ios::fixed,std::ios::floatfield);   // floatfield set to fixed
01406     s.precision(1);
01407     assure(numberOfSubChannels==subChannels.size(),"numberOfSubChannels="<<numberOfSubChannels<<" != subChannels.size()="<<subChannels.size());
01408     if (frameNr>=0) { // valid frameNr
01409         s << "SchedulingMap(frame="<<frameNr<<": "<<numberOfSubChannels<<"x"<<slotLength*1e6<<"us): ";
01410     } else {
01411         s << "SchedulingMap("<<numberOfSubChannels<<"x"<<slotLength*1e6<<"us): ";
01412     }
01413     double resourceUsage = this->getResourceUsage(); // getResourceUsage() is not const
01414     if (this->isEmpty()) {
01415         s << "empty." << std::endl;
01416     } else {
01417         s << resourceUsage*100.0 << "% full." << std::endl;
01418         for ( int subChannelIndex = 0; subChannelIndex < numberOfSubChannels; ++subChannelIndex )
01419         {
01420             s << subChannels[subChannelIndex].toString();
01421         }
01422     }
01423     return s.str();
01424 } // toString
01425 
01426 // doToString(): human-readable format
01427 std::string
01428 SchedulingMap::doToString() const
01429 {
01430     std::stringstream s;
01431     s.setf(std::ios::fixed,std::ios::floatfield);   // floatfield set to fixed
01432     s.precision(1);
01433     assure(numberOfSubChannels==subChannels.size(),"numberOfSubChannels="<<numberOfSubChannels<<" != subChannels.size()="<<subChannels.size());
01434     if (frameNr>=0) { // valid frameNr
01435         s << "SchedulingMap(frame="<<frameNr<<": "<<numberOfSubChannels<<"x"<<slotLength*1e6<<"us): ";
01436     } else {
01437         s << "SchedulingMap("<<numberOfSubChannels<<"x"<<slotLength*1e6<<"us): ";
01438     }
01439     if (this->isEmpty()) {
01440         s << "empty." << std::endl;
01441     } else {
01442         for ( int subChannelIndex = 0; subChannelIndex < numberOfSubChannels; ++subChannelIndex )
01443         {
01444             s << subChannels[subChannelIndex].toString();
01445         }
01446     }
01447     return s.str();
01448 } // doToString
01449 
01450 // dumpContents(): machine-readable format (table for Matlab,Gnuplot,etc)
01451 std::string
01452 SchedulingMap::dumpContents(const std::string& prefix) const
01453 {
01454     std::stringstream s;
01455     //s.setf(std::ios::fixed,std::ios::floatfield);   // floatfield set to fixed
01456     //s.precision(1);
01457     assure(numberOfSubChannels==subChannels.size(),"numberOfSubChannels="<<numberOfSubChannels<<" != subChannels.size()="<<subChannels.size());
01458     for ( int subChannelIndex = 0; subChannelIndex < numberOfSubChannels; ++subChannelIndex )
01459     {
01460         std::stringstream p;
01461         p << prefix << frameNr << "\t" << subChannelIndex << "\t";
01462         s << subChannels[subChannelIndex].dumpContents(p.str());
01463     }
01464     return s.str();
01465 } // dumpContents
01466 
01467 // static (does not need an object of this class)
01468 void
01469 SchedulingMap::writeHeaderToFile(std::ofstream& f)
01470 {
01471     if (f.is_open()) {
01472         f << "##### SchedulingMap over time #####" << std::endl;
01473         //f << "# numberOfSubChannels="<<numberOfSubChannels << std::endl;
01474         //f << "# numberOfTimeSlots="<<numberOfTimeSlots << std::endl;
01475         //f << "# numSpatialLayers="<<numSpatialLayers << std::endl;
01476         //f << "# slotLength="<<slotLength << std::endl;
01477         f << "# (time[s]) frameNr subChannel timeSlot stream/spatialLayer bits/symbol txPower[dBm] filled% #compounds userID cidList(#bits), totalbits" << std::endl;
01478     } else {
01479         throw wns::Exception("cannot write to file");
01480     }
01481 }
01482 
01483 void
01484 SchedulingMap::writeToFile(std::ofstream& f, const std::string& prefix) const
01485 {
01486     if (f.is_open()) {
01487         f << dumpContents(prefix);
01488     } else {
01489         throw wns::Exception("cannot write to file");
01490     }
01491 }
01492 
01493 void
01494 SchedulingMap::writeFile(std::string fileName) const
01495 {
01496     //std::ofstream *file = new std::ofstream(fileName.c_str());
01497     //(*file) << doToString();
01498     //if (*file) file->close();
01499     std::ofstream file(fileName.c_str(),std::ios_base::app); // append
01500     if (file.is_open())
01501     {
01502         writeToFile(file,"");
01503         file.close();
01504     } else {
01505         throw wns::Exception("cannot open file "+fileName);
01506     }
01507 }

Generated on Fri May 25 03:31:54 2012 for openWNS by  doxygen 1.5.5