Exemplo n.º 1
0
    def calcrxwaveform(self, p, bandwidth=None):
        """Pre-compute receive waveform and set 'dot11n-rxwaveform'.

        Use 'dot11n-channel' and 'dot11n-txwaveform' annotations to pre-compute
        the received waveform (modulo intereference and noise).
        """
        if bandwidth is None: bandwidth = DOT11N_BANDWIDTH
        # check for annotations
        for a in ['rxpower', 'dot11n-txwaveform', 'dot11n-channel']:
            errmsg = "[DOT11N_DSP]: cannot find '%s' annotation!"%(a)
            assert ANNO.supports(p,a), errmsg
        A = db2linear(p.getanno('rxpower'))
        H = p.getanno('dot11n-channel')
        x = p.getanno('dot11n-txwaveform')
        # check that channel dimensions match Ntx
        nrx = H.rows()
        ntx, hcols = x.rows(), H.cols()
        assert (hcols == ntx), "[DOT11N]: Got channel with invalid dimensions!"
        z = sqrt(A)*H.conv(x)
        # apply local frequency offset (and doppler) if annotations are found
        cfo = 0
        if p.hasanno('tx-cfo') and p.hasanno('rx-cfo'):
            cfo += p.getanno('tx-cfo') - p.getanno('rx-cfo')
        if p.hasanno('doppler'):
            cfo += p.getanno('doppler')
        z.apply_offset(cfo, bandwidth)
        # set rxwaveform annotation
        p.setanno('dot11n-rxwaveform', z)
        return p
Exemplo n.º 2
0
 def delrxwaveform(self, p):
     """Remove waveform annotations from packet `p`."""
     wanno = ['dot11n-txwaveform', 'dot11n-rxwaveform', \
              'dot11n-rxnoise', 'dot11n-rxadded', 'dot11n-channel']
     for a in [w for w in wanno if ANNO.supports(p,w)]:
         if p.hasanno(a): p.delanno(a)
     return p
Exemplo n.º 3
0
    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
Exemplo n.º 4
0
    def cleananno(self, p):
        """Remove unwanted annotations from packet `p`.

        Removes any annotations that could cause cyclic references.
        """
        if ANNO.supports(p, 'cif-collision'):
            coll = strcollision(p)
            p.delanno('cif-collision')
            p.setanno('cif-collision', coll, priv=True)
        return p
Exemplo n.º 5
0
 def DECODE(self, fsm, pkt):
     """DECODE state; monitor `radio` and manage packet decoding."""
     r = self.radio
     assert isinstance(r, Radio), "[DOT11A]: Cannot find radio in DECODE!"
     assert self.isbusy, "[DOT11A]: Carrier sense *not* busy in DECODE!"
     while fsm.active():
         # monitor events and RXD port
         yield self.RXD.recv(fsm, 1, renege=(r.rxdata, r.rxdone, r.txdata, r.txdone, self.detect))
         # receive pkt -> apply error model and forward to upper layers
         if fsm.acquired(self.RXD):
             assert len(fsm.got) == 1, (
                 "[DOT11A]: Received unexpected " + "number of packets from 'RXD' port in DECODE state!"
             )
             p = fsm.got[0]
             if p is pkt:
                 payload = self.decode(p)
                 if payload:
                     self.log_recv(p)
                     self.cleananno(p)  # replace/remove unwanted annotations
                     p.remove_payload()
                     yield self.TXU.send(fsm, [payload])
                     yield hold, fsm, const.EPSILON  # pause before resuming
                 pkt = None
         # rxdone received before RXD -> interface dropped packet?
         if r.rxdone in fsm.eventsFired:
             p = r.rxdone.signalparam
             if p is pkt:
                 qlen = self.RXD.length
                 drop = ANNO.supports(p, "cif-drp") and p.getanno("cif-drp")
                 errmsg = "[DOT11A]: Unexpected rxdone received in DECODE!"
                 assert (qlen == 0) and drop, errmsg
                 self.log_drop(p, drop="interface dropped packet")
                 pkt = None
         # rxdata -> drop new packets
         if r.rxdata in fsm.eventsFired:
             p = r.rxdata.signalparam
             assert p is not pkt, "[DOT11A]: Unexpected rxdata for pkt in DECODE!"
             self.log_drop(p, drop="ignore rxdata in DECODE")
         # detect -> drop detected packets
         if self.detect in fsm.eventsFired:
             p = r.rxdata.signalparam
             assert p is not pkt, "[DOT11A]: Unexpected detect for pkt in DECODE!"
             self.log_drop(p, drop="ignore detect in DECODE", decode=pkt.traceid)
         # ignore otherwise
         ignore = r.txdata in fsm.eventsFired
         ignore = ignore or (r.txdone in fsm.eventsFired)
         if ignore:
             pass
         # check if DECODE is done
         if pkt is None:
             yield fsm.goto(self.LISTEN)
     return
