Write AI layer, but it's untested.
This commit is contained in:
parent
f0694de02c
commit
61edaf6fa3
8 changed files with 106 additions and 22 deletions
|
@ -12,5 +12,10 @@ export default {
|
|||
border: 0.1,
|
||||
|
||||
// The resolution of the coverage map
|
||||
step: 0.005
|
||||
step: 0.005,
|
||||
|
||||
colour_scale: {
|
||||
min: "#ffffff",
|
||||
max: "#2cb42c"
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
import path from 'path';
|
||||
|
||||
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 Config from './ClientConfig.mjs';
|
||||
import { normalise } from '../../common/Math.mjs';
|
||||
|
||||
class LayerAI {
|
||||
get gateway_bounds() {
|
||||
|
@ -37,21 +39,28 @@ class LayerAI {
|
|||
);
|
||||
console.log(index);
|
||||
|
||||
for(let gateway of this.index) {
|
||||
let gateway_data = {
|
||||
// TODO: Swap this out for the real thing - probably a GeoJSON layer or something
|
||||
// This is just a placeholder
|
||||
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);
|
||||
}
|
||||
for(let gateway of this.index.index) {
|
||||
this.gateways.set(
|
||||
gateway.id,
|
||||
await tf.LayersModel.loadModel(`${window.location.href}/${path.dirname(Config.ai_index_file)}/${gateway.id}`)
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
map_bounds.north += Config.border;
|
||||
map_bounds.south -= Config.border;
|
||||
|
@ -59,7 +68,55 @@ class LayerAI {
|
|||
map_bounds.east += 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
23
package-lock.json
generated
|
@ -93,6 +93,12 @@
|
|||
"@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": {
|
||||
"version": "0.0.39",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
|
||||
|
@ -492,9 +498,9 @@
|
|||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30000984",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000984.tgz",
|
||||
"integrity": "sha512-n5tKOjMaZ1fksIpQbjERuqCyfgec/m9pferkFQbLmWtqLUdmt12hNhjSwsmPdqeiG2NkITOQhr1VYIwWSAceiA==",
|
||||
"version": "1.0.30000985",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000985.tgz",
|
||||
"integrity": "sha512-1ngiwkgqAYPG0JSSUp3PUDGPKKY59EK7NrGGX+VOxaKCNzRbNc7uXMny+c3VJfZxtoK3wSImTvG9T9sXiTw2+w==",
|
||||
"dev": true
|
||||
},
|
||||
"chalk": {
|
||||
|
@ -512,6 +518,11 @@
|
|||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
|
||||
"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": {
|
||||
"version": "0.3.6",
|
||||
"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
|
||||
|
@ -1041,9 +1052,9 @@
|
|||
}
|
||||
},
|
||||
"electron-to-chromium": {
|
||||
"version": "1.3.194",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.194.tgz",
|
||||
"integrity": "sha512-w0LHR2YD9Ex1o+Sz4IN2hYzCB8vaFtMNW+yJcBf6SZlVqgFahkne/4rGVJdk4fPF98Gch9snY7PiabOh+vqHNg==",
|
||||
"version": "1.3.199",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.199.tgz",
|
||||
"integrity": "sha512-gachlDdHSK47s0N2e58GH9HMC6Z4ip0SfmYUa5iEbE50AKaOUXysaJnXMfKj0xB245jWbYcyFSH+th3rqsF8hA==",
|
||||
"dev": true
|
||||
},
|
||||
"emojis-list": {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
"async-mqtt": "^2.3.0",
|
||||
"awilix": "^4.2.2",
|
||||
"better-sqlite3": "^5.4.0",
|
||||
"chroma-js": "^2.0.4",
|
||||
"debug": "^4.1.1",
|
||||
"leaflet": "^1.5.1",
|
||||
"path": "^0.12.7",
|
||||
|
@ -36,6 +37,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@types/better-sqlite3": "^5.4.0",
|
||||
"@types/chroma-js": "^1.4.1",
|
||||
"@types/leaflet": "^1.4.6",
|
||||
"rollup": "^1.17.0",
|
||||
"rollup-plugin-commonjs": "^10.0.1",
|
||||
|
|
|
@ -34,6 +34,9 @@ let plugins = [
|
|||
|
||||
// not all files you want to resolve are .js files
|
||||
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({
|
||||
|
|
|
@ -65,7 +65,13 @@ class AITrainer {
|
|||
this.settings.ai.output_directory,
|
||||
"index.json"
|
||||
),
|
||||
JSON.stringify(index)
|
||||
JSON.stringify({
|
||||
properties: {
|
||||
rssi_min: this.settings.ai.rssi_min,
|
||||
rssi_max: this.settings.ai.rssi_max
|
||||
},
|
||||
index
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"use strict";
|
||||
|
||||
import { normalise, clamp } from '../Helpers/Math.mjs';
|
||||
import { normalise, clamp } from '../../common/Math.mjs';
|
||||
|
||||
class DatasetFetcher {
|
||||
constructor({ settings, RSSIRepo }) {
|
||||
|
|
Loading…
Reference in a new issue