Para los diferentes entornos donde se propaga la señal, se diferencian por segmentos (fronteras) delimitados en metros desde el gateway.
El desnivel del terreno que existe aproximandamente a 90 mts desde el gateway tiene una sección de «sombra» en donde no se usarán los valores para generar el modelo. por lo que el segundo segmento no se usará para el cálculo, se indica en la variable como [1,0,1]
frontera = [0,90,125,250] # metros frontera_usar = [1,0,1] # usar
Usando estos parámetros y reordenando el algoritmo anterior para ser usado en cada segmento, se obtiene el siguiente resultado
Para la sección de sombra, para mantener la continuidad en la gráfica, se une el punto final del segmento anterior, y el primer punto del segmento posterior.
Los detalles de cada ecuación por segmentos son:
---- segmento: 0 ecuacion_up ecuacion_down alpha 2.579875 2.366443 beta -25.528314 -27.974302 eq_latex $ rssi = -10(2.58)log_{10}(d)-25.53 $ $ rssi = -10(2.37)log_{10}(d)-27.97 $ intervalox [1.0, 86.05] [1.0, 86.05] error_medio 6.17513 6.495915 error_std 7.697343 7.230741 eqg_latex $ d = 10^{(-25.53 - rssi)/(10(2.58))} $ $ d = 10^{(-27.97 - rssi)/(10(2.37))} $ intervaloy [-90.48339483394834, -25.745454545454542] [-82.15682656826569, -26.98787878787879] errorx_medio 43.575249 35.657177 errorx_std 89.139552 50.786448 ---- segmento: 1 ecuacion_up ecuacion_down alpha 7.068273 6.777292 beta 61.310998 57.364631 eq_latex $ rssi = -10(7.07)log_{10}(d)+61.31 $ $ rssi = -10(6.78)log_{10}(d)+57.36 $ intervalox [86.05, 124.08] [86.05, 124.08] error_medio 0.0 0.0 error_std 0.0 0.0 eqg_latex $ d = 10^{(61.31 - rssi)/(10(7.07))} $ $ d = 10^{(57.36 - rssi)/(10(6.78))} $ intervaloy [-86.67755403724453, -75.44247020329829] [-84.53164627778156, -73.75907940898257] errorx_medio 0.0 0.0 errorx_std 0.0 0.0 ---- segmento: 2 ecuacion_up ecuacion_down alpha 4.082007 4.159709 beta -1.212499 2.560248 eq_latex $ rssi = -10(4.08)log_{10}(d)-1.21 $ $ rssi = -10(4.16)log_{10}(d)+2.56 $ intervalox [124.08, 238.66] [126.91, 235.77] error_medio 3.623762 3.887403 error_std 4.452527 4.535259 eqg_latex $ d = 10^{(-1.21 - rssi)/(10(4.08))} $ $ d = 10^{(2.56 - rssi)/(10(4.16))} $ intervaloy [-105.64163822525596, -81.32270916334662] [-99.64505119453923, -80.30278884462152] errorx_medio 39.417734 39.102089 errorx_std 52.33983 45.251062
Instrucciones en Python
# ecuación por mínimos cuadrados de una ruta por segmentos # usando las medidas y distancia al gateway de cada punto # Revision 2022/07/23 # http://blog.espol.edu.ec/girni/ import numpy as np import pandas as pd import os import json import matplotlib.pyplot as plt import girni_lorawan_lib as girni # INGRESO carpeta_rsm = "resultado_c_Maiz_todo" frontera = [0,90,125,250] # metros segmento_usar = [1,0,1] # usar arch_var_general = 'variables_generales.txt' # PROCEDIMIENTO # carga variables desde archivos with open(arch_var_general) as linea: texto = linea.read() var_gen = json.loads(texto) globals().update(var_gen) partes = carpeta_rsm.strip('/').split('_') arch_nombre = partes[1]+'_'+partes[2] def linealiza_preparadatos(carpeta_rsm,arch_coord,var_gen): ''' desarrolla la ecuación para un gradiente ''' var_gen['movAvg_cual'] = [2,4] #cada cuantas muestras partes = carpeta_rsm.strip('/').split('_') arch_nombre = partes[1]+'_'+partes[2] carp_coord = var_gen['carp_coord'] medida = var_gen['medida'] precision = var_gen['precision'] # lee coordenadas y su distancia al gateway dist_Gtw = girni.coordenadas_leer(arch_coord,carp_coord) # lista.txt de archivos a usar arch_lista = medida+"_"+arch_nombre+"_lista.txt" archivo_ruta = carpeta_rsm + '/' + arch_lista archivoexiste = os.path.exists(archivo_ruta) if not(archivoexiste): puntoUsar_Colum = ['punto', 'up', 'down'] puntoUsar_Tipos = {'punto' : 'object', 'up' : 'int64', 'down' : 'int64'} puntoUsar = pd.DataFrame(columns = puntoUsar_Colum) puntoUsar = puntoUsar.astype(dtype = puntoUsar_Tipos) for unarchivo in os.listdir(carpeta_rsm): verifica = unarchivo.startswith('describe_') verifica = verifica and unarchivo.endswith('.csv') if verifica: partes = unarchivo.strip('.csv').split('_') unpunto = partes[2] puntodato = {'punto' : unpunto, 'up' : 1, 'down' : 1} puntodato = pd.DataFrame([puntodato]) puntoUsar = pd.concat([puntoUsar, puntodato], ignore_index = True) puntoUsar = puntoUsar.set_index('punto') puntoUsar.to_csv(archivo_ruta) # usa lista.txt de archivos seleccionados 1 ó 0 para enlace up,down if (archivoexiste): puntoUsar = pd.read_csv(archivo_ruta) puntoUsar = puntoUsar.set_index('punto') # Datos para gráfica desde lista.txt punto_columnas = ['codigopunto','dist_Gtw', medida+'_up',medida+'_up'+'_std', 'usar_up',medida+'_down', medida+'_down'+'_std', 'usar_down','dispositivo'] punto_tipos = {'codigopunto': 'object', 'dist_Gtw' : 'float64', medida+'_up' : 'float64', medida+'_up'+'_std': 'float64', 'usar_up' : 'int64', medida+'_down': 'float64', medida+'_down'+'_std' :'float64', 'usar_down' : 'int64', 'dispositivo': 'object'} punto_graf = pd.DataFrame(columns=punto_columnas) punto_graf = punto_graf.astype(dtype=punto_tipos) puntoSinDist = [] for unarchivo in os.listdir(carpeta_rsm): if unarchivo.startswith('describe_'): codigopunto = unarchivo.strip('.csv').split('_')[2] # lectura del archivo unresumen = carpeta_rsm+'/'+unarchivo descriptor = pd.read_csv(unresumen,index_col='Unnamed: 0') if (codigopunto in dist_Gtw.index): undato = {'codigopunto': codigopunto, 'dist_Gtw' : dist_Gtw[codigopunto], medida+'_up' : descriptor['rssi_up']['mean'], medida+'_up'+'_std': descriptor['rssi_up']['std'], 'usar_up' : puntoUsar['up'][codigopunto], medida+'_down': descriptor['rssi_down']['mean'], medida+'_down'+'_std' :descriptor['rssi_down']['std'], 'usar_down' : puntoUsar['down'][codigopunto], 'dispositivo': descriptor['dispositivo'][0] } undato = pd.DataFrame([undato]) punto_graf = pd.concat([punto_graf,undato], ignore_index=True) else: puntoSinDist.append(codigopunto) punto_graf = punto_graf.set_index('codigopunto') punto_graf = punto_graf.sort_values('dist_Gtw' ) return(punto_graf) punto_graf = linealiza_preparadatos(carpeta_rsm,arch_coord,var_gen) # Segmentos, intervalos de indices en tabla ---------- extiende = 15 # metros intervalos = [] intervalos_ext = [] n_sector = len(frontera) indices = np.arange(0,len(punto_graf['dist_Gtw']),1) for i in range(0,n_sector-1,1): desde = frontera[i] hasta = frontera[i+1] # intervalos, indices [a,b] sector = (punto_graf['dist_Gtw']>=desde) sector = sector & (punto_graf['dist_Gtw']<hasta) unintervalo = indices[sector] a = np.min(unintervalo) if i>0: a = a - 1 sector[a] = True b = np.max(unintervalo) intervalos.append([a,b]) punto_graf['sector_'+str(i)] = sector # intervalos extendidos if (desde-extiende)>0: desde = desde - extiende if (hasta + extiende) < np.max(punto_graf['dist_Gtw']): hasta = hasta + extiende sector_ext = (punto_graf['dist_Gtw']>=desde) sector_ext = sector_ext & (punto_graf['dist_Gtw']<=hasta) unintervalo = indices[sector_ext] a = np.min(unintervalo) b = np.max(unintervalo) intervalos_ext.append([a,b]) def linealiza_segmento(punto_graf,var_gen,segmento=-1): '''estima la ecuacion para cada segmento, usada solo cuando segmento >=0 [0,1,2,... ] ''' precision = var_gen['precision'] resultado = {} xi = np.array(punto_graf['dist_Gtw']) # enlace up/down enlaces =['up','down'] for unenlace in enlaces: usar = punto_graf['usar_'+unenlace] if segmento>=0: sector = punto_graf['sector_'+str(segmento)] usar = usar*sector yi = np.array(punto_graf[medida+'_'+unenlace]) # ecuacion eq = girni.linealiza_lstsq(xi[usar==1], yi[usar==1], digitos = precision) alpha = eq['alpha'] beta = eq['beta'] fd = lambda d: -10*alpha*(np.log10(d))+beta # puntos de ecuacion en tabla punto_graf['fi_'+unenlace] = fd(xi) resultado['ecuacion_'+unenlace] = eq resultado['tabla'] = punto_graf return (resultado) # segmentos a usar primero y último ---------- primero = segmento_usar.index(1) invertido = segmento_usar.copy() invertido.reverse() ultimo = len(segmento_usar) - invertido.index(1) - 1 # ecuaciones para todos los segmentos eq_intervalo = {} tabla = {} for i in range(0,n_sector-1,1): resultado = linealiza_segmento(punto_graf,var_gen,i) ecuacion = resultado.copy() ecuacion.pop('tabla') ecuacion = pd.DataFrame(ecuacion) eq_intervalo[i] = ecuacion tabla[i] = resultado['tabla'].copy() # intervalos de sombra corrige anteriores for i in range(0,n_sector-1,1): condicion = i>primero and i<ultimo if not(segmento_usar[i]) and i>0 and condicion: sector = punto_graf['sector_'+str(i)] # extremos [a,b] a = intervalos[i-1][1] b = intervalos[i][1] # extremo izquierdo a xa_up = tabla[i]['dist_Gtw'][a] ya_up = tabla[i-1]['fi_up'][a] ya_down = tabla[i-1]['fi_down'][a] # extremo derecho b xb_up = tabla[i]['dist_Gtw'][b] yb_up = tabla[i+1]['fi_up'][b] yb_down = tabla[i+1]['fi_down'][b] eq_up = girni.linealiza_lstsq([xa_up,xb_up], [ya_up,yb_up], digitos = precision) eq_down = girni.linealiza_lstsq([xa_up,xb_up], [ya_down,yb_down], digitos = precision) ecuacion = {'ecuacion_up' : eq_up, 'ecuacion_down' : eq_down} ecuacion = pd.DataFrame(ecuacion) eq_intervalo[i] = ecuacion # SALIDA for i in range(0,n_sector-1,1): print('\n ---- segmento:',i) print(eq_intervalo[i]) def graf_gradiente_segmento(arch_nombre,punto_graf,ecuacion,var_gen): ''' grafica de gradiente ''' medida = var_gen['medida'] precision = var_gen['precision'] escalabase = 10 # 10 escala = 'log' dist = punto_graf['dist_Gtw'] # enlace up/down enlaces = ['up','down'] colorenlace = ['blue','orange'] i=0 for unenlace in enlaces: # enlace_up/down media = punto_graf[medida+'_'+unenlace] std = punto_graf[medida+'_'+unenlace+'_std'] media_techo = media + std media_piso = media - std yi = np.array(media) fi = punto_graf['fi'+'_'+unenlace] usar = punto_graf['usar_'+unenlace] eq = ecuacion['ecuacion_'+unenlace] dyi_std = eq['error_std'] for j in range(0,len(dist),1): uncolor = colorenlace[i] etiqueta = dist.keys()[j] if not(usar[j]): uncolor = 'red' # medida up/down +/- std graf[i].scatter(dist[j],media[j], color=uncolor,marker='o') graf[i].scatter(dist[j],media_techo[j], color=uncolor,marker='+') graf[i].scatter(dist[j],media_piso[j], color=uncolor,marker='+') # etiquetas por punto graf[i].annotate(etiqueta,(dist[j],yi[j]),rotation=45) # linealizado up/down etiq_gradnt = eq['eq_latex'] etiq_gradnt = etiq_gradnt+' ; ['+str(int(np.min(dist))) etiq_gradnt = etiq_gradnt+','+str(int(np.max(dist)))+']' graf[i].plot(dist,fi,label = etiq_gradnt,color=colorenlace[i]) graf[i].plot(dist,fi+dyi_std,color=colorenlace[i],linestyle='dotted') graf[i].plot(dist,fi-dyi_std,color=colorenlace[i],linestyle='dotted') # etiquetado de grafico graf[i].set_ylabel(medida+'_'+enlaces[i]+' (dBm)',color=colorenlace[i]) graf[i].legend() graf[i].grid(True,linestyle='dotted',axis='x', which='both') if i==0: graf[0].set_title(arch_nombre+' '+medida) if i==1: graf[1].set_xlabel('distancia') i = i + 1 return(fig_gradnt) # grafica gradientes por segmentos # para limites en eje y techo_up = pd.DataFrame() piso_up = pd.DataFrame() techo_down = pd.DataFrame() piso_down = pd.DataFrame() graf=[0,0] fig_gradnt,graf = plt.subplots(2,1) escalabase = 10 # 10 escala = 'log' if escala == 'log': graf[0].set_xscale(escala,base=escalabase) graf[1].set_xscale(escala,base=escalabase) # grafica cada segmento for i in range(0,n_sector-1,1): sector = tabla[i]['sector_'+str(i)] punto_grupo = tabla[i][sector] #enlace_up media_up = punto_grupo[medida+'_up'] std_up = eq_intervalo[i]['ecuacion_up']['error_std'] media_up_techo = media_up + std_up media_up_piso = media_up - std_up # enlace_down media_down = punto_grupo[medida+'_down'] std_down = eq_intervalo[i]['ecuacion_up']['error_std'] media_down_techo = media_down + std_down media_down_piso = media_down - std_down techo_up = pd.concat([techo_up,media_up_techo]) piso_up = pd.concat([piso_up,media_up_piso]) techo_down = pd.concat([techo_down,media_down_techo]) piso_down = pd.concat([piso_down,media_down_piso]) if segmento_usar[i]: ecuacion = eq_intervalo[i] graf_gradiente_segmento(arch_nombre,punto_grupo,ecuacion,var_gen) condicion = i>primero and i<ultimo if not(segmento_usar[i]) and i>0 and condicion: a = tabla[i]['dist_Gtw'][intervalos[i][0]] b = tabla[i]['dist_Gtw'][intervalos[i][1]] graf[0].axvspan(a,b,alpha=0.5,color='gray') graf[1].axvspan(a,b,alpha=0.5,color='gray') # linea intermedia xi = punto_grupo['dist_Gtw'] ecuacion = eq_intervalo[i] fi_up = punto_grupo['fi_up'] fi_down = punto_grupo['fi_down'] graf[0].scatter(xi,media_up,color='blue',marker='o') graf[0].scatter(xi,media_up_techo,color='blue',marker='+') graf[0].scatter(xi,media_up_piso,color='blue',marker='+') graf[1].scatter(xi,media_down,color='orange',marker='o') graf[1].scatter(xi,media_down_techo,color='orange',marker='+') graf[1].scatter(xi,media_down_piso,color='orange',marker='+') alpha_up = eq_up['alpha'] beta_up = eq_up['beta'] fd_up = lambda d: -10*alpha_up*(np.log10(d))+beta_up fi_up = fd_up(xi) alpha_down = eq_down['alpha'] beta_down = eq_down['beta'] fd_down = lambda d: -10*alpha_down*(np.log10(d))+beta_down fi_down = fd_down(xi) etiq = eq_up['eq_latex'] etiq = etiq+' ; ['+str(int(a))+','+str(int(b))+']' graf[0].plot(xi,fi_up, label = etiq, color='blue', linestyle='dashed') etiq = eq_down['eq_latex'] etiq = etiq+' ; ['+str(int(a))+','+str(int(b))+']' graf[1].plot(xi,fi_down, label = etiq, color='brown',linestyle='dashed') # ajuste de eje y y_min = np.min([piso_up.min(),piso_down.min()]) y_max = np.max([techo_up.max(),techo_down.max()]) if y_min<-135: y_min = -135 #graf[0].set_ylim(y_min,y_max) #graf[1].set_ylim(y_min,y_max) plt.tight_layout() unarchivo = carpeta_rsm+'/ecuacion_segmentos_'+arch_nombre+'.png' fig_gradnt.savefig(unarchivo) plt.show()