"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;