def heatmap(self): csi_trace = self.csi_data.frames finalEntry, no_frames, no_subcarriers = get_CSI(self.csi_data) if len(finalEntry.shape) == 4: #>1 antenna stream. #Loading the first for ease. finalEntry = finalEntry[:, :, 3, 0] # from CSIKit.filters.wavelets.dwt import denoise # finalEntry = denoise(finalEntry) #Transpose to get subcarriers * amplitude. finalEntry = np.transpose(finalEntry) x_label = "Time (s)" try: x = self.csi_data.timestamps x = [timestamp - x[0] for timestamp in x] except AttributeError as e: #No timestamp in frame. Likely an IWL entry. #Will be moving timestamps to CSIData to account for this. x = [0] if sum(x) == 0: #Some files have invalid timestamp_low values which means we can't plot based on timestamps. #Instead we'll just plot by frame count. xlim = no_frames x_label = "Frame No." else: xlim = max(x) limits = [0, xlim, 1, no_subcarriers] # limits = [0, xlim, -64, 63] #TODO Add options for filtering. # for x in range(no_subcarriers): # hampelData = hampel(finalEntry[x], 5, 3) # runningMeanData = running_mean(hampelData, 20) # # smoothedData = dynamic_detrend(runningMeanData, 5, 3, 1.2, 10) # # doubleHampel = hampel(smoothedData, 10, 3) # finalEntry[x] = bandpass(9, 1, 2, Fs, runningMeanData) # # for i in range(0, 140): # # finalEntry[x][i] = 0 _, ax = plt.subplots() im = ax.imshow(finalEntry, cmap="jet", extent=limits, aspect="auto") cbar = ax.figure.colorbar(im, ax=ax) cbar.ax.set_ylabel("Amplitude (dBm)") plt.xlabel(x_label) plt.ylabel("Subcarrier Index") plt.title(self.csi_data.filename) plt.show()
def generate_json(path: str, metric: str = "amplitude") -> str: """ This function converts a csi_trace into the json format. It works for single entry or the whole trace. Parameters: path (str): Path to CSI file location. """ def default(prop): if "complex" in str(type(prop)): return str(prop) if "numpy" in str(type(prop)): return prop.tolist() if "__dict__" in dir(prop): return prop.__dict__ else: print("Prop has no __dict__ {}: \n {}".format(type(prop), prop)) reader = get_reader(path) csi_data = reader.read_file(path) csi_matrix, no_frames, no_subcarriers = get_CSI(csi_data, metric) print("CSI Shape: {}".format(csi_matrix.shape)) print("Number of Frames: {}".format(no_frames)) print("Generating CSI {}...".format(metric)) json_str = json.dumps(csi_matrix, default=default, indent=True) return json_str
def prepostfilter(self): csi_trace = self.csi_data.frames finalEntry, no_frames, _ = get_CSI(self.csi_data) finalEntry = finalEntry[15] hampelData = hampel(finalEntry, 10) smoothedData = running_mean(hampelData.copy(), 10) y = finalEntry y2 = hampelData y3 = smoothedData x = list([x.timestamp for x in csi_trace]) if sum(x) == 0: x = np.arange(0, no_frames, 1) plt.plot(x, y, label="Raw") plt.plot(x, y2, label="Hampel") plt.plot(x, y3, "r", label="Hampel + Running Mean") plt.xlabel("Time (s)") plt.ylabel("Amplitude (dBm)") plt.legend(loc="upper right") plt.show()
def load_csi_data(csi_data, subcarrier_range=ALL_CHANNELS, target_sample_rate=10, lowpass=True): frames = csi_data.frames #Identify the need for source resampling. no_frames = len(frames) first_timestamp = frames[0].timestamp last_timestamp = frames[-1].timestamp final_timestamp = last_timestamp - first_timestamp average_sample_rate = no_frames / final_timestamp #Check the average sample rate is close enough to that we'd expect. if abs(average_sample_rate - DEFAULT_FS) > 10: #Ideally we'd like to use some interpolation. #But supposedly scipy's interp1d is slow. #For now, we'll stick with downsampling since we're in control of data capture. if average_sample_rate > DEFAULT_FS: downsample_factor = int(average_sample_rate / DEFAULT_FS) frames = frames[::downsample_factor] #At this point, our trace object should have an avg sampling rate of 100Hz. #Retrieve CSI for the data we've got now. csi, _, _ = get_CSI(csi_data) timestamps = csi_data.timestamps # timestamps = [x["timestamp"] for x in trace] # timestamps_unscaled = [x["timestamp_low"] for x in trace] #Filter out unwanted subcarriers. csi = csi[[x for x in range(256) if x not in USELESS_SUBCARRIERS]] csi = csi[[x for x in subcarrier_range]] #Handle Lowpass filter. if lowpass: sampling_rate = 100 #Hz lowpass_cutoff = 10 #Hz order = 5 #n for x in range(csi.shape[0]): csi[x] = filters.lowpass(csi[x], lowpass_cutoff, sampling_rate, order) csi = np.nan_to_num(csi) csi_trans = np.transpose(csi) #Downsample to 10Hz. csi_trans = csi_trans[::10] timestamps = timestamps[::10] return csi_trans, timestamps, timestamps
def plotAllSubcarriers(self): finalEntry, no_frames, _ = get_CSI(self.csi_data) for x in finalEntry: plt.plot(np.arange(no_frames) / 20, x) plt.xlabel("Time (s)") plt.ylabel("Amplitude (dBm)") plt.legend(loc="upper right") plt.show()
def generate_npz(path: str, dest: str, metric: str = "amplitude"): reader = get_reader(path) csi_data = reader.read_file(path) if dest[-4:] != ".npz": dest += ".npz" csi_matrix, _, _ = get_CSI(csi_data, metric) np.savez_compressed(dest, csi_matrix) print("CSI matrix with shape: {}".format(csi_matrix.shape)) print("Generating CSI {}...".format(metric)) print("File written to: {}".format(dest))
def get_metadata(self) -> CSIMetadata: chipset = self.chipset bandwidth = self.bandwidth unmodified_csi_matrix = self.frames[0].csi_matrix _, no_frames, no_subcarriers = get_CSI(self) rx_count = (0, 0) tx_count = (0, 0) if len(unmodified_csi_matrix.shape) <= 2: rx_count, tx_count = (1, 1) elif len(unmodified_csi_matrix.shape) == 3: rx_count, tx_count = unmodified_csi_matrix.shape[1:] antenna_config_string = "{} Rx, {} Tx".format(rx_count, tx_count) timestamps = self.timestamps final_timestamp = timestamps[-1] #Check if timestamp is relative or epoch. time_length = 0 if len(str(final_timestamp)) > 9: #Likely an epoch timestamp. #Get diff between first and last. time_length = final_timestamp - timestamps[0] else: time_length = float(final_timestamp) if final_timestamp == 0: average_sample_rate = 0 else: average_sample_rate = no_frames/time_length data = { "chipset": chipset, "bandwidth": bandwidth, "antenna_config": antenna_config_string, "frames": no_frames, "subcarriers": no_subcarriers, "time_length": time_length, "average_sample_rate": average_sample_rate, "csi_shape": unmodified_csi_matrix.shape } return CSIMetadata(data)
def generate_csv(path: str, dest: str, metric: str = "amplitude"): reader = get_reader(path) csi_data = reader.read_file(path) csi_matrix, no_frames, no_subcarriers = get_CSI(csi_data, metric) no_rx, no_tx = csi_matrix.shape[2:] print("CSI Shape: {}".format(csi_matrix.shape)) print("Number of Frames: {}".format(no_frames)) print("Generating CSI {}...".format(metric)) print("CSV dimensions: {} Rows, {} Columns".format( no_frames, no_subcarriers * no_rx * no_tx)) csv_header = [] for subcarrier in range(no_subcarriers): for rx in range(no_rx): for tx in range(no_tx): csv_header.append("Sub {} RXTX {}/{}".format( subcarrier, rx, tx)) with open(dest, "w", newline="") as csv_file: writer = csv.writer(csv_file, delimiter=",") writer.writerow(csv_header) for frame in range(no_frames): frame_data = csi_matrix[frame] row_data = [] for subcarrier in range(no_subcarriers): subcarrier_data = frame_data[subcarrier] for rx in range(no_rx): rx_data = subcarrier_data[rx] for tx in range(no_tx): tx_data = rx_data[tx] row_data.append(tx_data) writer.writerow(row_data) print("File written to: {}".format(dest))
def get_metadata(self) -> CSIMetadata: chipset = self.chipset bandwidth = self.bandwidth unmodified_csi_matrix = self.frames[0].csi_matrix _, no_frames, no_subcarriers = get_CSI(self) rx_count = (0, 0) tx_count = (0, 0) if len(unmodified_csi_matrix.shape) <= 2: rx_count, tx_count = (1, 1) elif len(unmodified_csi_matrix.shape) == 3: rx_count, tx_count = unmodified_csi_matrix.shape[1:] antenna_config_string = "{} Rx, {} Tx".format(rx_count, tx_count) timestamps = self.timestamps final_timestamp = timestamps[-1] #Check if timestamp is relative or epoch. time_length = 0 if len(str(final_timestamp)) > 9: #Likely an epoch timestamp. #Get diff between first and last. time_length = final_timestamp - timestamps[0] else: time_length = round(float(final_timestamp), 1) if final_timestamp == 0: average_sample_rate = 0 else: average_sample_rate = round(no_frames/time_length, 1) rss_total = [] if hasattr(self.frames[0], "rssi"): rss_total = [x.rssi for x in self.frames] else: # Must sum a/b/c. for frame in self.frames: total_rss_for_frame = 0 divisor = 0 if frame.rssi_a != 0: total_rss_for_frame += frame.rssi_a divisor += 1 if frame.rssi_b != 0: total_rss_for_frame += frame.rssi_b divisor += 1 if frame.rssi_c != 0: total_rss_for_frame += frame.rssi_c divisor += 1 total_rss_for_frame /= divisor rss_total.append(total_rss_for_frame) average_rssi = round(np.mean(rss_total), 1) data = { "chipset": chipset, "bandwidth": bandwidth, "antenna_config": antenna_config_string, "frames": no_frames, "subcarriers": no_subcarriers, "time_length": time_length, "average_sample_rate": average_sample_rate, "average_rssi": average_rssi, "csi_shape": unmodified_csi_matrix.shape } return CSIMetadata(data)