Source code for pylayers.signal.waveform

# -*- coding:Utf-8 -*-
import doctest
import os
import logging
import pdb
import sys
import numpy as np
import scipy as sp
import scipy.io as io
import scipy.signal as si
import scipy.linalg as la
import matplotlib.pylab as plt
import pylayers.signal.bsignal as bs
from pylayers.measures import mesuwb

[docs]class Waveform(dict): """ Attributes ---------- st : time domain sf : frequency domain sfg : frequency domain integrated Methods ------- eval showpsd ip_generic fromfile fromfile2 read gui show """ def __init__(self,**kwargs): """ Parameters ---------- 'typ' : string 'generic', 'WGHz': float 0.499 'fcGHz': float 4.493 'fsGHz': float 100, 'threshdB': 3, 'twns': float 30 typ : 'generic','W1compensate','W1offset' """ defaults = {'typ':'generic', 'fGHz':[], 'WGHz': 0.499, 'fcGHz': 4.493, 'fsGHz': 100, 'threshdB': 3, 'twns': 30} for key, value in defaults.items(): if key not in kwargs: self[key] = value else: self[key] = kwargs[key] self.eval()
[docs] def eval(self): u""" evaluate waveform The :math:`\lambda/4*\pi` factor which is necessary to get the proper budget link ( from the Friis formula) is introduced in this function. """ if self['typ'] == 'generic': [st,sf]=self.ip_generic() #elif self['typ'] == 'mbofdm': # [st,sf]=self.mbofdm() elif self['typ'] == 'W1compensate': [st,sf]=self.fromfile() elif self['typ'] == 'W1offset': [st,sf]=self.fromfile2() elif self['typ'] == 'blackmann': sf = bs.FUsignal(x=fGHz,y=np.blackman(len(fGHz))) st = sf.ift() elif self['typ'] == 'rect': sf = bs.FUsignal(x=fGHz,y=np.ones(len(fGHz))) st = sf.ift() elif self['typ'] == 'hamming': sf = bs.FUsignal(x=fGHz,y=np.hamming(len(fGHz))) st = sf.ift() elif self['typ'] == 'ref156': [st,sf] = self.ref156() else: logging.critical('waveform typ not recognized, check your config \ file') self.st = st self.sf = sf self.fGHz = self.sf.x ygamma = -1j*0.3/(4*np.pi*self.fGHz) self.gamm = bs.FUsignal(x=self.fGHz,y=ygamma) self.sfg = self.sf*self.gamm self.sfgh = self.sfg.symH(0) self.stgh = self.sfgh.ifft(1)
[docs] def info(self): """ display information about waveform Results ------- >>> from pylayers.signal.waveform import * >>> w = Waveform(typ='generic',WGHz=0.499,fcGHz=4.49,fsGHz=100,threshdB=3,twns=30) >>> w.show() >>> plt.show() """ if self['typ']=='generic': for k in self.keys(): print(k , " : ",self[k]) else: print("typ:",self['typ'])
[docs] def showpsd(self,Tpns=1000): """ show psd Parameters ---------- Tpns : float """ plt.subplot(211) self.st.plot() plt.subplot(212) psd = self.st.psd(Tpns,50) plt.title('Tp = '+str(Tpns)+' ns') psd.plotdB(mask=True)
[docs] def ip_generic(self): """ Create an energy normalized Gaussian impulse (Usignal) ip_generic(self,parameters) """ Tw = self['twns'] fcGHz = self['fcGHz'] WGHz = self['WGHz'] thresh = self['threshdB'] fsGHz = self['fsGHz'] ts = 1.0/fsGHz self['ts'] = ts Np = fsGHz*Tw self['Np'] = Np #x = np.linspace(-0.5*Tw+ts/2,0.5*Tw+ts/2,Np,endpoint=False) #x = arange(-Tw,Tw,ts) w = bs.TUsignal() w.EnImpulse(fcGHz=fcGHz,WGHz=WGHz,threshdB=thresh,fsGHz=fsGHz) #W = w.ft() W = w.ft() return (w,W)
[docs] def ref156(self,beta=0.5): """ reference pulse of IEEE 802.15.6 UWB standard Parameters ---------- beta : float roll-off factor Tns = 1/499.2MHz Notes ----- From P8O2.15.6/D02 December 2010 Formula 96 p 215 """ Tw = self['twns'] fs = self['fsGHz'] Np = Tw*fs Ts = 1./fs beta = 0.5 Tns = 1./0.4992 x = np.linspace(-0.5*Tw+Ts/2, 0.5*Tw+Ts/2, Np, endpoint=False) z = x/Tns t1 = np.sin(np.pi*(1-beta)*z) t2 = np.cos(np.pi*(1+beta)*z) t3 = (np.pi*z)*(1-(4*beta*z)**2) y = (t1 + 4*beta*z*t2)/t3 st = bs.TUsignal() st.x = x st.y = y[None,:] sf = st.ftshift() return(st,sf)
[docs] def fromfile(self): """ get the measurement waveform from WHERE1 measurement campaign This function is not yet generic >>> from pylayers.signal.waveform import * >>> wav = Waveform(typ='W1compensate') >>> wav.show() """ M = mesuwb.UWBMeasure(1,h=1) w = bs.TUsignal() ts = M.RAW_DATA.timetx[0] tns = ts*1e9 ts = tns[1]-tns[0] y = M.RAW_DATA.tx[0] # find peak position u is the index of the peak # yap :after peak # ybp : before peak # yzp : zero padding maxy = max(y) u = np.where(y ==maxy)[0][0] yap = y[u:] ybp = y[0:u] yzp = np.zeros(len(yap)-len(ybp)-1) tnsp = np.arange(0, tns[-1]-tns[u]+0.5*ts, ts) tnsm = np.arange(-(tns[-1]-tns[u]), 0, ts) y = np.hstack((yzp, np.hstack((ybp, yap)))) tns = np.hstack((tnsm, tnsp)) # # Warning (check if 1/sqrt(30) is not applied elsewhere # w.x = tns w.y = y[None,:]*(1/np.sqrt(30)) # w : TUsignal # W : FUsignal (Hermitian redundancy removed) W = w.ftshift() return (w,W)
[docs] def fromfile2(self): """ get the measurement waveform from WHERE1 measurement campaign This function is not yet generic >>> from pylayers.signal.waveform import * >>> wav = Waveform(typ='W1offset') >>> wav.show() """ M = mesuwb.UWBMeasure(1,1) w = bs.TUsignal() ts = M.RAW_DATA.timetx[0] tns = ts*1e9 Ts = tns[1]-tns[0] y = M.RAW_DATA.tx[0] # find peak position u is the index of the peak # yap :after peak # ybp : before peak # yzp : zero padding # maxy = max(y) # u = np.where(y ==maxy)[0][0] # yap = y[u:] # ybp = y[0:u] yzp = np.zeros(len(y)-1) # tnsp = np.arange(0,tns[-1]-tns[u]+0.5*ts,ts) # tnsm = np.arange(-(tns[-1]-tns[u]),0,ts) N = len(ts)-1 tnsm = np.linspace(-tns[-1],-Ts,N) y = np.hstack((yzp,y)) tns = np.hstack((tnsm,tns)) # # Warning (check if 1/sqrt(30) is not applied elsewhere # w.x = tns w.y = (y*(1/np.sqrt(30)))[None,:] # w : TUsignal # W : FUsignal (Hermitian redundancy removed) W = w.ftshift() return (w,W)
[docs] def read(self,config): """ Parameters ---------- config : ConfigParser object Returns ------- w : waveform """ par = config.items("waveform") for k in range(len(par)): key = par[k][0] val = par[k][1] if key == "WGHz": self[key] = float(val) if key == "fcGHz": self[key] = float(val) if key == "feGHz": self[key] = float(val) if key == "threshdB": self[key] = float(val) if key == "twns": self[key] = float(val) if key == "typ": self[key] = val self.eval()
[docs] def bandwidth(self,th_ratio=10000,Npt=100): """ Determine effective bandwidth of the waveform. Parameters ---------- th_ratio : float threshold ratio threshold = max(abs())/th_ratio Npt : Number of points """ u=np.where(np.abs(self.sf.y)>np.max(np.abs(self.sf.y))/th_ratio) #fGHz = self.sf.x[u[1]] fGHz_start = self.sf.x[u[1]][0] fGHz_stop = self.sf.x[u[1]][-1] fGHz = np.linspace(fGHz_start,fGHz_stop,Npt) return fGHz
[docs] def gui(self): """ Get the Waveform parameter """ if self['typ'] == 'generic': self.st.plot() show() wavegui = multenterbox('','Waveform Parameter', ('Tw (ns) integer value', 'fc (GHz)', 'W (GHz)', 'thresh (dB)', 'fs (GHz) integer value'), ( self['twns'] , self['fcGHz'] , self['WGHz'] , self['threshdB'], self['feGHz'] )) self.parameters['Twns'] = eval(wavegui[0]) self.parameters['fcGHz'] = eval(wavegui[1]) self.parameters['WGHz'] = eval(wavegui[2]) self.parameters['threshdB'] = eval(wavegui[3]) self.parameters['fsGHz'] = eval(wavegui[4]) [st,sf] = self.ip_generic() self.st = st self.sf = sf st.plot() show()
[docs] def show(self,fig=[]): """ show waveform in time and frequency domain Parameters ---------- fig : figure """ # title construction if fig ==[]: fig = plt.figure() title ='' for pk in self.keys(): val = self[pk] title = title + pk + ': ' if type(val) != 'str': title = title + str(val) + ' ' #plt.title(title) ax1 = fig.add_subplot(2,1,1) ax1.plot(self.st.x,self.st.y[0,:]) plt.xlabel('time (ns)') plt.ylabel('level in linear scale') ax2 = fig.add_subplot(2,1,2) ax2.plot(self.sf.x,abs(self.sf.y[0,:])) plt.xlabel('frequency (GHz)') plt.ylabel('level in linear scale') fig.suptitle(title)
if __name__ == "__main__": plt.ion() doctest.testmod()