diff --git a/libs/fitting.py b/libs/fitting.py index 6d7642b..813a3c4 100644 --- a/libs/fitting.py +++ b/libs/fitting.py @@ -62,18 +62,20 @@ def modelfit_log_gamma( bounds_loc_x, bounds_loc_y, bounds_pwr, bounds_gamma ])) + sampled_rx_locs = rx_locs + sampled_rx_rsses = rx_rsses if monte_carlo_sampling and rx_rsses.shape[0] > 10: logistics = np.random.choice( np.arange(rx_rsses.shape[0]), size=int(monte_carlo_sampling_rate * rx_rsses.shape[0]), replace=False ) - rx_locs = rx_locs[logistics, :] - rx_rsses = rx_rsses[logistics, :] + sampled_rx_locs = rx_locs[logistics, :] + sampled_rx_rsses = rx_rsses[logistics] # fit popt, pcov = curve_fit( - modelfit_log_gamma_func, rx_locs, rx_rsses, + modelfit_log_gamma_func, sampled_rx_locs, sampled_rx_rsses, p0=seeds, bounds=bounds ) @@ -84,8 +86,15 @@ def modelfit_log_gamma( else: est_loc_x, est_loc_y, est_tx_pwr, est_env_gamma, est_loc_z = popt est_tx_loc = np.array([est_loc_x, est_loc_y, est_loc_z]) - est_rsses = log_gamma_loc(rx_locs, est_tx_loc, est_tx_pwr, est_env_gamma) - est_errors = est_rsses - rx_rsses - pmse = 1.0 * np.nansum(est_errors * est_errors) / est_errors.shape[0] - return pmse, est_tx_loc, est_tx_pwr, est_env_gamma, est_rsses + # compute fit mse + est_sampled_rsses = log_gamma_loc(sampled_rx_locs, est_tx_loc, est_tx_pwr, est_env_gamma) + est_errors = est_sampled_rsses - sampled_rx_rsses + fit_mse = 1.0 * np.nansum(est_errors * est_errors) / est_errors.shape[0] + + # compute the full original map if monte_carlo_sampling enabled + est_rsses = est_sampled_rsses + if monte_carlo_sampling and rx_rsses.shape[0] > 10: + est_rsses = log_gamma_loc(rx_locs, est_tx_loc, est_tx_pwr, est_env_gamma) + + return fit_mse, est_tx_loc, est_tx_pwr, est_env_gamma, est_rsses diff --git a/libs/util.py b/libs/util.py new file mode 100644 index 0000000..282aec1 --- /dev/null +++ b/libs/util.py @@ -0,0 +1,47 @@ +#!/usr/bin/python + + +import numpy as np +from libs.consts import NOISE_FLOOR + + +def touch(filepath): + try: + open(filepath, 'a').close() + return True + except BaseException: + pass + return False + + +def convert_mat_to_vector( + mat: np.ndarray, + block_size: float = 0.1 +): + ''' + ''' + rx_locs = [] + rx_rsses = [] + width, length = mat.shape + for i in range(width): + for j in range(length): + if mat[i, j] <= NOISE_FLOOR: + continue + rx_locs.append([(i + 0.5) * block_size, (j + 0.5) * block_size]) + rx_rsses.append(mat[i, j]) + return np.array(rx_locs), np.array(rx_rsses) + + +def convert_vector_to_mat( + rx_locs: np.ndarray, + rx_rsses: np.ndarray, + shape: tuple, + block_size: float = 0.1 +): + ''' + ''' + result = np.ones(shape) * -85.0 + for i in range(rx_locs.shape[0]): + x, y = rx_locs[i, :] / block_size + result[int(x), int(y)] = rx_rsses[i] + return result diff --git a/model_conventional_fitting.py b/model_conventional_fitting.py new file mode 100644 index 0000000..52a0708 --- /dev/null +++ b/model_conventional_fitting.py @@ -0,0 +1,156 @@ +#!/usr/bin/python + +import os +import sys +import pickle +import argparse + +from libs.util import touch +from libs.util import convert_mat_to_vector +from libs.util import convert_vector_to_mat +from libs.fitting import modelfit_log_gamma +from libs.plotting import plotRSS + + +def loadData(filepath): + try: + return pickle.load(open(filepath, "rb")) + except BaseException as e: + print("err: {}".format(e)) + pass + return None + + +def fittingSingle(filepath, args): + ''' + ''' + # load data from file + data = loadData(filepath) + if data is None: + print("err: failed to load file {}".format(filepath)) + return + + # convert data matrix to vectors + rx_locs, rx_rsses = convert_mat_to_vector(data, block_size=0.1) + + # start fitting + min_pmse = float('inf') + best_tx_loc = None + best_tx_pwr = None + best_env_gamma = None + best_rsses = None + for i in range(100): + result = modelfit_log_gamma( + rx_locs, + rx_rsses, + bounds_pwr=(-60, 0), + bounds_gamma=(2, 6), + bounds_loc_x=(0, 6.2), + bounds_loc_y=(0, 6.2), + monte_carlo_sampling=False, + monte_carlo_sampling_rate=0.8 + ) + # unpack + pmse, est_tx_loc, est_tx_pwr, est_env_gamma, est_rsses = result + if pmse < min_pmse: + print("|----- found better:", pmse, est_tx_loc, est_tx_pwr, est_env_gamma) + min_pmse = pmse + best_tx_loc = est_tx_loc + best_tx_pwr = est_tx_pwr + best_env_gamma = est_env_gamma + best_rsses = est_rsses + print("|- final:") + print("|--- tx loc: {:.3f}, {:.3f}".format(best_tx_loc[0], best_tx_loc[1])) + print("|--- tx pwr: {:.2f}".format(best_tx_pwr)) + print("|--- env gamma: {:.2f}".format(best_env_gamma)) + print("|--- fitting mse: {:.6f}".format(min_pmse)) + data_best_est = convert_vector_to_mat(rx_locs, best_rsses, data.shape, block_size=0.1) + + if args.outputfile: + filename = os.path.basename(args.outputfile) + with open(args.outputfile, 'a') as f: + f.write( + "{},".format(filename) + + "{:.3f},{:.3f},".format(best_tx_loc[0], best_tx_loc[1]) + + "{:.2f},{:.2f}".format(best_tx_pwr, best_env_gamma) + + "{:.6f}".format(min_pmse) + + "\n" + ) + + if args.visualize: + plotRSS( + data, + data_best_est, + est_tx_loc=best_tx_loc / 0.1 + ) + + +def main(args): + + # finding files + filepaths = [] + if args.filepath: + filepaths.append(args.filepath) + if args.folderpath: + files = os.listdir(args.folderpath) + filepaths.extend(["{}/{}".format(args.folderpath, file) for file in files if '.pickle' in file]) + + # prepare + if args.outputfile: + with open(args.outputfile, 'w') as f: + f.write("filename,tx_x,tx_y,tx_pwr,env_gamma,fit_mse\n") + + + # loop through and fit + for i in range(len(filepaths)): + print("- model fitting on file {}".format(filepaths[i])) + fittingSingle(filepaths[i], args) + + +if __name__ == '__main__': + p = argparse.ArgumentParser(description='Traditional Model Fitting') + p.add_argument( + '--filepath', '-f', + dest='filepath', + default=None, + help='input filepath for a pickle' + ) + p.add_argument( + '--folderpath', '-fd', + dest='folderpath', + default=None, + help='input folderpath for many pickles' + ) + p.add_argument( + '--visualize', '-v', + action='store_true', + default=False, + help='enable visualize' + ) + p.add_argument( + '--output', '-o', + dest='outputfile', + default=None, + help='output results to filepath' + ) + try: + args = p.parse_args() + except BaseException as e: + print(e) + sys.exit() + + if args.filepath is None and args.folderpath is None: + print("at least specify file `-f` or folder `-fd`") + sys.exit() + elif args.filepath is None and not os.path.isdir(args.folderpath): + print("folder {} not exit".format(args.folderpath)) + sys.exit() + elif args.folderpath is None and not os.path.isfile(args.filepath): + print("file {} not exit".format(args.filepath)) + sys.exit() + + if args.outputfile and not touch(args.outputfile): + print("cannot create file {}".format(args.outputfile)) + sys.exit() + + main(args) diff --git a/tests/fitting.py b/tests/fitting.py index 1f6b99c..7700099 100644 --- a/tests/fitting.py +++ b/tests/fitting.py @@ -10,35 +10,12 @@ import time import pickle import numpy as np from libs.consts import NOISE_FLOOR +from libs.util import convert_mat_to_vector +from libs.util import convert_vector_to_mat from libs.fitting import modelfit_log_gamma from libs.plotting import plotRSS -def convert_mat_to_vector(mat, block_size=0.1): - ''' - ''' - rx_locs = [] - rx_rsses = [] - width, length = mat.shape - for i in range(width): - for j in range(length): - if mat[i, j] <= NOISE_FLOOR: - continue - rx_locs.append([(i + 0.5) * block_size, (j + 0.5) * block_size]) - rx_rsses.append(mat[i, j]) - return np.array(rx_locs), np.array(rx_rsses) - - -def convert_vector_to_mat(rx_locs, rx_rsses, shape, block_size=0.1): - ''' - ''' - result = np.ones(shape) * -85.0 - for i in range(rx_locs.shape[0]): - x, y = rx_locs[i, :] / block_size - result[int(x), int(y)] = rx_rsses[i] - return result - - def test(): data_ori = pickle.load(open(os.path.join(os.path.dirname(__file__), "dev_map.pickle"), "rb")) rx_locs, rx_rsses = convert_mat_to_vector(data_ori) @@ -65,8 +42,6 @@ def test(): data_best_est, est_tx_loc=best_tx_loc / 0.1 ) - # print(rx_locs[:,1]) - # print(rx_locs[1,:]) if __name__ == "__main__":