Exemplo n.º 6
0
def _apply_fixed_delay(cm, *args, **kwargs):
    """Internal method to implement `FixedDelay` `ChannelModel` wrapper."""
    assert isinstance(cm, ChannelModel)
    assert hasattr(cm, '__subclass__')
    assert hasattr(cm, '__fixed_delay__')
    subclass = cm.__subclass__
    delay = cm.__fixed_delay__
    r = subclass.apply(cm, *args, **kwargs)
    if ANNO.supports(r, 'cm-delay'):
        r.delanno('cm-delay')
    if ANNO.supported(r) and (delay>0):
        r.setanno('cm-delay', delay)
    return r
Exemplo n.º 7
0
    def set_recvanno(self, p):
        """Overloaded to modify noisepower with noise figure.

        :return: Modified packet `p`.

        This method adds the `DOT11A_NOISEFIGURE` to the noisepower specified by
        `Radio`.
        """
        r = Radio.set_recvanno(self, p)
        if ANNO.supports(r, "noisepower"):
            noisepower = r.getanno("noisepower")
            noisepower += DOT11A_NOISEFIGURE
            r.setanno("noisepower", noisepower)
        return r
Exemplo n.º 8
0
def strcollision(p):
    """Get string representation of 'cif-collision' list from packet `p`."""
    coll = None
    if ANNO.supports(p, 'cif-collision'):
        coll = []
        for c in p.getanno('cif-collision'):
            try:
                s = c.traceid
                assert ANNO.supported(c), "s = %s, coll = %s"%(s, coll)
            except:
                s = c
                assert not ANNO.supported(c), "s = %s, coll = %s"%(s, coll)
            coll.append(s)
    return coll
Exemplo n.º 9
0
 def LISTEN(self, fsm, cif, rxport):
     """Listen to traffic sent by `ChannelInterface` on `rxport`."""
     assert (self.hasport(rxport) is not None), \
             "[CHANNEL]: Cannot listen on invalid Port!"
     # get data from rxport
     yield rxport.recv(fsm, 1)
     assert fsm.acquired(rxport) and (len(fsm.got)==1), \
             "[CHANNEL]: Error occurred during LISTEN on %s!"%(rxport)
     # forward on all outgoing edge
     p, u = fsm.got[0], cif
     neighbors = [str(c.traceid) for c in self.graph.neighbors(u) ]
     errmsg = "[CHANNEL]: Cannot forward non-Packet!"
     assert isinstance(p, Packet), errmsg
     for v in self.graph[u]:
         cmodel = self.graph[u][v]['model']
         errmsg = "[CHANNEL]: Cannot find corresponding TX Port!"
         assert (self.hasport((v, "TX") ) is not None)
         # if channel model for link is not active -> ignore packet
         if not cmodel.active: continue
         # filter packets using channel model
         drop = self.apply_filter(cmodel, p, u, v)
         if drop:
             self.log("drp",p,drop=drop,src=u.traceid,dst=v.traceid)
             continue            # continue with next link
         # copy and mark annotations
         c, txport = p.copy(), self.getport((v, "TX") )
         c.setanno('cif-src', u, ref=True)
         c.setanno('cif-dst', v, ref=True)
         # apply channel model
         propdelay = None
         r = self.apply_model(cmodel, c, u, v)
         if cmodel.verbose>CHANNEL_VERBOSE:
             cmodel.log_forward(c, src=u.traceid, dst=v.traceid)
         if ANNO.supports(r, 'cm-delay'):
             propdelay = r.getanno('cm-delay')
         # forward to destination
         if (r is None):
             self.log("drp",c,action="dropped by %s"%(cmodel.traceid) )
         elif (propdelay>0):
             # apply propagation delay
             f = FSM()
             f.goto(self.FORWARD, txport, [r])
             f.start(delay=propdelay)
         else:
             # send immediately (no delay)
             yield txport.send(fsm, [r])
     if self.verbose>CHANNEL_VERBOSE:
         self.log("fwd", p, dest="%s"%(neighbors) )
     # continue in LISTEN
     yield fsm.goto(self.LISTEN, cif, rxport)
