LoRaWAN-Signal-Mapping/client_src/js/Worker/AIWrapper.mjs

125 lines
2.9 KiB
JavaScript

"use strict";
import brain from 'brain.js';
import haversine from 'haversine-distance';
import {
normalise_lat, normalise_lng,
normalise_gateway_distance,
unnormalise_rssi
} from '../../../common/Normalisers.mjs';
class AIWrapper {
get training_mode() {
return this.index.properties.training_mode;
}
constructor() {
this.setup_complete = false;
this.map_bounds = null;
this.index = null;
this.Config = null;
this.gateways = new Map();
}
async setup({ bounds, index, Config }) {
this.map_bounds = bounds;
this.index = index;
this.Config = Config;
console.log("Loading models");
// WebGL isn't available inside WebWorkers yet :-(
for(let gateway of this.index.index) {
let net = new brain.NeuralNetwork(/*gateway.net_settings*/);
net.fromJSON(
gateway.frozen_net
);
this.gateways.set(
gateway.id,
{ ai: net, latitude: gateway.latitude, longitude: gateway.longitude }
);
}
console.log("Model setup complete.");
this.setup_complete = true;
}
predict_row(lat) {
if(!this.setup_complete)
throw new Error("Error: Can't do predictions until the setup is complete.");
let result = [],
stats = {
rssi_min: Infinity,
rssi_max: -Infinity
};
for(let lng = this.map_bounds.west; lng < this.map_bounds.east; lng += this.Config.step.lng) {
let max_predicted_rssi = -Infinity;
for(let [/*gateway_id*/, gateway] of this.gateways) {
// Generate the input data
let distance_from_gateway = haversine(
{ latitude: lat, longitude: lng },
gateway
);
let input_data = {
latitude: normalise_lat(lat),
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.");
}
// 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");
}
// Operate on the output
max_predicted_rssi = Math.max(
max_predicted_rssi,
next_value[0]
);
}
// Un-normalise the output of the neural nentwork to something sensible
max_predicted_rssi = unnormalise_rssi(max_predicted_rssi);
// Record the statistics
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;
result.push(max_predicted_rssi);
}
return { result, stats };
}
}
export default AIWrapper;