From 4493fbb0fac880b9e43a11488bb27fe756489a50 Mon Sep 17 00:00:00 2001
From: Starbeamrainbowlabs <sbrl@starbeamrainbowlabs.com>
Date: Tue, 30 Jul 2019 15:42:37 +0100
Subject: [PATCH] Tidy up normalising code

---
 common/Normalisers.mjs             | 69 ++++++++++++++++++++++
 server/settings.default.toml       |  5 --
 server/train-ai/DatasetFetcher.mjs | 94 ++++++++----------------------
 3 files changed, 92 insertions(+), 76 deletions(-)
 create mode 100644 common/Normalisers.mjs

diff --git a/common/Normalisers.mjs b/common/Normalisers.mjs
new file mode 100644
index 0000000..53f87b9
--- /dev/null
+++ b/common/Normalisers.mjs
@@ -0,0 +1,69 @@
+import { normalise, clamp } from './Math.mjs';
+
+function normalise_lat(lat) {
+	return normalise(lat,
+		{ min: -90, max: +90 },
+		{ min: 0, max: 1 }
+	);
+}
+	
+function normalise_lng(lng) {
+	return normalise(lng,
+		{ min: -180, max: +180 },
+		{ min: 0, max: 1 }
+	);
+}
+
+function unnormalise_lat(nlat) {
+	return normalise(nlat,
+		{ min: 0, max: 1 },
+		{ min: -90, max: +90 }
+	);
+}
+	
+function unnormalise_lng(nlng) {
+	return normalise(nlng,
+		{ min: 0, max: 1 },
+		{ min: -180, max: +180 }
+	);
+}
+
+function normalise_gateway_distance(distance) {
+	return clamp(normalise(distance,
+		{ min: 0, max: 20000 },
+		{ min: 0, max: 1 }
+	), 0, 20000);
+}
+
+function unnormalise_gateway_distance(ndistance) {
+	return clamp(normalise(ndistance,
+		{ min: 0, max: 1 },
+		{ min: 0, max: 20000 }
+	), 0, 20000);
+}
+
+function normalise_rssi(rssi) {
+	return clamp(normalise(rssi,
+		{ min: -150, max: 0 },
+		{ min: 0, max: 1 }
+	), 0, 1)
+}
+function unnormalise_rssi(rssi) {
+	return clamp(normalise(rssi,
+		{ min: 0, max: 1 },
+		{ min: -150, max: 0 }
+	), 0, 1)
+}
+
+export {
+	normalise_lat,
+	normalise_lng,
+	unnormalise_lat,
+	unnormalise_lng,
+	
+	normalise_gateway_distance,
+	unnormalise_gateway_distance,
+	
+	normalise_rssi,
+	unnormalise_rssi
+};
diff --git a/server/settings.default.toml b/server/settings.default.toml
index db68936..0dd67dc 100644
--- a/server/settings.default.toml
+++ b/server/settings.default.toml
@@ -54,11 +54,6 @@ devices = [
 [ai]
 # Settings relating to the training of the AI. Note that a number of these settings can also be specified by environment variables, to aid with fiddling with the parameters to find the right settings.
 
-# Min / max dataset values when training the AI, since neural networks only take values between 0 and 1.
-# Note that changing these means that you've got to retrain the AIs all over again!
-rssi_min = -150
-rssi_max = 0
-
 # The architecture of the neural network, as an arary of integers.
 # Each integer represents the number of nodes in a layer of the neural network.
 network_arch = [ 64 ]
diff --git a/server/train-ai/DatasetFetcher.mjs b/server/train-ai/DatasetFetcher.mjs
index e3b4756..4bd5919 100644
--- a/server/train-ai/DatasetFetcher.mjs
+++ b/server/train-ai/DatasetFetcher.mjs
@@ -2,7 +2,12 @@
 
 import haversine from 'haversine-distance';
 
-import { normalise, clamp } from '../../common/Math.mjs';
+import {
+	normalise_lat,
+	normalise_lng,
+	normalise_rssi,
+	normalise_gateway_distance,
+} from '../../common/Normalisers.mjs';
 
 class DatasetFetcher {
 	constructor({ settings, GatewayRepo, RSSIRepo, ReadingRepo }) {
@@ -12,92 +17,39 @@ class DatasetFetcher {
 		this.repo_reading = ReadingRepo;
 	}
 	
-	normalise_latlng(lat, lng) {
-		return {
-			latitude: normalise(lat,
-				{ min: -90, max: +90 },
-				{ min: 0, max: 1 }
-			),
-			longitude: normalise(lng,
-				{ min: -180, max: +180 },
-				{ min: 0, max: 1 }
-			)
-		};
-	}
-	
 	fetch_all(gateway_id) {
 		let gateway_location = this.repo_gateway.get_by_id(gateway_id);
 		
 		let result = [];
 		for(let rssi of this.repo_rssi.iterate_gateway(gateway_id)) {
-			let next_input = this.normalise_latlng(rssi.latitude, rssi.longitude);
-			let distance_from_gateway = haversine(gateway_location, rssi);
-			
-			next_input.distance = clamp(
-				normalise(distance_from_gateway,
-					{ min: 0, max: 20000 },
-					{ min: 0, max: 1 }
-				),
-			0, 1);
-			
-			// console.log(`Distance from gateway: ${haversine(gateway_location, rssi)}m`);
-			
-			let next_output = [
-				clamp(normalise(rssi.rssi,
-					{ min: this.settings.ai.rssi_min, max: this.settings.ai.rssi_max },
-					{ min: 0, max: 1 }
-				), 0, 1)
-			];
-			
 			result.push({
-				input: next_input,
-				output: next_output
+				input: {
+					latitude: normalise_lat(rssi.latitude),
+					longitude: normalise_lng(rssi.longitude),
+					distance: normalise_gateway_distance(
+						haversine(gateway_location, rssi)
+					)
+				},
+				output: [
+					normalise_rssi(rssi.rssi)
+				]
 			});
 		}
 		
 		for(let reading of this.repo_reading.iterate_unreceived()) {
-			let next_input = this.normalise_latlng(
-				reading.latitude,
-				reading.longitude
-			);
-			next_input.distance = clamp(
-				normalise(haversine(gateway_location, reading),
-					{ min: 0, max: 20000 },
-					{ min: 0, max: 1 }
-				),
-			0, 1);
-			
 			result.push({
-				input: next_input,
+				input: {
+					latitude: normalise_lat(reading.latitude),
+					longitude: normalise_lng(reading.longitude),
+					distance: normalise_gateway_distance(
+						haversine(gateway_location, reading)
+					)
+				},
 				output: [ 0 ]
 			});
 		}
-		
 		return result;
 	}
-	
-	*fetch_input(gateway_id) {
-		for(let rssi of this.repo_rssi.iterate_gateway(gateway_id))
-			yield this.normalise_latlng(rssi.latitude, rssi.longitude);
-		
-		for(let rssi of this.repo_reading.iterate_unreceived())
-			yield this.normalise_latlng(rssi.latitude, rssi.longitude);
-	}
-	
-	*fetch_output(gateway_id) {
-		for(let rssi of this.repo_rssi.iterate_gateway(gateway_id)) {
-			yield [
-				clamp(normalise(rssi.rssi,
-					{ min: this.settings.ai.rssi_min, max: this.settings.ai.rssi_max },
-					{ min: 0, max: 1 }
-				), 0, 1)
-			];
-		}
-		// Yield 0 for every unreceived message, since we want to train it to predict a *terrible* signal where the gateway is not
-		for(let rssi of this.repo_reading.iterate_unreceived()) {
-			yield [ 0 ];
-		}
-	}
 }
 
 export default DatasetFetcher;
