def thermalnoise(bandwidth): """Compute thermal noise floor for communication systems with given bandwidth. :param bandwidth: Bandwidth of system (in Hz). :return: Thermal noise noise power (in dBm). See `Thermal Noise`_ for more on how the thermal noise floor of a communications system is computed in this method. .. _`Thermal Noise`: http://en.wikipedia.org/wiki/Thermal_noise#Noise_in_decibels """ noise_dbm = -174.01 + linear2db(bandwidth) return noise_dbm
def rxenergy(self): """Calculate total receive energy of packets in `rxbuffer`. :return: Receive power (in dBm), or -Inf if nothing is in `rxbuffer`. This method uses the 'rxpower' annotation of packets in `rxbuffer` to determine the total receive power. Any packets that do not support this annotation will not contribute to the total power calculated. """ tot = 0 # sum total in milliwatts for p in self.rxbuffer: if ANNO.supports(p, 'rxpower'): prx = p.getanno('rxpower') # rxpower in dBm tot += db2linear(prx) tot_dbm = linear2db(tot) return tot_dbm
def calcper_data(self, p, **kwargs): """Calculate probability of error for data decoding. :param p: Packet being decoded. :param kwargs: Additional keywords arguments passed to `sinr_heap()` (or `sinr()`). :return: PER for decoding packet payload. This method sets the 'dot11a-sinr' and 'dot11a-per' annotations. The operation of this method depends on `DOT11A_USE_PIECEWISE_PER`. """ for a in ["cif-rxts", "cif-duration"]: errmsg = "[DOT11APHY]: calcper_data() cannot find " + "'%s' annotation!" % (a) assert ANNO.supports(p, a), errmsg # verify header parameters plen = len(p.payload) rate, length = p.rate, p.length assert 0 <= rate < len(DOT11A_DATARATE), "[DOT11A]: Invalid rate option (%s)!" % (rate) assert p.length == plen, "[DOT11A]: Header length reported " + "does not equal payload length; %s!=%s" % ( p.length, plen, ) # calculate PER using appropriate method if DOT11A_USE_PIECEWISE_PER: sinrheap = self.sinr_heap(p, **kwargs) t1 = p.getanno("cif-rxts") + p.getanno("cif-duration") t0 = t1 - self.calcnofdm(plen, rate) * DOT11A_TSYM xheap = [(max(ta, t0), min(tb, t1), sinr) for (ta, tb, sinr) in sinrheap if (ta < t1) and (tb > t0)] errmsg = "[DOT11APHY]: Unable to find valid data from SINR heap!" assert len(xheap) > 0, errmsg # calculate piecewise PER and average SINR psuccess, stot = 1.0, 0.0 for ta, tb, sinr in xheap: alpha = (tb - ta) / (t1 - t0) dlen = plen * alpha stot += db2linear(sinr) * alpha psuccess *= 1.0 - self.calcper(dlen, rate, sinr) per = 1.0 - psuccess sinr = linear2db(stot) else: # configure modulation and coding to calculate PER sinr, plen = self.sinr(p, **kwargs), length per = self.calcper(plen, rate, sinr) # set annotations and return PER p.setanno("dot11a-sinr", sinr) p.setanno("dot11a-per", per) return per
def sinr_heap(self, p, force=True): """Calculate signal-to-interference-and noise ratio (SINR) for each partition created by `interval_heap()`. :param p: Packet to inspect. :param force: If true, recalculate interval heap, else use existing annotation if it exists. :return: SINR heap. SINR heap has looks like this: [(t0, t1, sinr0), (t1, t2, sinr1), ... ] Note: This method uses the 'rxpower' and 'noisepower' annotations. """ # check packet errmsg = "[CHANNELIF]: sinr_heap() cannot process non-Packet!" assert ANNO.supported(p), errmsg for a in ['rxpower', 'noisepower']: errmsg = "[CHANNELIF]: sinr_heap() cannot find '%s' annotation!"%(a) assert ANNO.supports(p, a), errmsg # get parameters rxpower = p.getanno('rxpower') # in dBm noisepower = p.getanno('noisepower') # in dBm npow = db2linear(noisepower) # get interval heap if p.hasanno('cif-iheap') and not force: iheap = p.getanno('cif-iheap') else: iheap = self.interval_heap(p) # start creating sinr heap sinrheap = [] #print "%s: SINR heap for %s @ %.8f"%(self.traceid, p.traceid, now()) for ta,tb,coll in iheap: ipow = 0 for c in coll: errmsg = "[CHANNELIF]: sinr_heap() cannot find 'rxpower' " + \ "annotation in collision list!" assert ANNO.supports(c, 'rxpower'), errmsg ipow += db2linear(c.getanno('rxpower') ) sinr = rxpower - linear2db(ipow + npow) sinrheap.append((ta,tb,sinr) ) #print " --> (%.8f, %.8f): %.3f dB, coll = %s"%(ta,tb, sinr, [c.traceid for c in coll]) return sinrheap
def calcpathloss(cls, dist, bpdist=None, n=None, **kwargs): """Calculate propagation loss using breakpoint pathloss model. :param dist: Separation distance between transmitter and receiver. :param bpdist: Breakpoint distance (in meters). :param n: Pathloss exponent. :param kwargs: Additional parameters passed to `freespace()`. :return: Pathloss (in dB). The breakpoint pathloss model uses freespace propagation up to the breakpoint distance and the specified pathloss thereafter. """ if n is None: n = cls.n if ((bpdist>0) and (dist>bpdist)): bploss = cls.freespace(bpdist, n=2.0, **kwargs) PL = bploss + n*linear2db(dist/(1.0*bpdist) ) else: PL = cls.freespace(dist, n=2.0, **kwargs) return PL
def calcpathloss(cls, dist, refdist=None, refloss=None, n=None, **kwargs): """Calculate propagation loss using reference pathloss model. :param dist: Separation distance between transmitter and receiver. :param refdist: Reference distance (in meters). :param refloss: Pathloss at reference distance (in dB). :param n: Pathloss exponent. :return: Pathloss (in dB). If reference distance `refdist` is None, and no suitable class variable is defined, this method will simply return the `freespace` pathloss. If `refdist` is defined and `refloss` is None, this method will compute the reference pathloss as the freespace pathloss using loss exponent 2. """ if n is None: n = cls.n if refdist>0: if refloss is None: refloss = cls.freespace(refdist, n=2, **kwargs) PL = refloss + n*linear2db(dist/(1.0*refdist) ) else: PL = cls.freespace(dist, n=n, **kwargs) return PL
def calcper_header(self, p, **kwargs): """Calculate probability of error for header decoding. :param p: Packet being decoded. :param kwargs: Additional keywords arguments passed to `sinr_heap()` (or `sinr()`). :return: PER for header decoding. This method sets the 'dot11a-sinr' and 'dot11a-per' annotations. The operation of this method depends on `DOT11A_USE_PIECEWISE_PER`. """ for a in ["cif-rxts"]: errmsg = "[DOT11APHY]: calcper_header() cannot find " + "'%s' annotation!" % (a) assert ANNO.supports(p, a), errmsg # calculate PER using appropriate method plen = len(p.payload) if DOT11A_USE_PIECEWISE_PER: sinrheap = self.sinr_heap(p, **kwargs) t0 = p.getanno("cif-rxts") + DOT11A_TSHORT + DOT11A_TLONG t1 = t0 + DOT11A_TSIGNAL xheap = [(max(ta, t0), min(tb, t1), sinr) for (ta, tb, sinr) in sinrheap if (ta < t1) and (tb > t0)] errmsg = "[DOT11APHY]: Unable to find valid data from SINR heap!" assert len(xheap) > 0, errmsg # calculate piecewise PER and average SINR psuccess, stot = 1.0, 0.0 for ta, tb, sinr in xheap: alpha = (tb - ta) / (t1 - t0) hlen = len(Dot11A()) * alpha stot += db2linear(sinr) * alpha psuccess *= 1.0 - self.calcper(hlen, 0, sinr) per = 1.0 - psuccess sinr = linear2db(stot) else: sinr, hlen = self.sinr(p, **kwargs), len(p) - plen # configure modulation and coding to calculate PER per = self.calcper(hlen, 0, sinr) # set annotations and return PER p.setanno("dot11a-sinr", sinr) p.setanno("dot11a-per", per) return per