Exemplo n.º 10
0
 def LISTEN(self, fsm):
     """LISTEN state; monitor `radio` and manage packet detection."""
     r = self.radio
     assert isinstance(r, Radio), "[DOT11A]: Cannot find radio in LISTEN!"
     while fsm.active():
         # check rxenergy -> set csbusy?
         rxenergy = r.rxenergy()
         rxhigh = r.inreceive and (r.rxenergy() > DOT11A_CSTHRESHOLD)
         if rxhigh:
             self.set_csbusy(rxenergy="high, %.2f dBm" % (rxenergy), rxbuffer=[x.traceid for x in r.rxbuffer])
         else:
             self.set_csidle(rxenergy="%.2f dBm" % (rxenergy))
         # monitor events and RXD port
         yield self.RXD.recv(fsm, 1, renege=(r.rxdata, r.rxdone, r.txdata, r.txdone, self.detect))
         # RXD -> ignore incoming packets in LISTEN
         if fsm.acquired(self.RXD):
             assert len(fsm.got) == 1, (
                 "[DOT11A]: Received unexpected " + "number of packets from 'RXD' port in LISTEN state!"
             )
             p = fsm.got[0]
             self.log_drop(p, drop="not detected in LISTEN")
         # rxdata -> start DETECT thread
         if r.rxdata in fsm.eventsFired:
             p = r.rxdata.signalparam
             fname = "detect(%s)" % (p._id)
             ### XXX ####
             f = FSM()
             # f = self.newchild(fname, FSM, tracename=fname.upper() )
             f.goto(self.DETECT, p)
             f.start()
         # detect -> set csbusy -> goto DECODE
         if self.detect in fsm.eventsFired:
             p = self.detect.signalparam
             rxenergy = "%.2f dBm" % (r.rxenergy())
             sinr = "%.2f dB" % (self.sinr(p))
             self.set_csbusy(p, detect=True, rxenergy=rxenergy)
             danno = "dot11a-detect"
             errmsg = "[DOT11A]: Cannot find 'dot11a-detect' " + "annotation in detected packet!"
             assert ANNO.supports(p, danno) and p.getanno(danno), errmsg
             # yield hold, fsm, 0
             self.log("detect", p, rxenergy=rxenergy, sinr=sinr, rxbuffer=[x.traceid for x in r.rxbuffer])
             yield fsm.goto(self.DECODE, p)
         # ignore otherwise
         ignore = r.txdata in fsm.eventsFired
         ignore = ignore or (r.txdone in fsm.eventsFired)
         ignore = ignore or (r.rxdone in fsm.eventsFired)
         if ignore:
             pass
     return
Exemplo n.º 11
0
    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
Exemplo n.º 12
0
    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
