class DLink(Link): def __init__(self, **kwargs): """ deterministic link evaluation Parameters ---------- L : Layout Layout to be used a : np.ndarray (3,) position of a device dev_a b : np.ndarray (3,) position of a device dev_b Aa : Antenna Antenna of device dev_a Ab : Antenna Antenna of device dev_b Ta : np.ndarray (3,3) Rotation matrice of Antenna of device dev_a relative to global Layout scene Tb : np.ndarray (3,3) Rotation matrice of Antenna of device dev_b relative to global Layout scene fGHz : np.ndarray (Nptf,) frequency range of Nptf points used for evaluation of channel wav : Waveform Waveform to be applied on the channel save_idx : int number to identify the h5 file generated Advanced (change only if you really know what you do !) save_opt : list (['sig','ray','Ct','H']) information to be saved in the Links h5 file. Should never be Modified ! force_create : Boolean (False) forcecreating the h5py file (if already exist, will be erased) Notes ----- All simulations are stored into a unique file in your <PyProject>/output directory using the following convention: Links_<save_idx>_<LayoutFilename>.h5 where <save_idx> is an integer number to distinguish different links simulations and <LayoutFilename> is the Layout used for the link simulation. Dataset organisation: Links_<idx>_<Layout_name>.h5 | |/sig/si_ID#0/ | /si_ID#1/ | ... | |/ray/ray_ID#0/ | /ray_ID#1/ | ... | |/Ct/Ct_ID#0/ | /Ct_ID#1/ | ... | |/H/H_ID#0/ | /H_ID#1/ | ... | | |p_map |c_map |f_map |A_map |T_map Roots Dataset : c_map : Cycles (Nc x 3) p_map : Positions (Np x 3) f_map : Frequency (Nf x 3) T_map : Rotation matrices (Nt x 3) A_map : Antenna name (Na x 3) Groups and subgroups: Signature identifier (si_ID#N): ca_cb_cutoff Ray identifier (ray_ID#N): cutoff_ua_ub Ctilde identifier (Ct_ID#N): ua_ub_uf H identifier (H_ID#N): ua_ub_uf_uTa_uTb_uAa_uAb with ca : cycle number of a cb : cycle number of b cutoff : signature.run cutoff ua : indice of a position in 'p_map' position dataset ub : indice of a position in 'p_map' position dataset uf : indice of freq position in 'f_map' frequency dataset uTa : indice of a position in 'T_map' Rotation dataset uTb : indice of b position in 'T_map' Rotation dataset uAa : indice of a position in 'A_map' Antenna name dataset uAb : indice of b position in 'A_map' Antenna name dataset Examples -------- >>> from pylayers.simul.link import * >>> L = DLink(verbose=False) >>> aktk = L.eval() """ super(DLink,self).__init__() defaults={ 'L':Layout(), 'a':np.array(()), 'b':np.array(()), 'Aa':Antenna(), 'Ab':Antenna(), 'Ta':np.eye(3), 'Tb':np.eye(3), 'fGHz':np.linspace(2, 11, 181, endpoint=True), 'wav':wvf.Waveform(), 'cutoff':3, 'save_opt':['sig','ray','Ct','H'], 'save_idx':0, 'force_create':False, 'verbose':True } self._ca=-1 self._cb=-1 specset = ['a','b','Aa','Ab','Ta','Tb','L','fGHz','wav'] for key, value in defaults.items(): if key not in kwargs: if key in specset : setattr(self,'_'+key,value) else : setattr(self,key,value) else : if key in specset : setattr(self,'_'+key,kwargs[key]) else : setattr(self,key,kwargs[key]) force=self.force_create delattr(self,'force_create') self._Lname = self._L.filename ########### # init ant ########### self.tx = RadioNode(name = '', typ = 'tx', _fileini = 'radiotx.ini', _fileant = self.Aa._filename ) self.rx = RadioNode(name = '', typ = 'rx', _fileini = 'radiorx.ini', _fileant = self.Ab._filename, ) self.filename = 'Links_' + str(self.save_idx) + '_' + self._Lname + '.h5' filenameh5 = pyu.getlong(self.filename,pstruc['DIRLNK']) # check if save file alreasdy exists if not os.path.exists(filenameh5) or force: print 'Links save file for ' + self.L.filename + ' does not exist.' print 'Creating file. You\'ll see this message only once per Layout' self.save_init(filenameh5) # dictionnary data exists self.dexist={'sig':{'exist':False,'grpname':''}, 'ray':{'exist':False,'grpname':''}, 'Ct':{'exist':False,'grpname':''}, 'H':{'exist':False,'grpname':''} } try: self.L.dumpr() except: print('This is the first time the Layout is used. Graphs have to be built. Please Wait') self.L.build() self.L.dumpw() #self.L.build() ########### # init pos & cycles # # If a and b are not specified # they are chosen as center of gravity of cycle 0 # ########### if len(self.a)==0: self.ca = 1 # self.a = self.L.cy2pt(self.ca) else: if len(kwargs['a']) ==2: a=np.r_[kwargs['a'],1.0] else: a=kwargs['a'] self.a = a # self.ca = self.L.pt2cy(self.a) if len(self.b)==0: if len(self.L.Gt.node)>2: self.cb = 2 else: self.cb = 1 # self.b = self.L.cy2pt(self.cb) else: if len(kwargs['b']) ==2: b=np.r_[kwargs['b'],1.0] else: b=kwargs['b'] self.b = b # self.cb = self.L.pt2cy(self.b) ########### # init freq ########### self.fmin = self.fGHz[0] self.fmax = self.fGHz[-1] self.fstep = self.fGHz[1]-self.fGHz[0] self.Si = Signatures(self.L,self.ca,self.cb,cutoff=self.cutoff) self.R = Rays(self.a,self.b) self.C = Ctilde() self.H = Tchannel() @property def Lname(self): return self._Lname @property def L(self): return self._L @property def a(self): return self._a @property def b(self): return self._b @property def ca(self): return self._ca @property def cb(self): return self._cb @property def Aa(self): return self._Aa @property def Ab(self): return self._Ab @property def Ta(self): return self._Ta @property def Tb(self): return self._Tb @property def fGHz(self): return self._fGHz @property def wav(self): return self._wav @L.setter def L(self,L): # change layout and build/load self._L = L self.reset_config() @Lname.setter def Lname(self,Lname): # change layout and build/load self._L = Layout(Lname) self._Lname = Lname self.reset_config() @a.setter def a(self,position): if not self.L.ptin(position): raise NameError ('Warning : point a is not inside the Layout') # raise NameError ('Warning : point a is not inside the Layout') if not self.L.pt2cy(position) == self.ca: self.ca = self.L.pt2cy(position) self._a = position self.tx.position = position @b.setter def b(self,position): if not self.L.ptin(position): raise NameError ('Warning : point b is not inside the Layout') if not self.L.pt2cy(position) == self.cb: self.cb = self.L.pt2cy(position) self._b = position self.rx.position = position @ca.setter def ca(self,cycle): if not cycle in self.L.Gt.nodes(): raise NameError ('cycle ca is not inside Gt') self._ca = cycle self.a = self.L.cy2pt(cycle) @cb.setter def cb(self,cycle): if not cycle in self.L.Gt.nodes(): raise NameError ('cycle cb is not inside Gt') self._cb = cycle self.b = self.L.cy2pt(cycle) @Aa.setter def Aa(self,Ant): position = self.a rot = self.Ta self.tx = RadioNode(name = '', typ = 'tx', _fileini = 'radiotx.ini', _fileant = Ant._filename ) self._Aa = Ant # to be removed when radionode will be updated self.a = position self.Ta = rot @Ab.setter def Ab(self,Ant): position = self.b rot = self.Tb self.rx = RadioNode(name = '', typ = 'rx', _fileini = 'radiorx.ini', _fileant = Ant._filename, ) self._Ab = Ant # to be removed when radionode will be updated self.b = position self.Tb = rot @Ta.setter def Ta(self,orientation): self._Ta = orientation self.tx.orientation = orientation @Tb.setter def Tb(self,orientation): self._Tb = orientation self.rx.orientation = orientation @fGHz.setter def fGHz(self,freq): if not isinstance(freq,np.ndarray): freq=np.array([freq]) self._fGHz = freq if len(freq)>1: self.fmin = freq[0] self.fmax = freq[-1] self.fstep = freq[1]-freq[0] else: self.fmin = freq self.fmax = freq self.step = 0 @wav.setter def wav(self,waveform): self._wav = waveform if 'H' in dir(self): self.chanreal = self.H.applywavB(self.wav.sfg) def __repr__(self): """ __repr__ """ s = 'filename: ' + self.filename +'\n' s = s + 'Link Parameters :\n' s = s + '------- --------\n' s = s + 'Layout : ' + self.Lname + '\n\n' s = s + 'Node a \n' s = s + '------ \n' s = s + 'position : ' + str (self.a) + '\n' s = s + 'Antenna : ' + str (self.Aa._filename) + '\n' s = s + 'Rotation matrice : \n ' + str (self.Ta) + '\n\n' s = s + 'Node b \n' s = s + '------ \n' s = s + 'position : ' + str (self.b) + '\n' s = s + 'Antenna : ' + str (self.Ab._filename) + '\n' s = s + 'Rotation matrice : \n ' + str (self.Tb) + '\n\n' s = s + 'Link evaluation information : \n' s = s + '----------------------------- \n' s = s + 'distance : ' + str("%6.3f" % np.sqrt(np.sum((self.a-self.b)**2))) + ' m \n' s = s + 'delay : ' + str("%6.3f" % (np.sqrt(np.sum((self.a-self.b)**2))/0.3)) + ' ns\n' #s = s + 'Frequency range : \n' s = s + 'fmin (fGHz) : ' + str(self.fGHz[0]) +'\n' s = s + 'fmax (fGHz) : ' + str(self.fGHz[-1]) +'\n' s = s + 'fstep (fGHz) : ' + str(self.fGHz[1]-self.fGHz[0]) +'\n' s = s + 'Nf : ' + str(len(self.fGHz)) +'\n ' d = np.sqrt(np.sum((self.a-self.b)**2)) fc = (self.fGHz[-1]+self.fGHz[0])/2. L = 32.4+20*np.log(d)+20*np.log10(fcGHz) return s def help(self,letter='az',mod='meth'): """ help Parameters ---------- txt : string 'members' | 'methods' """ members = self.__dict__.keys() lmeth = np.sort(dir(self)) if mod=='memb': print np.sort(self.__dict__.keys()) if mod=='meth': for s in lmeth: if s not in members: if s[0]!='_': if len(letter)>1: if (s[0]>=letter[0])&(s[0]<letter[1]): try: doc = eval('self.'+s+'.__doc__').split('\n') print s+': '+ doc[0] except: pass else: if (s[0]==letter[0]): try: doc = eval('self.'+s+'.__doc__').split('\n') print s+': '+ doc[0] except: pass def reset_config(self): """ reset configuration when a new layout is loaded """ try: self.L.dumpr() except: self.L.build() self.L.dumpw() self.ca = 1 self.cb = 1 # self.a = self.L.cy2pt(self.ca) # self.b = self.L.cy2pt(self.cb) # change h5py file if layout changed self.filename = 'Links_' + str(self.save_idx) + '_' + self._Lname + '.h5' filenameh5 = pyu.getlong(self.filename,pstruc['DIRLNK']) if not os.path.exists(filenameh5) : print 'Links save file for ' + self.L.filename + ' does not exist.' print 'It is beeing created. You\'ll see that message only once per Layout' self.save_init(filenameh5) try: delattr(self,'Si') except: pass try: delattr(self,'R') except: pass try: delattr(self,'C') except: pass try: delattr(self,'H') except: pass def checkh5(self): """ check existence of previous simulation run with the same parameters. Returns ------- update self.dexist dictionnary """ # get identifier groupname in h5py file self.get_grpname() # check if grpnamee exist in the h5py file [self.fill_dexist(k,self.dexist[k]['grpname']) for k in self.save_opt] def save_init(self,filename_long): """ initialize save Link Parameters ---------- filename_long : str complete path and filename """ f=h5py.File(filename_long,'w') # try/except to avoid loosing the h5 file if # read/write error try: f.create_group('sig') f.create_group('ray') f.create_group('Ct') f.create_group('H') # mapping point a f.create_dataset('p_map',shape=(0,3), maxshape=(None,3),dtype='float64') # mapping cycles f.create_dataset('c_map',shape=(0,3), maxshape=(None,3),dtype='int') # mapping (fmin,fmax,fstep) f.create_dataset('f_map',shape=(0,3), maxshape=(None,3),dtype='float64') # mapping Antenna name f.create_dataset('A_map',shape=(0,1), maxshape=(None,1),dtype="S10") # mapping rotation matrices Antenna f.create_dataset('T_map',shape=(0,3,3), maxshape=(None,3,3),dtype='float64') f.close() except: f.close() raise NameError('Links: issue when initializing h5py file') def stack(self,key,array): """ stack new array in h5py file for a given key (dataframe/group) Parameters ---------- key : string array : np.ndarray Returns ------- idx : int indice of last element of the array of key """ try : lfilename=pyu.getlong(self.filename,pstruc['DIRLNK']) f=h5py.File(lfilename,'a') if key != 'T_map': sc = f[key].shape f[key].resize((sc[0]+1,sc[1])) f[key][-1,:]=array else: sc = f[key].shape f[key].resize((sc[0]+1,sc[1],sc[2])) f[key][-1,:,:]=array f.close() return np.array([sc[0]]) except: f.close() raise NameError('Link stack: issue during stacking') def _delete(self,key,grpname): """ Delete a key and associated data into h5py file Parameters ---------- key : string key of the h5py file grpname : string groupe name of the h5py file """ lfilename=pyu.getlong(self.filename,pstruc['DIRLNK']) f=h5py.File(lfilename,'a') # try/except to avoid loosing the h5 file if # read/write error try: del f[key][grpname] # print 'delete ',key , ' in ', grpname f.close() except: f.close() raise NameError('Link._delete: issue when deleting in h5py file') def save(self,obj,key,grpname,force=False): """ Save a given object in the correct group Parameters ---------- obj : Object (Signatures|Rays|Ctilde|Tchannel) key : string key of the h5py file gpname : string groupe name of the h5py file """ if not force : obj._saveh5(self.filename,grpname) # if save is forced, previous existing data are removed and # replaced by new ones. else : if self.dexist[key]['exist']: self._delete(key,grpname) obj._saveh5(self.filename,grpname) if self.verbose : print str(obj.__class__).split('.')[-1] + ' from '+ grpname + ' saved' def load(self,obj,grpname): """ Load a given object in the correct grp Parameters ---------- obj : Object (Signatures|Rays|Ctilde|Tchannel) grpname : string groupe name of the h5py file Examples -------- """ obj._loadh5(self.filename,grpname) if self.verbose : print str(obj.__class__).split('.')[-1] + ' from '+ grpname + ' loaded' def get_grpname(self): """ Determine the data group name for the given configuration Notes ----- Update the key grpname of self.dexist[key] dictionnary, where key = 'sig'|'ray'|'Ct'|'H' """ ############ # Signatures ############ array = np.array(([self.ca,self.cb,self.cutoff])) ua_opt, ua = self.get_idx('c_map',array) grpname = str(self.ca) + '_' +str(self.cb) + '_' + str(self.cutoff) self.dexist['sig']['grpname']=grpname ############ # Rays ############# # check existence of self.a in h5py file ua_opt, ua = self.get_idx('p_map',self.a) # check existence of self.b in h5py file ub_opt, ub = self.get_idx('p_map',self.b) # Write in h5py if no prior a-b link grpname = str(self.cutoff) + '_' + str(ua) + '_' +str(ub) self.dexist['ray']['grpname']=grpname ############ # Ctilde ############# # check existence of frequency in h5py file farray = np.array(([self.fmin,self.fmax,self.fstep])) uf_opt, uf = self.get_idx('f_map',farray) grpname = str(ua) + '_' + str(ub) + '_' + str(uf) self.dexist['Ct']['grpname'] = grpname ############ # H ############# # check existence of Rot a (Ta) in h5py file uTa_opt, uTa = self.get_idx('T_map',self.Ta) # check existence of Rot b (Tb) in h5py file uTb_opt, uTb = self.get_idx('T_map',self.Tb) # check existence of Antenna a (Aa) in h5py file uAa_opt, uAa = self.get_idx('A_map',self.Aa._filename) # check existence of Antenna b (Ab) in h5py file uAb_opt, uAb = self.get_idx('A_map',self.Ab._filename) grpname = str(ua) + '_' + str(ub) + '_' + str(uf) + \ '_' + str(uTa) + '_' + str(uTb) + \ '_' + str(uAa) + '_' + str(uAb) self.dexist['H']['grpname']=grpname def fill_dexist(self,key,grpname): """Check if the key's data with a given groupname already exists in the h5py file Parameters ---------- key: string key of the h5py group grpname : string groupe name of the h5py file Notes ----- update the key grpname of self.dexist[key] dictionnary """ try : lfilename=pyu.getlong(self.filename,pstruc['DIRLNK']) f=h5py.File(lfilename,'r') if grpname.decode('utf8') in f[key].keys(): self.dexist[key]['exist']=True else : self.dexist[key]['exist']=False f.close() except: f.close() raise NameError('Link exist: issue during stacking') def get_idx(self,key,array,tol=1e-3): """ try to get the index of the requested array in the group key of the hdf5 file. If array doesn't exist, the hdf5file[key] array is stacked Parameters ---------- key: string key of the h5py group array : np.ndarray array type to check existency tol : np.float64 tolerance (in meter for key == 'p_map') Returns ------- (u_opt, u): tuple u : np.ndarray the index in the array of the file[key] group u_opt : string ('r'|'s') return 'r' if array has been read into h5py file return 's' if array has been stacked into the array of group key See Also: -------- Links.array_exist """ umap = self.array_exist(key,array,tol=tol) lu = len(umap) # if exists take the existing one # otherwise value is created if lu != 0: u = umap u_opt='r' else : u = self.stack(key,array) u_opt='s' return u_opt,u[0] def array_exist(self,key,array,tol=1e-3) : """ check if an array of a given key (h5py group) has already been stored into the h5py file Parameters ---------- key: string key of the h5py group array : np.ndarray array type to check existency tol : np.float64 tolerance (in meter for key == 'p_map') Returns ------- (ua) ua : np.ndarray the indice in the array of the file[key] group if the array is emtpy, value doesn't exist TODO ---- Add a tolerance on the rotation angle (T_map) """ lfilename=pyu.getlong(self.filename,pstruc['DIRLNK']) try : f=h5py.File(lfilename,'a') fa = f[key][...] f.close() except: f.close() raise NameError('Link check_exist: issue during reading') if key == 'c_map': eq = array == fa # sum eq = 3 means cy0,cy1 and cutoff are the same in fa and array ua = np.where(np.sum(eq,axis=1)==3)[0] elif key == 'p_map': da = np.sqrt(np.sum((array-fa)**2,axis=1)) # indice points candidate in db for a ua = np.where(da<tol)[0] elif key == 'f_map': # fmin_h5 < fmin_rqst ufmi = np.where(fa[:,0]<=array[0])[0] lufmi = len(ufmi) # fmax_h5 > fmax_rqst ufma = np.where(fa[:,1]>=array[1])[0] lufma = len(ufma) # fstep_h5 < fstep_rqst ufst = np.where(fa[:,2]<=array[2])[0] lufst = len(ufst) # if fmin, fmax or fstep if (lufmi==0) and (lufma==0) and (lufst==0): ua = np.array([]) else : # find comon lines of fmin and fmax ufmima = np.where(np.in1d(ufmi,ufma))[0] # find comon lines of fmin, fmax and fstep ua = np.where(np.in1d(ufmima,ufst))[0] elif key == 'A_map': ua = np.where(fa==array)[0] elif key == 'T_map': eq = array == fa seq = np.sum(np.sum(eq,axis=1),axis=1) ua = np.where(seq==9)[0] else : raise NameError('Link.array_exist : invalid key') return ua def eval(self,**kwargs): """ Evaluate the link Parameters ---------- applywav :boolean Apply waveform to H force : list Force the computation (['sig','ray','Ct','H']) AND save (replace previous computations) si_algo : str ('old'|'new') signature.run algo type 'old' : call propaths2 'new' : call procone2 alg : 5 | 7 version of run for signature si_mt: boolean Multi thread version of algo version 7 si_progress: bollean ( False) display progression bar for signatures diffraction : boolean (False) takes into consideration diffraction points ra_number_mirror_cf : int rays.to3D number of ceil/floor reflexions ra_ceil_height_meter: float, ceil height ra_vectorized: boolean (True) if True used the (2015 new) vectorized approach to determine 2drays Returns ------- ak : ndarray alpha_k tk : ndarray tau_k Notes ----- update self.ak and self.tk self.ak : ndarray alpha_k self.tk : ndarray tau_k Examples -------- .. plot:: :include-source: >>> from pylayers.simul.link import * >>> L=DLink(verbose=False) >>> aktk = L.eval() See Also -------- pylayers.antprop.signature pylayers.antprop.rays Experimental ------------ alg = 2015 | 20152 (best) vectorized signature research si_reverb : number of reverb in source/target cycle if alg=2015 """ defaults={ 'applywav':True, 'si_algo':'old', 'si_mt':False, 'si_progress':False, 'diffraction':False, 'ra_vectorized':False, 'ra_ceil_height_meter':3, 'ra_number_mirror_cf':1, 'force':[], 'alg':7, 'si_reverb':4, 'threshold':0.1, } for key, value in defaults.items(): if key not in kwargs: kwargs[key]=value if 'cutoff' not in kwargs: kwargs['cutoff']=self.cutoff else: self.cutoff=kwargs['cutoff'] if 'force' in kwargs: if not isinstance(kwargs['force'],list): if kwargs['force'] == True : kwargs['force'] = ['sig','ray','Ct','H'] else : kwargs['force'] = [] # must be placed after all the init !!!! self.checkh5() ############ # Signatures ############ Si = Signatures(self.L,self.ca,self.cb,cutoff=kwargs['cutoff']) if (self.dexist['sig']['exist'] and not ('sig' in kwargs['force'])): self.load(Si,self.dexist['sig']['grpname']) else : if kwargs['alg']==2015: TMP=Si.run2015(cutoff=kwargs['cutoff'], cutoffbound=kwargs['si_reverb']) if kwargs['alg']==20152: TMP=Si.run2015_2(cutoff=kwargs['cutoff'], cutoffbound=kwargs['si_reverb']) if kwargs['alg']==5: Si.run5(cutoff=kwargs['cutoff'], algo=kwargs['si_algo'], diffraction=kwargs['diffraction'], progress=kwargs['si_progress']) if kwargs['alg']==7: if kwargs['si_mt']==7: Si.run7mt(cutoff=kwargs['cutoff'], algo=kwargs['si_algo'], diffraction=kwargs['diffraction'], threshold=kwargs['threshold'], progress=kwargs['si_progress']) else : Si.run7(cutoff=kwargs['cutoff'], algo=kwargs['si_algo'], diffraction=kwargs['diffraction'], threshold=kwargs['threshold'], progress=kwargs['si_progress']) #Si.run6(diffraction=kwargs['diffraction']) # save sig self.save(Si,'sig',self.dexist['sig']['grpname'],force = kwargs['force']) self.Si = Si ############ # Rays ############ R = Rays(self.a,self.b) if self.dexist['ray']['exist'] and not ('ray' in kwargs['force']): self.load(R,self.dexist['ray']['grpname']) else : # perform computation ... # ... with vetorized ray evaluation approach if kwargs['ra_vectorized']: r2d = Si.raysv(self.a,self.b) # ... or with original and slow approach ( to be removed in a near future) else : r2d = Si.rays(self.a,self.b) R = r2d.to3D(self.L,H=self.L.maxheight, N=kwargs['ra_number_mirror_cf']) R.locbas(self.L) # ...and save self.save(R,'ray',self.dexist['ray']['grpname'],force = kwargs['force']) self.R = R if self.R.nray == 0: raise NameError('No rays have been found. Try to re-run the simulation with a higher S.cutoff ') ############ # Ctilde ############ C=Ctilde() if self.dexist['Ct']['exist'] and not ('Ct' in kwargs['force']): self.load(C,self.dexist['Ct']['grpname']) else : R.fillinter(self.L) # Ctilde... C = R.eval(self.fGHz) # ...save Ct self.save(C,'Ct',self.dexist['Ct']['grpname'],force = kwargs['force']) self.C = C ############ # H ############ H = Tchannel() if self.dexist['H']['exist'] and not ('H' in kwargs['force']): self.load(H,self.dexist['H']['grpname']) else : # Ctilde antenna Cl=C.locbas(Tt=self.Ta, Tr=self.Tb) #T channel H = C.prop2tran(a=self.Aa,b=self.Ab,Friis=True,debug=True) self.save(H,'H',self.dexist['H']['grpname'],force = kwargs['force']) self.H = H if kwargs['applywav']: if self.H.isFriis: self.ir = self.H.applywavB(self.wav.sf) else: self.ir = self.H.applywavB(self.wav.sfg) return self.H.ak, self.H.tk def show(self,**kwargs): """ show the link Parameters ---------- s : int ca : string color a cb : string color b alpha : int figsize : tuple (20,10) fontsize : int 20 rays : boolean False cmap : colormap labels : boolean enabling edge label (useful for signature identification) pol : string 'tt','pp','tp','pt','co','cross',tot' col : string 'cmap' width : float alpha : float dB : boolean default False dyn : float dynamic in dB Examples -------- >>> from pylayers.simul.link import * >>> L=Link() >>> L.show(ray=True,dB=True) """ defaults ={'s':80, 'ca':'b', 'cb':'r', 'alpha':1, 'i':-1, 'figsize':(20,10), 'fontsize':20, 'rays':False, 'cmap':plt.cm.hot, 'pol':'tot', 'col':'k', 'width':1, 'alpha':1, 'col':'k', 'dB':False, 'labels':False, 'dyn':70} for key in defaults: if key not in kwargs: kwargs[key]=defaults[key] # # Layout # fig,ax = self.L.showG('s',nodes=False,figsize=kwargs['figsize'],labels=kwargs['labels']) plt.axis('off') # # Point A # ax.scatter(self.a[0], self.a[1], c=kwargs['ca'], s=kwargs['s'], alpha=kwargs['alpha']) ax.text(self.a[0]+0.1,self.a[1]+0.1,'A',fontsize=kwargs['fontsize']) # # Point B # ax.scatter(self.b[0], self.b[1], c=kwargs['cb'], s=kwargs['s'], alpha=kwargs['alpha']) ax.text(self.b[0]-0.1,self.b[1]+0.1,'B',fontsize=kwargs['fontsize']) # # Rays # if kwargs['rays']: ECtt,ECpp,ECtp,ECpt = self.C.energy() if kwargs['pol']=='tt': val = ECtt if kwargs['pol']=='pp': val = ECpp if kwargs['pol']=='tp': val = ECtp if kwargs['pol']=='pt': val = ECpt if kwargs['pol']=='tot': val = ECtt+ECpp+ECpt+ECtp if kwargs['pol']=='co': val = ECtt+ECpp if kwargs['pol']=='cross': val = ECtp+ECpt clm = kwargs['cmap'] # # Select group of interactions # if kwargs['i']==-1: li = self.R.keys() else: li = kwargs['i'] for i in li: lr = self.R[i]['rayidx'] for r in range(len(lr)): ir = lr[r] if kwargs['dB']: RayEnergy=max((20*np.log10(val[ir]/val.max())+kwargs['dyn']),0)/kwargs['dyn'] else: RayEnergy=val[ir]/val.max() if kwargs['col']=='cmap': col = clm(RayEnergy) width = RayEnergy alpha = 1 #alpha = RayEnergy else: col = kwargs['col'] width = kwargs['width'] alpha = kwargs['alpha'] fig,ax = self.R.show(i=i,r=r, colray=col, widthray=width, alpharay=alpha, fig=fig,ax=ax, layout=False, points=False) return fig,ax def _show3(self,rays=True, lay= True, ant= True, newfig= False, **kwargs): """ display the simulation scene using Mayavi using Mayavi Parameters ---------- rays: Ray3d object : display the rays of the simulation newfig : boolean (default : False) kwargs of Rays.show3() see also -------- pylayers.gis.layout pylayers.antprop.antenna pylayers.antprop.rays Examples -------- >>> from pylayers.simul.link import * >>> L=DLink(verbose=False) >>> aktk = L.eval() """ if not newfig: f=mlab.gcf() if 'centered' in kwargs: centered = kwargs['centered'] else : centered = False if centered: pg =np.zeros((3)) pg[:2]=self.L.pg if centered : ptx = self.tx.position-pg prx = self.rx.position-pg else : ptx = self.tx.position prx = self.rx.position if ant : Atx = self.tx.A Arx = self.rx.A Ttx = self.tx.orientation Trx = self.rx.orientation # evaluate antenna if required if not Atx.evaluated: Atx.Fsynth() elif len(Atx.SqG.shape) == 2 : Atx.Fsynth() if not Arx.evaluated: Arx.Fsynth() elif len(Arx.SqG.shape) == 2 : Arx.Fsynth() Atx._show3(T=Ttx.reshape(3,3),po=ptx, title=False,colorbar=False,newfig=False) Arx._show3(T=Trx.reshape(3,3),po=prx, title=False,colorbar=False,newfig=False,name = '') if lay: self.L._show3(newfig=False,opacity=0.7,centered=centered,**kwargs) if rays : try: self.R._show3(**kwargs) except: print 'Rays not computed yet'
def __init__(self, **kwargs): """ deterministic link evaluation Parameters ---------- L : Layout Layout to be used a : np.ndarray (3,) position of a device dev_a b : np.ndarray (3,) position of a device dev_b Aa : Antenna Antenna of device dev_a Ab : Antenna Antenna of device dev_b Ta : np.ndarray (3,3) Rotation matrice of Antenna of device dev_a relative to global Layout scene Tb : np.ndarray (3,3) Rotation matrice of Antenna of device dev_b relative to global Layout scene fGHz : np.ndarray (Nptf,) frequency range of Nptf points used for evaluation of channel wav : Waveform Waveform to be applied on the channel save_idx : int number to identify the h5 file generated Advanced (change only if you really know what you do !) save_opt : list (['sig','ray','Ct','H']) information to be saved in the Links h5 file. Should never be Modified ! force_create : Boolean (False) forcecreating the h5py file (if already exist, will be erased) Notes ----- All simulations are stored into a unique file in your <PyProject>/output directory using the following convention: Links_<save_idx>_<LayoutFilename>.h5 where <save_idx> is an integer number to distinguish different links simulations and <LayoutFilename> is the Layout used for the link simulation. Dataset organisation: Links_<idx>_<Layout_name>.h5 | |/sig/si_ID#0/ | /si_ID#1/ | ... | |/ray/ray_ID#0/ | /ray_ID#1/ | ... | |/Ct/Ct_ID#0/ | /Ct_ID#1/ | ... | |/H/H_ID#0/ | /H_ID#1/ | ... | | |p_map |c_map |f_map |A_map |T_map Roots Dataset : c_map : Cycles (Nc x 3) p_map : Positions (Np x 3) f_map : Frequency (Nf x 3) T_map : Rotation matrices (Nt x 3) A_map : Antenna name (Na x 3) Groups and subgroups: Signature identifier (si_ID#N): ca_cb_cutoff Ray identifier (ray_ID#N): cutoff_ua_ub Ctilde identifier (Ct_ID#N): ua_ub_uf H identifier (H_ID#N): ua_ub_uf_uTa_uTb_uAa_uAb with ca : cycle number of a cb : cycle number of b cutoff : signature.run cutoff ua : indice of a position in 'p_map' position dataset ub : indice of a position in 'p_map' position dataset uf : indice of freq position in 'f_map' frequency dataset uTa : indice of a position in 'T_map' Rotation dataset uTb : indice of b position in 'T_map' Rotation dataset uAa : indice of a position in 'A_map' Antenna name dataset uAb : indice of b position in 'A_map' Antenna name dataset Examples -------- >>> from pylayers.simul.link import * >>> L = DLink(verbose=False) >>> aktk = L.eval() """ super(DLink,self).__init__() defaults={ 'L':Layout(), 'a':np.array(()), 'b':np.array(()), 'Aa':Antenna(), 'Ab':Antenna(), 'Ta':np.eye(3), 'Tb':np.eye(3), 'fGHz':np.linspace(2, 11, 181, endpoint=True), 'wav':wvf.Waveform(), 'cutoff':3, 'save_opt':['sig','ray','Ct','H'], 'save_idx':0, 'force_create':False, 'verbose':True } self._ca=-1 self._cb=-1 specset = ['a','b','Aa','Ab','Ta','Tb','L','fGHz','wav'] for key, value in defaults.items(): if key not in kwargs: if key in specset : setattr(self,'_'+key,value) else : setattr(self,key,value) else : if key in specset : setattr(self,'_'+key,kwargs[key]) else : setattr(self,key,kwargs[key]) force=self.force_create delattr(self,'force_create') self._Lname = self._L.filename ########### # init ant ########### self.tx = RadioNode(name = '', typ = 'tx', _fileini = 'radiotx.ini', _fileant = self.Aa._filename ) self.rx = RadioNode(name = '', typ = 'rx', _fileini = 'radiorx.ini', _fileant = self.Ab._filename, ) self.filename = 'Links_' + str(self.save_idx) + '_' + self._Lname + '.h5' filenameh5 = pyu.getlong(self.filename,pstruc['DIRLNK']) # check if save file alreasdy exists if not os.path.exists(filenameh5) or force: print 'Links save file for ' + self.L.filename + ' does not exist.' print 'Creating file. You\'ll see this message only once per Layout' self.save_init(filenameh5) # dictionnary data exists self.dexist={'sig':{'exist':False,'grpname':''}, 'ray':{'exist':False,'grpname':''}, 'Ct':{'exist':False,'grpname':''}, 'H':{'exist':False,'grpname':''} } try: self.L.dumpr() except: print('This is the first time the Layout is used. Graphs have to be built. Please Wait') self.L.build() self.L.dumpw() #self.L.build() ########### # init pos & cycles # # If a and b are not specified # they are chosen as center of gravity of cycle 0 # ########### if len(self.a)==0: self.ca = 1 # self.a = self.L.cy2pt(self.ca) else: if len(kwargs['a']) ==2: a=np.r_[kwargs['a'],1.0] else: a=kwargs['a'] self.a = a # self.ca = self.L.pt2cy(self.a) if len(self.b)==0: if len(self.L.Gt.node)>2: self.cb = 2 else: self.cb = 1 # self.b = self.L.cy2pt(self.cb) else: if len(kwargs['b']) ==2: b=np.r_[kwargs['b'],1.0] else: b=kwargs['b'] self.b = b # self.cb = self.L.pt2cy(self.b) ########### # init freq ########### self.fmin = self.fGHz[0] self.fmax = self.fGHz[-1] self.fstep = self.fGHz[1]-self.fGHz[0] self.Si = Signatures(self.L,self.ca,self.cb,cutoff=self.cutoff) self.R = Rays(self.a,self.b) self.C = Ctilde() self.H = Tchannel()
def eval(self, fGHz=np.array([2.4])): """docstring for eval""" print 'Rays evaluation' self.I.eval(fGHz) B = self.B.eval(fGHz) B0 = self.B0.eval(fGHz) # Ct : f x r x 2 x 2 Ct = np.zeros((self.I.nf, self.nray, 2, 2), dtype=complex) # delays : ,r self.delays = np.zeros((self.nray)) # dis : ,r self.dis = np.zeros((self.nray)) #nf : number of frequency point nf = self.I.nf aod = np.empty((2, self.nray)) aoa = np.empty((2, self.nray)) # loop on interaction blocks for l in self: # l stands for the number of interactions r = self[l]['nbrays'] # reshape in order to have a 1D list of index # reshape ray index rrl = self[l]['rays'].reshape(r * l, order='F') # get the corresponding evaluated interactions A = self.I.I[:, rrl, :, :].reshape(self.I.nf, r, l, 2, 2, order='F') Bl = B[:, rrl, :, :].reshape(self.I.nf, r, l, 2, 2, order='F') B0l = B0[:, self[l]['rayidx'], :, :] alpha = self.I.alpha[rrl].reshape(r, l, order='F') gamma = self.I.gamma[rrl].reshape(r, l, order='F') si0 = self.I.si0[rrl].reshape(r, l, order='F') sout = self.I.sout[rrl].reshape(r, l, order='F') aoa[:, self[l]['rayidx']] = self[l]['aoa'] aod[:, self[l]['rayidx']] = self[l]['aod'] try: del Z except: pass ## loop on all the interactions of ray with l interactions for i in range(0, l): ############################################ ## # Divergence factor D ### not yet implementented ############################################ # if i == 0: # D0=1./si0[:,1] # rho1=si0[:,1]*alpha[:,i] # rho2=si0[:,1]*alpha[:,i]*gamma[:,i] # D=np.sqrt( # ( (rho1 ) / (rho1 + sout[:,i]) ) # *( (rho2) / (rho2 + sout[:,i]))) # D=D*D0 # rho1=rho1+(sout[:,i]*alpha[:,i]) # rho2=rho2+(sout[:,i]*alpha[:,i]*gamma[:,i]) ## gerer le loss # if np.isnan(D).any(): # p=np.nonzero(np.isnan(D))[0] # D[p]=1./sout[p,1] # else : # D=np.sqrt( # ( (rho1 ) / (rho1 + sout[:,i]) ) # *( (rho2) / (rho2 + sout[:,i]))) # rho1=rho1+(sout[:,i]*alpha[:,i]) # rho2=rho2+(sout[:,i]*alpha[:,i]*gamma[:,i]) ############################################ # A0 (X dot Y) # | | | # v v v ########################## ## B # I # B # I # B # ########################## # \_____/ \______/ # | | # Atmp(i) Atmp(i+1) # # Z=Atmp(i) dot Atmp(i+1) X = A[:, :, i, :, :] Y = Bl[:, :, i, :, :] ## Dot product interaction X Basis Atmp = np.sum(X[..., :, :, np.newaxis] * Y[..., np.newaxis, :, :], axis=-2) #*D[np.newaxis,:,np.newaxis,np.newaxis] if i == 0: ## First Baspdis added A0 = B0l[:, :, :, :] Z = np.sum(A0[..., :, :, np.newaxis] * Atmp[..., np.newaxis, :, :], axis=-2) else: # dot product previous interaction with latest Z = np.sum(Z[..., :, :, np.newaxis] * Atmp[..., np.newaxis, :, :], axis=-2) # fill the C tilde Ct[:, self[l]['rayidx'], :, :] = Z[:, :, :, :] # delay computation: self[l]['dis'] = self.I.si0[self[l]['rays'][0, :]] + np.sum( self.I.sout[self[l]['rays']], axis=0) # Power losses due to distances # will be removed once the divergence factor will be implemented Ct[:, self[l]['rayidx'], :, :] = Ct[:, self[l]['rayidx'], :, :] * 1. / ( self[l]['dis'][np.newaxis, :, np.newaxis, np.newaxis]) self.delays[self[l]['rayidx']] = self[l]['dis'] / 0.3 self.dis[self[l]['rayidx']] = self[l]['dis'] # To be corrected in a future version Ct = np.swapaxes(Ct, 1, 0) c11 = Ct[:, :, 0, 0] c12 = Ct[:, :, 0, 1] c21 = Ct[:, :, 1, 0] c22 = Ct[:, :, 1, 1] Cn = Ctilde() Cn.Cpp = bs.FUsignal(self.I.fGHz, c11) Cn.Ctp = bs.FUsignal(self.I.fGHz, c12) Cn.Cpt = bs.FUsignal(self.I.fGHz, c21) Cn.Ctt = bs.FUsignal(self.I.fGHz, c22) Cn.nfreq = self.I.nf Cn.nray = self.nray Cn.tauk = self.delays Cn.fGHz = self.I.fGHz # r x 2 Cn.tang = aod.T # r x 2 Cn.rang = aoa.T # add aoa and aod return (Cn)
def eval(self,**kwargs): """ Evaluate the link Parameters ---------- applywav :boolean Apply waveform to H force : list Force the computation (['sig','ray','Ct','H']) AND save (replace previous computations) si_algo : str ('old'|'new') signature.run algo type 'old' : call propaths2 'new' : call procone2 alg : 5 | 7 version of run for signature si_mt: boolean Multi thread version of algo version 7 si_progress: bollean ( False) display progression bar for signatures diffraction : boolean (False) takes into consideration diffraction points ra_number_mirror_cf : int rays.to3D number of ceil/floor reflexions ra_ceil_height_meter: float, ceil height ra_vectorized: boolean (True) if True used the (2015 new) vectorized approach to determine 2drays Returns ------- ak : ndarray alpha_k tk : ndarray tau_k Notes ----- update self.ak and self.tk self.ak : ndarray alpha_k self.tk : ndarray tau_k Examples -------- .. plot:: :include-source: >>> from pylayers.simul.link import * >>> L=DLink(verbose=False) >>> aktk = L.eval() See Also -------- pylayers.antprop.signature pylayers.antprop.rays Experimental ------------ alg = 2015 | 20152 (best) vectorized signature research si_reverb : number of reverb in source/target cycle if alg=2015 """ defaults={ 'applywav':True, 'si_algo':'old', 'si_mt':False, 'si_progress':False, 'diffraction':False, 'ra_vectorized':False, 'ra_ceil_height_meter':3, 'ra_number_mirror_cf':1, 'force':[], 'alg':7, 'si_reverb':4, 'threshold':0.1, } for key, value in defaults.items(): if key not in kwargs: kwargs[key]=value if 'cutoff' not in kwargs: kwargs['cutoff']=self.cutoff else: self.cutoff=kwargs['cutoff'] if 'force' in kwargs: if not isinstance(kwargs['force'],list): if kwargs['force'] == True : kwargs['force'] = ['sig','ray','Ct','H'] else : kwargs['force'] = [] # must be placed after all the init !!!! self.checkh5() ############ # Signatures ############ Si = Signatures(self.L,self.ca,self.cb,cutoff=kwargs['cutoff']) if (self.dexist['sig']['exist'] and not ('sig' in kwargs['force'])): self.load(Si,self.dexist['sig']['grpname']) else : if kwargs['alg']==2015: TMP=Si.run2015(cutoff=kwargs['cutoff'], cutoffbound=kwargs['si_reverb']) if kwargs['alg']==20152: TMP=Si.run2015_2(cutoff=kwargs['cutoff'], cutoffbound=kwargs['si_reverb']) if kwargs['alg']==5: Si.run5(cutoff=kwargs['cutoff'], algo=kwargs['si_algo'], diffraction=kwargs['diffraction'], progress=kwargs['si_progress']) if kwargs['alg']==7: if kwargs['si_mt']==7: Si.run7mt(cutoff=kwargs['cutoff'], algo=kwargs['si_algo'], diffraction=kwargs['diffraction'], threshold=kwargs['threshold'], progress=kwargs['si_progress']) else : Si.run7(cutoff=kwargs['cutoff'], algo=kwargs['si_algo'], diffraction=kwargs['diffraction'], threshold=kwargs['threshold'], progress=kwargs['si_progress']) #Si.run6(diffraction=kwargs['diffraction']) # save sig self.save(Si,'sig',self.dexist['sig']['grpname'],force = kwargs['force']) self.Si = Si ############ # Rays ############ R = Rays(self.a,self.b) if self.dexist['ray']['exist'] and not ('ray' in kwargs['force']): self.load(R,self.dexist['ray']['grpname']) else : # perform computation ... # ... with vetorized ray evaluation approach if kwargs['ra_vectorized']: r2d = Si.raysv(self.a,self.b) # ... or with original and slow approach ( to be removed in a near future) else : r2d = Si.rays(self.a,self.b) R = r2d.to3D(self.L,H=self.L.maxheight, N=kwargs['ra_number_mirror_cf']) R.locbas(self.L) # ...and save self.save(R,'ray',self.dexist['ray']['grpname'],force = kwargs['force']) self.R = R if self.R.nray == 0: raise NameError('No rays have been found. Try to re-run the simulation with a higher S.cutoff ') ############ # Ctilde ############ C=Ctilde() if self.dexist['Ct']['exist'] and not ('Ct' in kwargs['force']): self.load(C,self.dexist['Ct']['grpname']) else : R.fillinter(self.L) # Ctilde... C = R.eval(self.fGHz) # ...save Ct self.save(C,'Ct',self.dexist['Ct']['grpname'],force = kwargs['force']) self.C = C ############ # H ############ H = Tchannel() if self.dexist['H']['exist'] and not ('H' in kwargs['force']): self.load(H,self.dexist['H']['grpname']) else : # Ctilde antenna Cl=C.locbas(Tt=self.Ta, Tr=self.Tb) #T channel H = C.prop2tran(a=self.Aa,b=self.Ab,Friis=True,debug=True) self.save(H,'H',self.dexist['H']['grpname'],force = kwargs['force']) self.H = H if kwargs['applywav']: if self.H.isFriis: self.ir = self.H.applywavB(self.wav.sf) else: self.ir = self.H.applywavB(self.wav.sfg) return self.H.ak, self.H.tk
def eval(self,**kwargs): """ evaluate the link Parameters ---------- applywav :boolean Apply waveform to H force : list Force the computation (['sig','ray','Ct','H']) AND save (replace previous computations) alg : 1|'old'|'exp'|'exp2' version of run for signature si_progress: bollean ( False) display progression bar for signatures diffraction : boolean (False) takes into consideration diffraction points ra_number_mirror_cf : int rays.to3D number of ceil/floor reflexions ra_ceil_H: float, (default []) ceil height . If [] : Layout max ceil height If 0 : only floor reflection (outdoor case) If -1 : neither ceil nor floor reflection (2D case) ra_vectorized: boolean (True) if True used the (2015 new) vectorized approach to determine 2drays Returns ------- ak : ndarray alpha_k tk : ndarray tau_k Notes ----- update self.ak and self.tk self.ak : ndarray alpha_k self.tk : ndarray tau_k Examples -------- .. plot:: :include-source: >>> from pylayers.simul.link import * >>> L=DLink(verbose=False) >>> aktk = L.eval() See Also -------- pylayers.antprop.signature pylayers.antprop.rays Experimental ------------ alg = 2015 | 20152 (best) vectorized signature research si_reverb : number of reverb in source/target cycle if alg=2015 """ defaults={ 'applywav':True, 'si_progress':False, 'diffraction':True, 'ra_vectorized':True, 'ra_ceil_H':[], 'ra_number_mirror_cf':1, 'force':[], 'alg':1, 'si_reverb':4, 'threshold':0.1, 'verbose':[], } for key, value in defaults.items(): if key not in kwargs: kwargs[key]=value if 'cutoff' not in kwargs: kwargs['cutoff']=self.cutoff else: self.cutoff=kwargs['cutoff'] if 'force' in kwargs: if not isinstance(kwargs['force'],list): if kwargs['force'] == True : kwargs['force'] = ['sig','ray','Ct','H'] else : kwargs['force'] = [] if kwargs['verbose'] != []: self.verbose=kwargs['verbose'] # must be placed after all the init !!!! if self.verbose : print "checkh5" self.checkh5() ############ # Signatures ############ if self.verbose : print "Start Signatures" tic = time.time() Si = Signatures(self.L,self.ca,self.cb,cutoff=kwargs['cutoff']) if (self.dexist['sig']['exist'] and not ('sig' in kwargs['force'])): self.load(Si,self.dexist['sig']['grpname']) if self.verbose : print "load signature" else : if kwargs['alg']==1: Si.run(cutoff=kwargs['cutoff'], diffraction=kwargs['diffraction'], threshold=kwargs['threshold'], progress=kwargs['si_progress']) if self.verbose : print "default algorithm" if kwargs['alg']=='exp': TMP=Si.run_exp(cutoff=kwargs['cutoff'], cutoffbound=kwargs['si_reverb']) if self.verbose : print "experimental (ex 2015)" if kwargs['alg']=='exp2': TMP=Si.run_exp2(cutoff=kwargs['cutoff'], cutoffbound=kwargs['si_reverb']) if self.verbose : print "algo exp2 ( ex 20152)" #Si.run6(diffraction=kwargs['diffraction']) # save sig self.save(Si,'sig',self.dexist['sig']['grpname'],force = kwargs['force']) self.Si = Si toc = time.time() if self.verbose : print "Stop signature",toc-tic ############ # Rays ############ if self.verbose : print "Start Rays" tic = time.time() R = Rays(self.a,self.b) if self.dexist['ray']['exist'] and not ('ray' in kwargs['force']): self.load(R,self.dexist['ray']['grpname']) else : # perform computation ... # ... with vetorized ray evaluation approach if kwargs['ra_vectorized']: r2d = Si.raysv(self.a,self.b) # ... or with original and slow approach ( to be removed in a near future) else : r2d = Si.rays(self.a,self.b) if kwargs['ra_ceil_H'] == []: ceilheight = self.L.maxheight else: ceilheight = kwargs['ra_ceil_H'] R = r2d.to3D(self.L,H=ceilheight, N=kwargs['ra_number_mirror_cf']) R.locbas(self.L) # ...and save R.fillinter(self.L) C = Ctilde() C = R.eval(self.fGHz) self.save(R,'ray',self.dexist['ray']['grpname'],force = kwargs['force']) self.R = R toc = time.time() if self.verbose : print "Stop rays",toc-tic if self.R.nray == 0: raise NameError('No rays have been found. Try to re-run the simulation with a higher S.cutoff ') ############ # Ctilde ############ if self.dexist['Ct']['exist'] and not ('Ct' in kwargs['force']): C=Ctilde() self.load(C,self.dexist['Ct']['grpname']) else : #if not hasattr(R,'I'): # Ctilde... # Find an other criteria in order to decide whether the R has # already been evaluated #pdb.set_trace() C = R.eval(self.fGHz) # ...save Ct self.save(C,'Ct',self.dexist['Ct']['grpname'],force = kwargs['force']) self.C = C ############ # H ############ H = Tchannel() if self.dexist['H']['exist'] and not ('H' in kwargs['force']): self.load(H,self.dexist['H']['grpname']) else : # Ctilde antenna Cl=C.locbas(Tt=self.Ta, Tr=self.Tb) #T channel H = C.prop2tran(a=self.Aa,b=self.Ab,Friis=True,debug=True) self.save(H,'H',self.dexist['H']['grpname'],force = kwargs['force']) self.H = H if kwargs['applywav']: if self.H.isFriis: self.ir = self.H.get_cir(self.wav.sf) else: self.ir = self.H.get_cir(self.wav.sfg) return self.H.ak, self.H.tk
def eval(self,fGHz=np.array([2.4])): """docstring for eval""" print 'Rays evaluation' self.I.eval(fGHz) B=self.B.eval(fGHz) B0=self.B0.eval(fGHz) # Ct : f x r x 2 x 2 Ct = np.zeros((self.I.nf, self.nray, 2, 2), dtype=complex) # delays : ,r self.delays = np.zeros((self.nray)) # dis : ,r self.dis = np.zeros((self.nray)) #nf : number of frequency point nf = self.I.nf aod= np.empty((2,self.nray)) aoa= np.empty((2,self.nray)) # loop on interaction blocks for l in self: # l stands for the number of interactions r = self[l]['nbrays'] # reshape in order to have a 1D list of index # reshape ray index rrl = self[l]['rays'].reshape(r*l,order='F') # get the corresponding evaluated interactions A = self.I.I[:, rrl, :, :].reshape(self.I.nf, r, l, 2, 2,order='F') Bl = B[:, rrl, :, :].reshape(self.I.nf, r, l, 2, 2,order='F') B0l = B0[:, self[l]['rayidx'], :, :] alpha = self.I.alpha[rrl].reshape(r, l,order='F') gamma = self.I.gamma[rrl].reshape(r, l,order='F') si0 = self.I.si0[rrl].reshape(r, l,order='F') sout = self.I.sout[rrl].reshape(r, l,order='F') aoa[:,self[l]['rayidx']]=self[l]['aoa'] aod[:,self[l]['rayidx']]=self[l]['aod'] try: del Z except: pass ## loop on all the interactions of ray with l interactions for i in range(0, l): ############################################ ## # Divergence factor D ### not yet implementented ############################################ # if i == 0: # D0=1./si0[:,1] # rho1=si0[:,1]*alpha[:,i] # rho2=si0[:,1]*alpha[:,i]*gamma[:,i] # D=np.sqrt( # ( (rho1 ) / (rho1 + sout[:,i]) ) # *( (rho2) / (rho2 + sout[:,i]))) # D=D*D0 # rho1=rho1+(sout[:,i]*alpha[:,i]) # rho2=rho2+(sout[:,i]*alpha[:,i]*gamma[:,i]) ## gerer le loss # if np.isnan(D).any(): # p=np.nonzero(np.isnan(D))[0] # D[p]=1./sout[p,1] # else : # D=np.sqrt( # ( (rho1 ) / (rho1 + sout[:,i]) ) # *( (rho2) / (rho2 + sout[:,i]))) # rho1=rho1+(sout[:,i]*alpha[:,i]) # rho2=rho2+(sout[:,i]*alpha[:,i]*gamma[:,i]) ############################################ # A0 (X dot Y) # | | | # v v v ########################## ## B # I # B # I # B # ########################## # \_____/ \______/ # | | # Atmp(i) Atmp(i+1) # # Z=Atmp(i) dot Atmp(i+1) X = A [:, :, i, :, :] Y = Bl[:, :, i, :, :] ## Dot product interaction X Basis Atmp = np.sum(X[..., :, :, np.newaxis]*Y[ ..., np.newaxis, :, :], axis=-2) #*D[np.newaxis,:,np.newaxis,np.newaxis] if i == 0: ## First Baspdis added A0 = B0l[:, :, :, :] Z = np.sum(A0[..., :, :, np.newaxis]*Atmp[ ..., np.newaxis, :, :], axis=-2) else: # dot product previous interaction with latest Z = np.sum(Z[..., :, :, np.newaxis]*Atmp[ ..., np.newaxis, :, :], axis=-2) # fill the C tilde Ct[:, self[l]['rayidx'], :, :] = Z[:, :, :, :] # delay computation: self[l]['dis'] = self.I.si0[self[l]['rays'][ 0,:]] + np.sum(self.I.sout[self[l]['rays']], axis=0) # Power losses due to distances # will be removed once the divergence factor will be implemented Ct[:, self[l]['rayidx'], :, :] = Ct[:, self[l][ 'rayidx'], :, :]*1./(self[l]['dis'][np.newaxis, :, np.newaxis, np.newaxis]) self.delays[self[l]['rayidx']] = self[l]['dis']/0.3 self.dis[self[l]['rayidx']] = self[l]['dis'] # To be corrected in a future version Ct = np.swapaxes(Ct, 1, 0) c11 = Ct[:,:,0,0] c12 = Ct[:,:,0,1] c21 = Ct[:,:,1,0] c22 = Ct[:,:,1,1] Cn=Ctilde() Cn.Cpp = bs.FUsignal(self.I.fGHz, c11) Cn.Ctp = bs.FUsignal(self.I.fGHz, c12) Cn.Cpt = bs.FUsignal(self.I.fGHz, c21) Cn.Ctt = bs.FUsignal(self.I.fGHz, c22) Cn.nfreq = self.I.nf Cn.nray = self.nray Cn.tauk=self.delays Cn.fGHz = self.I.fGHz # r x 2 Cn.tang = aod.T # r x 2 Cn.rang = aoa.T # add aoa and aod return(Cn)
def __init__(self, **kwargs): """ deterministic link evaluation Parameters ---------- L : Layout Layout to be used a : np.ndarray (3,) position of a device dev_a b : np.ndarray (3,) position of a device dev_b Aa : Antenna Antenna of device dev_a Ab : Antenna Antenna of device dev_b Ta : np.ndarray (3,3) Rotation matrice of Antenna of device dev_a relative to global Layout scene Tb : np.ndarray (3,3) Rotation matrice of Antenna of device dev_b relative to global Layout scene fGHz : np.ndarray (Nf,) frequency range of Nf points used for evaluation of channel wav : Waveform Waveform to be applied on the channel save_idx : int number to identify the h5 file generated Advanced (change only if you really know what you do !) save_opt : list (['sig','ray','Ct','H']) information to be saved in the Links h5 file. Should never be Modified ! force_create : Boolean (False) forcecreating the h5py file (if already exist, will be erased) Notes ----- All simulations are stored into a unique file in your <PyProject>/output directory using the following convention: Links_<save_idx>_<LayoutFilename>.h5 where <save_idx> is an integer number to distinguish different links simulations and <LayoutFilename> is the Layout used for the link simulation. Dataset organisation: Links_<idx>_<Layout_name>.h5 | |/sig/si_ID#0/ | /si_ID#1/ | ... | |/ray/ray_ID#0/ | /ray_ID#1/ | ... | |/Ct/Ct_ID#0/ | /Ct_ID#1/ | ... | |/H/H_ID#0/ | /H_ID#1/ | ... | | |p_map |c_map |f_map |A_map |T_map Roots Dataset : c_map : Cycles (Nc x 3) p_map : Positions (Np x 3) f_map : Frequency (Nf x 3) T_map : Rotation matrices (Nt x 3) A_map : Antenna name (Na x 3) Groups and subgroups: Signature identifier (si_ID#N): ca_cb_cutoff Ray identifier (ray_ID#N): cutoff_ua_ub Ctilde identifier (Ct_ID#N): ua_ub_uf H identifier (H_ID#N): ua_ub_uf_uTa_uTb_uAa_uAb with ca : cycle number of a cb : cycle number of b cutoff : signature.run cutoff ua : indice of a position in 'p_map' position dataset ub : indice of a position in 'p_map' position dataset uf : indice of freq position in 'f_map' frequency dataset uTa : indice of a position in 'T_map' Rotation dataset uTb : indice of a position in 'T_map' Rotation dataset uAa : indice of a position in 'A_map' Antenna name dataset uAb : indice of b position in 'A_map' Antenna name dataset Examples -------- >>> from pylayers.simul.link import * >>> L = DLink(verbose=False) >>> aktk = L.eval() """ Link.__init__(self) defaults={ 'L':Layout(), 'a':np.array(()), 'b':np.array(()), 'Aa':Antenna(typ='Omni'), 'Ab':Antenna(typ='Omni'), 'Ta':np.eye(3), 'Tb':np.eye(3), 'fGHz':[], 'wav':wvf.Waveform(), 'cutoff':3, 'save_opt':['sig','ray','Ct','H'], 'save_idx':0, 'force_create':False, 'verbose':True, 'graph':'tcvirw' } self._ca=-1 self._cb=-1 specset = ['a','b','Aa','Ab','Ta','Tb','L','fGHz','wav'] # set default attribute for key, value in defaults.items(): if key not in kwargs: if key in specset : setattr(self,'_'+key,value) else : setattr(self,key,value) else : if key in specset : setattr(self,'_'+key,kwargs[key]) else : setattr(self,key,kwargs[key]) force=self.force_create delattr(self,'force_create') if self.fGHz == []: self.initfreq() else : pass try: self._Lname = self._L.filename except: self._L=Layout(self._L) self._Lname = self._L.filename ########### # Transmitter and Receiver positions ########### self.tx = RadioNode(name = '', typ = 'tx', _fileini = 'radiotx.ini', ) self.rx = RadioNode(name = '', typ = 'rx', _fileini = 'radiorx.ini', ) self.filename = 'Links_' + str(self.save_idx) + '_' + self._Lname + '.h5' filenameh5 = pyu.getlong(self.filename,pstruc['DIRLNK']) # check if save file alreasdy exists if not os.path.exists(filenameh5) or force: print 'Links save file for ' + self.L.filename + ' does not exist.' print 'Creating file. You\'ll see this message only once per Layout' self.save_init(filenameh5) # dictionnary data exists self.dexist={'sig':{'exist':False,'grpname':''}, 'ray':{'exist':False,'grpname':''}, 'Ct':{'exist':False,'grpname':''}, 'H':{'exist':False,'grpname':''} } try: self.L.dumpr() except: print('This is the first time the Layout is used. Graphs have to be built. Please Wait') self.L.build(graph=self.graph) self.L.dumpw() #self.L.build() ########### # init pos & cycles # # If a and b are not specified # they are chosen as center of gravity of cycle 0 # ########### if len(self.a)==0: self.ca = 1 # self.a = self.L.cy2pt(self.ca) else: if len(kwargs['a']) ==2: a=np.r_[kwargs['a'],1.0] else: a=kwargs['a'] self.a = a # self.ca = self.L.pt2cy(self.a) if len(self.b)==0: if len(self.L.Gt.node)>2: self.cb = 2 else: self.cb = 1 # self.b = self.L.cy2pt(self.cb) else: if len(kwargs['b']) ==2: b=np.r_[kwargs['b'],1.0] else: b=kwargs['b'] self.b = b # self.cb = self.L.pt2cy(self.b) ########### # init freq # TODO Check where it is used redundant with fGHz ########### #self.fmin = self.fGHz[0] #self.fmax = self.fGHz[-1] #self.fstep = self.fGHz[1]-self.fGHz[0] self.Si = Signatures(self.L,self.ca,self.cb,cutoff=self.cutoff) self.R = Rays(self.a,self.b) self.C = Ctilde() self.H = Tchannel()
class DLink(Link): def __init__(self, **kwargs): """ deterministic link evaluation Parameters ---------- L : Layout Layout to be used a : np.ndarray (3,) position of a device dev_a b : np.ndarray (3,) position of a device dev_b Aa : Antenna Antenna of device dev_a Ab : Antenna Antenna of device dev_b Ta : np.ndarray (3,3) Rotation matrice of Antenna of device dev_a relative to global Layout scene Tb : np.ndarray (3,3) Rotation matrice of Antenna of device dev_b relative to global Layout scene fGHz : np.ndarray (Nf,) frequency range of Nf points used for evaluation of channel wav : Waveform Waveform to be applied on the channel save_idx : int number to identify the h5 file generated Advanced (change only if you really know what you do !) save_opt : list (['sig','ray','Ct','H']) information to be saved in the Links h5 file. Should never be Modified ! force_create : Boolean (False) forcecreating the h5py file (if already exist, will be erased) Notes ----- All simulations are stored into a unique file in your <PyProject>/output directory using the following convention: Links_<save_idx>_<LayoutFilename>.h5 where <save_idx> is an integer number to distinguish different links simulations and <LayoutFilename> is the Layout used for the link simulation. Dataset organisation: Links_<idx>_<Layout_name>.h5 | |/sig/si_ID#0/ | /si_ID#1/ | ... | |/ray/ray_ID#0/ | /ray_ID#1/ | ... | |/Ct/Ct_ID#0/ | /Ct_ID#1/ | ... | |/H/H_ID#0/ | /H_ID#1/ | ... | | |p_map |c_map |f_map |A_map |T_map Roots Dataset : c_map : Cycles (Nc x 3) p_map : Positions (Np x 3) f_map : Frequency (Nf x 3) T_map : Rotation matrices (Nt x 3) A_map : Antenna name (Na x 3) Groups and subgroups: Signature identifier (si_ID#N): ca_cb_cutoff Ray identifier (ray_ID#N): cutoff_ua_ub Ctilde identifier (Ct_ID#N): ua_ub_uf H identifier (H_ID#N): ua_ub_uf_uTa_uTb_uAa_uAb with ca : cycle number of a cb : cycle number of b cutoff : signature.run cutoff ua : indice of a position in 'p_map' position dataset ub : indice of a position in 'p_map' position dataset uf : indice of freq position in 'f_map' frequency dataset uTa : indice of a position in 'T_map' Rotation dataset uTb : indice of a position in 'T_map' Rotation dataset uAa : indice of a position in 'A_map' Antenna name dataset uAb : indice of b position in 'A_map' Antenna name dataset Examples -------- >>> from pylayers.simul.link import * >>> L = DLink(verbose=False) >>> aktk = L.eval() """ Link.__init__(self) defaults={ 'L':Layout(), 'a':np.array(()), 'b':np.array(()), 'Aa':Antenna(typ='Omni'), 'Ab':Antenna(typ='Omni'), 'Ta':np.eye(3), 'Tb':np.eye(3), 'fGHz':[], 'wav':wvf.Waveform(), 'cutoff':3, 'save_opt':['sig','ray','Ct','H'], 'save_idx':0, 'force_create':False, 'verbose':True, 'graph':'tcvirw' } self._ca=-1 self._cb=-1 specset = ['a','b','Aa','Ab','Ta','Tb','L','fGHz','wav'] # set default attribute for key, value in defaults.items(): if key not in kwargs: if key in specset : setattr(self,'_'+key,value) else : setattr(self,key,value) else : if key in specset : setattr(self,'_'+key,kwargs[key]) else : setattr(self,key,kwargs[key]) force=self.force_create delattr(self,'force_create') if self.fGHz == []: self.initfreq() else : pass try: self._Lname = self._L.filename except: self._L=Layout(self._L) self._Lname = self._L.filename ########### # Transmitter and Receiver positions ########### self.tx = RadioNode(name = '', typ = 'tx', _fileini = 'radiotx.ini', ) self.rx = RadioNode(name = '', typ = 'rx', _fileini = 'radiorx.ini', ) self.filename = 'Links_' + str(self.save_idx) + '_' + self._Lname + '.h5' filenameh5 = pyu.getlong(self.filename,pstruc['DIRLNK']) # check if save file alreasdy exists if not os.path.exists(filenameh5) or force: print 'Links save file for ' + self.L.filename + ' does not exist.' print 'Creating file. You\'ll see this message only once per Layout' self.save_init(filenameh5) # dictionnary data exists self.dexist={'sig':{'exist':False,'grpname':''}, 'ray':{'exist':False,'grpname':''}, 'Ct':{'exist':False,'grpname':''}, 'H':{'exist':False,'grpname':''} } try: self.L.dumpr() except: print('This is the first time the Layout is used. Graphs have to be built. Please Wait') self.L.build(graph=self.graph) self.L.dumpw() #self.L.build() ########### # init pos & cycles # # If a and b are not specified # they are chosen as center of gravity of cycle 0 # ########### if len(self.a)==0: self.ca = 1 # self.a = self.L.cy2pt(self.ca) else: if len(kwargs['a']) ==2: a=np.r_[kwargs['a'],1.0] else: a=kwargs['a'] self.a = a # self.ca = self.L.pt2cy(self.a) if len(self.b)==0: if len(self.L.Gt.node)>2: self.cb = 2 else: self.cb = 1 # self.b = self.L.cy2pt(self.cb) else: if len(kwargs['b']) ==2: b=np.r_[kwargs['b'],1.0] else: b=kwargs['b'] self.b = b # self.cb = self.L.pt2cy(self.b) ########### # init freq # TODO Check where it is used redundant with fGHz ########### #self.fmin = self.fGHz[0] #self.fmax = self.fGHz[-1] #self.fstep = self.fGHz[1]-self.fGHz[0] self.Si = Signatures(self.L,self.ca,self.cb,cutoff=self.cutoff) self.R = Rays(self.a,self.b) self.C = Ctilde() self.H = Tchannel() @property def Lname(self): return self._Lname @property def L(self): return self._L @property def a(self): return self._a @property def b(self): return self._b @property def ca(self): return self._ca @property def cb(self): return self._cb @property def Aa(self): return self._Aa @property def Ab(self): return self._Ab @property def Ta(self): return self._Ta @property def Tb(self): return self._Tb @property def fGHz(self): return self._fGHz @property def wav(self): return self._wav @L.setter def L(self,L): # change layout and build/load self._L = L self.reset_config() @Lname.setter def Lname(self,Lname): # change layout and build/load self._L = Layout(Lname) self._Lname = Lname self.reset_config() @a.setter def a(self,position): if not self.L.ptin(position): raise NameError ('Warning : point a is not inside the Layout') # raise NameError ('Warning : point a is not inside the Layout') if not self.L.pt2cy(position) == self.ca: self.ca = self.L.pt2cy(position) self._a = position self.tx.position = position @b.setter def b(self,position): if not self.L.ptin(position): raise NameError ('Warning : point b is not inside the Layout') if not self.L.pt2cy(position) == self.cb: self.cb = self.L.pt2cy(position) self._b = position self.rx.position = position @ca.setter def ca(self,cycle): if not cycle in self.L.Gt.nodes(): raise NameError ('cycle ca is not inside Gt') self._ca = cycle self.a = self.L.cy2pt(cycle) @cb.setter def cb(self,cycle): if not cycle in self.L.Gt.nodes(): raise NameError ('cycle cb is not inside Gt') self._cb = cycle self.b = self.L.cy2pt(cycle) @Aa.setter def Aa(self,Ant): position = self.a rot = self.Ta self.tx = RadioNode(name = '', typ = 'tx', _fileini = 'radiotx.ini', ) self._Aa = Ant #to be removed when radionode will be updated self.a = position self.Ta = rot self.initfreq() @Ab.setter def Ab(self,Ant): position = self.b rot = self.Tb self.rx = RadioNode(name = '', typ = 'rx', _fileini = 'radiorx.ini', ) self._Ab = Ant #to be removed when radionode will be updated self.b = position self.Tb = rot self.initfreq() @Ta.setter def Ta(self,orientation): self._Ta = orientation self.tx.orientation = orientation @Tb.setter def Tb(self,orientation): self._Tb = orientation self.rx.orientation = orientation @fGHz.setter def fGHz(self,freq): if not isinstance(freq,np.ndarray): freq=np.array([freq]) self._fGHz = freq if self.Aa.typ == 'Omni': self.Aa.fGHz = self.fGHz if self.Ab.typ == 'Omni': self.Ab.fGHz = self.fGHz #if len(freq)>1: # self.fmin = freq[0] # self.fmax = freq[-1] # self.fstep = freq[1]-freq[0] #else: # self.fmin = freq # self.fmax = freq # self.step = 0 @wav.setter def wav(self,waveform): self._wav = waveform if 'H' in dir(self): if len(self.H.taud[0])!=0: self.chanreal = self.H.get_cir(self.wav.sfg) def __repr__(self): """ __repr__ """ s = 'filename: ' + self.filename +'\n' s = s + 'Link Parameters :\n' s = s + '------- --------\n' s = s + 'Layout : ' + self.Lname + '\n\n' s = s + 'Node a \n' s = s + '------ \n' s = s + 'position : ' + str (self.a) + '\n' s = s + 'Antenna : ' + str (self.Aa.typ) + '\n' s = s + 'Rotation matrice : \n ' + str (self.Ta) + '\n\n' s = s + 'Node b \n' s = s + '------ \n' s = s + 'position : ' + str (self.b) + '\n' s = s + 'Antenna : ' + str (self.Ab.typ) + '\n' s = s + 'Rotation matrice : \n ' + str (self.Tb) + '\n\n' s = s + 'Link evaluation information : \n' s = s + '----------------------------- \n' s = s + 'distance : ' + str("%6.3f" % np.sqrt(np.sum((self.a-self.b)**2))) + ' m \n' s = s + 'delay : ' + str("%6.3f" % (np.sqrt(np.sum((self.a-self.b)**2))/0.3)) + ' ns\n' #s = s + 'Frequency range : \n' s = s + 'fmin (fGHz) : ' + str(self.fGHz[0]) +'\n' s = s + 'fmax (fGHz) : ' + str(self.fGHz[-1]) +'\n' Nf = len(self.fGHz) if Nf>1: s = s + 'fstep (fGHz) : ' + str(self.fGHz[1]-self.fGHz[0]) +'\n' else: s = s + 'fstep (fGHz) : ' + str(self.fGHz[0]-self.fGHz[0]) +'\n' s = s + 'Nf : ' + str(Nf) +'\n ' d = np.sqrt(np.sum((self.a-self.b)**2)) if Nf>1: fcGHz = (self.fGHz[-1]+self.fGHz[0])/2. else: fcGHz = self.fGHz[0] L = 32.4+20*np.log(d)+20*np.log10(fcGHz) return s def initfreq(self): """ Automatic freq determination from Antennas """ fa = self.Aa.fGHz fb = self.Ab.fGHz # step try: sa = fa[1]-fa[0] except: #single frequency sa = fa[0] try: sb = fb[1]-fb[0] except: sb = fb[0] minf = max(min(fa),min(fb)) maxf = min(max(fa),max(fb)) sf = min(sa,sb) self.fGHz = np.arange(minf,maxf+sf,sf) def reset_config(self): """ reset configuration when a new layout is loaded """ try: self.L.dumpr() except: self.L.build() self.L.dumpw() self.ca = 1 self.cb = 1 # self.a = self.L.cy2pt(self.ca) # self.b = self.L.cy2pt(self.cb) # change h5py file if layout changed self.filename = 'Links_' + str(self.save_idx) + '_' + self._Lname + '.h5' filenameh5 = pyu.getlong(self.filename,pstruc['DIRLNK']) if not os.path.exists(filenameh5) : print 'Links save file for ' + self.L.filename + ' does not exist.' print 'It is beeing created. You\'ll see that message only once per Layout' self.save_init(filenameh5) try: delattr(self,'Si') except: pass try: delattr(self,'R') except: pass try: delattr(self,'C') except: pass try: delattr(self,'H') except: pass def checkh5(self): """ check existence of previous simulations run with the same parameters. Returns ------- update self.dexist dictionnary """ # get identifier group name in h5py file self.get_grpname() # check if group name exists in the h5py file [self.check_grpname(k,self.dexist[k]['grpname']) for k in self.save_opt] def save_init(self,filename_long): """ initialize save Link Parameters ---------- filename_long : str complete path and filename """ f=h5py.File(filename_long,'w') # try/except to avoid loosing the h5 file if # read/write error try: f.create_group('sig') f.create_group('ray') f.create_group('Ct') f.create_group('H') # mapping point a f.create_dataset('p_map',shape=(0,3), maxshape=(None,3),dtype='float64') # mapping cycles f.create_dataset('c_map',shape=(0,3), maxshape=(None,3),dtype='int') # mapping (fmin,fmax,fstep) f.create_dataset('f_map',shape=(0,3), maxshape=(None,3),dtype='float64') # mapping Antenna name f.create_dataset('A_map',shape=(0,1), maxshape=(None,1),dtype="S10") # mapping rotation matrices Antenna f.create_dataset('T_map',shape=(0,3,3), maxshape=(None,3,3),dtype='float64') f.close() except: f.close() raise NameError('Links: issue when initializing h5py file') def stack(self,key,array): """ stack new array in h5py file for a given key (dataframe/group) Parameters ---------- key : string array : np.ndarray Returns ------- idx : int indice of last element of the array of key """ try : lfilename=pyu.getlong(self.filename,pstruc['DIRLNK']) f=h5py.File(lfilename,'a') if key != 'T_map': sc = f[key].shape f[key].resize((sc[0]+1,sc[1])) f[key][-1,:]=array else: sc = f[key].shape f[key].resize((sc[0]+1,sc[1],sc[2])) f[key][-1,:,:]=array f.close() return np.array([sc[0]]) except: f.close() raise NameError('Link stack: issue during stacking') def _delete(self,key,grpname): """ Delete a key and associated data into h5py file Parameters ---------- key : string key of the h5py file grpname : string groupe name of the h5py file """ lfilename=pyu.getlong(self.filename,pstruc['DIRLNK']) f=h5py.File(lfilename,'a') # try/except to avoid loosing the h5 file if # read/write error try: del f[key][grpname] # print 'delete ',key , ' in ', grpname f.close() except: f.close() raise NameError('Link._delete: issue when deleting in h5py file') def save(self,obj,key,grpname,force=False): """ Save a given object in the correct group Parameters ---------- obj : Object (Signatures|Rays|Ctilde|Tchannel) key : string key of the h5py file gpname : string groupe name of the h5py file """ if not force : obj._saveh5(self.filename,grpname) # if save is forced, previous existing data are removed and # replaced by new ones. else : if self.dexist[key]['exist']: self._delete(key,grpname) obj._saveh5(self.filename,grpname) if self.verbose : print str(obj.__class__).split('.')[-1] + ' from '+ grpname + ' saved' def load(self,obj,grpname): """ Load a given object in the correct grp Parameters ---------- obj : Object (Signatures|Rays|Ctilde|Tchannel) grpname : string groupe name of the h5py file Examples -------- """ obj._loadh5(self.filename,grpname) if self.verbose : print str(obj.__class__).split('.')[-1] + ' from '+ grpname + ' loaded' def get_grpname(self): """ Determine the data group name for the given configuration Notes ----- Update the key grpname of self.dexist[key] dictionnary, where key = 'sig'|'ray'|'Ct'|'H' """ ############ # Signatures ############ array = np.array(([self.ca,self.cb,self.cutoff])) ua_opt, ua = self.get_idx('c_map',array) grpname = str(self.ca) + '_' +str(self.cb) + '_' + str(self.cutoff) self.dexist['sig']['grpname']=grpname ############ # Rays ############# # check existence of self.a in h5py file ua_opt, ua = self.get_idx('p_map',self.a) # check existence of self.b in h5py file ub_opt, ub = self.get_idx('p_map',self.b) # Write in h5py if no prior a-b link grpname = str(self.cutoff) + '_' + str(ua) + '_' +str(ub) self.dexist['ray']['grpname']=grpname ############ # Ctilde ############# # check existence of frequency in h5py file #farray = np.array(([self.fmin,self.fmax,self.fstep])) Nf = len(self.fGHz) if Nf > 1: farray = np.array(([self.fGHz[0],self.fGHz[-1],self.fGHz[1]-self.fGHz[0]])) else: farray = np.array(([self.fGHz[0],self.fGHz[-1],0])) uf_opt, uf = self.get_idx('f_map',farray) grpname = str(ua) + '_' + str(ub) + '_' + str(uf) self.dexist['Ct']['grpname'] = grpname ############ # H ############# # check existence of Rot a (Ta) in h5py file uTa_opt, uTa = self.get_idx('T_map',self.Ta) # check existence of Rot b (Tb) in h5py file uTb_opt, uTb = self.get_idx('T_map',self.Tb) # check existence of Antenna a (Aa) in h5py file #uAa_opt, uAa = self.get_idx('A_map',self.Aa._filename) uAa_opt, uAa = self.get_idx('A_map',self.Aa.typ) # check existence of Antenna b (Ab) in h5py file uAb_opt, uAb = self.get_idx('A_map',self.Ab.typ) grpname = str(ua) + '_' + str(ub) + '_' + str(uf) + \ '_' + str(uTa) + '_' + str(uTb) + \ '_' + str(uAa) + '_' + str(uAb) self.dexist['H']['grpname'] = grpname def check_grpname(self,key,grpname): """Check if the key's data with a given groupname already exists in the h5py file Parameters ---------- key: string key of the h5py group grpname : string groupe name of the h5py file Notes ----- update the key grpname of self.dexist[key] dictionnary """ try : lfilename=pyu.getlong(self.filename,pstruc['DIRLNK']) f = h5py.File(lfilename,'r') if grpname.decode('utf8') in f[key].keys(): self.dexist[key]['exist']=True else : self.dexist[key]['exist']=False f.close() except: f.close() raise NameError('Link exist: issue during stacking') def get_idx(self,key,array,tol=1e-3): """ try to get the index of the requested array in the group key of the hdf5 file. If array doesn't exist, the hdf5file[key] array is stacked Parameters ---------- key: string key of the h5py group array : np.ndarray array to check existence tol : np.float64 tolerance (in meters for key == 'p_map') Returns ------- (u_opt, u): tuple u : np.ndarray the index in the array of the file[key] group u_opt : string ('r'|'s') return 'r' if array has been read into h5py file return 's' if array has been stacked into the array of group key See Also: -------- Links.array_exist """ umap = self.array_exist(key,array,tol=tol) lu = len(umap) # if exists take the existing one # otherwise value is created if lu != 0: u = umap u_opt='r' else : u = self.stack(key,array) u_opt='s' return u_opt,u[0] def array_exist(self,key,array,tol=1e-3) : """ check if an array of a given key (h5py group) has already been stored into the h5py file Parameters ---------- key: string key of the h5py group array : np.ndarray array type to check existency tol : np.float64 tolerance (in meter for key == 'p_map') Returns ------- (ua) ua : np.ndarray the indice in the array of the file[key] group if the array is emtpy, value doesn't exist TODO ---- Add a tolerance on the rotation angle (T_map) """ lfilename=pyu.getlong(self.filename,pstruc['DIRLNK']) try : f=h5py.File(lfilename,'a') fa = f[key][...] f.close() except: f.close() raise NameError('Link check_exist: issue during reading') if key == 'c_map': eq = array == fa # sum eq = 3 means cy0,cy1 and cutoff are the same in fa and array ua = np.where(np.sum(eq,axis=1)==3)[0] elif key == 'p_map': da = np.sqrt(np.sum((array-fa)**2,axis=1)) # indice points candidate in db for a ua = np.where(da<tol)[0] elif key == 'f_map': # fmin_h5 < fmin_rqst ufmi = np.where(fa[:,0]<=array[0])[0] lufmi = len(ufmi) # fmax_h5 > fmax_rqst ufma = np.where(fa[:,1]>=array[1])[0] lufma = len(ufma) # fstep_h5 < fstep_rqst ufst = np.where(fa[:,2]<=array[2])[0] lufst = len(ufst) # if fmin, fmax or fstep if (lufmi==0) and (lufma==0) and (lufst==0): ua = np.array([]) else : # find comon lines of fmin and fmax ufmima = np.where(np.in1d(ufmi,ufma))[0] # find comon lines of fmin, fmax and fstep ua = np.where(np.in1d(ufmima,ufst))[0] elif key == 'A_map': ua = np.where(fa==array)[0] elif key == 'T_map': eq = array == fa seq = np.sum(np.sum(eq,axis=1),axis=1) ua = np.where(seq==9)[0] else : raise NameError('Link.array_exist : invalid key') return ua def eval(self,**kwargs): """ evaluate the link Parameters ---------- applywav :boolean Apply waveform to H force : list Force the computation (['sig','ray','Ct','H']) AND save (replace previous computations) si_algo : str ('old'|'new') signature.run algo type 'old' : call propaths2 'new' : call procone2 alg : 5|7 version of run for signature si_mt: boolean Multi thread version of algo version 7 si_progress: bollean ( False) display progression bar for signatures diffraction : boolean (False) takes into consideration diffraction points ra_number_mirror_cf : int rays.to3D number of ceil/floor reflexions ra_ceil_H: float, (default []) ceil height . If [] : Layout max ceil height ra_vectorized: boolean (True) if True used the (2015 new) vectorized approach to determine 2drays Returns ------- ak : ndarray alpha_k tk : ndarray tau_k Notes ----- update self.ak and self.tk self.ak : ndarray alpha_k self.tk : ndarray tau_k Examples -------- .. plot:: :include-source: >>> from pylayers.simul.link import * >>> L=DLink(verbose=False) >>> aktk = L.eval() See Also -------- pylayers.antprop.signature pylayers.antprop.rays Experimental ------------ alg = 2015 | 20152 (best) vectorized signature research si_reverb : number of reverb in source/target cycle if alg=2015 """ defaults={ 'applywav':True, 'si_algo':'old', 'si_mt':False, 'si_progress':False, 'diffraction':True, 'ra_vectorized':True, 'ra_ceil_H':[], 'ra_number_mirror_cf':1, 'force':[], 'alg':7, 'si_reverb':4, 'threshold':0.1, 'verbose':[], } for key, value in defaults.items(): if key not in kwargs: kwargs[key]=value if 'cutoff' not in kwargs: kwargs['cutoff']=self.cutoff else: self.cutoff=kwargs['cutoff'] if 'force' in kwargs: if not isinstance(kwargs['force'],list): if kwargs['force'] == True : kwargs['force'] = ['sig','ray','Ct','H'] else : kwargs['force'] = [] if kwargs['verbose'] != []: self.verbose=kwargs['verbose'] # must be placed after all the init !!!! if self.verbose : print "checkh5" self.checkh5() ############ # Signatures ############ if self.verbose : print "Start Signatures" tic = time.time() Si = Signatures(self.L,self.ca,self.cb,cutoff=kwargs['cutoff']) if (self.dexist['sig']['exist'] and not ('sig' in kwargs['force'])): self.load(Si,self.dexist['sig']['grpname']) if self.verbose : print "load signature" else : if kwargs['alg']==2015: TMP=Si.run2015(cutoff=kwargs['cutoff'], cutoffbound=kwargs['si_reverb']) if self.verbose : print "algo 2015" if kwargs['alg']==20152: TMP=Si.run2015_2(cutoff=kwargs['cutoff'], cutoffbound=kwargs['si_reverb']) if self.verbose : print "algo 20152" if kwargs['alg']==5: Si.run5(cutoff=kwargs['cutoff'], algo=kwargs['si_algo'], diffraction=kwargs['diffraction'], progress=kwargs['si_progress']) if self.verbose : print "algo 5" if kwargs['alg']==7: if kwargs['si_mt']==7: Si.run7mt(cutoff=kwargs['cutoff'], algo=kwargs['si_algo'], diffraction=kwargs['diffraction'], threshold=kwargs['threshold'], progress=kwargs['si_progress']) if self.verbose : print "algo 7 , si_mt" else : Si.run7(cutoff=kwargs['cutoff'], algo=kwargs['si_algo'], diffraction=kwargs['diffraction'], threshold=kwargs['threshold'], progress=kwargs['si_progress']) if self.verbose : print "algo 7" #Si.run6(diffraction=kwargs['diffraction']) # save sig self.save(Si,'sig',self.dexist['sig']['grpname'],force = kwargs['force']) self.Si = Si toc = time.time() if self.verbose : print "Stop signature",toc-tic ############ # Rays ############ if self.verbose : print "Start Rays" tic = time.time() R = Rays(self.a,self.b) if self.dexist['ray']['exist'] and not ('ray' in kwargs['force']): self.load(R,self.dexist['ray']['grpname']) else : # perform computation ... # ... with vetorized ray evaluation approach if kwargs['ra_vectorized']: r2d = Si.raysv(self.a,self.b) # ... or with original and slow approach ( to be removed in a near future) else : r2d = Si.rays(self.a,self.b) if kwargs['ra_ceil_H'] == []: ceilheight = self.L.maxheight else: ceilheight = kwargs['ra_ceil_H'] R = r2d.to3D(self.L,H=ceilheight, N=kwargs['ra_number_mirror_cf']) R.locbas(self.L) # ...and save R.fillinter(self.L) C=Ctilde() C = R.eval(self.fGHz) self.save(R,'ray',self.dexist['ray']['grpname'],force = kwargs['force']) self.R = R toc = time.time() if self.verbose : print "Stop rays",toc-tic if self.R.nray == 0: raise NameError('No rays have been found. Try to re-run the simulation with a higher S.cutoff ') ############ # Ctilde ############ if self.dexist['Ct']['exist'] and not ('Ct' in kwargs['force']): C=Ctilde() self.load(C,self.dexist['Ct']['grpname']) else : if not hasattr(R,'I'): # Ctilde... C = R.eval(self.fGHz) # ...save Ct self.save(C,'Ct',self.dexist['Ct']['grpname'],force = kwargs['force']) self.C = C ############ # H ############ H = Tchannel() if self.dexist['H']['exist'] and not ('H' in kwargs['force']): self.load(H,self.dexist['H']['grpname']) else : # Ctilde antenna Cl=C.locbas(Tt=self.Ta, Tr=self.Tb) #T channel H = C.prop2tran(a=self.Aa,b=self.Ab,Friis=True,debug=True) self.save(H,'H',self.dexist['H']['grpname'],force = kwargs['force']) self.H = H if kwargs['applywav']: if self.H.isFriis: self.ir = self.H.get_cir(self.wav.sf) else: self.ir = self.H.get_cir(self.wav.sfg) return self.H.ak, self.H.tk def show(self,**kwargs): """ show the link Parameters ---------- s : int ca : string color a cb : string color b alpha : int figsize : tuple (20,10) fontsize : int 20 rays : boolean False cmap : colormap labels : boolean enabling edge label (useful for signature identification) pol : string 'tt','pp','tp','pt','co','cross',tot' col : string 'cmap' width : float alpha : float dB : boolean default False dyn : float dynamic in dB Examples -------- >>> from pylayers.simul.link import * >>> L=Link() >>> L.show(rays=True,dB=True) """ defaults ={'s':80, 'ca':'b', 'cb':'r', 'alpha':1, 'i':-1, 'figsize':(20,10), 'fontsize':20, 'rays':False, 'cmap':plt.cm.hot, 'pol':'tot', 'col':'k', 'width':1, 'alpha':1, 'col':'k', 'dB':False, 'labels':False, 'dyn':70} for key in defaults: if key not in kwargs: kwargs[key]=defaults[key] # # Layout # fig,ax = self.L.showG('s',nodes=False,figsize=kwargs['figsize'],labels=kwargs['labels']) plt.axis('off') # # Point A # ax.scatter(self.a[0], self.a[1], c=kwargs['ca'], s=kwargs['s'], alpha=kwargs['alpha']) ax.text(self.a[0]+0.1,self.a[1]+0.1,'A',fontsize=kwargs['fontsize']) # # Point B # ax.scatter(self.b[0], self.b[1], c=kwargs['cb'], s=kwargs['s'], alpha=kwargs['alpha']) ax.text(self.b[0]-0.1,self.b[1]+0.1,'B',fontsize=kwargs['fontsize']) # # Rays # if kwargs['rays']: ECtt,ECpp,ECtp,ECpt = self.C.energy() if kwargs['pol']=='tt': val = ECtt if kwargs['pol']=='pp': val = ECpp if kwargs['pol']=='tp': val = ECtp if kwargs['pol']=='pt': val = ECpt if kwargs['pol']=='tot': val = ECtt+ECpp+ECpt+ECtp if kwargs['pol']=='co': val = ECtt+ECpp if kwargs['pol']=='cross': val = ECtp+ECpt clm = kwargs['cmap'] # # Select group of interactions # if kwargs['i']==-1: li = self.R.keys() else: li = kwargs['i'] for i in li: lr = self.R[i]['rayidx'] for r in range(len(lr)): ir = lr[r] try: if kwargs['dB']: RayEnergy=max((20*np.log10(val[ir]/val.max())+kwargs['dyn']),0)/kwargs['dyn'] else: RayEnergy=val[ir]/val.max() except: pass if kwargs['col']=='cmap': col = clm(RayEnergy) width = RayEnergy alpha = 1 #alpha = RayEnergy else: col = kwargs['col'] width = kwargs['width'] alpha = kwargs['alpha'] fig,ax = self.R.show(i=i,r=r, colray=col, widthray=width, alpharay=alpha, fig=fig,ax=ax, layout=False, points=False) return fig,ax def _show3(self,rays=True, lay= True, ant= True, newfig= False, **kwargs): """ display the simulation scene using Mayavi using Mayavi Parameters ---------- rays: Ray3d object : display the rays of the simulation newfig : boolean (default : False) kwargs of Rays.show3() see also -------- pylayers.gis.layout pylayers.antprop.antenna pylayers.antprop.rays Examples -------- >>> from pylayers.simul.link import * >>> L=DLink(verbose=False) >>> aktk = L.eval() """ if not newfig: f=mlab.gcf() if 'centered' in kwargs: centered = kwargs['centered'] else : centered = False if centered: pg =np.zeros((3)) pg[:2]=self.L.pg if centered : ptx = self.tx.position-pg prx = self.rx.position-pg else : ptx = self.tx.position prx = self.rx.position if ant : Atx = self.Aa Arx = self.Ab Ttx = self.tx.orientation Trx = self.rx.orientation # evaluate antenna if required if not Atx.evaluated: Atx.eval() try: Atx._show3(T=Ttx.reshape(3,3),po=ptx, title=False,colorbar=False,newfig=False) except: Atx.eval() Atx._show3(T=Ttx.reshape(3,3),po=ptx, title=False,colorbar=False,newfig=False) if not Arx.evaluated: Arx.eval() try: Arx._show3(T=Trx.reshape(3,3),po=prx, title=False,colorbar=False,newfig=False,name = '') except: Arx.eval() Arx._show3(T=Trx.reshape(3,3),po=prx, title=False,colorbar=False,newfig=False,name = '') if lay: self.L._show3(newfig=False,opacity=0.7,centered=centered,**kwargs) # mlab.text3d(self.a[0],self.a[1],self.a[2],'a', # scale=1, # color=(1,0,0)) # mlab.text3d(self.b[0],self.b[1],self.b[2],'b', # scale=1, # color=(1,0,0)) if rays : # check rays with energy # if hasattr(self,'H') and not kwargs.has_key('rlist'): # urays = np.where(self.H.y!=0)[0] # kwargs['rlist']=urays # import ipdb # ipdb.set_trace() try: self.R._show3(**kwargs) except: print 'Rays not computed yet'
def eval(self,**kwargs): """ evaluate the link Parameters ---------- applywav :boolean Apply waveform to H force : list Force the computation (['sig','ray','Ct','H']) AND save (replace previous computations) si_algo : str ('old'|'new') signature.run algo type 'old' : call propaths2 'new' : call procone2 alg : 5|7 version of run for signature si_mt: boolean Multi thread version of algo version 7 si_progress: bollean ( False) display progression bar for signatures diffraction : boolean (False) takes into consideration diffraction points ra_number_mirror_cf : int rays.to3D number of ceil/floor reflexions ra_ceil_H: float, (default []) ceil height . If [] : Layout max ceil height ra_vectorized: boolean (True) if True used the (2015 new) vectorized approach to determine 2drays Returns ------- ak : ndarray alpha_k tk : ndarray tau_k Notes ----- update self.ak and self.tk self.ak : ndarray alpha_k self.tk : ndarray tau_k Examples -------- .. plot:: :include-source: >>> from pylayers.simul.link import * >>> L=DLink(verbose=False) >>> aktk = L.eval() See Also -------- pylayers.antprop.signature pylayers.antprop.rays Experimental ------------ alg = 2015 | 20152 (best) vectorized signature research si_reverb : number of reverb in source/target cycle if alg=2015 """ defaults={ 'applywav':True, 'si_algo':'old', 'si_mt':False, 'si_progress':False, 'diffraction':True, 'ra_vectorized':True, 'ra_ceil_H':[], 'ra_number_mirror_cf':1, 'force':[], 'alg':7, 'si_reverb':4, 'threshold':0.1, 'verbose':[], } for key, value in defaults.items(): if key not in kwargs: kwargs[key]=value if 'cutoff' not in kwargs: kwargs['cutoff']=self.cutoff else: self.cutoff=kwargs['cutoff'] if 'force' in kwargs: if not isinstance(kwargs['force'],list): if kwargs['force'] == True : kwargs['force'] = ['sig','ray','Ct','H'] else : kwargs['force'] = [] if kwargs['verbose'] != []: self.verbose=kwargs['verbose'] # must be placed after all the init !!!! if self.verbose : print "checkh5" self.checkh5() ############ # Signatures ############ if self.verbose : print "Start Signatures" tic = time.time() Si = Signatures(self.L,self.ca,self.cb,cutoff=kwargs['cutoff']) if (self.dexist['sig']['exist'] and not ('sig' in kwargs['force'])): self.load(Si,self.dexist['sig']['grpname']) if self.verbose : print "load signature" else : if kwargs['alg']==2015: TMP=Si.run2015(cutoff=kwargs['cutoff'], cutoffbound=kwargs['si_reverb']) if self.verbose : print "algo 2015" if kwargs['alg']==20152: TMP=Si.run2015_2(cutoff=kwargs['cutoff'], cutoffbound=kwargs['si_reverb']) if self.verbose : print "algo 20152" if kwargs['alg']==5: Si.run5(cutoff=kwargs['cutoff'], algo=kwargs['si_algo'], diffraction=kwargs['diffraction'], progress=kwargs['si_progress']) if self.verbose : print "algo 5" if kwargs['alg']==7: if kwargs['si_mt']==7: Si.run7mt(cutoff=kwargs['cutoff'], algo=kwargs['si_algo'], diffraction=kwargs['diffraction'], threshold=kwargs['threshold'], progress=kwargs['si_progress']) if self.verbose : print "algo 7 , si_mt" else : Si.run7(cutoff=kwargs['cutoff'], algo=kwargs['si_algo'], diffraction=kwargs['diffraction'], threshold=kwargs['threshold'], progress=kwargs['si_progress']) if self.verbose : print "algo 7" #Si.run6(diffraction=kwargs['diffraction']) # save sig self.save(Si,'sig',self.dexist['sig']['grpname'],force = kwargs['force']) self.Si = Si toc = time.time() if self.verbose : print "Stop signature",toc-tic ############ # Rays ############ if self.verbose : print "Start Rays" tic = time.time() R = Rays(self.a,self.b) if self.dexist['ray']['exist'] and not ('ray' in kwargs['force']): self.load(R,self.dexist['ray']['grpname']) else : # perform computation ... # ... with vetorized ray evaluation approach if kwargs['ra_vectorized']: r2d = Si.raysv(self.a,self.b) # ... or with original and slow approach ( to be removed in a near future) else : r2d = Si.rays(self.a,self.b) if kwargs['ra_ceil_H'] == []: ceilheight = self.L.maxheight else: ceilheight = kwargs['ra_ceil_H'] R = r2d.to3D(self.L,H=ceilheight, N=kwargs['ra_number_mirror_cf']) R.locbas(self.L) # ...and save R.fillinter(self.L) C=Ctilde() C = R.eval(self.fGHz) self.save(R,'ray',self.dexist['ray']['grpname'],force = kwargs['force']) self.R = R toc = time.time() if self.verbose : print "Stop rays",toc-tic if self.R.nray == 0: raise NameError('No rays have been found. Try to re-run the simulation with a higher S.cutoff ') ############ # Ctilde ############ if self.dexist['Ct']['exist'] and not ('Ct' in kwargs['force']): C=Ctilde() self.load(C,self.dexist['Ct']['grpname']) else : if not hasattr(R,'I'): # Ctilde... C = R.eval(self.fGHz) # ...save Ct self.save(C,'Ct',self.dexist['Ct']['grpname'],force = kwargs['force']) self.C = C ############ # H ############ H = Tchannel() if self.dexist['H']['exist'] and not ('H' in kwargs['force']): self.load(H,self.dexist['H']['grpname']) else : # Ctilde antenna Cl=C.locbas(Tt=self.Ta, Tr=self.Tb) #T channel H = C.prop2tran(a=self.Aa,b=self.Ab,Friis=True,debug=True) self.save(H,'H',self.dexist['H']['grpname'],force = kwargs['force']) self.H = H if kwargs['applywav']: if self.H.isFriis: self.ir = self.H.get_cir(self.wav.sf) else: self.ir = self.H.get_cir(self.wav.sfg) return self.H.ak, self.H.tk
def eval(self,**kwargs): """ Evaluate the link Parameters ---------- force : boolean Force the computation (even if obj already exists) AND save (replace previous computations) si_algo : str ('old'|'new') signature.run algo type ra_ceil_height_meter : int rays.to3D ceil height in meters ra_number_mirror_cf : int rays.to3D number of ceil/floor reflexions Returns ------- ak : ndarray alpha_k tk : ndarray tau_k Notes ----- update self.ak and self.tk self.ak : ndarray alpha_k self.tk : ndarray tau_k Examples -------- .. plot:: :include-source: >>> from pylayers.simul.link import * >>> L=DLink(verbose=False) >>> aktk = L.eval() See Also -------- pylayers.antprop.signature pylayers.antprop.rays """ defaults={ 'output':['sig','ray','Ct','H'], 'si_algo':'old', 'diffraction':False, 'ra_ceil_height_meter':3, 'ra_number_mirror_cf':1, 'force':False, 'alg':7, 'threshold':0.1, } for key, value in defaults.items(): if key not in kwargs: kwargs[key]=value self.checkh5() if 'cutoff' not in kwargs: kwargs['cutoff']=self.cutoff ############ # Signatures ############ Si = Signatures(self.L,self.ca,self.cb,cutoff=kwargs['cutoff']) if self.dexist['sig']['exist'] and not kwargs['force']: self.load(Si,self.dexist['sig']['grpname']) else : if kwargs['alg']==5: Si.run5(cutoff=kwargs['cutoff'],algo=kwargs['si_algo'],diffraction=kwargs['diffraction']) if kwargs['alg']==7: Si.run7(cutoff=kwargs['cutoff'], algo=kwargs['si_algo'], diffraction=kwargs['diffraction'], threshold=kwargs['threshold']) #Si.run6(diffraction=kwargs['diffraction']) # save sig self.save(Si,'sig',self.dexist['sig']['grpname'],force = kwargs['force']) self.Si = Si ############ # Rays ############ R = Rays(self.a,self.b) if self.dexist['ray']['exist'] and not kwargs['force']: self.load(R,self.dexist['ray']['grpname']) else : # perform computation ... r2d = Si.rays(self.a,self.b) R = r2d.to3D(self.L,H=kwargs['ra_ceil_height_meter'], N=kwargs['ra_number_mirror_cf']) R.locbas(self.L) # ...and save self.save(R,'ray',self.dexist['ray']['grpname'],force = kwargs['force']) self.R = R if self.R.nray == 0: raise NameError('No rays have been found. Try to re-run the simulation with a higher S.cutoff ') ############ # Ctilde ############ C=Ctilde() if self.dexist['Ct']['exist'] and not kwargs['force']: self.load(C,self.dexist['Ct']['grpname']) else : R.fillinter(self.L) # Ctilde... C = R.eval(self.fGHz) # ...save Ct self.save(C,'Ct',self.dexist['Ct']['grpname'],force = kwargs['force']) self.C = C ############ # H ############ H=Tchannel() if self.dexist['H']['exist'] and not kwargs['force']: self.load(H,self.dexist['H']['grpname']) else : # Ctilde antenna Cl=C.locbas(Tt=self.Ta, Tr=self.Tb) #T channel H = C.prop2tran(a=self.Aa,b=self.Ab,Friis=True) self.save(H,'H',self.dexist['H']['grpname'],force = kwargs['force']) self.H = H return self.H.ak, self.H.tk
class DLink(Link): def __init__(self, **kwargs): """ deterministic link evaluation Parameters ---------- L : Layout Layout to be used a : np.ndarray (3,) position of a device dev_a b : np.ndarray (3,) position of a device dev_b Aa : Antenna Antenna of device dev_a Ab : Antenna Antenna of device dev_b Ta : np.ndarray (3,3) Rotation matrice of Antenna of device dev_a relative to global Layout scene Tb : np.ndarray (3,3) Rotation matrice of Antenna of device dev_b relative to global Layout scene fGHz : np.ndarray (Nf,) frequency range of Nf points used for evaluation of channel wav : Waveform Waveform to be applied on the channel save_idx : int number to identify the h5 file generated Advanced (change only if you really know what you do !) save_opt : list (['sig','ray','Ct','H']) information to be saved in the Links h5 file. Should never be Modified ! force_create : Boolean (False) forcecreating the h5py file (if already exist, will be erased) Notes ----- All simulations are stored into a unique file in your <PyProject>/output directory using the following convention: Links_<save_idx>_<LayoutFilename>.h5 where <save_idx> is an integer number to distinguish different links simulations and <LayoutFilename> is the Layout used for the link simulation. Dataset organisation: Links_<idx>_<Layout_name>.h5 | |/sig/si_ID#0/ | /si_ID#1/ | ... | |/ray/ray_ID#0/ | /ray_ID#1/ | ... | |/Ct/Ct_ID#0/ | /Ct_ID#1/ | ... | |/H/H_ID#0/ | /H_ID#1/ | ... | | |p_map |c_map |f_map |A_map |T_map Roots Dataset : c_map : Cycles (Nc x 3) p_map : Positions (Np x 3) f_map : Frequency (Nf x 3) T_map : Rotation matrices (Nt x 3) A_map : Antenna name (Na x 3) Groups and subgroups: Signature identifier (si_ID#N): ca_cb_cutoff Ray identifier (ray_ID#N): cutoff_ua_ub Ctilde identifier (Ct_ID#N): ua_ub_uf H identifier (H_ID#N): ua_ub_uf_uTa_uTb_uAa_uAb with ca : cycle number of a cb : cycle number of b cutoff : signature.run cutoff ua : indice of a position in 'p_map' position dataset ub : indice of a position in 'p_map' position dataset uf : indice of freq position in 'f_map' frequency dataset uTa : indice of a position in 'T_map' Rotation dataset uTb : indice of a position in 'T_map' Rotation dataset uAa : indice of a position in 'A_map' Antenna name dataset uAb : indice of b position in 'A_map' Antenna name dataset Examples -------- >>> from pylayers.simul.link import * >>> L = DLink(verbose=False) >>> aktk = L.eval() """ Link.__init__(self) defaults={ 'L':Layout('defstr.ini'), 'a':np.array(()), 'b':np.array(()), 'Aa':[], 'Ab':[], 'Ta':np.eye(3), 'Tb':np.eye(3), 'fGHz':[], 'wav':wvf.Waveform(), 'cutoff':3, 'save_opt':['sig','ray','Ct','H'], 'save_idx':0, 'force_create':False, 'verbose':False, 'graph':'tcvirw' } self._ca=-1 self._cb=-1 specset = ['a','b','Aa','Ab','Ta','Tb','L','fGHz','wav'] # set default attribute for key, value in defaults.items(): if key not in kwargs: if key in specset : setattr(self,'_'+key,value) else : setattr(self,key,value) else : if key in specset : setattr(self,'_'+key,kwargs[key]) else : setattr(self,key,kwargs[key]) force=self.force_create delattr(self,'force_create') # The frequency range is dependent from the antenna frequency range if self.fGHz == []: self.initfreq() else : pass if self.Aa==[]: self.Aa=Antenna(typ='Omni',fGHz=self.fGHz) if self.Ab==[]: self.Ab=Antenna(typ='Omni',fGHz=self.fGHz) self._Lname = self._L._filename self.filename = 'Links_' + str(self.save_idx) + '_' + self._Lname + '.h5' filenameh5 = pyu.getlong(self.filename,pstruc['DIRLNK']) # check if save file alreasdy exists if not os.path.exists(filenameh5) or force: print 'Links save file for ' + self.L.filename + ' does not exist.' print 'Creating file. You\'ll see this message only once per Layout' self.save_init(filenameh5) # dictionnary data exists self.dexist={'sig':{'exist':False,'grpname':''}, 'ray':{'exist':False,'grpname':''}, 'Ct':{'exist':False,'grpname':''}, 'H':{'exist':False,'grpname':''} } try: self.L.dumpr() except: print('This is the first time the Layout is used. Graphs have to be built. Please Wait') self.L.build(graph=self.graph) self.L.dumpw() #self.L.build() ########### # init pos & cycles # # If a and b are not specified # they are chosen as center of gravity of cycle 0 # ########### if len(self.a)==0: self.ca = 1 # self.a = self.L.cy2pt(self.ca) else: if len(kwargs['a']) ==2: a=np.r_[kwargs['a'],1.0] else: a=kwargs['a'] self.a = a # self.ca = self.L.pt2cy(self.a) if len(self.b)==0: if len(self.L.Gt.node)>2: self.cb = 2 else: self.cb = 1 # self.b = self.L.cy2pt(self.cb) else: if len(kwargs['b']) ==2: b=np.r_[kwargs['b'],1.0] else: b=kwargs['b'] self.b = b # self.cb = self.L.pt2cy(self.b) ########### # init freq # TODO Check where it is used redocdundant with fGHz ########### #self.fmin = self.fGHz[0] #self.fmax = self.fGHz[-1] #self.fstep = self.fGHz[1]-self.fGHz[0] self.Si = Signatures(self.L,self.ca,self.cb,cutoff=self.cutoff) self.R = Rays(self.a,self.b) self.C = Ctilde() self.H = Tchannel() @property def Lname(self): return self._Lname @property def L(self): return self._L @property def a(self): return self._a @property def b(self): return self._b @property def ca(self): return self._ca @property def cb(self): return self._cb @property def Aa(self): return self._Aa @property def Ab(self): return self._Ab @property def Ta(self): return self._Ta @property def Tb(self): return self._Tb @property def fGHz(self): return self._fGHz @property def wav(self): return self._wav @L.setter def L(self,L): # change layout and build/load plotfig=False if hasattr(self,'_maya_fig') and self._maya_fig._is_running: mlab.clf() plotfig=True if isinstance(L,str): self._L = Layout(L) self._Lname = L elif isinstance(L,Layout): self._L = L self._Lname = L.filename self.reset_config() if plotfig: self._show3() @Lname.setter def Lname(self,Lname): # change layout and build/load if hasattr(self,'_maya_fig') and self._maya_fig._is_running: mlab.clf() self._L = Layout(Lname) self._Lname = Lname self.reset_config() @a.setter def a(self,position): if not self.L.ptin(position): if position[0]<self.L.ax[0]: position[0]=self.L.ax[0] if position[0]>self.L.ax[1]: position[0]=self.L.ax[1] if position[1]<self.L.ax[2]: position[1]=self.L.ax[2] if position[1]>self.L.ax[3]: position[1]=self.L.ax[3] # raise NameError ('Warning : point a is not inside the Layout') # raise NameError ('Warning : point a is not inside the Layout') if not self.L.pt2cy(position) == self.ca: self.ca = self.L.pt2cy(position) self._a = position if hasattr(self,'_maya_fig') and self._maya_fig._is_running: self._update_show3(ant='a',delrays=True) @b.setter def b(self,position): if not self.L.ptin(position): if position[0]<self.L.ax[0]: position[0]=self.L.ax[0] if position[0]>self.L.ax[1]: position[0]=self.L.ax[1] if position[1]<self.L.ax[2]: position[1]=self.L.ax[2] if position[1]>self.L.ax[3]: position[1]=self.L.ax[3] # raise NameError ('Warning : point b is not inside the Layout') if not self.L.pt2cy(position) == self.cb: self.cb = self.L.pt2cy(position) self._b = position if hasattr(self,'_maya_fig') and self._maya_fig._is_running: self._update_show3(ant='b',delrays=True) @ca.setter def ca(self,cycle): if not cycle in self.L.Gt.nodes(): raise NameError ('cycle ca is not inside Gt') self._ca = cycle self.a = self.L.cy2pt(cycle) @cb.setter def cb(self,cycle): if not cycle in self.L.Gt.nodes(): raise NameError ('cycle cb is not inside Gt') self._cb = cycle self.b = self.L.cy2pt(cycle) @Aa.setter def Aa(self,Ant): if hasattr(self.Aa,'_mayamesh'): self.Aa._mayamesh.remove() # save rot rot = self.Ta self._Aa = Ant self.Ta = rot self.initfreq() if hasattr(self,'_maya_fig') and self._maya_fig._is_running: self._update_show3(ant='a') @Ab.setter def Ab(self,Ant): if hasattr(self.Ab,'_mayamesh'): self.Ab._mayamesh.remove() # save rot rot = self.Tb self._Ab = Ant self.Tb = rot self.initfreq() if hasattr(self,'_maya_fig') and self._maya_fig._is_running: self._update_show3(ant='b') @Ta.setter def Ta(self,orientation): self._Ta = orientation if hasattr(self,'_maya_fig') and self._maya_fig._is_running: self._update_show3(ant='a') @Tb.setter def Tb(self,orientation): self._Tb = orientation if hasattr(self,'_maya_fig') and self._maya_fig._is_running: self._update_show3(ant='b') @fGHz.setter def fGHz(self,freq): if not isinstance(freq,np.ndarray): freq=np.array([freq]) self._fGHz = freq # if self.Aa.typ == 'Omni': # self.Aa.fGHz = self.fGHz # if self.Ab.typ == 'Omni': # self.Ab.fGHz = self.fGHz #if len(freq)>1: # self.fmin = freq[0] # self.fmax = freq[-1] # self.fstep = freq[1]-freq[0] #else: # self.fmin = freq # self.fmax = freq # self.step = 0 @wav.setter def wav(self,waveform): self._wav = waveform if 'H' in dir(self): if len(self.H.taud[0])!=0: self.chanreal = self.H.get_cir(self.wav.sfg) def __repr__(self): """ __repr__ """ s = 'filename: ' + self.filename +'\n' s = s + 'Link Parameters :\n' s = s + '------- --------\n' s = s + 'Layout : ' + self.Lname + '\n\n' s = s + 'Node a \n' s = s + '------ \n' s = s + 'position : ' + str (self.a) + '\n' s = s + 'Antenna : ' + str (self.Aa.typ) + '\n' s = s + 'Rotation matrice : \n ' + str (self.Ta) + '\n\n' s = s + 'Node b \n' s = s + '------ \n' s = s + 'position : ' + str (self.b) + '\n' s = s + 'Antenna : ' + str (self.Ab.typ) + '\n' s = s + 'Rotation matrice : \n ' + str (self.Tb) + '\n\n' s = s + 'Link evaluation information : \n' s = s + '----------------------------- \n' s = s + 'distance : ' + str("%6.3f" % np.sqrt(np.sum((self.a-self.b)**2))) + ' m \n' s = s + 'delay : ' + str("%6.3f" % (np.sqrt(np.sum((self.a-self.b)**2))/0.3)) + ' ns\n' #s = s + 'Frequency range : \n' s = s + 'fmin (fGHz) : ' + str(self.fGHz[0]) +'\n' s = s + 'fmax (fGHz) : ' + str(self.fGHz[-1]) +'\n' Nf = len(self.fGHz) if Nf>1: s = s + 'fstep (fGHz) : ' + str(self.fGHz[1]-self.fGHz[0]) +'\n' else: s = s + 'fstep (fGHz) : ' + str(self.fGHz[0]-self.fGHz[0]) +'\n' s = s + 'Nf : ' + str(Nf) +'\n ' d = np.sqrt(np.sum((self.a-self.b)**2)) if Nf>1: fcGHz = (self.fGHz[-1]+self.fGHz[0])/2. else: fcGHz = self.fGHz[0] L = 32.4+20*np.log(d)+20*np.log10(fcGHz) return s def initfreq(self): """ Automatic freq determination from Antennas """ #sf = self.fGHz[1]-self.fGHz[0] sf = 1e15 if hasattr(self.Aa,'fGHz'): fa = self.Aa.fGHz if len(fa)==0: fa = np.array([2.4]) self.Aa.fGHz = fa # raise AttributeError("Incompatible frequency range in Antenna. Consider change Dlink.fGHz") print "Incompatible frequency range in Antenna. WARNING Dlink.fGHz changed to 2.4GHz" try: sa = fa[1]-fa[0] # step frequecy except: #single frequency sa = fa[0] # step if len(self.fGHz)>0: minfa = max(min(fa),min(self.fGHz)) maxfa = min(max(fa),max(self.fGHz)) else: minfa = min(fa) maxfa = max(fa) sf = min(sa,sf) self.fGHz = np.arange(minfa,maxfa+sf,sf) elif hasattr(self.Ab,'fGHz'): fb = self.Ab.fGHz if len(fb)==0: # raise AttributeError("Incompatible frequency range in Antenna. Consider change Dlink.fGHz") fb = np.array([2.4]) self.Ab.fGHz=fb # raise AttributeError("Incompatible frequency range in Antenna. Consider change Dlink.fGHz") print "Incompatible frequency range in Antenna. WARNING Dlink.fGHz changed to 2.4GHz" try: sb = fb[1]-fb[0] # step frequency except: sb = fb[0] if len(self.fGHz)>0: minfb = max(min(self.fGHz),min(fb)) maxfb = min(max(self.fGHz),max(fb)) else: minfb = min(fb) maxfb = max(fb) sf = min(sf,sb) self.fGHz = np.arange(minfb,maxfb+sf,sf) else: self.fGHz = np.array([2.3,2.4,2.5]) def reset_config(self): """ reset configuration when a new layout is loaded """ try: self.L.dumpr() except: self.L.build() self.L.dumpw() self.ca = 1 self.cb = 1 # self.a = self.L.cy2pt(self.ca) # self.b = self.L.cy2pt(self.cb) # change h5py file if layout changed self.filename = 'Links_' + str(self.save_idx) + '_' + self._Lname + '.h5' filenameh5 = pyu.getlong(self.filename,pstruc['DIRLNK']) if not os.path.exists(filenameh5) : print 'Links save file for ' + self.L.filename + ' does not exist.' print 'It is beeing created. You\'ll see that message only once per Layout' self.save_init(filenameh5) try: delattr(self,'Si') except: pass try: delattr(self,'R') except: pass try: delattr(self,'C') except: pass try: delattr(self,'H') except: pass def checkh5(self): """ check existence of previous simulations run with the same parameters. Returns ------- update self.dexist dictionnary """ # get identifier group name in h5py file self.get_grpname() # check if group name exists in the h5py file [self.check_grpname(k,self.dexist[k]['grpname']) for k in self.save_opt] def save_init(self,filename_long): """ initialize save Link Parameters ---------- filename_long : str complete path and filename """ f=h5py.File(filename_long,'w') # try/except to avoid loosing the h5 file if # read/write error try: f.create_group('sig') f.create_group('ray') f.create_group('Ct') f.create_group('H') # mapping point a f.create_dataset('p_map',shape=(0,3), maxshape=(None,3),dtype='float64') # mapping cycles f.create_dataset('c_map',shape=(0,3), maxshape=(None,3),dtype='int') # mapping (fmin,fmax,fstep) f.create_dataset('f_map',shape=(0,3), maxshape=(None,3),dtype='float64') # mapping Antenna name f.create_dataset('A_map',shape=(0,1), maxshape=(None,1),dtype="S10") # mapping rotation matrices Antenna f.create_dataset('T_map',shape=(0,3,3), maxshape=(None,3,3),dtype='float64') f.close() except: f.close() raise NameError('Links: issue when initializing h5py file') def stack(self,key,array): """ stack new array in h5py file for a given key (dataframe/group) Parameters ---------- key : string array : np.ndarray Returns ------- idx : int indice of last element of the array of key """ try : lfilename=pyu.getlong(self.filename,pstruc['DIRLNK']) f=h5py.File(lfilename,'a') if key != 'T_map': sc = f[key].shape f[key].resize((sc[0]+1,sc[1])) f[key][-1,:]=array else: sc = f[key].shape f[key].resize((sc[0]+1,sc[1],sc[2])) f[key][-1,:,:]=array f.close() return np.array([sc[0]]) except: f.close() raise NameError('Link stack: issue during stacking') def _delete(self,key,grpname): """ Delete a key and associated data into h5py file Parameters ---------- key : string key of the h5py file grpname : string groupe name of the h5py file """ lfilename=pyu.getlong(self.filename,pstruc['DIRLNK']) f=h5py.File(lfilename,'a') # try/except to avoid loosing the h5 file if # read/write error try: del f[key][grpname] # print 'delete ',key , ' in ', grpname f.close() except: f.close() raise NameError('Link._delete: issue when deleting in h5py file') def save(self,obj,key,grpname,force=False): """ Save a given object in the correct group Parameters ---------- obj : Object (Signatures|Rays|Ctilde|Tchannel) key : string key of the h5py file gpname : string groupe name of the h5py file """ if not force : obj._saveh5(self.filename,grpname) # if save is forced, previous existing data are removed and # replaced by new ones. else : if self.dexist[key]['exist']: self._delete(key,grpname) obj._saveh5(self.filename,grpname) if self.verbose : print str(obj.__class__).split('.')[-1] + ' from '+ grpname + ' saved' def load(self,obj,grpname): """ Load a given object in the correct grp Parameters ---------- obj : Object (Signatures|Rays|Ctilde|Tchannel) grpname : string groupe name of the h5py file Examples -------- """ obj._loadh5(self.filename,grpname) if self.verbose : print str(obj.__class__).split('.')[-1] + ' from '+ grpname + ' loaded' def get_grpname(self): """ Determine the data group name for the given configuration Notes ----- Update the key grpname of self.dexist[key] dictionnary, where key = 'sig'|'ray'|'Ct'|'H' """ ############ # Signatures ############ array = np.array(([self.ca,self.cb,self.cutoff])) ua_opt, ua = self.get_idx('c_map',array) grpname = str(self.ca) + '_' +str(self.cb) + '_' + str(self.cutoff) self.dexist['sig']['grpname']=grpname ############ # Rays ############# # check existence of self.a in h5py file ua_opt, ua = self.get_idx('p_map',self.a) # check existence of self.b in h5py file ub_opt, ub = self.get_idx('p_map',self.b) # Write in h5py if no prior a-b link grpname = str(self.cutoff) + '_' + str(ua) + '_' +str(ub) self.dexist['ray']['grpname']=grpname ############ # Ctilde ############# # check existence of frequency in h5py file #farray = np.array(([self.fmin,self.fmax,self.fstep])) Nf = len(self.fGHz) if Nf > 1: farray = np.array(([self.fGHz[0],self.fGHz[-1],self.fGHz[1]-self.fGHz[0]])) else: farray = np.array(([self.fGHz[0],self.fGHz[-1],0])) uf_opt, uf = self.get_idx('f_map',farray) grpname = str(ua) + '_' + str(ub) + '_' + str(uf) self.dexist['Ct']['grpname'] = grpname ############ # H ############# # check existence of Rot a (Ta) in h5py file uTa_opt, uTa = self.get_idx('T_map',self.Ta) # check existence of Rot b (Tb) in h5py file uTb_opt, uTb = self.get_idx('T_map',self.Tb) # check existence of Antenna a (Aa) in h5py file #uAa_opt, uAa = self.get_idx('A_map',self.Aa._filename) uAa_opt, uAa = self.get_idx('A_map',self.Aa.typ) # check existence of Antenna b (Ab) in h5py file uAb_opt, uAb = self.get_idx('A_map',self.Ab.typ) grpname = str(ua) + '_' + str(ub) + '_' + str(uf) + \ '_' + str(uTa) + '_' + str(uTb) + \ '_' + str(uAa) + '_' + str(uAb) self.dexist['H']['grpname'] = grpname def check_grpname(self,key,grpname): """Check if the key's data with a given groupname already exists in the h5py file Parameters ---------- key: string key of the h5py group grpname : string groupe name of the h5py file Notes ----- update the key grpname of self.dexist[key] dictionnary """ try : lfilename=pyu.getlong(self.filename,pstruc['DIRLNK']) f = h5py.File(lfilename,'r') if grpname.decode('utf8') in f[key].keys(): self.dexist[key]['exist']=True else : self.dexist[key]['exist']=False f.close() except: f.close() raise NameError('Link exist: issue during stacking') def get_idx(self,key,array,tol=1e-3): """ try to get the index of the requested array in the group key of the hdf5 file. If array doesn't exist, the hdf5file[key] array is stacked Parameters ---------- key: string key of the h5py group array : np.ndarray array to check existence tol : np.float64 tolerance (in meters for key == 'p_map') Returns ------- (u_opt, u): tuple u : np.ndarray the index in the array of the file[key] group u_opt : string ('r'|'s') return 'r' if array has been read into h5py file return 's' if array has been stacked into the array of group key See Also: -------- Links.array_exist """ umap = self.array_exist(key,array,tol=tol) lu = len(umap) # if exists take the existing one # otherwise value is created if lu != 0: u = umap u_opt='r' else : u = self.stack(key,array) u_opt='s' return u_opt,u[0] def array_exist(self,key,array,tol=1e-3) : """ check if an array of a given key (h5py group) has already been stored into the h5py file Parameters ---------- key: string key of the h5py group array : np.ndarray array type to check existency tol : np.float64 tolerance (in meter for key == 'p_map') Returns ------- (ua) ua : np.ndarray the indice in the array of the file[key] group if the array is emtpy, value doesn't exist TODO ---- Add a tolerance on the rotation angle (T_map) """ lfilename=pyu.getlong(self.filename,pstruc['DIRLNK']) try : f=h5py.File(lfilename,'a') fa = f[key][...] f.close() except: f.close() raise NameError('Link check_exist: issue during reading') if key == 'c_map': eq = array == fa # sum eq = 3 means cy0,cy1 and cutoff are the same in fa and array ua = np.where(np.sum(eq,axis=1)==3)[0] elif key == 'p_map': da = np.sqrt(np.sum((array-fa)**2,axis=1)) # indice points candidate in db for a ua = np.where(da<tol)[0] elif key == 'f_map': # fmin_h5 < fmin_rqst ufmi = np.where(fa[:,0]<=array[0])[0] lufmi = len(ufmi) # fmax_h5 > fmax_rqst ufma = np.where(fa[:,1]>=array[1])[0] lufma = len(ufma) # fstep_h5 < fstep_rqst ufst = np.where(fa[:,2]<=array[2])[0] lufst = len(ufst) # if fmin, fmax or fstep if (lufmi==0) and (lufma==0) and (lufst==0): ua = np.array([]) else : # find comon lines of fmin and fmax ufmima = np.where(np.in1d(ufmi,ufma))[0] # find comon lines of fmin, fmax and fstep ua = np.where(np.in1d(ufmima,ufst))[0] elif key == 'A_map': ua = np.where(fa==array)[0] elif key == 'T_map': eq = array == fa seq = np.sum(np.sum(eq,axis=1),axis=1) ua = np.where(seq==9)[0] else : raise NameError('Link.array_exist : invalid key') return ua def eval(self,**kwargs): """ evaluate the link Parameters ---------- applywav :boolean Apply waveform to H force : list Force the computation (['sig','ray','Ct','H']) AND save (replace previous computations) alg : 1|'old'|'exp'|'exp2' version of run for signature si_progress: bollean ( False) display progression bar for signatures diffraction : boolean (False) takes into consideration diffraction points ra_number_mirror_cf : int rays.to3D number of ceil/floor reflexions ra_ceil_H: float, (default []) ceil height . If [] : Layout max ceil height If 0 : only floor reflection (outdoor case) If -1 : neither ceil nor floor reflection (2D case) ra_vectorized: boolean (True) if True used the (2015 new) vectorized approach to determine 2drays progressbar: str None: no progress bar python : progress bar in ipython Returns ------- ak : ndarray alpha_k tk : ndarray tau_k Notes ----- update self.ak and self.tk self.ak : ndarray alpha_k self.tk : ndarray tau_k Examples -------- .. plot:: :include-source: >>> from pylayers.simul.link import * >>> L=DLink(verbose=False) >>> aktk = L.eval() See Also -------- pylayers.antprop.signature pylayers.antprop.rays Experimental ------------ alg = 2015 | 20152 (best) vectorized signature research si_reverb : number of reverb in source/target cycle if alg=2015 """ defaults={ 'applywav':True, 'si_progress':False, 'diffraction':True, 'ra_vectorized':True, 'ra_ceil_H':[], 'ra_number_mirror_cf':1, 'force':[], 'alg':1, 'si_reverb':4, 'threshold':0.1, 'verbose':[], 'progressbar':None, } for key, value in defaults.items(): if key not in kwargs: kwargs[key]=value if 'cutoff' not in kwargs: kwargs['cutoff']=self.cutoff else: self.cutoff=kwargs['cutoff'] if 'force' in kwargs: if not isinstance(kwargs['force'],list): if kwargs['force'] == True : kwargs['force'] = ['sig','ray','Ct','H'] else : kwargs['force'] = [] if kwargs['verbose'] != []: self.verbose=kwargs['verbose'] #pdb.set_trace() # must be placed after all the init !!!! if self.verbose : print "checkh5" self.checkh5() if isinstance(kwargs['progressbar'],str): if kwargs['progressbar'] =='notebook': pbar = tqdm.tqdm_notebook(total=100) elif kwargs['progressbar']=='python': pbar = tqdm.tqdm(total=100) elif isinstance(kwargs['progressbar'],tqdm.tqdm): pbar = kwargs['progressbar'] ############ # Signatures ############ if self.verbose : print "Start Signatures" tic = time.time() Si = Signatures(self.L,self.ca,self.cb,cutoff=kwargs['cutoff']) if (self.dexist['sig']['exist'] and not ('sig' in kwargs['force'])): self.load(Si,self.dexist['sig']['grpname']) if self.verbose : print "load signature" else : if kwargs['alg']==1: Si.run(cutoff=kwargs['cutoff'], diffraction=kwargs['diffraction'], threshold=kwargs['threshold'], progress=kwargs['si_progress']) if self.verbose : print "default algorithm" if kwargs['alg']=='exp': TMP=Si.run_exp(cutoff=kwargs['cutoff'], cutoffbound=kwargs['si_reverb']) if self.verbose : print "experimental (ex 2015)" if kwargs['alg']=='exp2': TMP=Si.run_exp2(cutoff=kwargs['cutoff'], cutoffbound=kwargs['si_reverb']) if self.verbose : print "algo exp2 ( ex 20152)" #Si.run6(diffraction=kwargs['diffraction']) # save sig self.save(Si,'sig',self.dexist['sig']['grpname'],force = kwargs['force']) self.Si = Si toc = time.time() if self.verbose : print "Stop signature",toc-tic try: pbar.update(20) except: pass ############ # Rays ############ if self.verbose : print "Start Rays" tic = time.time() R = Rays(self.a,self.b) if self.dexist['ray']['exist'] and not ('ray' in kwargs['force']): self.load(R,self.dexist['ray']['grpname']) else : # perform computation ... # ... with vetorized ray evaluation approach if kwargs['ra_vectorized']: r2d = Si.raysv(self.a,self.b) # ... or with original and slow approach ( to be removed in a near future) else : r2d = Si.rays(self.a,self.b) if kwargs['ra_ceil_H'] == []: ceilheight = self.L.maxheight else: ceilheight = kwargs['ra_ceil_H'] R = r2d.to3D(self.L,H=ceilheight, N=kwargs['ra_number_mirror_cf']) R.locbas(self.L) # ...and save R.fillinter(self.L) C = Ctilde() C = R.eval(self.fGHz) self.save(R,'ray',self.dexist['ray']['grpname'],force = kwargs['force']) self.R = R toc = time.time() if self.verbose : print "Stop rays",toc-tic if self.R.nray == 0: raise NameError('No rays have been found. Try to re-run the simulation with a higher S.cutoff ') try: pbar.update(20) except: pass ############ # Ctilde ############ if self.dexist['Ct']['exist'] and not ('Ct' in kwargs['force']): C=Ctilde() self.load(C,self.dexist['Ct']['grpname']) else : #if not hasattr(R,'I'): # Ctilde... # Find an other criteria in order to decide whether the R has # already been evaluated #pdb.set_trace() C = R.eval(self.fGHz) # ...save Ct self.save(C,'Ct',self.dexist['Ct']['grpname'],force = kwargs['force']) self.C = C try: pbar.update(20) except: pass ############ # H ############ H = Tchannel() if self.dexist['H']['exist'] and not ('H' in kwargs['force']): self.load(H,self.dexist['H']['grpname']) else : # Ctilde antenna Cl=C.locbas(Tt=self.Ta, Tr=self.Tb) #T channel H = C.prop2tran(a=self.Aa,b=self.Ab,Friis=True,debug=True) self.save(H,'H',self.dexist['H']['grpname'],force = kwargs['force']) self.H = H try: pbar.update(20) except: pass if kwargs['applywav']: if self.H.isFriis: self.ir = self.H.get_cir(self.wav.sf) else: self.ir = self.H.get_cir(self.wav.sfg) try: pbar.update(20) except: pass return self.H.ak, self.H.tk def show(self,**kwargs): """ show the link Parameters ---------- s : int ca : string color a cb : string color b alpha : int figsize : tuple (20,10) fontsize : int 20 rays : boolean False cmap : colormap labels : boolean enabling edge label (useful for signature identification) pol : string 'tt','pp','tp','pt','co','cross',tot' col : string 'cmap' width : float alpha : float dB : boolean default False dyn : float dynamic in dB Examples -------- >>> from pylayers.simul.link import * >>> L=Link() >>> L.show(rays=True,dB=True) """ defaults ={'s':80, 'ca':'b', 'cb':'r', 'alpha':1, 'i':-1, 'figsize':(20,10), 'fontsize':20, 'rays':False, 'cmap':plt.cm.hot, 'pol':'tot', 'col':'k', 'width':1, 'alpha':1, 'col':'k', 'dB':False, 'labels':False, 'aw':False, 'dyn':70} for key in defaults: if key not in kwargs: kwargs[key]=defaults[key] # # Layout # fig,ax = self.L.showG('s',nodes=False,figsize=kwargs['figsize'],labels=kwargs['labels'],aw=kwargs['aw']) plt.axis('off') # # Point A # ax.scatter(self.a[0], self.a[1], c=kwargs['ca'], s=kwargs['s'], alpha=kwargs['alpha']) ax.text(self.a[0]+0.1,self.a[1]+0.1,'A',fontsize=kwargs['fontsize']) # # Point B # ax.scatter(self.b[0], self.b[1], c=kwargs['cb'], s=kwargs['s'], alpha=kwargs['alpha']) ax.text(self.b[0]-0.1,self.b[1]+0.1,'B',fontsize=kwargs['fontsize']) # # Rays # if kwargs['rays']: ECtt,ECpp,ECtp,ECpt = self.C.energy() if kwargs['pol']=='tt': val = ECtt if kwargs['pol']=='pp': val = ECpp if kwargs['pol']=='tp': val = ECtp if kwargs['pol']=='pt': val = ECpt if kwargs['pol']=='tot': val = ECtt+ECpp+ECpt+ECtp if kwargs['pol']=='co': val = ECtt+ECpp if kwargs['pol']=='cross': val = ECtp+ECpt clm = kwargs['cmap'] # # Select group of interactions # if kwargs['i']==-1: li = self.R.keys() else: li = kwargs['i'] for i in li: lr = self.R[i]['rayidx'] for r in range(len(lr)): ir = lr[r] try: if kwargs['dB']: RayEnergy=max((20*np.log10(val[ir]/val.max())+kwargs['dyn']),0)/kwargs['dyn'] else: RayEnergy=val[ir]/val.max() except: pass if kwargs['col']=='cmap': col = clm(RayEnergy) width = RayEnergy alpha = 1 #alpha = RayEnergy else: col = kwargs['col'] width = kwargs['width'] alpha = kwargs['alpha'] fig,ax = self.R.show(i=i,r=r, colray=col, widthray=width, alpharay=alpha, fig=fig,ax=ax, layout=False, points=False) return fig,ax def _show3(self,rays=True, lay= True, ant= True, newfig= False, **kwargs): """ display the simulation scene using Mayavi using Mayavi Parameters ---------- rays: Ray3d object : display the rays of the simulation newfig : boolean (default : False) kwargs of Rays.show3() see also -------- pylayers.gis.layout pylayers.antprop.antenna pylayers.antprop.rays Examples -------- >>> from pylayers.simul.link import * >>> L=DLink(verbose=False) >>> aktk = L.eval() """ if not newfig: self._maya_fig=mlab.gcf() if 'centered' in kwargs: centered = kwargs['centered'] else : centered = False if centered: pg =np.zeros((3)) pg[:2]=self.L.pg if centered : ptx = self.a-pg prx = self.b-pg else : ptx = self.a prx = self.b self._maya_fig.scene.disable_render = True if ant : Atx = self.Aa Arx = self.Ab Ttx = self.Ta Trx = self.Tb # evaluate antenna if required if not Atx.evaluated: Atx.eval() try: Atx._show3(T=Ttx.reshape(3,3),po=ptx, title=False,colorbar=False,newfig=False,interact=False) except: Atx.eval() Atx._show3(T=Ttx.reshape(3,3),po=ptx, title=False,colorbar=False,newfig=False,interact=False) if not Arx.evaluated: Arx.eval() try: Arx._show3(T=Trx.reshape(3,3),po=prx, title=False,colorbar=False,newfig=False,name = '',interact=False) except: Arx.eval() Arx._show3(T=Trx.reshape(3,3),po=prx, title=False,colorbar=False,newfig=False,name = '',interact=False) if lay: self.L._show3(newfig=False,opacity=0.7,centered=centered,**kwargs) # mlab.text3d(self.a[0],self.a[1],self.a[2],'a', # scale=1, # color=(1,0,0)) # mlab.text3d(self.b[0],self.b[1],self.b[2],'b', # scale=1, # color=(1,0,0)) if rays : # check rays with energy # if hasattr(self,'H') and not kwargs.has_key('rlist'): # urays = np.where(self.H.y!=0)[0] # kwargs['rlist']=urays # import ipdb # ipdb.set_trace() try: self.R._show3(**kwargs) except: print 'Rays not computed yet' self._maya_fig.scene.disable_render = False def _update_show3(self,ant='a',delrays=False): """ """ antenna = eval('self.A'+ant) rot = eval('self.T'+ant).reshape(3,3) pos = eval('self.'+ant) if not antenna.full_evaluated: antenna.eval() if hasattr(antenna,'_mayamesh'): x, y, z, k, scalar = antenna._computemesh(T=rot,po=pos) antenna._mayamesh.mlab_source.set(x=x,y=y,z=z,scalars=scalar) else: antenna._show3(T=rot,po=pos, title=False,colorbar=False,newfig=False,name = '',interact=False) if delrays: import time for x in self._maya_fig.children[::-1]: if 'Rays' in x.name: x.remove()