コード例 #1
0
ファイル: dot11n_dsp.py プロジェクト: reidlindsay/wins
    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
コード例 #2
0
ファイル: interface.py プロジェクト: reidlindsay/wins
    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
コード例 #3
0
ファイル: mqam.py プロジェクト: reidlindsay/wins
    def calcber(cls, snr, mtype=None, nbps=None, order=None):
        """Calculate bit-error rate (BER) corresponding to the signal-to-noise
        ratio (SNR) provided in an AWGN channel.

        :param snr: Signal-to-noise ratio (in dB).
        :param mtype: Modulation type enumeration (see `mtype`).
        :param nbps: Number of bits per symbol (see `nbps`).
        :param order: Modulation order (see `order`).
        :return: Bit-error rate (BER) in [0,1].

        By default, this class uses BPSK modulation. Use any of the optional
        parameters `mtype`, `nbps`, or `order` to specify a different modulation
        type. The bit-error rate (BER) calculated in this method assumes an
        additive white gaussian noise (AWGN) channel. See `M-QAM Performance`_
        for more on this calculation.

        :note: If `snr` is a `numpy` array, this method will return an array of
               values corresponding to the specified parameters.

        .. _`M-QAM Performance`: http://en.wikipedia.org/wiki/Quadrature_amplitude_modulation#Quantized_QAM_performance
        """
        snrdb = snr
        # determine modulation type
        if (order is not None): nbps = log2(order)
        if (mtype is not None):
            assert (mtype.upper() in cls.Nbps.keys() ), \
                    "[MQAM]: Modulation type (%s) is not supported!"%(mtype)
            mtype = mtype.upper()
            nbps  = cls.Nbps[mtype]
        elif (nbps is not None):
            mtype = cls.nbps2mtype(nbps)
        else:
            mtype, nbps = "BPSK", 1
        assert (mtype in cls.Nbps) and (nbps==cls.Nbps[mtype]), \
               "[MQAM]: Unsupported modultation (%s, nbps=%s)!"(mtype,nbps)
        # calculate BER
        snr = db2linear(snrdb)
        M = 2**nbps
        if (M == 2):
            x = sqrt(2.0*snr)
            ser = 0.5*erfc(x/sqrt(2) )
            ber = ser
        else:
            x = sqrt(3.0*snr/(M-1))
            ter = 2.0*(1 - sqrt(1.0/M))*0.5*erfc(x/sqrt(2) )
            ser = 1 - (1-ter)**2.0
            ber = ser/log2(M)
        return ber
コード例 #4
0
ファイル: radio.py プロジェクト: reidlindsay/wins
    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
コード例 #5
0
ファイル: dot11a.py プロジェクト: reidlindsay/wins
    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
コード例 #6
0
ファイル: dot11a.py プロジェクト: reidlindsay/wins
    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
コード例 #7
0
ファイル: dot11n_dsp.py プロジェクト: reidlindsay/wins
    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)