Exemplo n.º 13
0
    def decode_header(self, p, checkcrc=False):
        """Waveform-level decoding of header.

        :param p: Packet to decode.
        :param checkcrc: If true, check header CRC.

        Set `checkcrc` to false when using `decode_header()` to just do
        detection. By default, the PHY does detection & decoding in the same
        functions, so this method is allows for some slight variation in usage.
        """
        # check annotations
        assert isinstance(p, Dot11N)
        for a in ['cif-rxts', 'dot11n-rxadded']:
            errmsg = "[DOT11N]: Cannot find '%s' annotation!"%(a)
            assert ANNO.supports(p, a), errmsg
        errmsg = "[DOT11N]: Packet was not added to input!"
        assert p.hasanno('dot11n-rxadded'), errmsg
        # get rx input stream
        y = self.getrxinput(p)
        detect = self.receiver.decode_header(y, checkcrc)   # check header crc?
        prepad = int(self.MINPAD + DOT11N_TSHORT*DOT11N_BANDWIDTH)
        startidx = self.receiver.start_index() - prepad
        crcok = detect
        # check header parameters
        plen = len(p.payload)
        # get header parameters from receiver after decoding
        rate, length = self.receiver.mcs(), self.receiver.length()
        okrate = (0<=rate<len(DOT11N_DATARATE) )
        oklen  = (length == plen)
        okpar  = crcok
        # calculate start time
        tstart = p.getanno('cif-rxts')
        tstart  += startidx/DOT11N_BANDWIDTH
        p.setanno('dot11n-start-index', startidx)
        p.setanno('dot11n-cfo', self.receiver.get_cfo() )
        # return decoding parameters
        if detect: header = "detect success"
        else:      header = "detect failed"
        if checkcrc:
            if crcok: header = "success"
            else:     header = "decoding failed"
        param = {'status':header, 'detect':detect, 'crcok':crcok, \
                 'rate':rate, 'length':length, 'start':tstart}
        return param
Exemplo n.º 14
0
    def decode_data(self, p):
        """Waveform-level decoding of packet payload.

        :param p: Packet to decode.
        :return: Decoded data string.
        """
        # check annotations
        assert isinstance(p, Dot11N)
        for a in ['cif-rxts', 'dot11n-header', 'dot11n-detect', 'dot11n-rxadded']:
            errmsg = "[DOT11N]: Cannot find '%s' annotation!"%(a)
            assert ANNO.supports(p, a), errmsg
        errmsg = "[DOT11N]: Packet was not added to input!"
        assert p.hasanno('dot11n-rxadded'), errmsg
        errmsg = "[DOT11N]: Packet was not detected!"
        assert p.getanno('dot11n-detect'), errmsg
        header = p.getanno('dot11n-header')
        errmsg = "[DOT11N]: Header decoding failed before decode_data()!"
        assert (header=="success"), errmsg
        # get parameters to check startidx
        Ngi      = int(DOT11N_TGI*DOT11N_BANDWIDTH)
        prepad   = int(self.MINPAD + DOT11N_TSHORT*DOT11N_BANDWIDTH)
        startidx = self.receiver.start_index() - prepad
        ## startidx = -8     # overwrite startidx
        ## self.receiver.set_start_index(prepad+startidx)
        # decode payload -> check if startidx is valid
        y = self.getrxinput(p)
        data = self.receiver.decode_data(y)
        # check if decoding error occurred
        #  -> do contents of data match and does CRC pass?
        crcchk, error = "FAIL", True
        if (data == str(p.payload)):
            if not CRC32.haserror(data):
                crcchk = "OK"
                error = False
        # hamming distance between decoded data and packet p
        hdist = hamming_distance(data, str(p.payload) )
        self.log("CRC", p.payload, crcchk=crcchk, error=error, hdist=hdist)
        # clean up waveform annotations
        self.delrxwaveform(p)
        # return decoding parameters
        param = {'data':data, 'error':error, 'nerror':hdist}
        # return decoded data
        return param
