![]() |
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 <OFDMAPHY/receiver/mimo/CorrelatedStaticZF.hpp> 00029 #include <OFDMAPHY/receiver/Receiver.hpp> 00030 00031 #include <WNS/geometry/Vector.hpp> 00032 00033 #include <boost/numeric/ublas/io.hpp> 00034 #include <boost/numeric/ublas/vector.hpp> 00035 #include <boost/numeric/ublas/vector_proxy.hpp> 00036 #include <boost/numeric/ublas/triangular.hpp> 00037 #include <boost/numeric/ublas/lu.hpp> 00038 00039 #include <math.h> 00040 00041 using namespace ofdmaphy::receiver::mimo; 00042 00043 STATIC_FACTORY_REGISTER_WITH_CREATOR(CorrelatedStaticZF, 00044 ICalculationStrategy, 00045 "CorrelatedStaticZF", 00046 ICalculationStrategyCreator); 00047 00048 CorrelatedStaticZF::CorrelatedStaticZF(const wns::pyconfig::View& _config, 00049 Receiver* _rx, 00050 wns::logger::Logger* _logger): 00051 ICalculationStrategy(_config, _rx, _logger), 00052 logger(_logger), 00053 rx(_rx), 00054 arrayOrientation(_config.get<double>("arrayOrientation")), 00055 antennaSpacing(_config.get<double>("antennaSpacing")), 00056 angleSpread(_config.get<double>("angleSpread")) 00057 { 00058 assure(arrayOrientation >= 0.0, "Antenna angle cannot be negative"); 00059 assure(arrayOrientation <= M_PI, "Anntenna angle cannot exceed PI"); 00060 } 00061 00062 std::vector<wns::Ratio> 00063 CorrelatedStaticZF::getPostProcessingSINRFactor(rise::TransmissionObjectPtr t) 00064 { 00065 // number of spatial streams and rx antennas 00066 int n_SS = t->getNumberOfSpatialStreams(); 00067 int n_RX = rx->getOFDMAStation()->getNumAntennas(); 00068 00069 if(n_SS > n_RX) 00070 { 00071 // More streams than receive antennas -> no usefull reception possible 00072 return std::vector<wns::Ratio>(n_SS, wns::Ratio::from_factor(1e-12)); 00073 } 00074 00075 // this is the MIMO Gain without any correlation 00076 wns::Ratio noCorrelationGain = wns::Ratio::from_factor(double(n_RX - n_SS + 1)/double(n_SS)); 00077 MESSAGE_SINGLE(NORMAL, *logger, "CorrelatedStaticZF: Gain w/o correlation: " << noCorrelationGain); 00078 00079 // get the transmitting station 00080 ofdmaphy::Station* txStation = dynamic_cast<ofdmaphy::Station*>(t->getTransmitter()->getStation()); 00081 assure(txStation, "Peer is not an OFDMA station"); 00082 00083 // get the peer mimo-processing routine and cast it to CorrelatedStaticZF to 00084 // read the required performance values 00085 CorrelatedStaticZF* peer = txStation->getReceiver()->getMIMOProcessing<CorrelatedStaticZF>(); 00086 00087 // calculate Angle of Departure and Angle of Arrival by creating two vectors 00088 // tx->rx and rx->tx 00089 wns::Position txPosition = txStation->getPosition(); 00090 wns::Position rxPosition = rx->getStation()->getPosition(); 00091 00092 double AoD = wns::geometry::Vector(txPosition, rxPosition).getAzimuth() 00093 + peer->getArrayOrientation(); 00094 if(AoD < 0) 00095 { 00096 AoD += M_PI; 00097 } 00098 else if(AoD > M_PI) 00099 { 00100 AoD -= M_PI; 00101 } 00102 00103 double AoA = wns::geometry::Vector(rxPosition, txPosition).getAzimuth() 00104 + this->arrayOrientation; 00105 if(AoA < 0) 00106 { 00107 AoA += M_PI; 00108 } 00109 else if(AoA > M_PI) 00110 { 00111 AoA -= M_PI; 00112 } 00113 00114 // compute loss due to tx and rx correlation 00115 std::vector<wns::Ratio> txLoss = getCorrelationLoss(n_SS, AoD, peer->getAntennaSpacing(), peer->getAngleSpread()); 00116 std::vector<wns::Ratio> rxLoss = getCorrelationLoss(n_RX, AoA, this->antennaSpacing, this->getAngleSpread()); 00117 00118 MESSAGE_BEGIN(NORMAL, *logger, m, "CorrelatedStaticZF:"); 00119 m << " tx pos " << txPosition; 00120 m << " rx pos " << rxPosition; 00121 MESSAGE_END(); 00122 00123 MESSAGE_BEGIN(NORMAL, *logger, m, "CorrelatedStaticZF: TX"); 00124 m << " orientation " << peer->getArrayOrientation(); 00125 m << " AoD " << AoD/M_PI*180 << "d"; 00126 m << " ASD " << peer->getAngleSpread() << "rad"; 00127 m << " spacing " << peer->getAntennaSpacing(); 00128 m << " -> loss: "; 00129 for(std::vector<wns::Ratio>::const_iterator it = txLoss.begin(); 00130 it != txLoss.end(); 00131 ++it) 00132 { 00133 m << (*it) << " "; 00134 } 00135 MESSAGE_END(); 00136 00137 MESSAGE_BEGIN(NORMAL, *logger, m, "CorrelatedStaticZF: RX"); 00138 m << " orientation " << this->getArrayOrientation(); 00139 m << " AoA " << AoA/M_PI*180 << "d"; 00140 m << " ASA " << this->getAngleSpread() << "rad"; 00141 m << " spacing " << this->getAntennaSpacing(); 00142 m << " -> loss: "; 00143 for(std::vector<wns::Ratio>::const_iterator it = rxLoss.begin(); 00144 it != rxLoss.end(); 00145 ++it) 00146 { 00147 m << (*it) << " "; 00148 } 00149 MESSAGE_END(); 00150 00151 // calculate result vector 00152 std::vector<wns::Ratio> r; 00153 std::vector<wns::Ratio>::iterator itTx = txLoss.begin(); 00154 std::vector<wns::Ratio>::iterator itRx = rxLoss.begin(); 00155 00156 for(; 00157 itTx != txLoss.end(); 00158 ++itTx, ++itRx) 00159 { 00160 r.push_back(noCorrelationGain - *itTx - *itRx); 00161 } 00162 00163 // single antenna fallback 00164 if(r[0].get_dB() < 0 and n_SS == 1) 00165 { 00166 std::vector<wns::Ratio> rFallBack; 00167 rFallBack.push_back(wns::Ratio::from_factor(1)); 00168 MESSAGE_BEGIN(NORMAL, *logger, m, "CorreltatedStaticZF: "); 00169 m << "Correlation makes MIMO impossible -> use only one rx antenna"; 00170 MESSAGE_END(); 00171 return rFallBack; 00172 } 00173 00174 return r; 00175 } 00176 00177 std::vector<wns::Ratio> 00178 CorrelatedStaticZF::getCorrelationLoss(int n, double angle, double spacing, double spread) 00179 { 00180 using namespace boost::numeric::ublas; 00181 00182 // Compute the correlation matrix m 00183 matrix< std::complex<double> > m(n,n); 00184 std::complex<double> j(0, 1.0); 00185 00186 for(double p = 0; p < n; ++p) 00187 { 00188 for(double q = 0; q < n; ++q) 00189 { 00190 if(p==q) 00191 { 00192 m(p,q) = 1.0; 00193 } 00194 else 00195 { 00196 m(p,q) = std::exp(-1.0*j*2.0*M_PI*(p-q)*spacing*cos(angle)) * std::exp(-0.5*std::pow(2.0*M_PI*(q-p)*spacing*sin(angle)*spread, 2.0)); 00197 } 00198 } 00199 } 00200 00201 // Compute the inverse of m using LU-factorization 00202 matrix< std::complex<double> > m_inv(n,n); 00203 00204 // create a permutation matrix for the LU-factorization 00205 permutation_matrix<std::size_t> pm(m.size1()); 00206 int res = lu_factorize(m, pm); 00207 if(res != 0) 00208 { 00209 // factorization not possible 00210 return(std::vector<wns::Ratio>(n, wns::Ratio::from_factor(1e10))); 00211 } 00212 00213 // create identity matrix of "inverse" 00214 m_inv.assign(identity_matrix< std::complex<double> >(m.size1())); 00215 00216 // backsubstitute to get the inverse 00217 lu_substitute(m, pm, m_inv); 00218 00219 std::vector<wns::Ratio> r; 00220 00221 for(int i = 0; i< n; ++i) 00222 { 00223 assure(m_inv(i,i).imag() < 1e-3, 00224 "Complex value at position " << i << " has imag-part of " << m_inv(i,i).imag()); 00225 r.push_back(wns::Ratio::from_factor(m_inv(i,i).real())); 00226 } 00227 return r; 00228 }
1.5.5