![]() |
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-2007 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 <RISE/plmapping/MI2PER.hpp> 00029 #include <RISE/plmapping/CodeRates.hpp> 00030 00031 #include <cmath> 00032 #include <sstream> 00033 #include <vector> 00034 #include <WNS/StaticFactoryBroker.hpp> 00035 #include <WNS/PyConfigViewCreator.hpp> 00036 #include <WNS/Assure.hpp> 00037 #include <WNS/Ttos.hpp> 00038 00039 using namespace rise; 00040 using namespace rise::plmapping; 00041 00042 STATIC_FACTORY_BROKER_REGISTER(CoderFullMapping, 00043 wns::service::phy::phymode::CoderFullMappingInterface, 00044 "rise.plmapping.CoderFullMapping"); 00045 00046 STATIC_FACTORY_REGISTER_WITH_CREATOR( TableCoder, CoderFullSpecification, "rise.CoderSpecification.Table", wns::PyConfigViewCreator); 00047 STATIC_FACTORY_REGISTER_WITH_CREATOR( FormulaCoder, CoderFullSpecification, "rise.CoderSpecification.Formula", wns::PyConfigViewCreator); 00048 00049 STATIC_FACTORY_REGISTER_WITH_CREATOR( GENERICM2P, wns::service::phy::phymode::MI2PERMappingInterface, "rise.plmapping.GENERIC", wns::PyConfigViewCreator); 00050 STATIC_FACTORY_REGISTER_WITH_CREATOR( WINNERM2P, wns::service::phy::phymode::MI2PERMappingInterface, "rise.plmapping.WINNER", wns::PyConfigViewCreator); 00051 STATIC_FACTORY_REGISTER_WITH_CREATOR( FixedM2P, wns::service::phy::phymode::MI2PERMappingInterface, "rise.plmapping.Fixed", wns::PyConfigViewCreator); 00052 STATIC_FACTORY_REGISTER_WITH_CREATOR( FormulaM2P, wns::service::phy::phymode::MI2PERMappingInterface, "rise.plmapping.Formula", wns::PyConfigViewCreator); 00053 00054 00055 TableCoder::TableCoder(const wns::pyconfig::View& config) 00056 : CoderFullSpecification(config), 00057 numberOfCWLs(0), 00058 logger(std::string("RISE"), std::string("MI2PERmapper")) 00059 //logger(config.get("logger")) // TODO 00060 { 00061 MESSAGE_SINGLE(VERBOSE, logger, "TableCoder::Constructor:"); 00062 // ugly, but we have to set some base class members here 00063 assure(config.knows("coderName"),"PyConfig: missing: coderName"); 00064 name = config.get<std::string>("coderName"); // inherited member name 00065 coding = config.get<Coding>("index"); // inherited 00066 rate = config.get<double>("rate"); // inherited 00067 codeWordLengths.clear(); // empty vector 00068 vectorOfTablesByCWLSize.clear(); // empty vector 00069 00070 assure(config.knows("cwlTable"),"PyConfig: missing: cwlTable"); 00071 numberOfCWLs = config.len("cwlTable"); // member 00072 if (numberOfCWLs==0) { 00073 MESSAGE_SINGLE(NORMAL, logger, "Coder["<<coding<<"]="<<name<<": empty table."); 00074 } else { 00075 MESSAGE_BEGIN(NORMAL, logger, m, "Coder["<<coding<<"]="<<name<<": cwlTable[0.."<<numberOfCWLs-1<<"]=("); 00076 //m << "brutto CWL[bits]=("; 00077 for (unsigned int cwlIndex=0; cwlIndex<numberOfCWLs; ++cwlIndex){ m << config.get<int>("cwlTable",cwlIndex) << ","; } 00078 m << ")"; 00079 MESSAGE_END(); 00080 00081 for (unsigned int cwlIndex=0; cwlIndex<numberOfCWLs; ++cwlIndex) { 00082 int CWL = config.get<int>("cwlTable",cwlIndex); 00083 //MESSAGE_SINGLE(NORMAL, logger, "Working on CWL: "<<CWL); 00084 codeWordLengths.push_back(CWL); //codeWordLengths[cwlIndex] = CWL; 00085 assure(codeWordLengths[cwlIndex] == CWL, "CWL problem"); 00086 } 00087 assure(codeWordLengths.size() == numberOfCWLs, "invalid codeWordLengths"); 00088 //CodeWordLengths codeWordLengths; // codeWordLengths[0..5]={300,600,...} 00089 std::sort(codeWordLengths.begin(),codeWordLengths.end()); 00090 //MESSAGE_BEGIN(NORMAL, logger, m, " - codeWordLengths=("); 00091 // for (unsigned int cwlIndex=0; cwlIndex<numberOfCWLs; ++cwlIndex){ m << codeWordLengths[cwlIndex] << ","; } 00092 // m << ")"; 00093 //MESSAGE_END(); 00094 00095 //SizeRegistry sizeRegistry; // member 00096 for (unsigned int cwlIndex=0; cwlIndex<numberOfCWLs; ++cwlIndex){ 00097 int CWL = codeWordLengths[cwlIndex]; 00098 //MESSAGE_SINGLE(VERBOSE, logger, " - Reading table for CWL=" << CWL ); 00099 assure(config.knows("sizeRegistry["+wns::Ttos(CWL)+"]"),"PyConfig: missing: "<<"sizeRegistry["<<CWL<<"]"); 00100 unsigned int tableSize = config.len("sizeRegistry["+wns::Ttos(CWL)+"]"); 00101 MESSAGE_SINGLE(VERBOSE, logger, " - Reading table for CWL="<<CWL<<": "<<tableSize<<" elements."); 00102 LookupTable table(tableSize); // temporary object 00103 for (unsigned int miIndex=0; miIndex<tableSize; ++miIndex) { // forall mi values 00104 double perValue = config.get<double>("sizeRegistry["+wns::Ttos(CWL)+"]["+wns::Ttos(miIndex)+"][1]"); 00105 // the original tables often have ripple near per=1.0. Bad thing. 00106 // mathematical correction to make function monotonously decreasing: 00107 if (perValue>1.0) perValue=1.0; 00108 int past=1; 00109 while(((int)miIndex-past>=0) && (table[miIndex-past] < perValue)) { 00110 table[miIndex-past]=perValue; past++; 00111 } 00112 table[miIndex] = perValue; 00113 } // forall mi values 00114 assure(table.size() == tableSize, "wrong size of table"); 00115 //sizeRegistry.insert(CWL, table); // table is copied 00116 // better: 00117 vectorOfTablesByCWLSize.push_back(table); // table is copied 00118 } // forall CWLs 00119 //assure(sizeRegistry.size() == numberOfCWLs, "wrong size of sizeRegistry"); 00120 assure(vectorOfTablesByCWLSize.size() == numberOfCWLs, "wrong size of vectorOfTablesByCWLSize"); 00121 } // if not empty 00122 } // CoderFullSpecification::configure() 00123 00124 unsigned int 00125 TableCoder::suitableCWL(unsigned int blockLength /* gross */) const 00126 { 00127 unsigned int distance = 0; 00128 unsigned int minDistance = INT_MAX; 00129 unsigned int result = 0; 00130 //MESSAGE_SINGLE(NORMAL, logger, "CoderFullSpecification::suitableCWL("<<blockLength<<")"); 00131 assure(numberOfCWLs == codeWordLengths.size(), "invalid codeWordLengths"); 00132 for (unsigned int cwlIndex=0; cwlIndex<numberOfCWLs; ++cwlIndex){ 00133 unsigned int cwl = codeWordLengths.at(cwlIndex); // =codeWordLengths[cwlIndex] 00134 distance = cwl > blockLength ? cwl - blockLength : blockLength - cwl; 00135 if (distance<minDistance) { 00136 minDistance = distance; 00137 result = cwl; 00138 } else if (distance==minDistance) { 00139 // Use the smaller of two CWLs in case of doubt 00140 result = std::min( result, cwl ); 00141 } 00142 } 00143 MESSAGE_SINGLE(NORMAL, logger, "CoderFullSpecification::suitableCWL("<<blockLength<<") = "<<result); 00144 return result; 00145 } 00146 00147 unsigned int 00148 TableCoder::suitableCWLposition(unsigned int blockLength /* gross */) const 00149 { 00150 unsigned int distance = 0; 00151 unsigned int minDistance = INT_MAX; 00152 unsigned int resultCWL = 0; 00153 unsigned int resultCWLposition = 0; 00154 //MESSAGE_SINGLE(NORMAL, logger, "CoderFullSpecification::suitableCWL("<<blockLength<<")"); 00155 assure(numberOfCWLs == codeWordLengths.size(), "invalid codeWordLengths"); 00156 for (unsigned int cwlIndex=0; cwlIndex<numberOfCWLs; ++cwlIndex){ 00157 unsigned int cwl = codeWordLengths.at(cwlIndex); // =codeWordLengths[cwlIndex] 00158 distance = cwl > blockLength ? cwl - blockLength : blockLength - cwl; 00159 //MESSAGE_SINGLE(NORMAL, logger, "CoderFullSpecification::suitableCWL("<<blockLength<<"): compare["<<cwlIndex<<"] with cwl="<<cwl); 00160 if (distance<minDistance) { 00161 minDistance = distance; 00162 resultCWL = cwl; resultCWLposition = cwlIndex; 00163 } else if (distance==minDistance) { 00164 // Use the smaller of two CWLs in case of doubt 00165 resultCWL = std::min( resultCWL, cwl ); 00166 } 00167 } 00168 MESSAGE_SINGLE(NORMAL, logger, "CoderFullSpecification::suitableCWL("<<blockLength<<") = "<<resultCWL); 00169 return resultCWLposition; 00170 } 00171 00172 const CodeWordLengths& 00173 TableCoder::getCWLvector() const 00174 { 00175 return codeWordLengths; 00176 } 00177 00178 double 00179 TableCoder::mapMI2PER(double mi, 00180 /* blockLength=payload[net], not CWL[gross] */ 00181 unsigned int blockLength) const 00182 { 00183 MESSAGE_SINGLE(NORMAL,logger,"CoderFullSpecification::mapMI2PER(mi="<<mi<<",bl="<<blockLength<<")"); 00184 if (mi > (1.0 - 1e-6)) { return 0.0; } // mi=1.0 => no PER 00185 00186 //unsigned int bruttobits = (unsigned int) ((1.0*blockLength) / getRate()); 00187 unsigned int bruttobits = (unsigned int) ((1.0*blockLength) / rate); // member 00188 00189 // We only have tables for discrete CWLs, so 00190 // method 1 is, to choose the next matching CWL in table: 00191 // try to find the best Matching Codeword Length 00192 //unsigned int CWL = suitableCWL(bruttobits); 00193 unsigned int CWLposition = suitableCWLposition(bruttobits); 00194 // method 2 would be a kind of interpolation (but never average PER values!!!) 00195 00196 MESSAGE_BEGIN(NORMAL, logger, m, "Mapping for block: netto="); 00197 m << blockLength << " Bits, brutto=" 00198 << bruttobits << " Bits, using table for CWL=" << codeWordLengths.at(CWLposition) << " Bits."; 00199 MESSAGE_END(); 00200 00201 // obtain lookup table for the best matching code word length 00202 //const LookupTable &table = sizeRegistry.find(CWL); // copy??? 00203 assure(vectorOfTablesByCWLSize.size()>CWLposition,"invalid size"); 00204 const LookupTable& table = vectorOfTablesByCWLSize[CWLposition]; 00205 // ^ reference (faster, without copy) 00206 00207 // round mi for lookup 00208 //int MI = int(1000.0*mi + 0.5); // implicit policy for the table 00209 //return table[MI]; 00210 // NEW: interpolation: 00211 int MI1 = int(1000.0*mi); 00212 int MI2 = int(1000.0*mi)+1; 00213 double PER1= table[MI1]; 00214 double PER2= table[MI2]; 00215 double PER = PER1 + (PER2-PER1)*(mi*1000.0-(double)MI1); // linear interpolation 00216 return PER; 00217 } // CoderFullSpecification::mapMI2PER() 00218 00219 double 00220 TableCoder::PER2MIB(double per, unsigned int blockLength /* smaller number (payload) */) const 00221 { 00222 if (per <= 0.0) { return 1.0; } 00223 if (per >= 1.0) { return 0.0; } 00224 unsigned int bruttobits = (unsigned int) ((1.0*blockLength) / rate); // member 00225 unsigned int CWLposition = suitableCWLposition(bruttobits); 00226 assure(vectorOfTablesByCWLSize.size()>CWLposition,"CWLposition out of bounds"); 00227 const LookupTable& table = vectorOfTablesByCWLSize[CWLposition]; 00228 const unsigned int tableSize=table.size(); 00229 assure(tableSize>0,"empty table"); 00230 unsigned int leftBracket=0; 00231 unsigned int rightBracket=tableSize-1; 00232 unsigned int currentPosition=tableSize*3/4; // good guess for mi tables 00233 double mi=1.0; // best case 00234 double leftPER = table[leftBracket]; 00235 double rightPER = table[rightBracket]; 00236 double slope = rightPER - leftPER; // always negative for MI2PER 00237 double riseOrFall = (slope>=0) ? 1.0 : -1.0; 00238 // successive approximation: 00239 while ( (rightBracket-leftBracket)>1 ) { 00240 double PER = table[currentPosition]; 00241 //std::cout << "PER2MIB(): ["<<leftBracket<<","<<currentPosition<<","<<rightBracket<<"]: per=["<<leftPER<<","<<PER<<","<<rightPER<<"]" <<std::endl; 00242 if ( riseOrFall*(per-PER)>0 ) { // go right 00243 leftBracket = currentPosition; 00244 leftPER = table[leftBracket]; 00245 } else { // go left 00246 rightBracket = currentPosition; 00247 rightPER = table[rightBracket]; 00248 } 00249 currentPosition = (rightBracket + leftBracket)/2; // middle 00250 } 00251 // linear interpolation: 00252 double leftMI = leftBracket/1000.0; 00253 double rightMI = rightBracket/1000.0; 00254 if (rightBracket==1000) { rightPER=0.0; } // few tables have >0 at the end which leads to errors 00255 double deltaPER = (per-leftPER)/(rightPER-leftPER); 00256 //MESSAGE_SINGLE(NORMAL, logger, "PER2MIB(per="<<per<<", blockLength="<<blockLength<<"): "<<leftMI<<"<=MI<="<<rightMI<<", leftPER="<<leftPER<<", rightPER="<<rightPER<<", deltaPER="<<deltaPER); 00257 assure(deltaPER>=0.0,"PER2MIB(per="<<per<<", blockLength="<<blockLength<<"): "<<leftMI<<"<=MI<="<<rightMI<<", leftPER="<<leftPER<<", rightPER="<<rightPER<<", deltaPER="<<deltaPER); 00258 assure(deltaPER<=1.0,"PER2MIB(per="<<per<<", blockLength="<<blockLength<<"): "<<leftMI<<"<=MI<="<<rightMI<<", leftPER="<<leftPER<<", rightPER="<<rightPER<<", deltaPER="<<deltaPER); 00259 mi = leftMI + (rightMI-leftMI)*deltaPER; 00260 return mi; 00261 } 00262 00263 00264 double 00265 FormulaCoder::mapMI2PER(double /*mi*/, 00266 unsigned int /*blockLength*/) const 00267 { 00268 assure(false, "Currently No working implementation here"); 00269 /* 00270 // by formula: 00271 ser = pow(10.0, serlog); 00272 spp = double(compound->getLengthInBits()) 00273 /double(PHYTools::getBitsPerSymbol(phyMode)); 00274 // FIXME: Wrongness because of truncation of the Symbols per Packet 00275 per=1-pow((1-ser),spp); 00276 */ 00277 return 0.0; 00278 } 00279 00280 double 00281 FormulaCoder::PER2MIB(double /*per*/, unsigned int /*blockLength*/) const 00282 { 00283 assure(false, "Currently No working implementation here"); 00284 return 0.0; 00285 } 00286 00287 /**************************************************************/ 00288 00290 CoderFullSpecification* 00291 getCoderSpec(const wns::pyconfig::View& config) 00292 { 00293 std::string coderSpecType = config.get<std::string>("nameInCoderSpecFactory"); 00294 return CoderSpecFactory::creator(coderSpecType)->create(config); 00295 } 00296 00297 CoderFullMapping::CoderFullMapping(const wns::pyconfig::View& config) 00298 : CoderMapping(config), 00299 logger(std::string("RISE"), std::string("CoderFullMapping")) 00300 { 00301 const std::string coderFullMapName("coderMap"); 00302 //MESSAGE_SINGLE(NORMAL, logger, "CoderFullMapping::configure()"); 00303 coderFullSpecVector.clear(); // empty vector 00304 //logger = config.get("logger"); 00305 00306 // read in all the tables for the different codeRates and codeWordSizes 00307 //assure(config.knows(""),"PyConfig: missing: "); 00308 //assure(config.knows("coderFullMapping"),"PyConfig: missing: coderFullMapping"); 00309 // at this point, the config points to the contents of CoderFullMapping() 00310 assure(config.knows(coderFullMapName),"PyConfig: missing:"<<coderFullMapName); 00311 unsigned int numberOfCoders = config.len(coderFullMapName); 00312 MESSAGE_SINGLE(NORMAL, logger, "CoderFullMapping::configure(): Storing Mapping for "<<numberOfCoders<<" CodingSpecifications "); 00313 00314 for (Coding coding=0u; coding<numberOfCoders; ++coding) { 00315 //for (int ii=0; ii<numberOfCoders; ++ii){ 00316 //Coding coding = (Coding) ii; // both int 00317 //MESSAGE_SINGLE(NORMAL, logger, " - Index of CoderSpecification = "<<coding); 00318 assure(config.knows(coderFullMapName+"["+ wns::Ttos(coding) +"]"),"PyConfig: missing:"<<coderFullMapName<<"["<<wns::Ttos(coding)<<"]"); 00319 wns::pyconfig::View coderSpecConfig = config.getView(coderFullMapName+"["+wns::Ttos(coding)+"]"); 00320 // temporary object, copied into the container: 00321 CoderFullSpecification* coderFullSpecification = getCoderSpec(coderSpecConfig); 00322 //codeNameRegistry.insert(coding, coderFullSpecification); // copy object 00323 // better, new way: 00324 coderFullSpecVector.push_back(coderFullSpecification); // copy object 00325 // ^ same as coderFullSpecVector[coding] = coderFullSpecification; 00326 // inherited structure: 00327 //coderSpecificationVector.push_back(CoderSpecification(coderNum,rate,coderName)); 00328 } // forall coders 00329 maxCodeIndex = numberOfCoders-1; // inherited 00330 MESSAGE_SINGLE(NORMAL, logger, "CoderFullMapping::configure(): Stored Mapping for "<<numberOfCoders<<" CodingSpecifications "); 00331 } 00332 00333 CoderFullMapping::~CoderFullMapping() 00334 { 00335 while (!coderFullSpecVector.empty()) 00336 { 00337 delete *(coderFullSpecVector.begin()); 00338 coderFullSpecVector.erase(coderFullSpecVector.begin()); 00339 } 00340 } 00341 00342 00343 bool 00344 CoderFullMapping::isConfigured() const 00345 { 00346 return !coderFullSpecVector.empty(); // true if not empty 00347 } 00348 00349 const CoderFullSpecification& 00350 CoderFullMapping::getCoderFullSpecification(Coding c) const 00351 { 00352 assure(!coderFullSpecVector.empty(), "empty vector"); 00353 assure(coderFullSpecVector.size()>c, "bad vector size"); 00354 return *(coderFullSpecVector[c]); 00355 } 00356 00357 00358 double 00359 CoderFullMapping::mapMI2PER(double mi, 00360 unsigned int blockLength, /* blockLength=payload, not CWL */ 00361 Coding coding) const 00362 { 00363 if (mi > (1.0 - 1e-6)) { return 0.0; } // mi=1.0 => no PER 00364 assure(!coderFullSpecVector.empty(), "empty vector"); 00365 assure(isConfigured(), "object is not yet configured"); 00366 assure(coderFullSpecVector.size()>coding, "bad vector size"); 00367 //CoderFullSpecification coderFullSpecification = codeNameRegistry.find(coding); 00368 const CoderFullSpecification &coderFullSpecification = *(coderFullSpecVector[coding]); 00369 return coderFullSpecification.mapMI2PER(mi, blockLength); 00370 } 00371 00372 double 00373 CoderFullMapping::PER2MIB(double per, unsigned int blockLength, Coding coding) const 00374 { 00375 assure(!coderFullSpecVector.empty(), "empty vector"); 00376 assure(isConfigured(), "object is not yet configured"); 00377 assure(coderFullSpecVector.size()>coding, "bad vector size"); 00378 const CoderFullSpecification &coderFullSpecification = *(coderFullSpecVector[coding]); 00379 return coderFullSpecification.PER2MIB(per, blockLength); 00380 } 00381 00382 00383 /**************************************************************/ 00384 00385 // constructor 00386 GENERICM2P::GENERICM2P(const wns::pyconfig::View& config) 00387 : coderFullMapping(wns::service::phy::phymode::CoderFullMappingInterface::getCoderFullMapping(config.get("mi2per"))) 00388 { 00389 assure(coderFullMapping,"undefined coderFullMapping"); 00390 } 00391 00392 double 00393 GENERICM2P::mapMI2PER(double mi, 00394 unsigned int blockLength, /* blockLength=payload, not CWL */ 00395 Coding coding) const 00396 { 00397 assure(coderFullMapping,"undefined coderFullMapping"); 00398 return coderFullMapping->mapMI2PER(mi, blockLength, coding); 00399 } 00400 00401
1.5.5