From f7c57c943a97c3d0173ba3a6f5d4a65413298caa Mon Sep 17 00:00:00 2001 From: Agrimagsrl Date: Sun, 9 Aug 2020 16:02:52 +0200 Subject: [PATCH] add port_wifi_indoor_positioning --- MANIFEST | 2 +- micromlgen/__init__.py | 1 + micromlgen/micromlgen.py | 2 +- micromlgen/platforms.py | 13 ++++ .../wifiindoorpositioning.jinja | 43 ++++++++++++ micromlgen/wifiindoorpositioning.py | 69 +++++++++++++++++++ setup.py | 4 +- 7 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 micromlgen/templates/wifiindoorpositioning/wifiindoorpositioning.jinja create mode 100644 micromlgen/wifiindoorpositioning.py diff --git a/MANIFEST b/MANIFEST index 4f17062..f9d0c78 100644 --- a/MANIFEST +++ b/MANIFEST @@ -6,7 +6,6 @@ micromlgen/decisiontree.py micromlgen/gaussiannb.py micromlgen/logisticregression.py micromlgen/micromlgen.py -micromlgen/patches.py micromlgen/pca.py micromlgen/platforms.py micromlgen/randomforest.py @@ -14,6 +13,7 @@ micromlgen/rvm.py micromlgen/sefr.py micromlgen/svm.py micromlgen/utils.py +micromlgen/templates/_skeleton.jinja micromlgen/templates/classmap.jinja micromlgen/templates/dot.jinja micromlgen/templates/testset.jinja diff --git a/micromlgen/__init__.py b/micromlgen/__init__.py index 435f1cf..5a1ff75 100644 --- a/micromlgen/__init__.py +++ b/micromlgen/__init__.py @@ -1,3 +1,4 @@ import micromlgen.platforms as platforms from micromlgen.micromlgen import port from micromlgen.utils import port_testset, port_trainset +from micromlgen.wifiindoorpositioning import port_wifi_indoor_positioning diff --git a/micromlgen/micromlgen.py b/micromlgen/micromlgen.py index ce7890a..5ff0057 100644 --- a/micromlgen/micromlgen.py +++ b/micromlgen/micromlgen.py @@ -33,4 +33,4 @@ def port( return port_gaussiannb(**locals()) elif is_pca(clf): return port_pca(**locals()) - raise TypeError('clf MUST be one of SVC, LinearSVC, OneClassSVC, RVC, DecisionTree, RandomForest, LogisticRegression, GaussianNB, SEFR, PCA') \ No newline at end of file + raise TypeError('clf MUST be one of %s' % ', '.join(platforms.ALLOWED_CLASSIFIERS)) \ No newline at end of file diff --git a/micromlgen/platforms.py b/micromlgen/platforms.py index dd659da..594c172 100644 --- a/micromlgen/platforms.py +++ b/micromlgen/platforms.py @@ -3,4 +3,17 @@ ALL = [ ARDUINO, ATTINY +] + +ALLOWED_CLASSIFIERS = [ + 'SVC', + 'LinearSVC', + 'OneClassSVC', + 'RVC', + 'SEFR', + 'DecisionTree', + 'RandomForest', + 'GaussianNB', + 'LogisticRegression', + 'PCA' ] \ No newline at end of file diff --git a/micromlgen/templates/wifiindoorpositioning/wifiindoorpositioning.jinja b/micromlgen/templates/wifiindoorpositioning/wifiindoorpositioning.jinja new file mode 100644 index 0000000..c6a6807 --- /dev/null +++ b/micromlgen/templates/wifiindoorpositioning/wifiindoorpositioning.jinja @@ -0,0 +1,43 @@ +#pragma once + +namespace Eloquent { + namespace Projects { + class WifiIndoorPositioning { + public: + /** + * Get feature vector + */ + float* getFeatures() { + static float features[{{ X[0]|length }}] = {0}; + uint8_t numNetworks = WiFi.scanNetworks(); + + for (uint8_t i = 0; i < {{ X[0]|length }}; i++) { + features[i] = 0; + } + + for (uint8_t i = 0; i < numNetworks; i++) { + int featureIdx = ssidToFeatureIdx(WiFi.SSID(i)); + + if (featureIdx >= 0) { + features[featureIdx] = WiFi.RSSI(i); + } + } + + return features; + } + + protected: + /** + * Convert SSID to featureIdx + */ + int ssidToFeatureIdx(String ssid) { + {% for network, idx in networkmap.items() %} + if (ssid.equals("{{ network }}")) + return {{ idx }}; + {% endfor %} + + return -1; + } + }; + } +} \ No newline at end of file diff --git a/micromlgen/wifiindoorpositioning.py b/micromlgen/wifiindoorpositioning.py new file mode 100644 index 0000000..f979191 --- /dev/null +++ b/micromlgen/wifiindoorpositioning.py @@ -0,0 +1,69 @@ +import json +import numpy as np +from micromlgen.utils import jinja + + +def parse_samples(samples, parser): + for line in samples.split('\n'): + if '{' in line and '}' in line: + data = json.loads(line) + info = {k: v for k, v in data.items() if k.startswith('__')} + networks = {k: v for k, v in data.items() if not k.startswith('__')} + yield parser(info, networks) + + +def get_classmap(samples): + """Get {location: classIdx} mapping""" + + def parser(info, networks): + return info['__location'] + + locations = list(parse_samples(samples, parser)) + return {location: i for i, location in enumerate(sorted(set(locations)))} + + +def get_networkmap(samples): + """Get {network: featureIdx} mapping""" + + def parser(info, networks): + return networks.keys() + + networks = [list(x) for x in parse_samples(samples, parser)] + networks = [network for sub in networks for network in sub] + return {network: i for i, network in enumerate(sorted(set(networks)))} + + +def get_x(samples, networkmap): + """Get features array""" + + def parser(info, networks): + x = [0] * len(networkmap) + for network, rssi in networks.items(): + x[networkmap.get(network)] = rssi + return x + + return np.asarray(list(parse_samples(samples, parser)), dtype=np.int8) + + +def get_y(samples, classmap): + """Get locationIdx array""" + + def parser(info, networks): + location = info['__location'] + assert location in classmap, 'Unknown location %s' % location + return classmap[location] + + return np.asarray(list(parse_samples(samples, parser))) + + +def port_wifi_indoor_positioning(samples): + classmap = get_classmap(samples) + networkmap = get_networkmap(samples) + X = get_x(samples, networkmap) + y = get_y(samples, classmap) + # classmap is flipped wrt the format `port` expects: flip it + classmap = {v: k for k, v in classmap.items()} + return X, y, classmap, jinja('wifiindoorpositioning/wifiindoorpositioning.jinja', { + 'X': X, + 'networkmap': networkmap + }) diff --git a/setup.py b/setup.py index 7be5dd1..47414c2 100644 --- a/setup.py +++ b/setup.py @@ -7,13 +7,13 @@ setup( name = 'micromlgen', packages = ['micromlgen'], - version = '1.1.7', + version = '1.1.8', license='MIT', description = 'Generate C code for microcontrollers from Python\'s sklearn classifiers', author = 'Simone Salerno', author_email = 'eloquentarduino@gmail.com', url = 'https://github.com/eloquentarduino/micromlgen', - download_url = 'https://github.com/eloquentarduino/micromlgen/archive/v_117.tar.gz', + download_url = 'https://github.com/eloquentarduino/micromlgen/archive/v_118.tar.gz', keywords = [ 'ML', 'microcontrollers',