UWBIRIEEE802154APathlossModel.cc

00001 /* -*- mode:c++ -*- ********************************************************
00002  * file:        UWBIRIEEE802154APathlossModel.h
00003  *
00004  * author:      Jerome Rousselot <jerome.rousselot@csem.ch>
00005  *
00006  * copyright:   (C) 2008-2009 Centre Suisse d'Electronique et Microtechnique (CSEM) SA
00007  *        Systems Engineering
00008  *              Real-Time Software and Networking
00009  *              Jaquet-Droz 1, CH-2002 Neuchatel, Switzerland.
00010  *
00011  *              This program is free software; you can redistribute it
00012  *              and/or modify it under the terms of the GNU General Public
00013  *              License as published by the Free Software Foundation; either
00014  *              version 2 of the License, or (at your option) any later
00015  *              version.
00016  *              For further information see file COPYING
00017  *              in the top level directory
00018  * description: this AnalogueModel implements the IEEE 802.15.4A Channel Model
00019  ***************************************************************************/
00020 
00021 #include "UWBIRIEEE802154APathlossModel.h"
00022 
00023 const bool UWBIRIEEE802154APathlossModel::implemented_CMs[] = {
00024             false, //  There is no Channel Model 0: start at 1
00025             true,  //  CM1
00026             true,  //  CM2
00027             true,  //  CM3
00028             false, //  CM4 (requires alternate PDP)
00029             true,  //  CM5
00030             true,  //  CM6
00031             true,  //  CM7
00032             false,  //  CM8 (alternate PDP)
00033             false  //  CM9 (requires alternate PDP)
00034         };
00035 
00036 const UWBIRIEEE802154APathlossModel::CMconfig UWBIRIEEE802154APathlossModel::CMconfigs[] = {
00037     // CM0
00038     {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
00039     // *CM1*
00040       //PL0,      n, sigma_s (undefined)
00041     { 0.000040738, 1.79,  0,
00042       //Aant, kappa, Lmean,   Lambda
00043       3,    1.12,   3,    0.047E9,
00044       //lambda_1, lambda_2,   Beta
00045       1.54E9,   0.15E9,   0.095,
00046       //Gamma, k_gamma, gamma_0, sigma_cluster,
00047       22.61E-9, 0,  12.53E-9, 1.883649089,
00048       //m_0, k_m, var_m_0, var_k_m, strong_m_0 (undefined)
00049       0.67,   0,  0.28,     0,    0,
00050       //gamma_rise, gamma_1, xi (all undefined)
00051       0, 0, 0},
00052 
00053     // *CM2*
00054       //PL0,      n, sigma_s (undefined)
00055     { 0.00001349, 4.58, 0,
00056       //Aant, kappa, Lmean,   Lambda
00057       3,    1.12,   3.5,  0.12E9,
00058       //lambda_1, lambda_2,   Beta
00059       1.77E9,   0.15E9,   0.045,
00060       //Gamma, k_gamma, gamma_0, sigma_cluster,
00061       26.27E-9, 0,  17.5E-9,  1.963360277,
00062       //m_0, k_m, var_m_0, var_k_m, strong_m_0 (undefined)
00063       0.69,   0,  0.32,     0,    0,
00064       //gamma_rise, gamma_1, xi (all undefined)
00065       0, 0, 0},
00066 
00067     // *CM3*
00068       //PL0,      n, sigma_s (undefined)
00069     { 0.000218776, 1.63, 1.9,
00070       //Aant, kappa, Lmean,   Lambda
00071       3,    -3.5,   5.4,  0.016E9,
00072       //lambda_1, lambda_2,   Beta
00073       0.19E9,   2.97E9,   0.0184,
00074       //Gamma, k_gamma, gamma_0, sigma_cluster (undefined),
00075       14.6E-9, 0,   6.4E-9,  0,
00076       //m_0, k_m, var_m_0, var_k_m, strong_m_0 (undefined)
00077       0.42,   0,  0.31,     0,    0,
00078       //gamma_rise, gamma_1, xi (all undefined)
00079       0, 0, 0},
00080 
00081     // *CM4*
00082       //PL0,      n, sigma_s (undefined)
00083     { 0.000007244, 3.07, 3.9,
00084       //Aant, kappa, Lmean,   Lambda (undefined)
00085       3,    -5.3,   1,  0,
00086       //lambda_1, lambda_2,   Beta (all undefined)
00087       0,  0,  0,
00088       //Gamma, k_gamma, gamma_0, sigma_cluster (all undefined),
00089       0, 0,   0,  0,
00090       //m_0, k_m, var_m_0, var_k_m, strong_m_0 (undefined)
00091       0.5,  0,  0.25,     0,    0,
00092       //gamma_rise, gamma_1, xi
00093       15.21, 11.84, 0.86},
00094 
00095     // *CM5* Outdoor LOS
00096       //PL0,      n, sigma_s
00097     { 0.000046881, 1.76, 0.83,
00098       //Aant, kappa, Lmean,   Lambda
00099       3,    -1.6,   13.6, 0.0048E9,
00100       //lambda_1, lambda_2,   Beta
00101       0.27E9,   2.41E9,   0.062,
00102       //Gamma, k_gamma, gamma_0, sigma_cluster (undefined),
00103       31.7E-9, 0,   3.7E-9,  0,
00104       //m_0, k_m, var_m_0, var_k_m, strong_m_0 (undefined)
00105       0.77,   0,  0.78,     0,    0,
00106       //gamma_rise, gamma_1, xi (all undefined)
00107       0, 0, 0},
00108 
00109       // *CM6* Outdoor NLOS
00110         //PL0,      n, sigma_s
00111     { 0.000046881, 2.5, 2,
00112       //Aant, kappa, Lmean,   Lambda
00113       3,    0.4,  10.5, 0.0243E9,
00114       //lambda_1, lambda_2,   Beta
00115       0.15E9,   1.13E9,   0.062,
00116       //Gamma, k_gamma, gamma_0, sigma_cluster (undefined),
00117       104.7E-9, 0,  9.3E-9,  0,
00118       //m_0, k_m, var_m_0, var_k_m, strong_m_0 (undefined)
00119       0.56,   0,  0.25,     0,    0,
00120       //gamma_rise, gamma_1, xi (all undefined)
00121       0, 0, 0},
00122 
00123       // *CM7* Open Outdoor NLOS
00124         //PL0,      n, sigma_s
00125     { 0.000012706, 1.58, 3.96,
00126       //Aant, kappa (?), Lmean,   Lambda
00127       3,    0,  3.31, 0.0305E9,
00128       //lambda_1, lambda_2,   Beta
00129       0.0225E9,   0,  0,
00130       //Gamma, k_gamma, gamma_0, sigma_cluster (undefined),
00131       56E-9, 0,   0.92E-9,  0,
00132       //m_0, k_m, var_m_0, var_k_m, strong_m_0 (undefined)
00133       4.1,  0,  2.5,    0,    0,
00134       //gamma_rise, gamma_1, xi (all undefined)
00135       0, 0, 0},
00136 
00137       // *CM8* Industrial LOS
00138         //PL0,      n, sigma_s
00139     { 0.000002138, 1.2, 6,
00140       //Aant, kappa (?), Lmean,   Lambda
00141       3,    -5.6,   4.75, 0.0709E9,
00142       //lambda_1, lambda_2,   Beta (all undefined)
00143       0,  0,  0,
00144       //Gamma, k_gamma, gamma_0, sigma_cluster (undefined),
00145       13.47E-9, 0.926,  0.651E-9,  4.32,
00146       //m_0, k_m, var_m_0, var_k_m, strong_m_0
00147       0.36,   0,  1.13,     0,    12.99,
00148       //gamma_rise, gamma_1, xi (all undefined)
00149       0, 0, 0},
00150 
00151     {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}  // CM9
00152 };
00153 
00154 void UWBIRIEEE802154APathlossModel::filterSignal(Signal& s) {
00155     // We create a new "fake" txPower to add multipath taps
00156     // and then attenuation is applied to all pulses.
00157 
00158   // (1) Power Delay Profile realization
00159 
00160     txPower = s.getTransmissionPower();
00161     newTxPower = new TimeMapping<Linear>(); //dynamic_cast<TimeMapping<Linear>*> (txPower->clone()); // create working copy
00162     pulsesIter = newTxPower->createIterator(); // create an iterator that we will use many times in addEchoes
00163     // generate number of clusters for this channel (channel coherence time > packet air time)
00164     L = max(1, poisson(cfg.Lmean));
00165     // Choose block shadowing
00166     S = pow(10,(normal(0, cfg.sigma_s)/10));
00167 
00168     // Loop on each value of the original mapping and generate multipath echoes
00169     ConstMappingIterator* iter = txPower->createConstIterator();
00170 
00171     while (iter->inRange()) {
00172         // generate echoes for each non zero value
00173         if (iter->getValue() != 0) {
00174           // give the pulse start position
00175             addEchoes(iter->getPosition().getTime() - IEEE802154A::mandatory_pulse/2);
00176         }
00177         if (!iter->hasNext()) {
00178             break;
00179         }
00180         iter->next();
00181     }
00182     delete iter;
00183     delete pulsesIter;
00184     s.setTransmissionPower(newTxPower);
00185 
00186 
00187     // compute distance
00188     Move srcMove = s.getMove();
00189     Coord srcCoord, rcvCoord;
00190     distance = 0;
00191     srcCoord = srcMove.getPositionAt(s.getSignalStart());
00192     rcvCoord = move->getPositionAt(s.getSignalStart());
00193     distance = rcvCoord.distance(srcCoord);
00194 
00195   // Total radiated power Prx at that distance  [W]
00196     //double attenuation = 0.5 * ntx * nrx * cfg.PL0 / pow(distance / d0, cfg.n);
00197     double attenuation = getPathloss(fc, BW);
00198     pathlosses.record(attenuation);
00199     // Power intensity I at that distance [W/m²]
00200     //attenuation = attenuation /(4*PI*pow(distance, cfg.n));
00201     // create mapping
00202     SimpleTimeConstMapping* attMapping = new SimpleTimeConstMapping(
00203         attenuation, s.getSignalStart(), s.getSignalStart()+s.getSignalLength());
00204 
00205     s.addAttenuation(attMapping);
00206 
00207 }
00208 
00209 void UWBIRIEEE802154APathlossModel::addEchoes(simtime_t pulseStart) {
00210   // statistics
00211   nbCalls = nbCalls + 1;
00212   double power = 0;
00213     // loop control variables
00214     bool moreTaps = true;
00215     arg.setTime(pulseStart + IEEE802154A::mandatory_pulse/2);
00216     double pulseEnergy = txPower->getValue(arg);
00217     if(doShadowing) {
00218       pulseEnergy = pulseEnergy - S;
00219     }
00220     simtime_t tau_kl = 0;
00221     simtime_t fromClusterStart = 0;
00222     // start time of cluster number "cluster"
00223     clusterStart = 0;
00224     gamma_l = cfg.gamma_0;
00225     Mcluster = normal(0, cfg.sigma_cluster);
00226     Omega_l = pow(10, Mcluster / 10);
00227     // tapEnergy values are normalized
00228     double tapEnergy = sqrt( Omega_l / ( cfg.gamma_0 * ( (1-cfg.Beta)*cfg.lambda_1 + cfg.Beta*cfg.lambda_2 + 1 ) ) );
00229     // nakagami fading parameters
00230     double mfactor = 0;
00231     double mmean = 0, msigma = 0;
00232     bool firstTap = true;
00233     simtime_t echoEnd = 0;
00234     for (int cluster = 0; cluster < L; cluster++) {
00235         while (moreTaps) {
00236             // modify newTxPower
00237             // we add three points for linear interpolation
00238           // we set the start and end point before adding the new values for correct interpolation
00239             double pValueStart = newTxPower->getValue(arg);
00240             double pValueEnd = newTxPower->getValue(arg);
00241             simtime_t echoStart = pulseStart + clusterStart + tau_kl;
00242             echoEnd = pulseStart + clusterStart + tau_kl + IEEE802154A::mandatory_pulse;
00243             simtime_t echoPeak = pulseStart + clusterStart + tau_kl + IEEE802154A::mandatory_pulse/2;
00244             arg.setTime(echoEnd);
00245             newTxPower->setValue(arg, pValueEnd);
00246             arg.setTime(echoStart);
00247             newTxPower->setValue(arg, pValueStart);
00248             bool raising = true;
00249 
00250             if(firstTap) {
00251               mfactor = cfg.m_0;
00252             } else {
00253               mmean = cfg.m_0 - cfg.k_m*tau_kl.dbl();
00254               msigma = cfg.var_m_0 - cfg.var_k_m*tau_kl.dbl();
00255               mfactor = normal(mmean, msigma);
00256             }
00257             /*
00258             if(doSmallScaleShadowing) {
00259               double tmp = sqrt(mfactor*mfactor-mfactor);
00260               double riceK = tmp/(mfactor-tmp);
00261               //dw;
00262               finalTapEnergy = finalTapEnergy * 10^(mfactor/10);
00263             }
00264             */
00265             double finalTapEnergy = tapEnergy * pulseEnergy;
00266 
00267             // We cannot add intermediate points "online" as we need the interpolated
00268             // values of the signal before adding this echo pulse.
00269             map<simtime_t, double> intermediatePoints;
00270             // We need to evaluate all points of the mapping already stored that intersect
00271             // with this pulse.
00272             pulsesIter->jumpTo(arg);
00273             simtime_t currentPoint = echoStart;
00274             while(currentPoint < echoEnd) {
00275               if(raising && pulsesIter->getNextPosition().getTime() < echoPeak) {
00276                 // there is a point in the first half of the echo
00277                 // retrieve its value
00278                 pulsesIter->next();
00279                 double oldValue = pulsesIter->getValue();
00280                 currentPoint = pulsesIter->getPosition().getTime();
00281                 // interpolate current echo point
00282                 double echoValue = ((currentPoint - echoStart)/(0.5*IEEE802154A::mandatory_pulse)).dbl();
00283                 echoValue = echoValue * finalTapEnergy;
00284                 intermediatePoints[currentPoint] = echoValue + oldValue;
00285               } else if(raising && pulsesIter->getNextPosition().getTime() >= echoPeak) {
00286           // We reached the peak of the pulse.
00287                 currentPoint = echoPeak;
00288                 arg.setTime(currentPoint);
00289                 pulsesIter->jumpTo(arg);
00290                 double oldValue = pulsesIter->getValue();
00291                 intermediatePoints[currentPoint] = oldValue + finalTapEnergy;
00292           raising = false;
00293               } else if(!raising && pulsesIter->getNextPosition().getTime() < echoEnd) {
00294                 // there is a point in the second half of the echo
00295                 // retrieve its value
00296                 pulsesIter->next();
00297                 double oldValue = pulsesIter->getValue();
00298                 currentPoint = pulsesIter->getPosition().getTime();
00299                 // interpolate current echo point
00300                 double echoValue = 1 - ((currentPoint - echoPeak)/(0.5*IEEE802154A::mandatory_pulse)).dbl();
00301                 echoValue = echoValue * finalTapEnergy;
00302                 intermediatePoints[currentPoint] = echoValue + oldValue;
00303               } else if (!raising && pulsesIter->getNextPosition().getTime() >= echoEnd) {
00304                 currentPoint = echoEnd; // nothing to do, we already set this point
00305               }
00306             }
00307 
00308             // Add all points stored in intermediatePoints.
00309             map<simtime_t, double>::iterator newPointsIter;
00310             newPointsIter = intermediatePoints.begin();
00311             while(newPointsIter != intermediatePoints.end()) {
00312               arg.setTime(newPointsIter->first);
00313               newTxPower->setValue(arg, newPointsIter->second);
00314               newPointsIter++;
00315             }
00316 
00317             power = power + finalTapEnergy; // statistics
00318 
00319             // Update values for next iteration
00320             double mix1 = exponential(1 / cfg.lambda_1);
00321             double mix2 = exponential(1 / cfg.lambda_2);
00322             if(mix1 == numeric_limits<double>::infinity()) {
00323                 mix1 = 0;
00324             }
00325             if(mix2 == numeric_limits<double>::infinity()) {
00326                 mix2 = 0;
00327             }
00328             tau_kl += mix1 * cfg.Beta + (1 - cfg.Beta) * mix2;
00329             //fromClusterStart += tau_kl;
00330             tapEnergy = gamma_l.dbl() * ((1 - cfg.Beta) * cfg.lambda_1 + cfg.Beta * cfg.lambda_2 + 1);
00331             tapEnergy = Omega_l / tapEnergy;
00332             tapEnergy = tapEnergy * exp(-tau_kl.dbl() / gamma_l.dbl());
00333             tapEnergy = sqrt(tapEnergy);
00334             if (tapEnergy < tapThreshold) {
00335                 moreTaps = false;
00336             }
00337         }
00338         double nextClusterStart = exponential(1 / cfg.Lambda);
00339         if(nextClusterStart > 0.001 || nextClusterStart == numeric_limits<double>::infinity()) {
00340           moreTaps = false;
00341         } else {
00342           clusterStart = clusterStart + nextClusterStart; // sum(x_n) over n=1..cluster
00343           gamma_l = cfg.k_gamma * clusterStart + cfg.gamma_0;
00344           Mcluster = normal(0, cfg.sigma_cluster);
00345           Omega_l = pow(10, (10 * log( exp( -clusterStart.dbl() / cfg.Gamma ) ) + Mcluster) / 10);
00346           // new constraint to increase speed
00347           if(Omega_l > 0.1) {
00348             moreTaps = true;
00349           } else {
00350           moreTaps = false;
00351           }
00352         }
00353     }
00354     arg.setTime(echoEnd);
00355     newTxPower->setValue(arg, 0);
00356     averagePower = averagePower + power;
00357     averagePowers.record( averagePower / ((double) nbCalls));
00358 }
00359 
00360 /*
00361  * Returns the integral of formula (12) assuming constant nrx, ntx over BW
00362  * and kappa != 0.5
00363  */
00364 double UWBIRIEEE802154APathlossModel::getPathloss(double fc, double BW) {
00365   double pathloss = 0.5; // "antenna attenuation factor"
00366   pathloss = pathloss * cfg.PL0;  // pathloss at reference distance
00367   pathloss = pathloss * ntx * nrx; // antenna effects
00368   pathloss = pathloss / pow(distance/d0, cfg.n); // distance
00369   /*
00370   // and frequency dependent effects
00371   pathloss = pathloss / pow(fc, 2*(cfg.kappa+1));
00372   pathloss = pathloss / (-2*cfg.kappa-1);
00373   pathloss = pathloss * ( pow(fc+BW/2,-2*cfg.kappa-1) - pow(fc-BW/2,-2*cfg.kappa-1) );
00374   */
00375   // old version was ignoring frequency dependent effects
00376   //double attenuation = 0.5 * ntx * nrx * cfg.PL0 / pow(distance / d0, cfg.n);
00377   return pathloss;
00378 }
00379 
00380 double UWBIRIEEE802154APathlossModel::Rayleigh(double param) {
00381     return weibull(2, sqrt(2) * param);
00382 }
00383