![]() |
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/stations/station.hpp> 00029 #include <RISE/transmissionobjects/transmissionobjectbf.hpp> 00030 #include <RISE/antenna/Beamforming.hpp> 00031 #include <WNS/rng/RNGen.hpp> 00032 #include <boost/numeric/ublas/blas.hpp> 00033 #include <boost/numeric/ublas/lu.hpp> 00034 00035 #include <cmath> 00036 #include <algorithm> 00037 #include <fstream> 00038 00039 using namespace rise::antenna; 00040 00041 Beamforming::Beamforming(const wns::pyconfig::View& pyConfigView, 00042 Station* const station) 00043 : Antenna(pyConfigView, station), 00044 pd_noAntennaElements(1), 00045 pd_lastPowerReceived(), 00046 pd_receivedTO2PatternMap(), 00047 arrayLayout(linear), 00048 positionErrorVariance(pyConfigView.get<double>("positionErrorVariance")), 00049 dis(0.0, positionErrorVariance, wns::simulator::getRNG()) 00050 00051 { 00052 pd_noAntennaElements = pyConfigView.get<long int>("noOfElements"); 00053 if (pyConfigView.get<std::string>("arrayLayout") == "circular") 00054 arrayLayout = circular; 00055 00056 if (drawPattern == true) 00057 drawRadiationPattern(); 00058 00059 MESSAGE_BEGIN(NORMAL, log, m,"Beamforming antenna initiated with layout (linear=0): "); 00060 m << arrayLayout << ", " << pd_noAntennaElements << " elements, and " 00061 << positionErrorVariance << " variance in position estimation"; 00062 MESSAGE_END(); 00063 00064 // Create the steervectors for all 360 degrees once and for all These 00065 // steervectors only depend on the geometry of the array (noAntennaElements, 00066 // ArrayLayout) which is known once the BF antenna is created. 00067 steervectors.resize(360, 0); 00068 00069 for (unsigned long int i = 0; i < 360; i++) 00070 { 00071 steervectors[i] = new boost::numeric::ublas::vector<std::complex<double> >(pd_noAntennaElements); 00072 for (unsigned long int j = 0; j < pd_noAntennaElements; j++) 00073 { 00074 // Now I have to add pi here!? 00075 std::complex<double> c = std::polar(1.0, calculatePhaseDelta(j, double(i)*M_PI/180+M_PI)); 00076 (*steervectors[i])(j) = c; 00077 } 00078 } 00079 } 00080 00081 Beamforming::~Beamforming() 00082 { 00083 for (unsigned long int i = 0; i < 360; ++i) 00084 { 00085 delete steervectors[i]; 00086 } 00087 pd_receivedTO2PatternMap.clear(); 00088 } 00089 00090 wns::Ratio 00091 Beamforming::getGain(const wns::Position& pos, 00092 const TransmissionObjectPtr& TO) const 00093 { 00094 TO2PatternMap::const_iterator itr = pd_receivedTO2PatternMap.find(TO); 00095 assure(itr != pd_receivedTO2PatternMap.end(), "The TransmissionObject is not registered for receiving at this antenna!"); 00096 return getGain(pos, itr->second); 00097 } 00098 00099 wns::Ratio 00100 Beamforming::getGain(const wns::Position& pos, 00101 PatternPtr pattern) const 00102 { 00103 double phi = (pos - getPosition()).getAzimuth(); 00104 if (phi < 0) phi += M_PI + M_PI; 00105 unsigned long int index = (unsigned long int)(180 * phi / M_PI + 0.5); // 0.5 to round 00106 if(index == 360) index = 0; 00107 assure(index < pattern->getSize(), "pattern index out of range"); 00108 00109 wns::Ratio a_directivity = pd_getGainEntry(index, pattern); 00110 MESSAGE_BEGIN(VERBOSE, log, m,"Directivity in ("); 00111 m << pos.getX() << "," << pos.getY() << "," << pos.getZ() << "): " << a_directivity.get_dB(); 00112 MESSAGE_END(); 00113 return a_directivity; 00114 } 00115 00116 wns::Ratio 00117 Beamforming:: pd_getGainEntry(unsigned long int index, 00118 PatternPtr pattern) const 00119 { 00120 assure(index < pattern->getSize(), "pattern index out of range"); 00121 double t = pattern->pattern.at(index); 00122 return wns::Ratio::from_factor(t*t); 00123 } 00124 00125 void 00126 Beamforming::setPowerReceivedForStation(Station* const id, 00127 const wns::Power power) 00128 { 00129 pd_lastPowerReceived[id] = power; 00130 } 00131 00132 void 00133 Beamforming::setTxPowerForStation(Station* const id, 00134 const wns::Power power) 00135 { 00136 pd_lastTxPower[id] = power; 00137 } 00138 00139 void 00140 Beamforming::startReceiving(const TransmissionObjectPtr& TO, 00141 PatternPtr pattern) 00142 { 00143 pd_receivedTO2PatternMap[TO] = pattern; 00144 } 00145 00146 void 00147 Beamforming::stopReceiving(const TransmissionObjectPtr& TO) 00148 { 00149 pd_receivedTO2PatternMap.erase(pd_receivedTO2PatternMap.find(TO)); 00150 } 00151 00152 std::map<rise::Station*, wns::CandI> 00153 Beamforming::calculateCandIsTx(const std::map<Station*, wns::Power>& station2iIntercellPlusNoise, 00154 wns::Power xFriendlyness, 00155 wns::Power txPower, 00156 bool eirpLimited) 00157 { 00158 // SINR estimation in Tx case, in other words does the following: how much 00159 // do I interfere station A when I send simultaniously to all the other 00160 // stations from the given combination (B, C,...). This means that in the 00161 // calculation of SINR for station A, the following values, or its estimations 00162 // should be used: 00163 00164 // Tx power for X + pathloss from me to A + X's pattern towards A, 00165 00166 // where X traverses all the stations from the given combination: in case X = A 00167 // the value is signal strength, and if they are different the value is summed 00168 // to interference. 00169 00170 std::vector<Station*> combination; 00171 for(std::map<Station*, wns::Power>::const_iterator itr = station2iIntercellPlusNoise.begin(); 00172 itr != station2iIntercellPlusNoise.end(); 00173 itr ++) 00174 { 00175 combination.push_back(itr->first); 00176 } 00177 std::map <Station*, PatternPtr > outpattern; 00178 std::vector<Station*>::const_iterator s; 00179 for (s = combination.begin(); s != combination.end(); s++) 00180 { 00181 std::vector<Station*> undesired = combination; 00182 undesired.erase(std::find(undesired.begin(), undesired.end(), *s)); 00183 outpattern[*s] = p_calculateBeam(*s, undesired, xFriendlyness); 00184 } 00185 00186 double txPowerReduction = 0.0; 00187 if(eirpLimited){ 00188 // if required, the txPower is restricted to the EIRP 00189 wns::service::phy::ofdma::SumPattern sumPattern; 00190 assure(sumPattern.getSize() == 0, "new sum Pattern is not empty"); 00191 assure(!combination.empty(), "combination is empty"); 00192 for (s = combination.begin(); s != combination.end(); s++) { 00193 MESSAGE_SINGLE(VERBOSE, log, "maximum gain of pattern to add: " << outpattern[*s]->getMaxGain()); 00194 sumPattern.add(outpattern[*s]); 00195 MESSAGE_SINGLE(VERBOSE, log, "current maximum gain of pattern: " << sumPattern.getMaxGain()); 00196 } 00197 txPowerReduction = sumPattern.getMaxGain().get_factor(); 00198 MESSAGE_SINGLE(NORMAL, log, "Tx power reduction per concurrent stream due to EIRP 1/" << txPowerReduction); 00199 } 00200 else if (!eirpLimited){ 00201 // in SDMA, the txPower of the antenna is equally distributed to all 00202 // concurrent streams 00203 txPowerReduction = combination.size()*1.0; 00204 MESSAGE_SINGLE(NORMAL, log, "Tx power reduction per concurrent stream is 1/" << txPowerReduction); 00205 } 00206 00207 std::map<rise::Station*, wns::CandI > candis; 00208 00209 for (s = combination.begin(); s != combination.end(); s++) 00210 { 00211 double signal = 0.0; 00212 double iIntra = 0.0; 00213 00214 // the angle is fixed, traverse the patterns 00215 unsigned long int grad = (unsigned long int)(pd_azimuthAngles[*s]*180/M_PI + 0.5); //0.5 to round 00216 if (grad == 360) grad = 0; 00217 assure(grad < outpattern[*s]->getSize(), "pattern index (grad) out of range"); 00218 00219 float pathloss = pd_lastTxPower[*s].get_mW() / pd_lastPowerReceived[*s].get_mW(); 00220 00221 for (std::vector<Station*>::const_iterator interferer = combination.begin(); interferer != combination.end(); interferer++) 00222 { 00223 assure(pd_lastTxPower.find(*interferer) != pd_lastTxPower.end(), 00224 "TX power of station not yet registred at this antenna!"); 00225 00226 if ((*s) == (*interferer)) 00227 signal = outpattern[*s]->pattern.at(grad) * outpattern[*s]->pattern.at(grad) * 00228 txPower.get_mW() / pathloss / txPowerReduction; 00229 else 00230 iIntra += outpattern[*interferer]->pattern.at(grad) * outpattern[*interferer]->pattern.at(grad) * 00231 txPower.get_mW() / pathloss / txPowerReduction; 00232 } 00233 00234 // sum up entire interference 00235 double interference = 0.0; 00236 // add inter-cell interference and noise 00237 interference += station2iIntercellPlusNoise.find(*s)->second.get_mW(); 00238 // add intra-cell interference 00239 interference += iIntra; 00240 00241 assure(interference > 0.0, "Interference + Noise is not positive!"); 00242 assure(signal > 0.0, "Carrier Signal is not greater than zero!"); 00243 00244 //return value 00245 wns::CandI candi = wns::CandI(); 00246 candi.sdma.iIntra = wns::Power::from_mW(iIntra); 00247 candi.C = wns::Power::from_mW(signal); 00248 candi.I = wns::Power::from_mW(interference); 00249 candis[*s] = candi; 00250 } 00251 return candis; 00252 } 00253 00254 00255 std::map<rise::Station*, wns::CandI > 00256 Beamforming::calculateCandIsRx(const std::vector<Station*>& combination, 00257 wns::Power iInterPlusNoise) 00258 { 00259 assure(iInterPlusNoise.get_mW() > 0.0, "given interference plus noise is not positive!"); 00260 00261 std::map <Station*, PatternPtr > outpattern; 00262 std::vector<Station*>::const_iterator s; 00263 for (s = combination.begin(); s != combination.end(); s++) 00264 { 00265 std::vector<Station*> undesired = combination; 00266 undesired.erase(std::find(undesired.begin(), undesired.end(), *s)); 00267 // in order to calculate the perfect beam, which seems to be 00268 // unrealistic, only the inter-cell interference should be given to 00269 // calculate the beam 00270 outpattern[*s] = p_calculateBeam(*s, undesired, iInterPlusNoise); 00271 } 00272 00273 std::map<rise::Station*, wns::CandI > candis; 00274 00275 for (s = combination.begin(); s != combination.end(); s++) 00276 { 00277 double signal = 0.0; 00278 double iIntra = 0.0; 00279 00280 unsigned long int grad = 0; 00281 // the pattern is fixed, angles change 00282 for (std::vector<Station*>::const_iterator interferer = combination.begin(); interferer != combination.end(); interferer++) 00283 { 00284 grad = (unsigned long int)(pd_azimuthAngles[*interferer]*180/M_PI +0.5); //0.5 to round 00285 if(grad == 360) grad = 0; 00286 assure(grad < outpattern[*s]->getSize(), "pattern index (grad) out of range"); 00287 00288 if ((*s) == (*interferer)) 00289 { 00290 MESSAGE_BEGIN(VERBOSE, log, m, ""); 00291 m << "amplitude factor to desired station: " << outpattern[*s]->pattern.at(grad); 00292 MESSAGE_END(); 00293 signal = outpattern[*s]->pattern.at(grad) * outpattern[*s]->pattern.at(grad) * pd_lastPowerReceived[*s].get_mW(); 00294 } 00295 else 00296 { 00297 MESSAGE_BEGIN(VERBOSE, log, m, ""); 00298 m << "amplitude factor to interferer: " << outpattern[*s]->pattern.at(grad); 00299 MESSAGE_END(); 00300 iIntra += outpattern[*s]->pattern.at(grad) * outpattern[*s]->pattern.at(grad) * pd_lastPowerReceived[*interferer].get_mW(); 00301 } 00302 } 00303 //sum up the entire interference 00304 double interference = 0.0; 00305 // add omni-directional interference and noise 00306 interference += iInterPlusNoise.get_mW(); 00307 //add intra-cell interference 00308 interference += iIntra; 00309 00310 assure(interference > 0.0, "Interference is not positive!"); 00311 assure(signal > 0.0, "Carrier Signal is not greater than zero!"); 00312 00313 //return value 00314 wns::CandI candi = wns::CandI(); 00315 candi.sdma.iIntra = wns::Power::from_mW(iIntra); 00316 candi.C = wns::Power::from_mW(signal); 00317 candi.I = wns::Power::from_mW(interference); 00318 candis[*s] = candi; 00319 } 00320 return candis; 00321 } 00322 00323 double 00324 Beamforming::estimateDoA(Station* id) 00325 { 00326 double azi = (id->getPosition() - this->getStation()->getPosition()).getAzimuth(); 00327 azi += dis() * M_PI/180; 00328 return( azi ); 00329 } 00330 00331 00332 PatternPtr 00333 Beamforming::calculateAndSetBeam(Station* id, 00334 const std::vector<Station*>& undesired, 00335 wns::Power omniPower) 00336 { 00337 PatternPtr beam = p_calculateBeam(id, undesired, omniPower); 00338 return beam; 00339 } 00340 00341 double 00342 Beamforming::calculatePhaseDelta(int antennaNo, double stationPhi) const 00343 { 00344 // stationPhi in radians 00345 double delta = 0.0; 00346 double alpha = 0.0; 00347 // antenna spacing: lambda/2 = pi 00348 double antennaSpacing = M_PI; 00349 // radius of array is adapted to the antennaSpacing 00350 double r = antennaSpacing/2 / sin(M_PI / double(pd_noAntennaElements)); 00351 00352 switch (arrayLayout) 00353 { 00354 case circular: 00355 // antenna elements are assumed to be on a circle with (x=0, y=0) as 00356 // center, first element is located at (x=r, y=0) 00357 alpha = double(antennaNo) * 2.0 * M_PI / double(pd_noAntennaElements); 00358 delta = r*sqrt(2.0-2.0*cos(alpha))*sin(-stationPhi-alpha/2.0); 00359 00360 break; 00361 case linear: 00362 default: // Linear is default 00363 // elements are assumed to be lined up along the y-axis, first antenna 00364 // element located at (x=0, y=0) 00365 delta = double(antennaNo)*antennaSpacing*sin(stationPhi); 00366 } 00367 00368 return delta; 00369 } 00370 00371 00372 PatternPtr 00373 Beamforming::p_calculateBeam(Station* id, 00374 const std::vector<Station*>& undesired, 00375 wns::Power omniPower) 00376 { 00377 // assure that the cov matrix, which is inverted later, has 00378 // non-zero diagonal-elements. Otherwise the algorithms performes unpredictable 00379 assure(omniPower.get_mW() > 0, "beam pattern calculation requires positive level of omni-directional power"); 00380 00381 std::complex<double> c; 00382 boost::numeric::ublas::vector<std::complex<double> > steervector(pd_noAntennaElements); 00383 boost::numeric::ublas::matrix<std::complex<double> > kov(pd_noAntennaElements, pd_noAntennaElements); 00384 kov = 00385 boost::numeric::ublas::zero_matrix<std::complex<double> >(pd_noAntennaElements, pd_noAntennaElements); 00386 00387 assure(getStation() != id, "Desired and beamforming station are the same!"); 00388 //build covariance matrix: 00389 wns::Position myPosition = getPosition(); 00390 for (std::vector<Station*>::const_iterator s = undesired.begin(); s != undesired.end(); s ++){ 00391 //build steering vector: 00392 assure(*s != getStation(), "Undesired and beamforming station are the same!"); 00393 assure(*s != id, "Undesired and desired station are the same!"); 00394 00395 pd_azimuthAngles [*s] = ((*s)->getAntenna()->getPosition() - myPosition).getAzimuth(); 00396 //add positionError to azimuth calculation (in order to model the actual position estimation) 00397 pd_azimuthAngles [*s] += dis() * M_PI/180; 00398 00399 if (pd_azimuthAngles[*s] < 0) 00400 pd_azimuthAngles[*s] += M_PI + M_PI; 00401 00402 for (unsigned long int i = 0; i < pd_noAntennaElements; i++) 00403 { 00404 c = std::polar(1.0, calculatePhaseDelta(i, pd_azimuthAngles[*s])); 00405 steervector(i) = c; 00406 } 00407 assure(pd_lastPowerReceived.find(*s) != pd_lastPowerReceived.end(), "Station is not yet registered at this antenna!"); 00408 //Hermitian rank 1 update 00409 kov += pd_lastPowerReceived[*s].get_mW() 00410 * boost::numeric::ublas::outer_prod(steervector, boost::numeric::ublas::conj(steervector)); 00411 } 00412 00413 //desired station as last, is also needed for weight calculation 00414 pd_azimuthAngles [id] = (id->getAntenna()->getPosition() - myPosition).getAzimuth(); 00415 //add positionError to azimuth calculation (in order to model the actual position estimation) 00416 pd_azimuthAngles [id] += dis() * M_PI/180; 00417 00418 if (pd_azimuthAngles[id] < 0) 00419 pd_azimuthAngles[id] += M_PI + M_PI; 00420 for (unsigned long int i = 0; i < pd_noAntennaElements; i++) 00421 { 00422 c = std::polar(1.0, calculatePhaseDelta(i, pd_azimuthAngles[id])); 00423 steervector(i) = c; 00424 } 00425 assure(pd_lastPowerReceived.find(id) != pd_lastPowerReceived.end(), "Station is not yet registered at this antenna!"); 00426 //Hermitian rank 1 update 00427 kov += pd_lastPowerReceived[id].get_mW() 00428 * boost::numeric::ublas::outer_prod(steervector, boost::numeric::ublas::conj(steervector)); 00429 00430 //covariance matrix almost complete, now only noise entries necessary: 00431 std::complex<double> n = std::complex<double>(omniPower.get_mW(), 0); 00432 for (unsigned long int i = 0; i < pd_noAntennaElements; i++){ 00433 kov(i, i) = kov(i, i) + n; 00434 } 00435 //Calculate Weight vector 00436 boost::numeric::ublas::vector<std::complex<double> > w(pd_noAntennaElements); 00437 // restore full matrix: 00438 p_herm_rest(kov, pd_noAntennaElements); 00439 //Solving kov*w = sttervector using LU method: 00440 boost::numeric::ublas::permutation_matrix<> p(pd_noAntennaElements); 00441 boost::numeric::ublas::lu_factorize(kov, p); 00442 w = steervector; 00443 boost::numeric::ublas::lu_substitute(kov, p, w); 00444 00445 // compute antenna pattern: 00446 std::complex<double> pattern[360]; 00447 boost::numeric::ublas::vector<std::complex<double> > wTrans = boost::numeric::ublas::trans(w); 00448 for (unsigned long int i = 0; i < 360; i++){ 00449 pattern[i] = boost::numeric::ublas::inner_prod(wTrans, (*steervectors[i])); 00450 } 00451 //Normalize pattern to transmit / receive the same power as an omni-antenna: 00452 double sumPower = 0.0; 00453 for (unsigned long int i = 0; i < 360; i++) 00454 sumPower += pow(std::abs(pattern[i]),2); 00455 sumPower = sumPower / 360; 00456 00457 PatternPtr beam(new Pattern()); 00458 beam->pattern.reserve(360); 00459 for (unsigned long int i = 0; i < 360; i++) 00460 { 00461 double amplitudeFactor = std::abs(pattern[i])/sqrt(sumPower); 00462 beam->pattern.push_back(amplitudeFactor); 00463 } 00464 assure(beam->getSize() == 360, "pattern has no valid size"); 00465 // the omni attenuation factor is no longer needed, it is always one 00466 //beam->omniAttenuation = wns::Ratio::from_factor(1); 00467 unsigned long int grad = (unsigned long int)(pd_azimuthAngles[id]*180/M_PI +0.5); //0.5 to round 00468 if(grad == 360) grad = 0; 00469 assure(grad < beam->pattern.size(), "pattern index (grad) out of range"); 00470 double desiredAntennaFactor = beam->pattern.at(grad); 00471 00472 MESSAGE_BEGIN(VERBOSE, log, m, ""); 00473 m << "antenna factor in look direction: "<< desiredAntennaFactor << "\n"; 00474 m << "antenna factor(s) to undesired station(s): "; 00475 for (std::vector<Station*>::const_iterator s = undesired.begin(); s != undesired.end(); s ++){ 00476 grad = (unsigned long int)(pd_azimuthAngles[*s]*180/M_PI +0.5); //0.5 to round 00477 if(grad == 360) grad = 0; 00478 m << beam->pattern.at(grad) << " "; 00479 } 00480 MESSAGE_END(); 00481 00482 for (std::vector<Station*>::const_iterator s = undesired.begin(); s != undesired.end(); s ++){ 00483 grad = (unsigned long int)(pd_azimuthAngles[*s]*180/M_PI +0.5); //0.5 to round 00484 if(grad == 360) grad = 0; 00485 00486 if( beam->pattern.at(grad) > desiredAntennaFactor){ 00487 MESSAGE_BEGIN(NORMAL, log, m, ""); 00488 m << "antenna factor in look direction: "<< desiredAntennaFactor 00489 << " is smaller than antenna factor to undesired station " 00490 << beam->pattern.at(grad); 00491 MESSAGE_END(); 00492 drawRadiationPattern(); 00493 } 00494 } 00495 return beam; 00496 } 00497 00498 00499 void Beamforming::p_herm_rest(boost::numeric::ublas::matrix<std::complex<double> >& c, const unsigned long int m) const 00500 { 00501 //Restoration of efficiently stored hermitian matrix 00502 std::complex<double> z; 00503 double re, im; 00504 for (unsigned long int i = 0; i < m; i++){ 00505 for (unsigned long int j = i+1; j < m; j++){ 00506 re = c(i, j).real(); 00507 im = c(i, j).imag(); 00508 z = std::complex<double>(re, -im); 00509 c(j, i) = z; 00510 // real part symmetrically completed, imaginary part neg. symm. 00511 } 00512 } 00513 } 00514 00515 void Beamforming::drawRadiationPattern(std::string file, PatternPtr pattern) 00516 { 00517 const unsigned long int resolution = 360; 00518 double step = 2 * M_PI / resolution; 00519 //double zero_dB_length = radius; 00520 double length = 0, angle = 0; 00521 wns::Ratio gain = wns::Ratio::from_dB(0), 00522 gain_min = wns::Ratio::from_dB(-10); 00523 std::fstream outfile; 00524 outfile.open(file.c_str(), std::ios::out | std::ios::app); 00525 if (!outfile.is_open()) 00526 { 00527 MESSAGE_BEGIN(NORMAL, log, m,"File "); 00528 m << file + " could not be opened." + " Simulation will continue.\n"; 00529 MESSAGE_END(); 00530 return; 00531 } 00532 wns::Position myPosition = getPosition(); 00533 for (unsigned long int k=0; k<resolution; k++) 00534 { 00535 angle = step * k; 00536 gain = pd_getGainEntry(k, pattern); 00537 // if (gain<gain_min) length = 0; 00538 // else length = (zero_dB_length /(-gain_min.get_dB())) * gain.get_dB() + zero_dB_length; 00539 length = gain.get_factor(); 00540 outfile << myPosition.getX() + length * cos(angle) << " " 00541 << myPosition.getY() + length * sin(angle) << std::endl; 00542 } 00543 outfile << "\n"; 00544 outfile.close(); 00545 } 00546 00547 void Beamforming::drawRadiationPattern() const 00548 { 00549 const unsigned long int resolution = 360; 00550 double step = 2 * M_PI / resolution, length = radius, angle = 0; 00551 std::fstream outfile; 00552 outfile.open(patternOutputFile.c_str(), std::ios::out | std::ios::app); 00553 if (!outfile.is_open()) 00554 { 00555 MESSAGE_BEGIN(NORMAL, log, m,"File "); 00556 m << patternOutputFile + " could not be opened." + " Simulation will continue.\n"; 00557 MESSAGE_END(); 00558 return; 00559 } 00560 wns::Position myPosition = getPosition(); 00561 for (unsigned long int k=0; k<resolution; k++) 00562 { 00563 angle = step * k; 00564 outfile << myPosition.getX() + length * cos(angle) << " " 00565 << myPosition.getY() + length * sin(angle) << std::endl; 00566 } 00567 outfile << "\n"; 00568 outfile.close(); 00569 } 00570 00571
1.5.5