diff --git a/libs/spacemap.py b/libs/spacemap.py index c0ff87c..198266d 100644 --- a/libs/spacemap.py +++ b/libs/spacemap.py @@ -19,7 +19,7 @@ class SpaceBlock(): self.has_transmitter = False self.loss_penetration = 0.0 self.loss_reflection = -100.0 - self.related_rays = [] + self.prev_ray = None def __mul__(self, val): return SpaceBlock(self.x * val, self.y * val, self.z * val) @@ -49,6 +49,12 @@ class SpaceBlock(): def __eq__(self, blk): return self.distance(blk) < FLOAT_TOLERANCE + def __contains__(self, lst): + for each in lst: + if self == each: + return True + return False + def includes(self, x, y, z=None, block_size=0.1): flag = x >= self.x and x < (self.x + block_size) flag = flag and y >= self.y and y < (self.y + block_size) @@ -110,7 +116,7 @@ class SpaceRay(): ''' def __init__(self, point1, point2): self.start = point1 - if not isinstance(point2, SpaceBlock): + if isinstance(point2, float): self.end = point1 + SpaceBlock(np.cos(point2), np.sin(point2)) * MAX_RANGE else: self.end = point2 @@ -122,16 +128,19 @@ class SpaceRay(): self.angle_theta_cos = None self.angle_theta_tan = self.slope = None # power and propagation - self.begininng_pwr = 0.0 - self.begininng_phase = 0.0 - self.this_starting_pwr = 0.0 - self.this_starting_phase = 0.0 - self.this_ending_pwr = 0.0 - self.this_ending_phase = 0.0 - self.this_pass_through_loss = None - self.this_pass_through_blks = None - self.this_gamma = None - self.loss_total = None + self.init_pwr = None + self.init_phase = None + self.starting_loss = None + self.starting_distance = None + self.ending_pwr = None + self.ending_phase = None + self.ending_loss = None + self.ending_distance = None + self.passthrough_loss = None + self.passthrough_blks = None + self.reflection_blks = None + self.gamma = 2.0 + # distance traveled prior to this distance self.distance_traveled = None self.reflection_count = 0 # id @@ -139,6 +148,23 @@ class SpaceRay(): self.prev_ray = None self.next_rays = [] + def __eq__(self, spaceray): + return (self.start - self.end) == (spaceray.start - spaceray.end) + + def __contains__(self, lst): + for each in lst: + if self == each: + return True + return False + + 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}, ".format(self.starting_loss, self.ending_loss) + + "prev_ray = {}".format(self.prev_ray) + ) + def getAngle(self, degree=False): if self.angle_theta is None: self.angle_theta = np.arctan2( @@ -174,65 +200,81 @@ class SpaceRay(): self.distance = self.start.distance(self.end) return self.distance - def setTravelDistance(self, prior_distance): - self.distance_traveled = prior_distance + self.getDistance() + def setStartingDistance(self, val): + self.starting_distance = val + + def getTraveledDistance(self): + if self.starting_distance is None: + print("need to run `setStartingLoss` first") + return + if self.ending_distance is None: + self.ending_distance = self.starting_distance + self.getDistance() + return self.ending_distance def derivePassAndReflectBlocks(self, space_map): - self.this_pass_through_blks = [] - self.this_reflection_blks = [] - step_blk = SpaceBlock(self.getAngleThetaCos(), self.getAngleThetaSin()) * factor - for i in range(1, int(self.getDistance() / factor)): + self.passthrough_blks = [] + 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)): next_blk = self.start + step_blk * i # assume 2D - x_idx, y_idx = [int(x) for x in (next_blk / factor).round()] - if x_idx < bounds[0] and x_idx > -1 and y_idx < bounds[1] and y_idx > -1: - if space_map.map[x_idx, y_idx].loss_penetration < 0: - self.this_pass_through_blks.append(space_map.map[x_idx, y_idx]) + x_idx, y_idx = [int(x) for x in (next_blk / space_map.bs).round()] + if x_idx < space_map.map.shape[0] and x_idx > -1 and y_idx < space_map.map.shape[1] and y_idx > -1: + early_stop_flag = True + if space_map.map[x_idx, y_idx].loss_penetration < 100: + self.passthrough_blks.append(space_map.map[x_idx, y_idx]) if space_map.map[x_idx, y_idx].loss_reflection > -100: - self.this_reflection_blks.append(space_map.map[x_idx, y_idx]) - # space_map.map[x_idx, y_idx].related_rays.append(self) + self.reflection_blks.append(space_map.map[x_idx, y_idx]) + continue + if early_stop_flag: + break def getPassThroughLoss(self): - if self.this_pass_through_blks is None: - print("need to run `derivePassAndReflectBlocks` first") - return - self.this_pass_through_loss = np.sum([ - each.loss_penetration - for each in self.this_pass_through_blks - ]) + if self.passthrough_loss is None: + if self.passthrough_blks is None: + print("need to run `derivePassAndReflectBlocks` first") + return + self.passthrough_loss = np.sum([ + each.loss_penetration + for each in self.passthrough_blks + ]) + return self.passthrough_loss - def setTotalLoss(self, prior_loss): + def getEndingLoss(self): ''' excluding the end penetration/reflection loss ''' - if self.this_pass_through_loss is None: - print("need to run `getPassThroughLoss` first") + if self.starting_loss is None: + print("need to run `setStartingLoss` first") return - self.loss_total = prior_loss + self.this_pass_through_loss - - def setInitPower(self, power, gamma=2.0): - self.begininng_pwr = power - self.this_gamma = gamma - - def computeResultingPwr(self): - if self.loss_total is None: - print("need to run `setTotalLoss` first") + if self.passthrough_loss is None and self.getPassThroughLoss() is None: return - if self.begininng_pwr is None: + self.ending_loss = self.starting_loss + self.passthrough_loss + return self.ending_loss + + def setStartingLoss(self, val): + self.starting_loss = val + + def setInitPower(self, amplitude, phase=0.0): + self.init_pwr = amplitude + self.init_phase = phase + + def getEndingPower(self): + if self.ending_loss is None: + if self.getEndingLoss() is None: + return + if self.init_pwr is None: print("need to run `setInitPower` first") return - if self.distance_traveled is None: - print("need to run `setTravelDistance` first") - return - self.this_ending_pwr = log_gamma_dist( - np.array([self.distance_traveled]), - self.begininng_pwr, - self.this_gamma, - loss = self.loss_total, - gaussian_noise = False, - is_squared = False + self.ending_pwr = log_gamma_dist( + np.array([self.ending_distance]), + self.init_pwr, + self.gamma, + loss = self.ending_loss, + gaussian_noise = False )[0] - return self.this_ending_pwr + return self.ending_pwr class SpaceMap(): @@ -301,13 +343,45 @@ class SpaceMap(): self.env_gamma = val def traceRay(self, tx_power: float, tx_loc: SpaceBlock, rx_loc: SpaceBlock): + # round + rx_loc = ((rx_loc / self.bs).round() + 0.5) * self.bs + # fake_init_ray = SpaceRay(None, None) rays = [] for direction in np.arange(0, 359.99, self.ray_trace_deg_step): ray = SpaceRay(tx_loc, direction / 180.0 * np.pi) - ray.setPower(tx_power, self.env_gamma) - ray.ray_id = "ray_{0:.3f}".format(direction) + ray.setInitPower(tx_power, self.env_gamma) + ray.setStartingLoss(0.0) + ray.setStartingDistance(0.0) + ray.derivePassAndReflectBlocks(self) rays.append(ray) + # fake_init_ray.next_rays.append(ray) + # BFS + rx_loc_rays = [] while len(rays) > 0: ray = rays.pop(0) + # if no reflections exist, then only passing through, simple + if not ray.reflection_blks: + # if passing through the receiver block, we have a LoS here + if rx_loc in ray.passthrough_blks: + path = SpaceRay(ray.start, rx_loc) + # prevent 0 distance + if path.getDistance() < FLOAT_TOLERANCE: + continue + # inherit ray properties + path.passthrough_blks = ray.passthrough_blks[:ray.passthrough_blks.index(rx_loc)] + path.setInitPower(ray.init_pwr, ray.gamma) + path.setStartingDistance(ray.starting_distance) + path.setStartingLoss(ray.starting_loss) + path.prev_ray = ray.prev_ray + # + path.getTraveledDistance() + path.getPassThroughLoss() + path.getEndingLoss() + # + path.getEndingPower() + if path not in rx_loc_rays: + rx_loc_rays.append(path) + continue + return rx_loc_rays diff --git a/tests/spacemap.py b/tests/spacemap.py index 875d381..4634f0b 100644 --- a/tests/spacemap.py +++ b/tests/spacemap.py @@ -16,19 +16,10 @@ from libs.plotting import plotSpace def test(): spacemap = SpaceMap(width=6.4, length=6.4, block_size=0.1) - print(spacemap.getLosses()) - print(spacemap.getLoss(np.array([1, 2, 3]), 1)) - ray = SpaceRay(SpaceBlock(0.0, 0.0), SpaceBlock(2, 6.38)) - ray.derivePassAndReflectBlocks(spacemap) - ray.getPassThroughLoss() - ray.setTotalLoss(0.0) - ray.setInitPower(0, gamma=2.0) - ray.setTravelDistance(0.0) - pwr = ray.computeResultingPwr() - print("pwr = {}".format(pwr)) - print(ray.this_pass_through_blks[0].related_rays) - print(ray.this_pass_through_blks[0]) plotSpace(spacemap) + rx_locs_rays = spacemap.traceRay(0.0, SpaceBlock(0.0, 0.0), SpaceBlock(6.25, 3.2)) + for ray in rx_locs_rays: + print(ray) if __name__ == "__main__":