Write AI layer, but it's untested.

This commit is contained in:
Starbeamrainbowlabs 2019-07-23 15:45:29 +01:00
parent f0694de02c
commit 61edaf6fa3
8 changed files with 106 additions and 22 deletions

View file

@ -12,5 +12,10 @@ export default {
border: 0.1, border: 0.1,
// The resolution of the coverage map // The resolution of the coverage map
step: 0.005 step: 0.005,
colour_scale: {
min: "#ffffff",
max: "#2cb42c"
}
}; };

View file

@ -3,10 +3,12 @@
import path from 'path'; import path from 'path';
import L from 'leaflet'; import L from 'leaflet';
import tf from '@tensorflow/tfjs'; import * as tf from '@tensorflow/tfjs';
import chroma from 'chroma-js';
import GetFromUrl from './Helpers/GetFromUrl.mjs'; import GetFromUrl from './Helpers/GetFromUrl.mjs';
import Config from './ClientConfig.mjs'; import Config from './ClientConfig.mjs';
import { normalise } from '../../common/Math.mjs';
class LayerAI { class LayerAI {
get gateway_bounds() { get gateway_bounds() {
@ -37,21 +39,28 @@ class LayerAI {
); );
console.log(index); console.log(index);
for(let gateway of this.index) { for(let gateway of this.index.index) {
let gateway_data = { this.gateways.set(
// TODO: Swap this out for the real thing - probably a GeoJSON layer or something gateway.id,
// This is just a placeholder await tf.LayersModel.loadModel(`${window.location.href}/${path.dirname(Config.ai_index_file)}/${gateway.id}`)
layer: L.layerGroup([ );
]),
ai: await tf.loadModel(`${window.location.href}/${path.dirname(Config.ai_index_file)}/${gateway.id}`)
}
this.gateways.set(gateway.id, gateway_data);
}
} }
async render_map() { this.layer = this.generate_layer();
this.layer.addTo(this.map);
}
generate_layer() {
return L.geoJSON(this.render_map(), {
style: (feature) => { return {
fillColor: feature.properties.colour,
fillOpacity: 0.4
} }
});
}
render_map() {
// FUTURE: Do this in a web worker?
let map_bounds = this.gateway_bounds; let map_bounds = this.gateway_bounds;
map_bounds.north += Config.border; map_bounds.north += Config.border;
map_bounds.south -= Config.border; map_bounds.south -= Config.border;
@ -59,7 +68,55 @@ class LayerAI {
map_bounds.east += Config.border; map_bounds.east += Config.border;
map_bounds.west -= Config.border; map_bounds.west -= Config.border;
let coverage = [],
colour_scale = chroma.scale(
Config.colour_scale.min,
Config.colour_scale.max
).domain(
this.index.properties.rssi_min,
this.index.properties.rssi_max
);
for(let lat = map_bounds.west; lat < map_bounds.east; lat += Config.step) {
for(let lng = map_bounds.south; lng < map_bounds.north; lng += Config.step) {
let max_predicted_rssi = -Infinity;
for(let [, ai] of this.gateways) {
max_predicted_rssi = Math.max(
max_predicted_rssi,
ai.predict(
tf.tensor1d([ lat, lng ])
)
);
}
max_predicted_rssi = normalise(max_predicted_rssi,
{ min: 0, max: 1 },
{
min: this.index.properties.rssi_min,
max: this.index.properties.rssi_max
}
);
coverage.push({
type: "Feature",
geometry: {
type: "Polygon",
coordinates: [
[lat, lng],
[lat + Config.step, lng],
[lat + Config.step, lng + Config.step],
[lat, lng + Config.step]
]
},
properties: {
colour: colour_scale(max_predicted_rssi)
}
})
}
}
return coverage;
} }
} }

23
package-lock.json generated
View file