Exemplo n.º 15
0
    def getrxinput(self, p):
        """Get input to receiver for specified packet.

        :param p: Packet to grab from input stream.

        Get the samples corresponding to the input for a given packet. This uses
        the timestamp annotation 'cif-rxts' and 'cif-duration' annotation to
        find the appropriate input samples from `rxinput`.
        """
        #self.stdout("%s: called getrxinput() on %s @ %.8f\n"%(self.traceid, p.traceid, now()))
        errmsg = "[DOT11N]: in getrxinput(), no input stream found!"
        assert (self.rxinput is not None), errmsg
        # check annotations
        for a in ['cif-rxts', 'cif-duration', 'dot11n-rxadded']:
            errmsg = "[DOT11N]: Cannot find '%s' annotation!"%(a)
            assert ANNO.supports(p, a), errmsg
        assert p.getanno('dot11n-rxadded')
        # calculate start/end of waveform
        tstart = p.getanno('cif-rxts')
        duration = p.getanno('cif-duration')
        tend = tstart + duration
        # pad returned waveform
        minpad = self.MINPAD
        tstart -= minpad/DOT11N_BANDWIDTH
        tend   += minpad/DOT11N_BANDWIDTH
        # extract from input stream
        rxts, w = self.rxinput
        rxend = rxts + w.cols()/DOT11N_BANDWIDTH
        errmsg = "[DOT11N]: in getrxinput(), packet starts before input " + \
                 "stream! tpacket, tbuffer = (%.6f, %.6f)"%(tstart, rxts)
        assert (tstart>=rxts), errmsg
        # calculare indices
        istart = int((tstart-rxts)*DOT11N_BANDWIDTH)
        istop  = int((tend-rxts)*DOT11N_BANDWIDTH)-1
        assert (istart>-1), "[DOT11N]: In getrxinput(), requested " + \
                "packet starting before start of input stream!"
        assert (istop<=w.cols()), "[DOT11N]: In getrxinput(), requested " + \
                "packet beyond end of input stream!"
        # get rxinput
        y = w.get_cols(istart, istop)
        return y
Exemplo n.º 16
0
    def duration(self, p, *args, **kwargs):
        """Convenience method to get duration of packet `p`.

        :return: Duration of packet `p` in seconds.

        By default, this method calls `PHY.duration()` on the physical layer
        associated with this `MAC` (i.e. `phy`). If `phy` is not a valid `PHY`,
        this method will attempt to find and return the 'cif-duration' annotation.

        Overload this method as needed.

        :note: If duration cannot be determined, this method may raise an
               exception.
        """
        if isinstance(self.phy, PHY):
            return self.phy.duration(p, *args, **kwargs)
        elif ANNO.supports(p, 'cif-duration'):
            return p.getanno('cif-duration')
        else:
            raise RuntimeError, "[MAC]: Could not determine duration! " + \
                    "No valid PHY and 'cif-duration' annotation not found!"
Exemplo n.º 17
0
    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
Exemplo n.º 18
0
    def sinr(self, p, **kwargs):
        """Calculate signal-to-interference-and-noise ratio (SINR).

        :param p: Packet to compute SINR for.
        :param kwargs: Additional keyword arguments passed to `sinr_heap()`.

        This method uses the 'rxpower', 'noisepower', and 'cif-collision'
        annotations to calculate the SINR of the received packet p.

        :note: This method sets the 'phy-sinr' annotation indicating the SINR (in dB).
        """
        for a in ["rxpower", "noisepower", "cif-collision"]:
            errmsg = "[DOT11APHY]: sinr() cannot find '%s' annotation!" % (a)
            assert ANNO.supports(p, a), errmsg
        # get SINR heap
        sinrheap = self.sinr_heap(p, **kwargs)
        minsinr = +inf
        # find minimum SINR
        for ta, tb, sinr in sinrheap:
            if sinr < minsinr:
                minsinr = sinr
        # set annotations
        p.setanno("phy-sinr", minsinr)
        return minsinr
