class GenerateData: '''generate training data using a propagation model ''' def __init__(self, seed: int, alpha: float, std: float, grid_length: int, cell_length: int, sensor_density: int, noise_floor: int): self.seed = seed self.alpha = alpha self.std = std self.grid_length = grid_length self.cell_length = cell_length self.sensor_density = sensor_density self.noise_floor = noise_floor self.propagation = Propagation(self.alpha, self.std) def log(self, power, cell_percentage, sample_per_label, sensor_file, root_dir, num_tx, num_tx_upper, min_dist, max_dist): '''the meta data of the data ''' with open(root_dir + '.txt', 'w') as f: f.write(f'seed = {self.seed}\n') f.write(f'alpha = {self.alpha}\n') f.write(f'std = {self.std}\n') f.write(f'grid length = {self.grid_length}\n') f.write(f'cell length = {self.cell_length}\n') f.write(f'sensor density = {self.sensor_density}\n') f.write(f'noise floor = {self.noise_floor}\n') f.write(f'power = {power}\n') f.write(f'cell percentage = {cell_percentage}\n') f.write(f'sample per label = {sample_per_label}\n') f.write(f'sensor file = {sensor_file}\n') f.write(f'root file = {root_dir}\n') f.write(f'number of TX = {num_tx}\n') f.write(f'num TX upperbound = {num_tx_upper}\n') f.write(f'min distance = {min_dist}\n') f.write(f'max distance = {max_dist}\n') def generate(self, power: float, cell_percentage: float, sample_per_label: int, sensor_file: str, root_dir: str, num_tx: int, num_tx_upper: bool, min_dist: int, max_dist: int): ''' The generated input data is not images, but instead matrix. Because saving as images will loss some accuracy Args: power -- the power of the transmitter cell_percentage -- percentage of cells being label (see if all discrete location needs to be labels) sample_per_label -- samples per cell sensor_file -- sensor location file root_dir -- the output directory ''' Utility.remove_make(root_dir) self.log(power, cell_percentage, sample_per_label, sensor_file, root_dir, num_tx, num_tx_upper, min_dist, max_dist) random.seed(self.seed) np.random.seed(self.seed) # 1 read the sensor file, do a checking if str(self.grid_length) not in sensor_file[:sensor_file.find('-')]: print( f'grid length {self.grid_length} and sensor file {sensor_file} not match' ) sensors = [] with open(sensor_file, 'r') as f: indx = 0 for line in f: x, y = line.split() sensors.append(Sensor(int(x), int(y), indx)) indx += 1 # 2 start from (0, 0), generate data, might skip some locations label_count = int(self.grid_length * self.grid_length * cell_percentage) population = [(i, j) for j in range(self.grid_length) for i in range(self.grid_length)] labels = random.sample(population, label_count) counter = 0 for label in sorted(labels): tx = label # each label create a directory tx_float = (tx[0] + random.uniform(0, 1), tx[1] + random.uniform(0, 1)) if counter % 100 == 0: print(f'{counter/len(labels)*100}%') folder = f'{root_dir}/{counter:06d}' os.mkdir( folder ) # update on Aug. 27, change the name of the folder from label to counter index for i in range(sample_per_label): targets = [tx_float] grid = np.zeros((self.grid_length, self.grid_length)) grid.fill(Default.noise_floor) for sensor in sensors: dist = Utility.distance_propagation( tx_float, (sensor.x, sensor.y)) * Default.cell_length pathloss = self.propagation.pathloss(dist) rssi = power - pathloss grid[sensor.x][ sensor. y] = rssi if rssi > Default.noise_floor else Default.noise_floor # the other TX population_set = set(population) if num_tx_upper is False: num_tx_copy = num_tx else: num_tx_copy = random.randint(1, num_tx) intru = tx while num_tx_copy > 1: # get one new TX at a time self.update_population(population_set, intru, Default.grid_length, min_dist, max_dist) ntx = random.sample(population_set, 1)[0] ntx = (ntx[0] + random.uniform(0, 1), ntx[1] + random.uniform(0, 1) ) # TX is not at the center of grid cell targets.append(ntx) for sensor in sensors: dist = Utility.distance_propagation( ntx, (sensor.x, sensor.y)) * Default.cell_length pathloss = self.propagation.pathloss(dist) rssi = power - pathloss exist_rssi = grid[sensor.x][sensor.y] grid[sensor.x][sensor.y] = Utility.linear2db( Utility.db2linear(exist_rssi) + Utility.db2linear(rssi)) num_tx_copy -= 1 intru = ntx np.save(f'{folder}/{i}.npy', grid.astype(np.float32)) np.save(f'{folder}/{i}.target', np.array(targets).astype(np.float32)) if i == 0: imageio.imwrite(f'{folder}/{tx}.png', grid) counter += 1 def update_population(self, population_set, intruder, grid_len, min_dist, max_dist): '''Update the population (the TX candidate locations) Args: population_set -- set -- the TX candidate locations intruder -- tuple<int, int> -- the new selected TX grid_len -- int -- grid length min_dist -- int -- minimum distance between two TX. for far away sensors max_dist -- int -- maximum distance between two TX. for close by sensors ''' if max_dist is None: cur_x = intruder[0] cur_y = intruder[1] for x in range(-min_dist, min_dist + 1): for y in range(-min_dist, min_dist + 1): nxt_x = cur_x + x nxt_y = cur_y + y if 0 <= nxt_x < grid_len and 0 <= nxt_y < grid_len and Utility.distance( intruder, (nxt_x, nxt_y)) < min_dist: if (nxt_x, nxt_y) in population_set: population_set.remove((nxt_x, nxt_y)) else: cur_x = intruder[0] cur_y = intruder[1] for x, y in population_set.copy(): if not (min_dist <= Utility.distance(intruder, (x, y)) <= max_dist): population_set.remove((x, y))
class GenerateData: '''generate training data using a propagation model ''' def __init__(self, seed: int, alpha: float, std: float, grid_length: int, cell_length: int, sensor_density: int, noise_floor: int): self.seed = seed self.alpha = alpha self.std = std self.grid_length = grid_length self.cell_length = cell_length self.sensor_density = sensor_density self.noise_floor = noise_floor self.propagation = Propagation(self.alpha, self.std) def log(self, power, cell_percentage, sample_per_label, sensor_file, root_dir, num_tx, num_tx_upper, min_dist, max_dist, edge, splat): '''the meta data of the data ''' with open(root_dir + '.txt', 'w') as f: f.write(f'seed = {self.seed}\n') f.write(f'alpha = {self.alpha}\n') f.write(f'std = {self.std}\n') f.write(f'grid length = {self.grid_length}\n') f.write(f'cell length = {self.cell_length}\n') f.write(f'sensor density = {self.sensor_density}\n') f.write(f'noise floor = {self.noise_floor}\n') f.write(f'power = {power}\n') f.write(f'cell percentage = {cell_percentage}\n') f.write(f'sample per label = {sample_per_label}\n') f.write(f'sensor file = {sensor_file}\n') f.write(f'root file = {root_dir}\n') f.write(f'number of TX = {num_tx}\n') f.write(f'num TX upperbound = {num_tx_upper}\n') f.write(f'min distance = {min_dist}\n') f.write(f'max distance = {max_dist}\n') f.write(f'edge = {edge}\n') f.write(f'splat = {splat}\n') def check_edge(self, tx, edge): '''if tx is at the edge, return false Args: tx -- tuple<int, int> ''' if edge <= tx[0] < self.grid_length-edge and edge <= tx[1] < self.grid_length-edge: return True return False def generate(self, power: float, cell_percentage: float, sample_per_label: int, sensor_file: str,\ root_dir: str, num_tx: int, num_tx_upper: bool, min_dist: int, max_dist: int, edge: int, vary_power: int, splat: bool): ''' The generated input data is not images, but instead matrix. Because saving as images will loss some accuracy Args: power -- the power of the transmitter cell_percentage -- percentage of cells being label (see if all discrete location needs to be labels) sample_per_label -- samples per cell sensor_file -- sensor location file root_dir -- the output directory ''' Utility.remove_make(root_dir) self.log(power, cell_percentage, sample_per_label, sensor_file, root_dir, num_tx, num_tx_upper, min_dist, max_dist, edge, splat) # random.seed(self.seed) # need to comment this line when running simulate_data.py, or they will generate the same TX locations # 1 read the sensor file, do a checking if str(self.grid_length) not in sensor_file[:sensor_file.find('-')]: print(f'grid length {self.grid_length} and sensor file {sensor_file} not match') sensors = [] with open(sensor_file, 'r') as f: indx = 0 for line in f: x, y = line.split() sensors.append(Sensor(int(x), int(y), indx)) indx += 1 # 2 start from (0, 0), generate data, might skip some locations population = [(i, j) for i in range(self.grid_length) for j in range(self.grid_length) if self.check_edge((i, j), edge)] # Tx is not at edge label_count = int(len(population)*cell_percentage) labels = random.sample(population, label_count) counter = 0 for label in sorted(labels): tx = label # each label create a directory tx_float = (tx[0] + random.uniform(0, 1), tx[1] + random.uniform(0, 1)) if counter % 100 == 0: print(f'{counter/len(labels)*100}%') folder = f'{root_dir}/{counter:06d}' os.mkdir(folder) # update on Aug. 27, change the name of the folder from label to counter index for i in range(sample_per_label): power_delta = random.uniform(-vary_power, vary_power) targets = [tx_float] # ground truth location power_deltas = [power_delta] # ground truth power grid = np.zeros((self.grid_length, self.grid_length)) grid.fill(Default.noise_floor) for sensor in sensors: if not splat: dist = Utility.distance_propagation(tx_float, (sensor.x, sensor.y)) * Default.cell_length pathloss = self.propagation.pathloss(dist) else: pathloss = mysplat.pathloss(tx_float[0], tx_float[1], sensor.x, sensor.y) + random.uniform(-0.25, 0.25) rssi = (power + power_delta) - pathloss grid[sensor.x][sensor.y] = rssi if rssi > Default.noise_floor else Default.noise_floor # the other TX population_set = set(population) if num_tx_upper is False: num_tx_copy = num_tx else: num_tx_copy = random.randint(1, num_tx) intru = tx while num_tx_copy > 1: # get one new TX at a time self.update_population(population_set, intru, Default.grid_length, min_dist, max_dist) ntx = random.sample(population_set, 1)[0] ntx = (ntx[0] + random.uniform(0, 1), ntx[1] + random.uniform(0, 1)) # TX is not at the center of grid cell power_delta = random.uniform(-vary_power, vary_power) targets.append(ntx) power_deltas.append(power_delta) for sensor in sensors: if not splat: dist = Utility.distance_propagation(ntx, (sensor.x, sensor.y)) * Default.cell_length pathloss = self.propagation.pathloss(dist) else: pathloss = mysplat.pathloss(ntx[0], ntx[1], sensor.x, sensor.y) + random.uniform(-0.25, 0.25) rssi = (power + power_delta) - pathloss exist_rssi = grid[sensor.x][sensor.y] grid[sensor.x][sensor.y] = Utility.linear2db(Utility.db2linear(exist_rssi) + Utility.db2linear(rssi)) num_tx_copy -= 1 intru = ntx np.save(f'{folder}/{i}.npy', grid.astype(np.float32)) np.save(f'{folder}/{i}.target', np.array(targets).astype(np.float32)) np.savetxt(f'{folder}/{i}.txt', np.array(power_deltas).astype(np.float32)) # Dec. 12, 2020: save in txt format (currently not used in the CNN) self.save_ipsn_input(grid, targets, power_deltas, sensors, f'{folder}/{i}.json') # if i == 0: # imageio.imwrite(f'{folder}/{tx}.png', grid) counter += 1 def save_ipsn_input(self, grid, targets, power_deltas, sensors, output_file): ''' Args: grid -- np.ndarray, n = 2 targets -- list<tuple<float, float>> power_deltas -- list<float> -- power of the TX, varying sensors -- list<Sensors> output_file -- str ''' tx_data = {} for i, tx in enumerate(targets): tx_data[str(i)] = { "location": (round(tx[0], 3), round(tx[1], 3)), "gain": round(power_deltas[i], 3) } sensor_data = {} for i, sen in enumerate(sensors): sensor_data[str(i)] = round(grid[sen.x][sen.y], 3) ipsn_input = IpsnInput(tx_data, sensor_data) with open(output_file, 'w') as f: f.write(ipsn_input.to_json_str()) def generate_ipsn(self, power: str, sensor_file: str, root_dir: str, splat: bool): '''generate the training data for the IPSN20 localization algorithm ''' # sensors Utility.remove_make(root_dir) sensors = [] with open(sensor_file, 'r') as f, open(root_dir + '/sensors', 'w') as f_out: indx = 0 for line in f: x, y = line.split() f_out.write('{} {} {} {}\n'.format(x, y, 1, 1)) # uniform cost sensors.append(Sensor(int(x), int(y), indx)) indx += 1 # covariance matrix sen_num = len(sensors) with open(root_dir + '/cov', 'w') as f: cov = np.zeros((sen_num, sen_num)) for i in range(sen_num): for j in range(sen_num): if i == j: cov[i, j] = 1 # assume the std is 1 f.write('{} '.format(cov[i, j])) f.write('\n') # hypothesis total_loc = self.grid_length*self.grid_length with open(root_dir + '/hypothesis', 'w') as f: for tx_1dindex in range(total_loc): t_x = tx_1dindex // self.grid_length t_y = tx_1dindex % self.grid_length for sen in sensors: if not splat: dist = Utility.distance_propagation((t_x, t_y), (sen.x, sen.y)) * Default.cell_length pathloss = self.propagation.pathloss(dist) else: pathloss = mysplat.pathloss(t_x, t_y, sen.x, sen.y) + random.uniform(-0.25, 0.25) f.write('{} {} {} {} {:.3f} {}\n'.format(t_x, t_y, sen.x, sen.y, power - pathloss, 1)) def update_population(self, population_set, intruder, grid_len, min_dist, max_dist): '''Update the population (the TX candidate locations) Args: population_set -- set -- the TX candidate locations intruder -- tuple<int, int> -- the new selected TX grid_len -- int -- grid length min_dist -- int -- minimum distance between two TX. for far away sensors max_dist -- int -- maximum distance between two TX. for close by sensors ''' if max_dist is None: cur_x = intruder[0] cur_y = intruder[1] for x in range(-min_dist, min_dist+1): for y in range(-min_dist, min_dist+1): nxt_x = cur_x + x nxt_y = cur_y + y if 0 <= nxt_x < grid_len and 0 <= nxt_y < grid_len and Utility.distance(intruder, (nxt_x, nxt_y)) < min_dist: if (nxt_x, nxt_y) in population_set: population_set.remove((nxt_x, nxt_y)) else: cur_x = intruder[0] cur_y = intruder[1] for x, y in population_set.copy(): if not (min_dist <= Utility.distance(intruder, (x, y)) <= max_dist): population_set.remove((x, y))