1
/*******************************************************************************
2
* This file is part of openWNS (open Wireless Network Simulator)
3
* _____________________________________________________________________________
5
* Copyright (C) 2004-2007
6
* Chair of Communication Networks (ComNets)
7
* Kopernikusstr. 5, D-52074 Aachen, Germany
8
* phone: ++49-241-80-27910,
9
* fax: ++49-241-80-22242
10
* email: info@openwns.org
11
* www: http://www.openwns.org
12
* _____________________________________________________________________________
14
* openWNS is free software; you can redistribute it and/or modify it under the
15
* terms of the GNU Lesser General Public License version 2 as published by the
16
* Free Software Foundation;
18
* openWNS is distributed in the hope that it will be useful, but WITHOUT ANY
19
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
20
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
23
* You should have received a copy of the GNU Lesser General Public License
24
* along with this program. If not, see <http://www.gnu.org/licenses/>.
26
******************************************************************************/
28
#include <RISE/plmapping/PhyModeMapper.hpp>
30
#include <WNS/pyconfig/Parser.hpp>
31
#include <WNS/pyconfig/helper/Functions.hpp>
32
#include <WNS/node/tests/Stub.hpp>
33
#include <WNS/TestFixture.hpp>
39
namespace rise { namespace plmapping { namespace tests {
42
* @brief Test of the PhyModeMapper (PhyMode-to-SINR table)
43
* @author Rainer Schoenen (rs@comnets.rwth-aachen.de)
45
class PhyModeMapperTest
46
: public wns::TestFixture
48
CPPUNIT_TEST_SUITE( PhyModeMapperTest );
49
CPPUNIT_TEST( testConstructorDestructor );
50
//CPPUNIT_TEST( testPythonConstructor );
51
CPPUNIT_TEST( testGetListofPhyModes );
52
CPPUNIT_TEST( testGetPhyModeForIndex );
53
CPPUNIT_TEST( testGetLowestPhyMode );
54
CPPUNIT_TEST( testGetHighestPhyMode );
55
CPPUNIT_TEST( testGetBestPhyMode );
56
CPPUNIT_TEST( testGetMinSINRRatio );
57
CPPUNIT_TEST( testGetMinSINR );
58
CPPUNIT_TEST( testGetSINRRange );
59
CPPUNIT_TEST( testMinimumSINR );
60
CPPUNIT_TEST( testCalculateSINRRanges );
61
CPPUNIT_TEST( testCalculateLTESINRRanges );
64
CPPUNIT_TEST_SUITE_END();
70
void testConstructorDestructor();
71
void testGetListofPhyModes();
72
void testGetPhyModeForIndex();
73
void testGetLowestPhyMode();
74
void testGetHighestPhyMode();
75
void testGetBestPhyMode();
76
void testGetMinSINRRatio();
77
void testGetMinSINR();
78
void testGetSINRRange();
79
void testMinimumSINR();
80
void testCalculateSINRRanges();
81
void testCalculateLTESINRRanges();
84
PhyModeMapper* testPhyModeMapper;
86
wns::service::phy::phymode::CoderMappingInterface* coderMapper;
87
wns::service::phy::phymode::CoderFullMappingInterface* mi2perMapper;
95
using namespace rise::plmapping::tests;
97
/********************************* Test *****************************/
99
CPPUNIT_TEST_SUITE_REGISTRATION( PhyModeMapperTest );
101
PhyModeMapperTest::PhyModeMapperTest() : /* 1. */
103
useCout(false), // switch true|false here to see an output to stdout.
104
testPhyModeMapper(NULL),
105
coderMapper(NULL), // Singleton
106
mi2perMapper(NULL) // Singleton
110
PhyModeMapperTest::~PhyModeMapperTest() /* 5. */
114
void PhyModeMapperTest::prepare() /* 2. */
116
wns::pyconfig::Parser pyconfig;
118
"import rise.CoderSpecification\n"
119
"coderMapping = rise.CoderSpecification.default\n" // Table
120
//"coderMapping = rise.CoderSpecification.CoderMapping(mapping = \"Formula\")\n"
123
wns::pyconfig::View coderMappingConfig = pyconfig.getView("coderMapping");
124
coderMapper = wns::service::phy::phymode::CoderMappingInterface::getCoderMapping(coderMappingConfig);
125
mi2perMapper = wns::service::phy::phymode::CoderFullMappingInterface::getCoderFullMapping(coderMappingConfig);
126
CPPUNIT_ASSERT(coderMapper != NULL);
127
CPPUNIT_ASSERT(mi2perMapper != NULL);
128
CPPUNIT_ASSERT(coderMapper == dynamic_cast<wns::service::phy::phymode::CoderMappingInterface*>(mi2perMapper));
131
CPPUNIT_ASSERT(testPhyModeMapper == NULL);
134
"from rise.PhyMode import PhyMode,PhyModeMapper\n"
135
"from rise.SNR2MI import default,Table,Formula\n"
136
"from rise.CoderSpecification import defaultCoderMapping,TableCoder,FormulaCoder\n"
137
"from openwns.interval import Interval\n\n"
138
"bpsk = PhyMode(modulation = \"BPSK\", coding = \"LDPC_SEUK-1/2\")\n"
139
"qpsk = PhyMode(modulation = \"QPSK\", coding = \"LDPC_SEUK-1/2\")\n"
140
"qam16 = PhyMode(modulation = \"QAM16\", coding = \"LDPC_SEUK-1/2\")\n"
141
"qam64 = PhyMode(modulation = \"QAM64\", coding = \"LDPC_SEUK-1/2\")\n"
142
"snr2miMapper = rise.SNR2MI.default\n"
143
//"snr2miMapper = rise.SNR2MI.Formula()\n"
144
"mi2perMapper = rise.CoderSpecification.defaultCoderMapping\n"
145
//"mi2perMapper = rise.CoderSpecification.CoderMapping(mapping = "Formula")\n"
146
"class Baseline(PhyModeMapper):\n"
147
" def __init__(self):\n"
148
" symbolDuration = 1e-6\n"
149
" subCarriersPerSubChannel = 12\n"
150
" # configure base class rise.PhyMode.PhyModeMapper():\n"
151
" super(Baseline, self).__init__(symbolDuration, subCarriersPerSubChannel, snr2miMapper=snr2miMapper, mi2perMapper=mi2perMapper)\n"
152
" self.setMinimumSINR(-1.0);\n"
153
" self.addPhyMode(Interval(-200.0, 1.0, \"(]\"), bpsk)\n"
154
" self.addPhyMode(Interval( 1.0, 6.5, \"(]\"), qpsk)\n"
155
" self.addPhyMode(Interval( 6.5, 14.0, \"(]\"), qam16)\n"
156
" self.addPhyMode(Interval( 14.0, 200.0, \"(]\"), qam64)\n"
157
"phyModeMapper = Baseline()\n"
159
testPhyModeMapper = new PhyModeMapper(pyconfig.getView("phyModeMapper"));
162
void PhyModeMapperTest::cleanup() /* 4. */
164
delete testPhyModeMapper;
165
testPhyModeMapper=NULL;
168
void PhyModeMapperTest::testConstructorDestructor() /* 3. */
170
CPPUNIT_ASSERT(coderMapper != NULL); // global Singleton
171
CPPUNIT_ASSERT(coderMapper->getMaxCodeIndex() > 0u);
172
CPPUNIT_ASSERT(testPhyModeMapper != NULL);
175
void PhyModeMapperTest::testGetListofPhyModes()
177
PhyModeMapper::PhyModeVector phyModeVector =
178
testPhyModeMapper->getListofPhyModes();
179
//const std::vector<wns::SmartPtr<const wns::service::phy::phymode::PhyModeInterface> > phyModePtrVector =
180
const std::vector< wns::service::phy::phymode::PhyModeInterfacePtr > phyModePtrVector =
181
testPhyModeMapper->getListofPhyModePtr();
182
int listSize = (int)phyModeVector.size();
183
if (useCout) std::cout << "testGetListofPhyModes(): "<<listSize<<" elements" << std::endl;
184
CPPUNIT_ASSERT(listSize > 0);
185
CPPUNIT_ASSERT_EQUAL(4, listSize); // according to Python spec above
186
CPPUNIT_ASSERT_EQUAL(listSize, testPhyModeMapper->getPhyModeCount());
187
for (unsigned int phymodeIndex=0; (int)phymodeIndex<listSize; ++phymodeIndex){
188
if (useCout) std::cout << "phyModeVector["<<phymodeIndex<<"]: valid="<<phyModeVector[phymodeIndex]->isValid() << std::endl;
189
CPPUNIT_ASSERT(phyModeVector[phymodeIndex]->isValid());
190
CPPUNIT_ASSERT(phyModePtrVector[phymodeIndex]->isValid());
191
//CPPUNIT_ASSERT_EQUAL(&phyModeVector[phymodeIndex], phyModePtrVector[phymodeIndex]);
192
//CPPUNIT_ASSERT_EQUAL(phyModeVector[phymodeIndex], *phyModePtrVector[phymodeIndex]);
193
const PhyMode phyMode = *phyModeVector[phymodeIndex];
194
const PhyMode* phyModePtr = static_cast<const rise::plmapping::PhyMode*>(phyModePtrVector[phymodeIndex].getPtr());
195
CPPUNIT_ASSERT_EQUAL(phyMode,*phyModePtr);
196
CPPUNIT_ASSERT(phyMode.isValid());
197
CPPUNIT_ASSERT(phyModePtr->isValid());
198
CPPUNIT_ASSERT(phyMode.dataRateIsValid());
199
CPPUNIT_ASSERT(phyModePtr->dataRateIsValid());
200
CPPUNIT_ASSERT(phyMode.toInt() > 0);
201
CPPUNIT_ASSERT(phyModePtr->toInt() > 0);
202
CPPUNIT_ASSERT_EQUAL(phyMode.toInt(), phyModePtr->toInt());
203
double bitsPerSymbol = phyMode.getBitsPerSymbol();
204
CPPUNIT_ASSERT(bitsPerSymbol > 0.0);
205
double dataRate = phyMode.getDataRate();
206
CPPUNIT_ASSERT(dataRate > 0.0);
207
CPPUNIT_ASSERT_EQUAL(bitsPerSymbol,phyMode.getDataRate(1.0,1));
208
if (phymodeIndex>0) // compare order
209
CPPUNIT_ASSERT(PhyModeIsBetter(phyMode,*phyModeVector[phymodeIndex-1]));
211
//if (useCout) std::cout << ""<< << std::endl;
215
void PhyModeMapperTest::testGetPhyModeForIndex()
217
unsigned int phyModeCount = testPhyModeMapper->getPhyModeCount();
218
unsigned int phymodeIndex = phyModeCount/2; // middle
219
//const PhyMode& phyMode = testPhyModeMapper->getPhyModeForIndex(phymodeIndex);
220
//wns::SmartPtr<const wns::service::phy::phymode::PhyModeInterface> phyMode = testPhyModeMapper->getPhyModeForIndex(phymodeIndex);
221
wns::service::phy::phymode::PhyModeInterfacePtr phyModePtr = testPhyModeMapper->getPhyModeForIndex(phymodeIndex);
222
CPPUNIT_ASSERT(phyModePtr->isValid());
223
unsigned int phymodeIndex2 = testPhyModeMapper->getIndexForPhyMode(*phyModePtr);
224
CPPUNIT_ASSERT_EQUAL(phymodeIndex,phymodeIndex2);
227
void PhyModeMapperTest::testGetLowestPhyMode()
229
//const PhyMode& phyMode = testPhyModeMapper->getLowestPhyMode();
230
//wns::SmartPtr<const wns::service::phy::phymode::PhyModeInterface> phyMode = testPhyModeMapper->getLowestPhyMode();
231
wns::service::phy::phymode::PhyModeInterfacePtr phyModePtr = testPhyModeMapper->getLowestPhyMode();
232
CPPUNIT_ASSERT(phyModePtr->isValid());
235
void PhyModeMapperTest::testGetHighestPhyMode()
237
//const PhyMode& phyMode = testPhyModeMapper->getHighestPhyMode();
238
//wns::SmartPtr<const wns::service::phy::phymode::PhyModeInterface> phyMode = testPhyModeMapper->getHighestPhyMode();
239
wns::service::phy::phymode::PhyModeInterfacePtr phyModePtr = testPhyModeMapper->getHighestPhyMode();
240
CPPUNIT_ASSERT(phyModePtr->isValid());
243
void PhyModeMapperTest::testGetBestPhyMode()
245
for (double sinr=-2.0; sinr<20.0; sinr+=1.0) {
246
//wns::SmartPtr<const wns::service::phy::phymode::PhyModeInterface> phyModePtr =
247
wns::service::phy::phymode::PhyModeInterfacePtr phyModePtr =
248
testPhyModeMapper->getBestPhyMode(sinr);
249
CPPUNIT_ASSERT(phyModePtr->isValid());
250
unsigned int bestPhyModeIndex = testPhyModeMapper->getBestPhyModeIndex(sinr);
251
//wns::SmartPtr<const wns::service::phy::phymode::PhyModeInterface> phyModePtr2 =
252
wns::service::phy::phymode::PhyModeInterfacePtr phyModePtr2 =
253
testPhyModeMapper->getPhyModeForIndex(bestPhyModeIndex);
254
CPPUNIT_ASSERT(*phyModePtr == *phyModePtr2);
258
void PhyModeMapperTest::testGetMinSINRRatio()
260
//wns::SmartPtr<const wns::service::phy::phymode::PhyModeInterface> phyMode =
261
wns::service::phy::phymode::PhyModeInterfacePtr phyModePtr =
262
testPhyModeMapper->getHighestPhyMode();
263
CPPUNIT_ASSERT(phyModePtr->isValid());
264
wns::Ratio ratio = testPhyModeMapper->getMinSINRRatio(*phyModePtr);
265
if (useCout) std::cout << "testGetMinSINRRatio: "<<ratio << std::endl;
268
void PhyModeMapperTest::testGetMinSINR()
270
//const PhyMode& phyMode = testPhyModeMapper->getHighestPhyMode();
271
//wns::SmartPtr<const wns::service::phy::phymode::PhyModeInterface> phyMode =
272
wns::service::phy::phymode::PhyModeInterfacePtr phyModePtr =
273
testPhyModeMapper->getHighestPhyMode();
274
CPPUNIT_ASSERT(phyModePtr->isValid());
275
double minSINR = testPhyModeMapper->getMinSINR(*phyModePtr);
276
CPPUNIT_ASSERT(minSINR > 0.0);
279
void PhyModeMapperTest::testGetSINRRange()
281
std::vector< wns::SmartPtr<PhyMode> > phyModeVector =
282
testPhyModeMapper->getListofPhyModes();
283
unsigned int listSize = phyModeVector.size();
284
CPPUNIT_ASSERT(listSize > 0);
285
CPPUNIT_ASSERT_EQUAL(4u, listSize); // according to Python spec above
286
unsigned int phyModeCount = testPhyModeMapper->getPhyModeCount();
287
CPPUNIT_ASSERT_EQUAL(listSize, phyModeCount);
288
unsigned int phymodeIndex = listSize/2; // middle
289
const PhyMode phyMode = *phyModeVector[phymodeIndex];
290
CPPUNIT_ASSERT(phyMode.isValid());
291
double min = testPhyModeMapper->getSINRRange(phyMode).min();
292
double max = testPhyModeMapper->getSINRRange(phyMode).max();
293
// if (useCout) std::cout << "testGetSINRRange: " <<min<<"..."<<max << std::endl;
294
CPPUNIT_ASSERT(max > min);
295
double test_sinr = (max+min)/2.0; // within the interval
296
//wns::SmartPtr<const wns::service::phy::phymode::PhyModeInterface> phyMode2i =
297
wns::service::phy::phymode::PhyModeInterfacePtr phyModePtr2i =
298
testPhyModeMapper->getBestPhyMode(test_sinr);
299
wns::SmartPtr<const PhyMode> phyModePtr2 =
300
wns::staticCast<const rise::plmapping::PhyMode>(phyModePtr2i);
301
CPPUNIT_ASSERT(*phyModePtr2 == phyMode);
304
void PhyModeMapperTest::testMinimumSINR()
306
double minimumSINR = testPhyModeMapper->getMinimumSINR(); // -1.0
307
WNS_ASSERT_MAX_REL_ERROR( -1.0, minimumSINR, 1e-6 );
308
CPPUNIT_ASSERT(testPhyModeMapper->sinrIsAboveLimit(+10.0) == true);
309
CPPUNIT_ASSERT(testPhyModeMapper->sinrIsAboveLimit(-10.0) == false);
310
wns::Ratio snr = wns::Ratio::from_dB(10.0);
311
CPPUNIT_ASSERT(testPhyModeMapper->sinrIsAboveLimit(snr) == true);
313
CPPUNIT_ASSERT(testPhyModeMapper->sinrIsAboveLimit(snr) == false);
316
void PhyModeMapperTest::testCalculateSINRRanges()
318
if (useCout) std::cout<<std::endl;
319
unsigned int bl = 8; // smallest
320
for(int b=1; b<=10; ++b) { // iterate through several payload lengths
321
//bl = bl<<1; // *2 <<=
323
if (useCout) std::cout<<"calculateSINRRanges(bl="<<bl<<"):"<<std::endl;
324
double targetPER = 1.0;
325
for(int i=1; i<=4; ++i) {
326
targetPER /= 10.0; // 10^-i
327
testPhyModeMapper->calculateSINRRanges(targetPER, bl /* smaller number (payload) */);
328
double minimumSINR = testPhyModeMapper->getMinimumSINR();
329
CPPUNIT_ASSERT(minimumSINR != -1.0);
330
// now the tables have changed. Test new:
332
testGetBestPhyMode();
334
std::cout<<" calculateSINRRanges(targetPER="<<targetPER<<", bl="<<bl<<"):"<<std::endl;
335
std::cout<<" minimumSINR = "<<minimumSINR<<std::endl;
336
unsigned int phyModeCount = testPhyModeMapper->getPhyModeCount();
337
for(unsigned int phymodeIndex=0; phymodeIndex<phyModeCount; phymodeIndex++) {
338
//wns::SmartPtr<const wns::service::phy::phymode::PhyModeInterface> phyMode =
339
wns::service::phy::phymode::PhyModeInterfacePtr phyModePtr =
340
testPhyModeMapper->getPhyModeForIndex(phymodeIndex);
341
double min = testPhyModeMapper->getSINRRange(*phyModePtr).min();
342
double max = testPhyModeMapper->getSINRRange(*phyModePtr).max();
343
std::cout<<" SINRRange("<<*phyModePtr<<") = "<<min<<"..."<<max<<std::endl;
350
void PhyModeMapperTest::testCalculateLTESINRRanges()
352
delete testPhyModeMapper;
353
wns::pyconfig::Parser pyconfig;
355
"from rise.PhyMode import PhyMode,PhyModeMapper\n"
356
"from rise.SNR2MI import default,Table,Formula\n"
357
"from rise.CoderSpecification import defaultCoderMapping,TableCoder,FormulaCoder,CoderMapping\n"
358
"from openwns.interval import Interval\n\n"
359
//"snr2miMapper = rise.SNR2MI.default\n"
360
"snr2miMapper = Table()\n" // rise.SNR2MI.Table()\n"
361
//"snr2miMapper = rise.SNR2MI.Formula()\n"
362
//"mi2perMapper = rise.CoderSpecification.defaultCoderMapping\n"
363
"mi2perMapper = CoderMapping(mapping = \"Table\")\n" // rise.CoderSpecification.CoderMapping(mapping = \"Table\")\n"
364
//"mi2perMapper = rise.CoderSpecification.CoderMapping(mapping = \"Formula\")\n"
365
"class LTEMapper(PhyModeMapper):\n"
366
" def __init__(self):\n"
367
" symbolDuration = 1e-6\n"
368
" subCarriersPerSubChannel = 12\n"
369
" # configure base class rise.PhyMode.PhyModeMapper():\n"
370
" super(LTEMapper, self).__init__(symbolDuration, subCarriersPerSubChannel, snr2miMapper=snr2miMapper, mi2perMapper=mi2perMapper)\n"
371
" self.setMinimumSINR(-1.0);\n"
372
" self.addPhyMode(Interval(-200.0, 2.8, \"(]\"), PhyMode(\"QPSK-Turbo_UMTS-1/3\"))\n"
373
" self.addPhyMode(Interval( 2.8, 4.9, \"(]\"), PhyMode(\"QPSK-Turbo_UMTS-1/2\"))\n"
374
" self.addPhyMode(Interval( 4.9, 7.6, \"(]\"), PhyMode(\"QPSK-Turbo_UMTS-2/3\"))\n"
375
" self.addPhyMode(Interval( 7.6, 10.1, \"(]\"), PhyMode(\"QAM16-Turbo_UMTS-1/2\"))\n"
376
" self.addPhyMode(Interval( 10.1, 13.0, \"(]\"), PhyMode(\"QAM16-Turbo_UMTS-2/3\"))\n"
377
" self.addPhyMode(Interval( 13.0, 14.9, \"(]\"), PhyMode(\"QAM16-Turbo_UMTS-5/6\"))\n"
378
" self.addPhyMode(Interval( 14.9, 18.2, \"(]\"), PhyMode(\"QAM64-Turbo_UMTS-2/3\"))\n"
379
" self.addPhyMode(Interval( 18.2, 200.0, \"(]\"), PhyMode(\"QAM64-Turbo_UMTS-5/6\"))\n"
380
"phyModeMapper = LTEMapper()\n"
383
testPhyModeMapper = new PhyModeMapper(pyconfig.getView("phyModeMapper"));
384
if (useCout) std::cout<<std::endl;
385
unsigned int bl = 8; // smallest
386
for(int b=1; b<=10; ++b) { // iterate through several payload lengths
388
//if (useCout) std::cout<<"calculateSINRRanges(bl="<<bl<<"):"<<std::endl;
389
double targetPER = 1.0;
390
for(int i=1; i<=4; ++i) {
391
targetPER /= 10.0; // 10^-i
392
testPhyModeMapper->calculateSINRRanges(targetPER, bl /* smaller number (payload) */);
393
double minimumSINR = testPhyModeMapper->getMinimumSINR();
394
CPPUNIT_ASSERT(minimumSINR != -1.0);
395
// now the tables have changed. Test new:
396
//testGetSINRRange();
397
//testGetBestPhyMode();
399
std::cout<<"#calculateLTESINRRanges(targetPER="<<targetPER<<", bl="<<bl<<"):"<<std::endl;
400
std::cout<<"\tself.setMinimumSINR("<<minimumSINR<<")"<<std::endl;
401
unsigned int phyModeCount = testPhyModeMapper->getPhyModeCount();
402
for(unsigned int phymodeIndex=0; phymodeIndex<phyModeCount; phymodeIndex++) {
403
//wns::SmartPtr<const wns::service::phy::phymode::PhyModeInterface> phyMode =
404
wns::service::phy::phymode::PhyModeInterfacePtr phyModePtr =
405
testPhyModeMapper->getPhyModeForIndex(phymodeIndex);
406
double min = testPhyModeMapper->getSINRRange(*phyModePtr).min();
407
double max = testPhyModeMapper->getSINRRange(*phyModePtr).max();
408
//std::cout<<" SINRRange("<<*phyModePtr<<") = "<<min<<"..."<<max<<std::endl;
409
std::cout<<"\tself.addPhyMode(Interval("<<min<<","<<max<<",\"(]\"),PhyMode(\""<<*phyModePtr<<"\"))"<<std::endl;
411
// format for Matlab: modeSwitchSNRs = [ 0.9 2.1 3.8 7.7 9.8 12.6 15.0 18.2 23.0 ];
412
std::cout<<"modeSwitchSNRs = "<<testPhyModeMapper->printSwitchingPoints()<<";"
413
<<" % targetPER="<<targetPER<<", bl="<<bl<<std::endl;