def _idw_interpolate(sensor_data, target_grid_len): ''' Args: sensor_data -- np.2darray -- Rx data from a single Tx target_grid_len -- int -- the target grid length for the Rx Return: np.1darray -- interpolated, shape = target_grid_len**2 ''' pre_gl = len(sensor_data) factor = int(target_grid_len / pre_gl) interpolate = np.zeros((target_grid_len, target_grid_len)) for new_x in range(target_grid_len): for new_y in range(target_grid_len): if new_x % factor == 0 and new_y % factor == 0 and sensor_data[ new_x // factor][ new_y // factor] != 0: # don't need to interpolate interpolate[new_x][new_y] = sensor_data[new_x // factor][new_y // factor] else: v_x, v_y = new_x / factor, new_y / factor # virtual point in the coarse grid points = [] # pick some points from the coarse grid edge = int(8 / factor) for pre_x in range(math.floor(v_x - edge), math.ceil(v_x + 1) + edge): if pre_x < 0 or pre_x >= pre_gl: # the x range continue for pre_y in range(math.floor(v_y - edge), math.ceil(v_y + 1) + edge): if pre_y >= 0 and pre_y < pre_gl and sensor_data[ pre_x][pre_y] != 0: points.append((pre_x, pre_y, distance((v_x, v_y), (pre_x, pre_y)))) points = sorted(points, key=lambda tup: tup[2]) # sort by distance threshold = min(MultiIntepolate.NEIGHBOUR_NUM, len(points)) weights = np.zeros(threshold) for i in range(threshold): point = points[i] dist = distance((v_x, v_y), point) weights[i] = ( 1. / dist )**2 # inverse weighted distance or inverse weighted square weights /= np.sum(weights) # normalize them idw = 0 for i in range(threshold): w = weights[i] pre_rss = sensor_data[points[i][0]][points[i][1]] idw += w * pre_rss interpolate[new_x][new_y] = idw return interpolate.reshape(target_grid_len * target_grid_len)
def _interpolate_idw(pre_inter, factor): '''Fix one transmitters, interpolate the sensors Args: pre_inter -- np.1darray -- pre interpolated, shape = pre_gl*pre_gl factor -- int Return: np.1darray -- interpolated, shape = gre_gl*gre_gl*factor*factor ''' pre_gl = int(math.sqrt( len(pre_inter))) # previous grid length (coarse grid) pre_inter = pre_inter.reshape((pre_gl, pre_gl)) new_gl = pre_gl * factor # new grid length (find grid) inter = np.zeros((new_gl, new_gl)) for new_x in range(new_gl): for new_y in range(new_gl): if new_x % factor == 0 and new_y % factor == 0: # don't need to interpolate inter[new_x][new_y] = pre_inter[new_x // factor][new_y // factor] else: v_x, v_y = float(new_x) / factor, float( new_y ) / factor # virtual point in the coarse grid / real point in the fine grid # pick some close points from the coarse grid points = [] for pre_x in range(math.floor(v_x - 1), math.ceil(v_x + 1) + 1): for pre_y in range(math.floor(v_y - 1), math.ceil(v_y + 1) + 1): if pre_x >= 0 and pre_x < pre_gl and pre_y >= 0 and pre_y < pre_gl: points.append((pre_x, pre_y, distance((v_x, v_y), (pre_x, pre_y)))) points = sorted(points, key=lambda tup: tup[2]) # sort by distance threshold = min(NEIGHBOR_NUM, len(points)) weights = np.zeros(threshold) for i in range(threshold): point = points[i] dist = distance((v_x, v_y), point) weights[i] = ( 1. / dist )**2 # inverse weighted distance or inverse weighted square weights /= np.sum(weights) # normalize them idw = 0 for i in range(threshold): w = weights[i] pre_rss = pre_inter[points[i][0]][points[i][1]] idw += w * pre_rss inter[new_x][new_y] = idw return inter.reshape(new_gl * new_gl)
def get_log10_weight(to_tx_dists, tx, rx0): '''get the weights from project_dists Args: project_dists -- np.1darray tx -- (float, float) rx0 -- (float, float) -- location to be interpolated Return: np.1darray ''' for i, dist in enumerate(to_tx_dists): if dist == 0: to_tx_dists[ i] = IpsnInterpolate.ILDW_DIST # this value can tweak log10_dist_to_tx = np.log10(to_tx_dists) reference_dist = np.log10(distance(tx, rx0)) log10_dist_to_rx0 = log10_dist_to_tx - reference_dist log10_dist_to_rx0 = np.absolute(log10_dist_to_rx0) weight = np.zeros(len(log10_dist_to_rx0)) for i, dist in enumerate(log10_dist_to_rx0): if dist > 0: weight[i] = (1. / dist) maxx = max(weight) for i, w in enumerate(weight): if w == 0: weight[i] = 2 * maxx if maxx > 0 else 1 return weight
def find_d0_pd0(self, num=4): '''find some largest RSS, average them as the P(d0) and d0 Args: num (int): ''' means = [] dic = defaultdict(list) for i in range(len(self.locations)): for j in range(len(self.locations)): if i == j: continue dist = distance(self.locations[i], self.locations[j]) dic[dist].append((i, j, self.means[i, j])) means.append(self.means[i][j]) # X, Y = [], [] threshold = sorted(np.array(means))[-num] d0, pd0 = [], [] for key, vals in sorted( dic.items()): # distance --> [ (loc1, loc2) ...] for val in vals: i, j, mean = val if mean >= threshold: d0.append(key) pd0.append(mean) if len(d0) == num: return np.array(d0).mean(), np.array(pd0).mean()
def _ildw(self, tx_data, tx_1dindex): '''Interpolate one Tx Args: tx_data -- np.1darray -- contains zeros values Return: tx_data -- np.1darray -- the zero values are filled up ''' tx = (tx_1dindex // self.full_grid_len, tx_1dindex % self.full_grid_len ) # ildw requires the location of the transmitter grid_pathloss = tx_data.reshape(self.full_grid_len, self.full_grid_len) grid_interpolate = np.copy(grid_pathloss) # find the zero elements and impute them for x in range(grid_pathloss.shape[0]): for y in range(grid_pathloss.shape[1]): if grid_pathloss[x][ y] != 0.0: # skip the ones that don't need to interpolate continue points = [] d = self.range for i in range(x - d, x + d + 1): for j in range(y - d, y + d + 1): if i < 0 or i >= grid_pathloss.shape[ 0] or j < 0 or j >= grid_pathloss.shape[1]: continue if grid_pathloss[i][ j] == 0.0: # only use the known point to interpolate continue dist = distance((x, y), (i, j)) points.append((i, j, dist)) points = sorted(points, key=lambda tup: tup[2]) threshold = min(IpsnInterpolate.NEIGHBOR_NUM, len(points)) weights = np.zeros(threshold) dist_to_tx = np.zeros(threshold) for i in range(threshold): nei = (points[i][0], points[i][1]) dist_to_tx[i] = distance(tx, nei) rx0 = (x, y) weights = IpsnInterpolate.get_log10_weight(dist_to_tx, tx, rx0) weights /= np.sum(weights) idw_pathloss = 0 for i in range(threshold): w = weights[i] rss = grid_pathloss[points[i][0]][points[i][1]] idw_pathloss += w * rss grid_interpolate[x][y] = idw_pathloss return grid_interpolate.reshape(self.full_grid_len * self.full_grid_len)
def combine_sensor_data(self): '''Combine sensor data from multiply granularity. each granularity has full data in 1 dimension (from the SPLAT!) ''' grid_lens = sorted(TxMultiGran.RX_CELL_LEN.keys()) # [5, 10, 20] if len(grid_lens) != len(Global.GRAN_LEVEL): print((self.x, self.y), 'length of grid_lens and granularity level doesn\'t match !') return # map granularity level to grid length # {1200 --> 5, 400 --> 10, 0 --> 20} gran_level2grid_len = {} for gran_level, grid_len in zip(reversed(Global.GRAN_LEVEL), grid_lens): gran_level2grid_len[gran_level] = grid_len # map grid length to ratio. the ratio of finest_rx_grid_len to different grid_len finest_rx_grid_len = grid_lens[-1] grid_len2ratio = {} for grid_len in grid_lens: grid_len2ratio[grid_len] = int( finest_rx_grid_len / grid_len) # {5 --> 4, 10 --> 2, 20 --> 1} self.sensor_data = np.zeros( (finest_rx_grid_len, finest_rx_grid_len)) # fill up this array t_x = self.x * grid_len2ratio[TxMultiGran.TX_GRID_LEN] t_y = self.y * grid_len2ratio[TxMultiGran.TX_GRID_LEN] for x in range(finest_rx_grid_len): for y in range(finest_rx_grid_len): dist = distance((x, y), (t_x, t_y)) * TxMultiGran.RX_CELL_LEN[ finest_rx_grid_len] # distance in meters gran_level = self.get_gran_level(Global.GRAN_LEVEL, dist) grid_len = gran_level2grid_len[gran_level] ratio = grid_len2ratio[grid_len] if x % ratio == 0 and y % ratio == 0: # granularity control by this ratio if TxMultiGran.TX_GRID_LEN == grid_lens[0]: # when the Tx granularity equals to the lowest Rx granularity gran_data = self.granularity_data[grid_len] gran_grid_len = int(math.sqrt(len(gran_data))) index = x // ratio * gran_grid_len + y // ratio self.sensor_data[x][y] = gran_data[index] else: # when the Tx granularity not equal to the lowest Rx granularity, only use the finest granularity gran_data = self.granularity_data[finest_rx_grid_len] gran_grid_len = int(math.sqrt(len(gran_data))) index = x * gran_grid_len + y self.sensor_data[x][y] = gran_data[index] if self.debug: num_wireless_link = np.count_nonzero(self.sensor_data) TxMultiGran.NUM_WIRELESS_LINK += num_wireless_link print('Tx = ({}, {})'.format(self.x, self.y), '; number of wireless links to sensors', num_wireless_link, '; Total = {}'.format(TxMultiGran.NUM_WIRELESS_LINK))
def predict(self, tx, rx): '''Predice the receiver's RSS at rx, when the transmitter is at tx Args: tx (tuple(float, float)) rx (tuple(float, float)) ''' dist = distance(tx, rx) tx = Point(tx[0], tx[1]) rx = Point(rx[0], rx[1]) nW = self.wall.count_intersect(tx, rx) nW = nW if nW <= self.C else self.C # offset = 0 # if dist < 2 and nW == 0: # offset = 6.37 return self.p_d0 - 10 * self.n * math.log10( dist / self.d0) - nW * self.waf + self.intercept
def compute_errors(self, inter_data, dist_close, dist_far): '''Compute the interpolation errors Args: inter_data -- np.2darray dist_close -- int dist_far -- int -- distance threshold between tx and rx coarse_gran -- int ''' grid_is_inter = np.zeros( (self.full_grid_len, self.full_grid_len) ) # the places for sensors in coarse grid, no interpolation happening for x in self.index: for y in self.index: grid_is_inter[x, y] = 1. size = len(inter_data) errors_all = [] # errors for all tx-rx errors_close = [] # errors for tx-rx with small distance errors_far = [] # errors for tx-rx with large distance for i in range(size): tx = (i // self.full_grid_len, i % self.full_grid_len) for j in range(size): rx = (j // self.full_grid_len, j % self.full_grid_len) if grid_is_inter[rx[0]][rx[1]] == 1. or i == j: continue error = inter_data[i][j] - self.full_data[i][j] dist = distance(tx, rx) if dist < dist_close: errors_close.append(error) elif dist > dist_far: errors_far.append(error) errors_all.append(error) mean_error = np.mean(errors_all) mean_absolute_error = np.mean(np.absolute(errors_all)) mean_error_close = np.mean(errors_close) mean_absolute_error_close = np.mean(np.absolute(errors_close)) mean_error_far = np.mean(errors_far) mean_absolute_error_far = np.mean(np.absolute(errors_far)) std = np.std(np.absolute(errors_all)) std_close = np.std(np.absolute(errors_close)) std_far = np.std(np.absolute(errors_far)) return Output(None, mean_error, mean_absolute_error, mean_error_close, mean_absolute_error_close, \ mean_error_far, mean_absolute_error_far, std, std_close, std_far)
def _idw(self, tx_data): '''Interpolate one Tx Args: tx_data -- np.1darray -- contains zeros values Return: tx_data -- np.1darray -- the zero values are filled up ''' grid_pathloss = tx_data.reshape(self.full_grid_len, self.full_grid_len) grid_interpolate = np.copy(grid_pathloss) # find the zero elements and impute them for x in range(grid_pathloss.shape[0]): for y in range(grid_pathloss.shape[1]): if grid_pathloss[x][ y] != 0.0: # skip the ones that don't need to interpolate continue points = [] d = self.range for i in range(x - d, x + d + 1): for j in range(y - d, y + d + 1): if i < 0 or i >= grid_pathloss.shape[ 0] or j < 0 or j >= grid_pathloss.shape[1]: continue if grid_pathloss[i][ j] == 0.0: # only use the known point to interpolate continue dist = distance((x, y), (i, j)) points.append((i, j, dist)) points = sorted(points, key=lambda tup: tup[2]) threshold = min(IpsnInterpolate.NEIGHBOR_NUM, len(points)) weights = np.zeros(threshold) for i in range(threshold): dist = points[i][2] weights[i] = (1. / dist)**IpsnInterpolate.IDW_EXPONENT weights /= np.sum(weights) idw_pathloss = 0 for i in range(threshold): w = weights[i] rss = grid_pathloss[points[i][0]][points[i][1]] idw_pathloss += w * rss grid_interpolate[x][y] = idw_pathloss return grid_interpolate.reshape(self.full_grid_len * self.full_grid_len)
def main0(): '''Read the Utah data, location transform ''' means, stds, locations, wall = read_utah_data(path='dataUtah') lt = LocationTransform(locations, cell_len=1) print(means) print(stds) print(locations) print(wall) print(lt) errors = [] for real_loc in lt.real_location: gridcell = lt.real_2_gridcell(real_loc) real_loc2 = lt.gridcell_2_real(gridcell) error = distance(real_loc, real_loc2) errors.append(error) print('({:5.2f}, {:5.2f}) -> ({:2d}, {:2d}) -> ({:5.2f}, {:5.2f}); error = {:3.2f}'.format(real_loc[0], real_loc[1], gridcell[0], gridcell[1], real_loc2[0], real_loc2[1], error)) plot_cdf(errors)
def regresssion_n_waf(self): '''Do a regression to get the n and waf ''' X, y = [], [] for i in range(len(self.locations)): for j in range(len(self.locations)): if i == j: continue dist = distance(self.locations[i], self.locations[j]) tx = Point(self.locations[i][0], self.locations[i][1]) rx = Point(self.locations[j][0], self.locations[j][1]) nW = self.wall.count_intersect(tx, rx) nW = nW if nW <= self.C else self.C y.append(self.means[i][j] - self.p_d0) # y.append(self.means[i][j]) X.append([math.log10(dist / self.d0), nW]) # X.append([math.log10(dist), nW]) reg = LinearRegression(fit_intercept=True).fit(X, y) print('Regression score:', reg.score(X, y)) return reg.coef_[0], reg.coef_[1], reg.intercept_
def main1(): mean, stds, locations, wall = read_utah_data() # print(mean) # print(stds) # print(locations) lt = LocationTransform(locations, cell_len=1) # print(lt) num = len(mean) with open('dataUtah/means.txt', 'w') as f: for i in range(num): for j in range(num): f.write('{:6.2f} '.format(mean[i][j])) f.write('\n') with open('dataUtah/stds.txt', 'w') as f: for std in stds: f.write('{:.3f}\n'.format(std)) with open('dataUtah/locations.txt', 'w') as f: for i in range(num): cell = lt.grid_location[i] real_loc = lt.real_location[i] f.write('{:3d} - '.format(cell[0] * lt.grid_len + cell[1])) f.write('({:2d}, {:2d}) - '.format(cell[0], cell[1])) f.write('({:7.4f}, {:7.4f})\n'.format(real_loc[0], real_loc[1])) errors = [] for real_loc in lt.real_location: gridcell = lt.real_2_gridcell(real_loc) real_loc2 = lt.gridcell_2_real(gridcell) error = distance(real_loc, real_loc2) errors.append(error) print( '({:5.2f}, {:5.2f}) -> ({:2d}, {:2d}) -> ({:5.2f}, {:5.2f}); error = {:3.2f}' .format(real_loc[0], real_loc[1], gridcell[0], gridcell[1], real_loc2[0], real_loc2[1], error)) plot_cdf(errors)
def correct(self): X, Y = [], [] for i in range(len(self.locations)): for j in range(len(self.locations)): if i == j: continue dist = distance(self.locations[i], self.locations[j]) tx = Point(self.locations[i][0], self.locations[i][1]) rx = Point(self.locations[j][0], self.locations[j][1]) nW = self.wall.count_intersect(tx, rx) nW = nW if nW <= self.C else self.C X.append(dist) Y.append(self.means[i][j] + nW * self.waf) # Y.append(self.means[i][j]) plt.rcParams['font.size'] = 20 plt.figure(figsize=(10, 10)) plt.scatter(np.log10(X), Y) # plt.scatter(X, Y) plt.title('Wall Correction') plt.xlabel('Log Distance (m)') plt.ylabel('RSS (dBm)') plt.ylim([-85, -30]) plt.savefig('visualize/RSS-logdist-wallcorrect.png')
def _idw_interpolate_2(pre_inter, target_grid_len, tx, tx_pl): '''Fix one transmitters, interpolate the sensors Args: pre_inter -- np.1darray -- pre interpolated, shape = pre_gl*pre_gl target_grid_len -- int -- the Tx that needs to interpolate Rx factor -- int Return: np.1darray -- interpolated, shape = gre_gl*gre_gl*factor*factor ''' pre_gl = int(math.sqrt( len(pre_inter))) # previous grid length (coarse grid) pre_inter = pre_inter.reshape((pre_gl, pre_gl)) factor = int(target_grid_len / pre_gl) tx_x, tx_y = tx // target_grid_len, tx % target_grid_len inter = np.zeros((target_grid_len, target_grid_len)) for new_x in range(target_grid_len): for new_y in range(target_grid_len): if new_x % factor == 0 and new_y % factor == 0: # don't need to interpolate inter[new_x][new_y] = pre_inter[new_x // factor][new_y // factor] else: v_x, v_y = float(new_x) / factor, float( new_y ) / factor # virtual point in the coarse grid / real point in the fine grid # pick some close points from the coarse grid points = [] for pre_x in range(math.floor(v_x - 1), math.ceil(v_x + 1) + 1): for pre_y in range(math.floor(v_y - 1), math.ceil(v_y + 1) + 1): if pre_x >= 0 and pre_x < pre_gl and pre_y >= 0 and pre_y < pre_gl: points.append( (pre_x, pre_y, distance((v_x, v_y), (pre_x, pre_y))) ) # the distance between the virtual Rx in the coarse grid and coarse Rx dist_to_tx_fine = distance( (new_x, new_y), (tx_x, tx_y)) # distance in the fine grid if dist_to_tx_fine < 4: dist_to_tx_coarse = distance( (v_x, v_y), (tx_x / factor, tx_y / factor)) points.append( (tx_x / factor, tx_y / factor, dist_to_tx_coarse) ) # the additional Rx at the same location as the Tx points = sorted(points, key=lambda tup: tup[2]) # sort by distance threshold = min(MultiIntepolate.NEIGHBOUR_NUM, len(points)) weights = np.zeros(threshold) for i in range(threshold): point = points[i] dist = distance((v_x, v_y), point) dist = 0.01 if dist == 0.0 else dist weights[i] = ( 1. / dist )**2 # inverse weighted distance or inverse weighted square weights /= np.sum(weights) # normalize them idw = 0 for i in range(threshold): w = weights[i] try: pre_rss = pre_inter[points[i][0]][points[i][1]] except: pre_rss = tx_pl # the additional Rx at the same location as the Tx idw += w * pre_rss inter[new_x][new_y] = idw return inter.reshape(target_grid_len * target_grid_len)