Exemplo n.º 19
0
    def addrxinput(self, p, **kwargs):
        """Update local waveform with new packet.

        :param p: Packet to add to `rxinput`.
        :param kwargs: Keyword arguments passed to `calcrxwaveform()`.
        """
        # check if waveform has been calculated or already been added to input
        if p.hasanno('dot11n-rxadded'): return
        if not p.hasanno('dot11n-rxwaveform'): self.calcrxwaveform(p, **kwargs)
        # check other annotations
        for a in ['cif-rxts', 'dot11n-rxwaveform', 'noisepower']:
            errmsg = "[DOT11N_DSP]: cannot find '%s' annotation!"%(a)
            assert ANNO.supports(p,a), errmsg
        # get parameters
        y = p.getanno('dot11n-rxwaveform')
        npow = db2linear(p.getanno('noisepower'))
        nrx  = y.rows()
        yts  = p.getanno('cif-rxts')
        errmsg = "[DOT11N]: Cannot add waveform with %d "%(y.cols() ) + \
                 "(> %d) samples in addrxinput()!"%(self.MAXINPUT)
        assert (y.cols()<self.MAXINPUT), errmsg
        # apply pad to front and back of new input
        pad  = Waveform.zeros(nrx,2*self.MINPAD)
        y    = pad.concat_horizontal(y.concat_horizontal(pad) )
        yts -= pad.cols()/DOT11N_BANDWIDTH
        # initialize rxinput if it is not already set
        if self.rxinput is None:
            #self.log("rxadded", p)
            noise =  Waveform.randn(nrx, y.cols(), 0, npow)
            self.rxinput = (yts, y+noise)
            p.setanno('dot11n-rxadded', True)
            return p
        # update rxinput
        (rxts, w) = self.rxinput
        rxend = rxts + w.cols()/DOT11N_BANDWIDTH
        assert (y.rows() == nrx), "[DOT11N]: Invalid row size in addrxinput()!"
        assert (w.rows() == nrx), "[DOT11N]: Invalid row size in addrxinput()!"
        # get indices for begin/end of rxinput and new input
        rxa, rxb = 0, w.cols()-1
        ya = rxa + int((yts-rxts)*DOT11N_BANDWIDTH)
        yb = ya + y.cols() - 1
        istart, istop = min(rxa, ya), max(rxb, yb)
        errmsg = "[DOT11N]: Cannot use addrxinput() to add " + \
                "waveform that starts prior to current input stream!"
        assert (istart==rxa), errmsg
        # new waveform starts after current input ends -> reinitialize input
        if ya>rxb:
            self.rxinput = None
            return self.addrxinput(p)
        # add pads to y as needed
        if ya>istart:
            pad = Waveform.zeros(nrx, ya - istart)
            y = pad.concat_horizontal(y)
            self.log("-DSP.PAD.IN", p, npad=ya-istart)
        if yb<istop:
            pad = Waveform.zeros(nrx, istop - yb)
            y = y.concat_horizontal(pad)
            self.log("+DSP.PAD.IN", p, npad=istop-yb)
        # add pads to (end of) rxinput as needed
        if rxb<istop:
            noise = Waveform.randn(nrx, istop-rxb, 0, npow)
            w = w.concat_horizontal(noise)
            self.log("+DSP.PAD.RX", p, npad=istop-rxb)
        # combine waveforms
        errmsg = "[DOT11N]: Incompatible waveform dimensions, " + \
                 "y ~ %d x %d, "%(y.rows(),y.cols()) + \
                 "w ~ %d x %d, "%(w.rows(),w.cols()) + \
                 "y: [%d, %d], w: [%d, %d]"%(ya,yb,rxa,rxb)
        assert (y.cols() == w.cols() ), errmsg
        assert (y.rows() == w.rows() ), errmsg
        assert (y.cols()>0), errmsg
        assert (y.rows()>0), errmsg
        z = y + w
        # trim input if necessary
        if z.cols()> self.MAXINPUT:
            trimidx = z.cols() - self.MAXINPUT
            z = z.get_cols(trimidx, z.cols()-1)
            rxts += trimidx/DOT11N_BANDWIDTH
        self.rxinput = (rxts, z)
        p.setanno('dot11n-rxadded', True)
