![]() |
User Manual, Developers Guide and API Documentation |
![]() |
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 }
1.5.5