@ -93,6 +93,12 @@
"@types/integer": "*" "@types/integer": "*"
} }
}, },
"@types/chroma-js": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/@types/chroma-js/-/chroma-js-1.4.1.tgz",
"integrity": "sha512-i9hUiO3bwgmzZUDwBuR65WqsBQ/nwN+H2fKX0bykXCdd8cFQEuIj8vI7FXjyb2f5z5h+pv76I/uakikKSgaqTA==",
"dev": true
},
"@types/estree": { "@types/estree": {
"version": "0.0.39", "version": "0.0.39",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
@ -492,9 +498,9 @@
} }
}, },
"caniuse-lite": { "caniuse-lite": {
"version": "1.0.30000984", "version": "1.0.30000985",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000984.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000985.tgz",
"integrity": "sha512-n5tKOjMaZ1fksIpQbjERuqCyfgec/m9pferkFQbLmWtqLUdmt12hNhjSwsmPdqeiG2NkITOQhr1VYIwWSAceiA==", "integrity": "sha512-1ngiwkgqAYPG0JSSUp3PUDGPKKY59EK7NrGGX+VOxaKCNzRbNc7uXMny+c3VJfZxtoK3wSImTvG9T9sXiTw2+w==",
"dev": true "dev": true
}, },
"chalk": { "chalk": {
@ -512,6 +518,11 @@
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==" "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g=="
}, },
"chroma-js": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.0.4.tgz",
"integrity": "sha512-gk71qOrSdBTLbsd0DIUO3QjZL8tTvMwpG1EoXYScy7rI4rcO4EyYH6zGuvCgUDumKumqg0pt6Ua+vWnMJsTYhw=="
},
"class-utils": { "class-utils": {
"version": "0.3.6", "version": "0.3.6",
"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
@ -1041,9 +1052,9 @@
} }
}, },
"electron-to-chromium": { "electron-to-chromium": {
"version": "1.3.194", "version": "1.3.199",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.194.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.199.tgz",
"integrity": "sha512-w0LHR2YD9Ex1o+Sz4IN2hYzCB8vaFtMNW+yJcBf6SZlVqgFahkne/4rGVJdk4fPF98Gch9snY7PiabOh+vqHNg==", "integrity": "sha512-gachlDdHSK47s0N2e58GH9HMC6Z4ip0SfmYUa5iEbE50AKaOUXysaJnXMfKj0xB245jWbYcyFSH+th3rqsF8hA==",
"dev": true "dev": true
}, },
"emojis-list": { "emojis-list": {

View file

@ -26,6 +26,7 @@
"async-mqtt": "^2.3.0", "async-mqtt": "^2.3.0",
"awilix": "^4.2.2", "awilix": "^4.2.2",
"better-sqlite3": "^5.4.0", "better-sqlite3": "^5.4.0",
"chroma-js": "^2.0.4",
"debug": "^4.1.1", "debug": "^4.1.1",
"leaflet": "^1.5.1", "leaflet": "^1.5.1",
"path": "^0.12.7", "path": "^0.12.7",
@ -36,6 +37,7 @@
}, },
"devDependencies": { "devDependencies": {
"@types/better-sqlite3": "^5.4.0", "@types/better-sqlite3": "^5.4.0",
"@types/chroma-js": "^1.4.1",
"@types/leaflet": "^1.4.6", "@types/leaflet": "^1.4.6",
"rollup": "^1.17.0", "rollup": "^1.17.0",
"rollup-plugin-commonjs": "^10.0.1", "rollup-plugin-commonjs": "^10.0.1",

View file

@ -34,6 +34,9 @@ let plugins = [
// not all files you want to resolve are .js files // not all files you want to resolve are .js files
extensions: ['.mjs', '.js', '.jsx', '.json'], // Default: [ '.mjs', '.js', '.json', '.node' ] extensions: ['.mjs', '.js', '.jsx', '.json'], // Default: [ '.mjs', '.js', '.json', '.node' ]
// Use the polyfills we've installed as dependencies instead of the Node.js natives, since those aren't available in the browser
preferBuiltins: false
}), }),
// json({ // json({

View file

@ -65,7 +65,13 @@ class AITrainer {
this.settings.ai.output_directory, this.settings.ai.output_directory,
"index.json" "index.json"
), ),
JSON.stringify(index) JSON.stringify({
properties: {
rssi_min: this.settings.ai.rssi_min,
rssi_max: this.settings.ai.rssi_max
},
index
})
); );
} }

View file

@ -1,6 +1,6 @@
"use strict"; "use strict";
import { normalise, clamp } from '../Helpers/Math.mjs'; import { normalise, clamp } from '../../common/Math.mjs';
class DatasetFetcher { class DatasetFetcher {
constructor({ settings, RSSIRepo }) { constructor({ settings, RSSIRepo }) {