Exemplo n.º 20
0
    def interval_heap(self, p):
        """Create interval heap from collision list in packet `p`.

        :param p: Packet containing collision list in 'cif-collision' annotation.
        :return: Interval heap.

        This method uses the 'cif-rxts' and 'cif-duration' annotations of packet
        `p` and each packet in its collision list to create an interval heap. To
        do this, the method will create a list of partitions over the duration
        of packet `p` and sort colliding packets into the appropriate
        partitions. An interval heap looks like:

            [(t0,t1,[...]), (t1,t2,[...]), ...]

        This method sets the 'cif-iheap' annotation.
        """
        # get packet p parameters
        for a in ['cif-collision', 'cif-rxts']:
            errmsg = "[CHANNELIF]: interval_heap() requires '%s' annotation!"%(a)
            assert ANNO.supports(p, a), errmsg
        coll = p.getanno('cif-collision')
        duration = const.EPSILON
        if p.hasanno('cif-duration'): duration = p.getanno('cif-duration')
        ta = p.getanno('cif-rxts')
        tb = ta + duration
        # get times for all packets in collision list
        times = [ta, tb]
        for c in coll:
            errmsg = "[CHANNELIF]: interval_heap() requires 'cif-rxts' " + \
                     "annotation in collision list packet!"
            assert ANNO.supports(c, 'cif-rxts'), errmsg
            duration = const.EPSILON
            if c.hasanno('cif-duration'): duration = c.getanno('cif-duration')
            t0 = c.getanno('cif-rxts')  # start of packet c
            t1 = t0 + duration          # end of packet c
            # check if t0, t1 are in times
            t0intimes = any([(abs(t0-t)<2*const.EPSILON) for t in times])
            if (not t0intimes) and (ta<t0<tb): times.append(t0)
            t1intimes = any([(abs(t1-t)<2*const.EPSILON) for t in times])
            if (not t1intimes) and (ta<t1<tb): times.append(t1)
        # sort times and create interval heap
        times.sort()
        iheap = [(times[k], times[k+1], []) for k in range(len(times)-1) ]
        #print "%s: Interval heap for %s (%.8f, %.8f) @ %.8f"%(self.traceid, \
        #        p.traceid, ta,tb, now())
        for c in coll:
            errmsg = "[CHANNELIF]: interval_heap() requires 'cif-rxts' " + \
                     "annotation in collision list packet!"
            assert ANNO.supports(c, 'cif-rxts'), errmsg
            duration = const.EPSILON
            if c.hasanno('cif-duration'): duration = c.getanno('cif-duration')
            t0 = c.getanno('cif-rxts')  # start of packet c
            t1 = t0 + duration          # end of packet c
            # insert into interval heap
            #print "  + inserting %s, (%.8f, %.8f)"%(c.traceid,t0,t1)
            for k in range(len(iheap)):
                ia, ib = iheap[k][0], iheap[k][1]
                errmsg = "[CHANNELIF]: malformed interval in  " + \
                         "interval_heap()! (ia=%s, ib=%s)"%(ia, ib)
                assert (ia<ib), errmsg
                if (t0<ib) and (t1>ia):
                    iheap[k][2].append(Reference(c))
                    #print "    --> inserted  into (%.8f, %.8f)"%(ia,ib)
                else:
                    #print "    --> not added into (%.8f, %.8f)"%(ia,ib)
                    pass
        # set iheap annotation
        p.setanno('cif-iheap', iheap, priv=True)
        return iheap