diff --git a/libs/plotting.py b/libs/plotting.py index 79bda1a..ec3e0f9 100644 --- a/libs/plotting.py +++ b/libs/plotting.py @@ -6,11 +6,11 @@ import matplotlib.pyplot as plt from libs.consts import COLORMAP_MIN from libs.consts import COLORMAP_MAX -from libs.spacemap import SpaceMap def plotSpace( - space_map: SpaceMap, + space_map, + space_rays = None, cminmax: tuple = (COLORMAP_MIN, COLORMAP_MAX) ): ''' @@ -30,8 +30,14 @@ def plotSpace( vmin=cminmax[0], vmax=cminmax[1] ) + ax1.set_xlim([0,64]) + ax1.set_ylim([0,64]) plt.colorbar() + if space_rays: + for each in space_rays: + ax1.plot([each.start.x / 0.1, each.end.x / 0.1], [each.start.y / 0.1, each.end.y / 0.1], 'b-') + ax2 = fig.add_subplot(1, 2, 2) ax2.set_title("reflection loss") plt.imshow( @@ -42,6 +48,8 @@ def plotSpace( vmin=cminmax[0], vmax=cminmax[1] ) + ax2.set_xlim([0,64]) + ax2.set_ylim([0,64]) plt.colorbar() # plt.show() diff --git a/libs/spacemap.py b/libs/spacemap.py index d44a657..2bd371d 100644 --- a/libs/spacemap.py +++ b/libs/spacemap.py @@ -7,6 +7,7 @@ from libs.consts import MAX_RANGE from libs.consts import NOISE_FLOOR from libs.consts import FLOAT_TOLERANCE from libs.models import log_gamma_dist +from libs.plotting import plotSpace class SpaceBlock(): @@ -20,6 +21,14 @@ class SpaceBlock(): self.has_transmitter = False self.loss_penetration = 0.0 self.loss_reflection = -100.0 + self.orientation = None + # backup linked list + self.left = None # <- + self.right = None # -> + self.up = None # ^ + self.down = None # v + self.top = None # . (3d on top) + self.bottom = None # o (3d underneath) def __mul__(self, val): return SpaceBlock(self.x * val, self.y * val, self.z * val) @@ -106,6 +115,12 @@ class SpaceBlock(): self.loss_penetration = penetration self.loss_reflection = reflection + def setOrientation(self, orientation=0.0): + self.orientation = orientation + + def getOrientation(self): + return self.orientation + def getLoss(self): return [self.loss_penetration, self.loss_reflection] @@ -159,11 +174,22 @@ class SpaceRay(): def __str__(self): return ( "SpaceRay(start = {0}, end = {1}): ".format(self.start, self.end) + - "pwr_init = {0:.2f}, pwr_end = {1:.2f}, ".format(self.init_pwr, self.ending_pwr) + - "loss_start = {0:.2f}, loss_end = {1:.2f}\n".format(self.starting_loss, self.ending_loss) + + "pwr_init = {0}, pwr_end = {1}, ".format(self.init_pwr, self.ending_pwr) + + "loss_start = {0}, loss_end = {1}\n".format(self.starting_loss, self.ending_loss) + " <- prev_ray = {}".format(self.prev_ray) ) + def __iter__(self): + self.__prev_ray = self + return self + + def __next__(self): + if self.__prev_ray is None: + raise StopIteration + tmp = self.__prev_ray + self.__prev_ray = self.__prev_ray.prev_ray + return tmp + def getAngle(self, degree=False): if self.angle_theta is None: self.angle_theta = np.arctan2( @@ -215,7 +241,8 @@ class SpaceRay(): self.reflection_blks = [] step_blk = SpaceBlock(self.getAngleThetaCos(), self.getAngleThetaSin()) * space_map.bs early_stop_flag = False - for i in range(1, int(self.getDistance() / space_map.bs)): + # reflect_blk_min_gap = 2 + for i in range(2, int(self.getDistance() / space_map.bs) - 1): next_blk = self.start + step_blk * i # assume 2D x_idx, y_idx = [int(x) for x in (next_blk / space_map.bs).round()] @@ -306,6 +333,12 @@ class SpaceMap(): y = self.bs * (j + 0.5) for i in range(self.map.shape[0]): self.map[i, j] = SpaceBlock(self.bs * (i + 0.5), y) + for j in range(self.map.shape[1]): + for i in range(self.map.shape[0]): + self.map[i, j].up = self.map[i, j+1] if j < self.map.shape[1]-1 else None + self.map[i, j].down = self.map[i, j-1] if j > 0 else None + self.map[i, j].left = self.map[i-1, j] if i < 0 else None + self.map[i, j].right = self.map[i+1, j] if i < self.map.shape[0]-1 else None # propagation self.env_gamma = 2.0 @@ -326,6 +359,9 @@ class SpaceMap(): for i in range(self.map.shape[0]): self.setLoss(i, j, penetrations[i ,j], reflections[i, j]) + def setOrientation(self, i, j, orientation): + self.map[i, j].setOrientation(orientation) + def setLoss(self, i, j, penetration, reflection): self.map[i, j].setLoss(penetration, reflection) self.__loss_p[i, j] = penetration @@ -341,7 +377,7 @@ class SpaceMap(): def setEnvGamma(self, val: float): self.env_gamma = val - def traceRay(self, tx_power: float, tx_loc: SpaceBlock, rx_loc: SpaceBlock): + def traceRay(self, tx_power: float, tx_loc: SpaceBlock, rx_loc: SpaceBlock, debug: bool = False): def getPathFromRay(ray, stop_blk): path = SpaceRay(ray.start, stop_blk) # prevent 0 distance @@ -385,6 +421,38 @@ class SpaceMap(): sig_pwr += np.power(10, path.getEndingPower() / 10.0) return 10.0 * np.log10(sig_pwr) + def removeRedundantPaths(paths): + paths_len = len(paths) + duplicated_ones = {} + # calcualte pair-wise distance + for i in range(paths_len): + for j in range(i + 1, paths_len): + if abs(paths[i].start - paths[j].start) < 2.0 * self.bs: + if i not in duplicated_ones: + duplicated_ones[i] = [0, []] + duplicated_ones[i][0] += 1 + duplicated_ones[i][1].append(j) + if j not in duplicated_ones: + duplicated_ones[j] = [0, []] + duplicated_ones[j][0] += 1 + duplicated_ones[j][1].append(i) + # removal + to_be_removed = [] + while len(duplicated_ones) > 0: + idx = sorted(list(duplicated_ones.keys()), key=lambda x: duplicated_ones[x][0], reverse=True)[0] + for target_idx in duplicated_ones[idx][1]: + if target_idx not in to_be_removed: + to_be_removed.append(target_idx) + duplicated_ones[idx][0] -= 1 + duplicated_ones[target_idx][0] -= 1 + if duplicated_ones[target_idx][0] == 0: + del duplicated_ones[target_idx] + continue + del duplicated_ones[target_idx][1][duplicated_ones[target_idx][1].index(idx)] + del duplicated_ones[idx] + for each in sorted(to_be_removed, reverse=True): + del paths[each] + # # round # rx_loc = ((rx_loc / self.bs).round() + 0.5) * self.bs # fake_init_ray = SpaceRay(None, None) @@ -418,14 +486,21 @@ class SpaceMap(): continue ref_blk = ray.reflection_blks[0] path = getPathFromRay(ray, ref_blk) + # too weak if path is None or path.getEndingPower() < NOISE_FLOOR: continue + # penetrated ray ray_p = getRayFromPath(path, ray.getAngle(), t='penetrate') if ray_p is not None: rays.append(ray_p) - # ray_r = getRayFromPath(path, path.getAngle() + 0.5 * np.pi, t='reflect') - # ray_r = getRayFromPath(path, path.getAngle() - 0.5 * np.pi, t='reflect') - + # reflected ray + if ref_blk.getOrientation() is None: + # if no orientation info provided, cannot calculate reflected ray + continue + ray_r = getRayFromPath(path, 2.0 * ref_blk.getOrientation() - path.getAngle() , t='reflect') + if ray_r is not None: + rays.append(ray_r) + # clean up for too nearby paths + removeRedundantPaths(rx_loc_paths) return aggreatePower(rx_loc_paths), rx_loc_paths - - + \ No newline at end of file diff --git a/tests/spacemap.py b/tests/spacemap.py index a25dac5..a55b98a 100644 --- a/tests/spacemap.py +++ b/tests/spacemap.py @@ -16,15 +16,21 @@ from libs.plotting import plotSpace def test(): spacemap = SpaceMap(width=6.4, length=6.4, block_size=0.1) - for i in range(10, 40): - spacemap.setLoss(i, 10, penetration=-5.0, reflection=-80.0) - spacemap.setLoss(i, 20, penetration=-5.0, reflection=-80.0) + # add walls + for i in range(0, 64): + spacemap.setLoss(i, 10, penetration=-5.0, reflection=-100.0) + spacemap.setOrientation(i, 10, orientation=0.0) + spacemap.setLoss(i, 50, penetration=-50.0, reflection=-10.0) + spacemap.setOrientation(i, 50, orientation=0.0) plotSpace(spacemap, cminmax=(-50, 0.0)) rx_loc = SpaceBlock(6.25, 3.2) rx_loc_rss, rx_loc_paths = spacemap.traceRay(0.0, SpaceBlock(0.0, 0.0), rx_loc) + multipaths = [] for path in rx_loc_paths: - print(path) - print(rx_loc_rss) + print("found path: {}".format(path)) + multipaths.extend(list(path)) + print("rss = {:.6f}dB".format(rx_loc_rss)) + plotSpace(spacemap, space_rays=multipaths, cminmax=(-50, 0.0)) if __name__ == "__main__":