2019-07-25 15:44:26 +00:00
|
|
|
"use strict";
|
|
|
|
|
|
|
|
|
2019-07-29 17:06:50 +00:00
|
|
|
import brain from 'brain.js';
|
|
|
|
import haversine from 'haversine-distance';
|
2019-07-25 15:44:26 +00:00
|
|
|
|
2019-07-30 14:55:15 +00:00
|
|
|
import {
|
2019-07-30 15:40:12 +00:00
|
|
|
normalise_lat, normalise_lng,
|
2019-07-30 14:55:15 +00:00
|
|
|
|
|
|
|
normalise_gateway_distance,
|
|
|
|
|
|
|
|
unnormalise_rssi
|
|
|
|
} from '../../../common/Normalisers.mjs';
|
|
|
|
|
2019-07-25 15:44:26 +00:00
|
|
|
|
|
|
|
class AIWrapper {
|
2019-08-06 11:44:18 +00:00
|
|
|
get training_mode() {
|
|
|
|
return this.index.properties.training_mode;
|
|
|
|
}
|
|
|
|
|
2019-07-25 15:44:26 +00:00
|
|
|
constructor() {
|
|
|
|
this.setup_complete = false;
|
|
|
|
|
|
|
|
this.map_bounds = null;
|
|
|
|
this.index = null;
|
2019-07-25 17:56:59 +00:00
|
|
|
this.Config = null;
|
2019-07-25 15:44:26 +00:00
|
|
|
|
|
|
|
this.gateways = new Map();
|
|
|
|
}
|
|
|
|
|
2019-07-25 17:56:59 +00:00
|
|
|
async setup({ bounds, index, Config }) {
|
2019-07-25 15:44:26 +00:00
|
|
|
this.map_bounds = bounds;
|
|
|
|
this.index = index;
|
2019-07-25 17:56:59 +00:00
|
|
|
this.Config = Config;
|
|
|
|
|
|
|
|
console.log("Loading models");
|
|
|
|
|
|
|
|
// WebGL isn't available inside WebWorkers yet :-(
|
2019-07-25 15:44:26 +00:00
|
|
|
|
|
|
|
for(let gateway of this.index.index) {
|
2019-07-30 17:38:44 +00:00
|
|
|
let net = new brain.NeuralNetwork(/*gateway.net_settings*/);
|
2019-07-29 17:06:50 +00:00
|
|
|
net.fromJSON(
|
2019-07-30 17:38:44 +00:00
|
|
|
gateway.frozen_net
|
2019-07-29 17:06:50 +00:00
|
|
|
);
|
|
|
|
|
2019-07-25 15:44:26 +00:00
|
|
|
this.gateways.set(
|
|
|
|
gateway.id,
|
2019-07-30 17:38:44 +00:00
|
|
|
{ ai: net, latitude: gateway.latitude, longitude: gateway.longitude }
|
2019-07-25 15:44:26 +00:00
|
|
|
);
|
|
|
|
}
|
2019-07-25 17:56:59 +00:00
|
|
|
console.log("Model setup complete.");
|
2019-07-25 15:44:26 +00:00
|
|
|
this.setup_complete = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
predict_row(lat) {
|
2019-07-25 17:56:59 +00:00
|
|
|
if(!this.setup_complete)
|
2019-07-25 15:44:26 +00:00
|
|
|
throw new Error("Error: Can't do predictions until the setup is complete.");
|
|
|
|
|
2019-07-25 17:56:59 +00:00
|
|
|
let result = [],
|
2019-07-25 15:44:26 +00:00
|
|
|
stats = {
|
|
|
|
rssi_min: Infinity,
|
|
|
|
rssi_max: -Infinity
|
|
|
|
};
|
|
|
|
|
2019-07-25 17:56:59 +00:00
|
|
|
for(let lng = this.map_bounds.west; lng < this.map_bounds.east; lng += this.Config.step.lng) {
|
2019-07-25 15:44:26 +00:00
|
|
|
let max_predicted_rssi = -Infinity;
|
|
|
|
|
2019-08-06 11:44:18 +00:00
|
|
|
for(let [/*gateway_id*/, gateway] of this.gateways) {
|
|
|
|
// Generate the input data
|
2019-07-29 17:06:50 +00:00
|
|
|
let distance_from_gateway = haversine(
|
|
|
|
{ latitude: lat, longitude: lng },
|
2019-07-30 17:38:44 +00:00
|
|
|
gateway
|
2019-07-29 17:06:50 +00:00
|
|
|
);
|
2019-08-06 11:44:18 +00:00
|
|
|
|
|
|
|
let input_data = {
|
2019-07-30 17:38:44 +00:00
|
|
|
latitude: normalise_lat(lat),
|
2019-08-06 11:44:18 +00:00
|
|
|
longitude: normalise_lng(lng)
|
|
|
|
};
|
|
|
|
if(this.training_mode !== "unified")
|
|
|
|
input_data.distance = normalise_gateway_distance(distance_from_gateway);
|
|
|
|
|
|
|
|
// Validate the input data
|
|
|
|
if(Number.isNaN(input_data.latitude)
|
|
|
|
|| Number.isNaN(input_data.longitude)
|
|
|
|
|| (
|
|
|
|
this.training_mode !== "unified"
|
|
|
|
&& Number.isNaN(input_data.distance))
|
|
|
|
) {
|
|
|
|
console.error(input_data);
|
|
|
|
throw new Error("Error: Invalid neural network input.");
|
2019-07-30 17:38:44 +00:00
|
|
|
}
|
2019-07-30 14:55:15 +00:00
|
|
|
|
2019-08-06 11:44:18 +00:00
|
|
|
// Run the input through the neural network
|
|
|
|
let next_value = gateway.ai.run(input_data);
|
|
|
|
if(Number.isNaN(next_value[0])) {
|
|
|
|
console.log(next_value);
|
|
|
|
throw new Error("Error: Neural network returned NaN");
|
2019-08-02 14:09:07 +00:00
|
|
|
}
|
|
|
|
|
2019-08-06 11:44:18 +00:00
|
|
|
// Operate on the output
|
2019-07-25 15:44:26 +00:00
|
|
|
max_predicted_rssi = Math.max(
|
|
|
|
max_predicted_rssi,
|
2019-07-30 17:38:44 +00:00
|
|
|
next_value[0]
|
2019-07-25 15:44:26 +00:00
|
|
|
);
|
|
|
|
}
|
2019-08-06 11:44:18 +00:00
|
|
|
|
|
|
|
// Un-normalise the output of the neural nentwork to something sensible
|
2019-07-30 14:55:15 +00:00
|
|
|
max_predicted_rssi = unnormalise_rssi(max_predicted_rssi);
|
2019-07-25 15:44:26 +00:00
|
|
|
|
2019-08-06 11:44:18 +00:00
|
|
|
// Record the statistics
|
2019-07-25 15:44:26 +00:00
|
|
|
if(max_predicted_rssi > stats.rssi_max)
|
|
|
|
stats.rssi_max = max_predicted_rssi;
|
|
|
|
if(max_predicted_rssi < stats.rssi_min)
|
|
|
|
stats.rssi_min = max_predicted_rssi;
|
|
|
|
|
2019-08-06 11:44:18 +00:00
|
|
|
|
2019-07-25 15:44:26 +00:00
|
|
|
result.push(max_predicted_rssi);
|
|
|
|
}
|
|
|
|
|
|
|
|
return { result, stats };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default AIWrapper;
|