diff --git a/.github/workflows/python_actions.yml b/.github/workflows/python_actions.yml
index 6b6dde67..664a0eed 100644
--- a/.github/workflows/python_actions.yml
+++ b/.github/workflows/python_actions.yml
@@ -69,7 +69,7 @@ jobs:
coveralls-token: ${{ secrets.COVERALLS_REPO_TOKEN }}
- name: Lint with flake8
- run: flake8 examples spinn_gym
+ run: flake8 examples spinn_gym integration_tests unittests
- name: Lint with pylint
uses: ./support/actions/pylint
with:
diff --git a/.ratexcludes b/.ratexcludes
index f63e4903..e8f90c80 100644
--- a/.ratexcludes
+++ b/.ratexcludes
@@ -1,5 +1,6 @@
**/*.colour_map
**/*.col
+**/*.csv
**/SpiNNUtils/**
**/SpiNNMachine/**
**/SpiNNMan/**
diff --git a/c_code/Makefile b/c_code/Makefile
index 1e27ffc5..f983a4f7 100644
--- a/c_code/Makefile
+++ b/c_code/Makefile
@@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-DIRS = breakout inverted_pendulum double_inverted_pendulum multi_arm_bandit logic store_recall
+DIRS = breakout inverted_pendulum double_inverted_pendulum multi_arm_bandit logic store_recall icub_vor_env
#DIRS = breakout double_inverted_pendulum multi_arm_bandit logic store_recall
all: $(DIRS)
diff --git a/c_code/icub_vor_env/Makefile b/c_code/icub_vor_env/Makefile
new file mode 100644
index 00000000..359c9bd9
--- /dev/null
+++ b/c_code/icub_vor_env/Makefile
@@ -0,0 +1,32 @@
+# Copyright (c) 2019-2021 The University of Manchester
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+ifndef NEURAL_MODELLING_DIRS
+ $(error NEURAL_MODELLING_DIRS is not set. Please define
+ NEURAL_MODELLING_DIRS (possibly by running "source setup" in the
+ neural_modelling folder within the sPyNNaker source folder))
+endif
+
+APP := icub_vor_env
+BUILD_DIR = $(abspath $(CURRENT_DIR)/../../build/$(APP))/
+SOURCES = icub_vor_env.c
+MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
+CURRENT_DIR := $(dir $(MAKEFILE_PATH))
+EXTRA_SRC_DIR := $(abspath $(CURRENT_DIR))/src
+SOURCE_DIRS += $(EXTRA_SRC_DIR)
+APP_OUTPUT_DIR := $(abspath $(CURRENT_DIR)../../spinn_gym/model_binaries/)/
+CFLAGS += -I$(NEURAL_MODELLING_DIRS)/src
+
+include $(SPINN_DIRS)/make/local.mk
\ No newline at end of file
diff --git a/c_code/icub_vor_env/src/icub_vor_env.c b/c_code/icub_vor_env/src/icub_vor_env.c
new file mode 100644
index 00000000..a29e295b
--- /dev/null
+++ b/c_code/icub_vor_env/src/icub_vor_env.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2013-2021 The University of Manchester
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+//
+// icub_vor_env.c
+// Environment to simulate ICub robot for particular network, see
+// https://www.overleaf.com/project/5f1ee9467b6572000190b496
+// (replace with link to document in future)
+//
+// Copyright © 2020 Andrew Gait, Petrut Bogdan. All rights reserved.
+//
+// Standard includes
+#include
+#include
+#include
+#include
+
+#include
+
+// Spin 1 API includes
+#include
+
+// Common includes
+#include
+#include
+
+// Front end common includes
+#include
+#include
+#include "random.h"
+
+#include
+
+
+//----------------------------------------------------------------------------
+// Enumerations
+//----------------------------------------------------------------------------
+// Regions where information for the environment is written
+typedef enum {
+ REGION_SYSTEM,
+ REGION_ICUB_VOR_ENV,
+ REGION_RECORDING,
+ REGION_ICUB_VOR_ENV_DATA,
+} region_t;
+
+// we may need some of these at some point, so keeping them for now
+//typedef enum {
+// SPECIAL_EVENT_INPUT_1,
+// SPECIAL_EVENT_INPUT_2,
+// SPECIAL_EVENT_INPUT_3,
+// SPECIAL_EVENT_INPUT_4,
+// SPECIAL_EVENT_INPUT_5,
+// SPECIAL_EVENT_INPUT_6,
+// SPECIAL_EVENT_INPUT_7,
+// SPECIAL_EVENT_INPUT_8,
+//} special_event_t;
+
+// printing info during run is enabled
+#define PRINT_LOGS false
+
+// These are the keys to be received for left/right choice
+typedef enum {
+ KEY_CHOICE_LEFT = 0x0,
+ KEY_CHOICE_RIGHT = 0x1
+} lr_key_t;
+
+//----------------------------------------------------------------------------
+// Globals
+//----------------------------------------------------------------------------
+
+static uint32_t _time;
+
+//! Should simulation run for ever? 0 if not
+static uint32_t infinite_run;
+
+
+//! Parameters set from Python code go here
+// - error_window_size
+// - number_of_inputs
+// - perfect eye position, perfect eye velocity arrays
+uint32_t error_window_size;
+uint32_t output_size;
+accum mid_neuron;
+uint32_t number_of_inputs;
+accum *perfect_eye_pos;
+accum *perfect_eye_vel;
+
+accum pos_to_vel; // 1/ (0.001 * 2 * np.pi * 10)
+accum gain;
+
+//! Global error value
+accum error_value = 0.0k;
+
+//! Global eye position and velocity
+accum current_eye_pos;
+accum current_eye_vel;
+
+//! count left and right spikes
+uint32_t spike_counters[2] = {0};
+
+//! wta decision or difference in L/R
+bool wta_decision;
+
+
+//! Encode the error into a series of rates which are then sent on
+accum min_rate = 2.0k;
+accum max_rate = 20.0k;
+
+//! The upper bits of the key value that model should transmit with
+static uint32_t key;
+
+//! How many ticks until next error window (default size 10ms)
+static uint32_t tick_in_error_window = 0;
+
+//! How many ticks until end of head loop
+static uint32_t tick_in_head_loop = 0;
+
+//! the number of timer ticks that this model should run for before exiting.
+uint32_t simulation_ticks = 0;
+
+//----------------------------------------------------------------------------
+// Inline functions
+//----------------------------------------------------------------------------
+
+// This is the function for sending a spike out from the environment, currently
+// related to the counts at the Left and Right atoms
+static inline void send_spike(int input, accum value)
+{
+ // The rate value needs to be sent as a uint32_t, so convert and send
+ spin1_send_mc_packet(key | (input), bitsk(value), WITH_PAYLOAD);
+}
+
+// Required if using auto-pause and resume
+void resume_callback(void) {
+ recording_reset();
+}
+
+// Initialize environment with values sent from python DSG
+static bool initialize(uint32_t *timer_period)
+{
+ io_printf(IO_BUF, "Initialise icub_vor_env: started\n");
+
+ // Get the address this core's DTCM data starts at from SRAM
+ data_specification_metadata_t *address = data_specification_get_data_address();
+
+ // Read the header
+ if (!data_specification_read_header(address)) {
+ return false;
+ }
+
+ // Get the timing details and set up thse simulation interface
+ if (!simulation_initialise(data_specification_get_region(REGION_SYSTEM, address),
+ APPLICATION_NAME_HASH, timer_period, &simulation_ticks,
+ &infinite_run, &_time, 1, 0)) {
+ return false;
+ }
+ io_printf(IO_BUF, "simulation time = %u\n", simulation_ticks);
+
+
+ // Read icub_vor region, which for now contains the information
+ // about keys on received mc packets
+ address_t icub_vor_env_address_region = data_specification_get_region(
+ REGION_ICUB_VOR_ENV, address);
+ key = icub_vor_env_address_region[0];
+ io_printf(IO_BUF, "\tKey=%08x\n", key);
+ io_printf(IO_BUF, "\tTimer period=%d\n", *timer_period);
+
+ // Get recording region
+ void *recording_region = data_specification_get_region(
+ REGION_RECORDING, address);
+
+ // Setup recording
+ uint32_t recording_flags = 0;
+ if (!recording_initialize(&recording_region, &recording_flags)) {
+ rt_error(RTE_SWERR);
+ return false;
+ }
+
+ // Now get the data associated with the environment
+ address_t icub_vor_env_data_region = data_specification_get_region(
+ REGION_ICUB_VOR_ENV_DATA, address);
+
+ // Ideally I guess this could be set up using a struct, but let's keep it simpler for now
+ error_window_size = icub_vor_env_data_region[0];
+ output_size = icub_vor_env_data_region[1];
+ number_of_inputs = icub_vor_env_data_region[2];
+ gain = kbits(icub_vor_env_data_region[3]);
+ pos_to_vel = kbits(icub_vor_env_data_region[4]);
+ wta_decision = (bool)(icub_vor_env_data_region[5]);
+ min_rate = kbits(icub_vor_env_data_region[6]);
+ max_rate = kbits(icub_vor_env_data_region[7]);
+ perfect_eye_pos = (accum *)&icub_vor_env_data_region[8];
+ perfect_eye_vel = (accum *)&icub_vor_env_data_region[8 + number_of_inputs];
+ // End of initialise
+ mid_neuron = (accum) (output_size) * 0.5k;
+
+ io_printf(IO_BUF, "Initialise: completed successfully\n");
+
+ return true;
+}
+
+static inline void update_count(uint32_t index) {
+ // Update the count values in here when a mc packet is received
+// io_printf(IO_BUF, "At time %u, update index %u \n", _time, index);
+ spike_counters[index] += 1;
+}
+
+// when a packet is received, update the error
+void mc_packet_received_callback(uint keyx, uint payload)
+{
+ use(payload);
+ update_count(keyx & 0x1);
+
+// uint32_t compare;
+// compare = keyx & 0x1; // This is an odd and even check.
+// // If no payload has been set, make sure the loop will run
+// if (payload == 0) { payload = 1; }
+//
+// // Update the spike counters based on the key value
+// for (uint count = payload; count > 0; count--) {
+// if (compare == KEY_CHOICE_LEFT) {
+// update_count(0);
+// }
+// else if (compare == KEY_CHOICE_RIGHT) {
+// update_count(1);
+// }
+// else {
+// io_printf(IO_BUF, "Unexpected key value %d\n", key);
+// }
+// }
+}
+
+// Test the counters for the head after this loop
+void test_the_head(void) {
+ // Here I am testing this is working by sending a spike out to
+ // wherever this vertex connects to, depending on which counter is higher.
+ accum pos_diff;
+ // Compute the integer difference in the number of spikes between L (agonist) and R (antagonist)
+ // WTA experiments
+ int32_t counter_diff;
+
+ if (wta_decision) {
+ counter_diff = spike_counters[0] > spike_counters[1] ?
+ spike_counters[0] : -spike_counters[1];
+ }
+ else {
+ counter_diff = (spike_counters[0] - spike_counters[1]);
+ }
+
+ // Compute the contribution to position (1 bit set in counter_diff = 2**-15)
+ pos_diff = kbits(counter_diff) * gain;
+ // TODO why should this scaling factor be cca. 15? 16.54949.. when gain=20
+ current_eye_vel = pos_diff * 16.5494949k;
+ current_eye_pos = current_eye_pos + MULT_NO_ROUND_CUSTOM_ACCUM(pos_diff, pos_to_vel);
+
+// accum previous_eye_pos = current_eye_pos;
+ current_eye_pos = current_eye_pos + pos_diff;
+ // Check bounds
+ if (current_eye_pos < -1.0k) {
+ current_eye_pos = -1.0k;
+ }
+ else if (current_eye_pos > 1.0k) {
+ current_eye_pos = 1.0k;
+ }
+// pos_diff = current_eye_pos - previous_eye_pos;
+
+ // Compute the current velocity
+ // Version in which the position is modified by the spikes
+// current_eye_vel = MULT_NO_ROUND_CUSTOM_ACCUM(pos_diff, pos_to_vel);
+ // Check speed bounds
+ if (current_eye_vel < -1.0k) {
+ current_eye_vel = -1.0k;
+ }
+ else if (current_eye_vel > 1.0k) {
+ current_eye_vel = 1.0k;
+ }
+
+ // Error is relative (in both cases) as the test is done based on > or < 0.0
+ accum error_pos = perfect_eye_pos[tick_in_head_loop] - current_eye_pos;
+// accum error_vel = perfect_eye_vel[tick_in_head_loop] - current_eye_vel;
+ // TODO what should happen if error_pos and error_vel cancel each other out?
+// error_value = (0.9k * error_pos + 0.1k * error_vel);
+// error_value = (error_pos + error_vel);
+ error_value = (error_pos);
+
+ // The above could easily be replaced by a comparison to the perfect eye
+ // position and velocity at the current value of tick_in_head_loop, once it has
+ // been worked out how the spike counters at L and R translate to head/eye movement
+
+ accum low_threshold = absk(error_value) * mid_neuron;
+ accum up_threshold = low_threshold - mid_neuron;
+
+ // The first 100 values in the connecting pop are agonist, then the next 100 are antagonist
+ uint32_t loop_size = output_size / 2;
+ for (uint32_t n=0; n < loop_size; n++) {
+ accum loop_value = (accum) n;
+ // Unless otherwise specified, rate values are min_rate
+ accum agonist_rate = min_rate;
+ accum antagonist_rate = min_rate;
+ if (loop_value < up_threshold) {
+ if (error_value >= 0.0k) {
+ // Antagonist is max_rate
+ antagonist_rate = max_rate;
+ } else {
+ // Agonist is max_rate
+ agonist_rate = max_rate;
+ }
+ } else if (loop_value < low_threshold) {
+ accum loop_to_up_value = loop_value - up_threshold;
+ accum low_to_up_value = low_threshold - up_threshold;
+// threshold_calc = inter_value1 / inter_value2;
+ accum encoded_error_rate = max_rate - (
+ (max_rate-min_rate) * (loop_to_up_value / low_to_up_value));
+ if (error_value >= 0.0k) {
+ // Antagonist is encoded_error_rate
+ antagonist_rate = encoded_error_rate;
+ } else {
+ // Agonist is encoded_error_rate
+ agonist_rate = encoded_error_rate;
+ }
+ }
+
+ // Now send the relevant spikes to the connected SSP population
+ send_spike(n, agonist_rate);
+ send_spike(n+loop_size, antagonist_rate);
+ }
+
+}
+
+void timer_callback(uint unused, uint dummy)
+{
+ use(unused);
+ use(dummy);
+
+ _time++;
+
+ // If the time has run out
+ if (!infinite_run && _time >= simulation_ticks) {
+ //spin1_pause();
+ recording_finalise();
+
+ // go into pause and resume state to avoid another tick
+ simulation_handle_pause_resume(resume_callback);
+
+ io_printf(IO_BUF, "infinite_run %d; time %d\n", infinite_run, _time);
+ io_printf(IO_BUF, "simulation_ticks %d\n", simulation_ticks);
+
+ io_printf(IO_BUF, "Exiting on timer.\n");
+ simulation_ready_to_read();
+
+ _time -= 1;
+ return;
+ }
+ // Otherwise the simulation is still running
+ else {
+ // Increment ticks for head loop and error window
+ tick_in_head_loop++;
+ tick_in_error_window++;
+
+ // Test whether we have reached the end of the head inputs
+ if (tick_in_head_loop == number_of_inputs) {
+ // Reset back to zero if so
+ tick_in_head_loop = 0;
+ }
+
+ // If ticks_in_error_window has reached error_window_size then compare
+ // the counters and calculate error
+ if (tick_in_error_window == error_window_size) {
+ // Check spike counters and calculate error value
+ test_the_head();
+
+ // Do recording
+ recording_record(0, &spike_counters[0], 4);
+ recording_record(1, &spike_counters[1], 4);
+ recording_record(2, &error_value, 4);
+ recording_record(3, ¤t_eye_pos, 4);
+ recording_record(4, ¤t_eye_vel, 4);
+
+ // Reset ticks in error window
+ tick_in_error_window = 0;
+
+ // Reset the spike_counters
+ spike_counters[0] = 0;
+ spike_counters[1] = 0;
+ }
+
+ }
+}
+
+//----------------------------------------------------------------------------
+// Entry point
+//----------------------------------------------------------------------------
+void c_main(void)
+{
+ // Load DTCM data
+ uint32_t timer_period;
+ if (!initialize(&timer_period)) {
+ io_printf(IO_BUF, "Error in initialisation - exiting!\n");
+ rt_error(RTE_SWERR);
+ return;
+ }
+
+ // Initialise (probably unnecessary...)
+ tick_in_error_window = 0;
+ tick_in_head_loop = 0;
+
+ // Set timer tick (in microseconds)
+ io_printf(IO_BUF, "setting timer tick callback for %d microseconds\n",
+ timer_period);
+ spin1_set_timer_tick(timer_period);
+
+ io_printf(IO_BUF, "simulation_ticks %d\n", simulation_ticks);
+
+ // Register callbacks
+ spin1_callback_on(TIMER_TICK, timer_callback, 2);
+ spin1_callback_on(MC_PACKET_RECEIVED, mc_packet_received_callback, -1);
+ spin1_callback_on(MCPL_PACKET_RECEIVED, mc_packet_received_callback, -1);
+
+ _time = UINT32_MAX;
+
+ current_eye_pos = 0.0k;
+ current_eye_vel = 1.0k;
+
+ simulation_run();
+
+}
diff --git a/examples/icub_vor_env/icub_vor_env_test.py b/examples/icub_vor_env/icub_vor_env_test.py
new file mode 100644
index 00000000..911c8ecb
--- /dev/null
+++ b/examples/icub_vor_env/icub_vor_env_test.py
@@ -0,0 +1,173 @@
+# Copyright (c) 2021 The University of Manchester
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+import pyNN.spiNNaker as p
+import spinn_gym as gym
+
+import matplotlib.pyplot as plt
+import numpy as np
+import os
+
+
+# Examples of get functions for variables
+def get_error(icub_vor_env_pop):
+ b_vertex = icub_vor_env_pop._vertex
+ error = b_vertex.get_recorded_data('error')
+ return error.tolist()
+
+
+def get_l_count(icub_vor_env_pop):
+ b_vertex = icub_vor_env_pop._vertex
+ left_count = b_vertex.get_recorded_data('l_count')
+ return left_count.tolist()
+
+
+def get_r_count(icub_vor_env_pop):
+ b_vertex = icub_vor_env_pop._vertex
+ right_count = b_vertex.get_recorded_data('r_count')
+ return right_count.tolist()
+
+
+def get_eye_pos(icub_vor_env_pop):
+ b_vertex = icub_vor_env_pop._vertex
+ eye_positions = b_vertex.get_recorded_data('eye_pos')
+ return eye_positions.tolist()
+
+
+def get_eye_vel(icub_vor_env_pop):
+ b_vertex = icub_vor_env_pop._vertex
+ eye_velocities = b_vertex.get_recorded_data('eye_vel')
+ return eye_velocities.tolist()
+
+
+# Setup
+p.setup(timestep=1.0)
+# p.set_number_of_neurons_per_core(p.SpikeSourcePoisson, 100)
+
+# Build input SSP and output population
+input_size = 2
+output_size = 200
+
+input_rate = 20
+input_pop = p.Population(input_size, p.SpikeSourcePoisson(rate=input_rate),
+ label='SSP_input')
+output_pop = p.Population(output_size, p.SpikeSourcePoisson(rate=0),
+ label='SSP_output')
+
+# get head_positions and head_velocities from file (1000 samples)
+base_dir = "./"
+head_pos = np.loadtxt(os.path.join(
+ base_dir, "normalised_head_positions_1000.csv"))
+head_vel = np.loadtxt(os.path.join(
+ base_dir, "normalised_head_velocities_1000.csv"))
+
+# The values in the files are [0,1] when we really want [-1,1]; obtain this
+# by multiplying by 2 and subtracting 1
+
+head_pos = (head_pos * 2.0) - 1.0
+head_vel = (head_vel * 2.0) - 1.0
+
+# perfect eye positions and velocities are exactly out of phase with head
+perfect_eye_pos = np.concatenate((head_pos[500:], head_pos[:500]))
+perfect_eye_vel = np.concatenate((head_vel[500:], head_vel[:500]))
+
+# Report 4 points:
+for i in [0, 250, 500, 750]:
+ print("At {}: head pos {:4.6f}, head vel {:4.6f}, eye pos {:4.6f}, "
+ " eye vel {:4.6f}".format(
+ i, head_pos[i], head_vel[i], perfect_eye_pos[i],
+ perfect_eye_vel[i]))
+
+# build ICubVorEnv model pop
+error_window_size = 10
+icub_vor_env_model = gym.ICubVorEnv(
+ head_pos, head_vel, perfect_eye_vel, perfect_eye_pos, error_window_size,
+ output_size)
+icub_vor_env_pop = p.Population(input_size, icub_vor_env_model)
+
+# Set recording for input and output pop (env pop records by default)
+input_pop.record('spikes')
+output_pop.record('spikes')
+
+# Input -> ICubVorEnv projection
+# i2a = p.Projection(input_pop, icub_vor_env_pop, p.AllToAllConnector())
+p.external_devices.activate_live_output_to(input_pop, icub_vor_env_pop)
+
+# ICubVorEnv -> output, setup live output to the SSP vertex
+p.external_devices.activate_live_output_to(
+ icub_vor_env_pop, output_pop, "CONTROL")
+
+# Store simulator and run
+runtime = 10000
+p.run(runtime)
+
+# Get the data from the ICubVorEnv pop
+errors = get_error(icub_vor_env_pop=icub_vor_env_pop)
+l_counts = get_l_count(icub_vor_env_pop=icub_vor_env_pop)
+r_counts = get_r_count(icub_vor_env_pop=icub_vor_env_pop)
+rec_eye_pos = get_eye_pos(icub_vor_env_pop=icub_vor_env_pop)
+rec_eye_vel = get_eye_vel(icub_vor_env_pop=icub_vor_env_pop)
+
+# get the spike data from input and output and plot
+# spikes_in = input_pop.get_data('spikes').segments[0].spiketrains
+# spikes_out = output_pop.get_data('spikes').segments[0].spiketrains
+# Figure(
+# Panel(spikes_in, xlabel="Time (ms)", ylabel="nID",
+# xticks=True, yticks=True),
+# Panel(spikes_out, xlabel="Time (ms)", ylabel="nID",
+# xticks=True, yticks=True)
+# )
+# plt.show()
+
+spikes_in_spin = input_pop.spinnaker_get_data('spikes')
+spikes_out_spin = output_pop.spinnaker_get_data('spikes')
+
+# end simulation
+p.end()
+
+# plot the data from the ICubVorEnv pop
+x_plot = [(n) for n in range(0, runtime, error_window_size)]
+plt.figure(figsize=(15, 11))
+
+plt.subplot(5, 1, 1)
+plt.scatter(
+ [i[1] for i in spikes_in_spin], [i[0] for i in spikes_in_spin], s=1)
+plt.xlim([0, runtime])
+
+plt.subplot(5, 1, 2)
+plt.plot(x_plot, l_counts, 'bo', label="l_counts")
+plt.plot(x_plot, r_counts, 'ro', label="r_counts")
+plt.legend(loc="best")
+plt.xlim([0, runtime])
+
+plt.subplot(5, 1, 3)
+plt.plot(x_plot, rec_eye_pos, label="eye position")
+plt.plot(x_plot, rec_eye_vel, label="eye velocity")
+# plt.plot(perfect_eye_pos, label="eye position", ls='--')
+# plt.plot(perfect_eye_vel, label="eye velocity", ls='--')
+plt.legend(loc="best")
+plt.xlim([0, runtime])
+
+plt.subplot(5, 1, 4)
+plt.plot(x_plot, errors, label="errors")
+plt.legend(loc="best")
+plt.xlim([0, runtime])
+
+plt.subplot(5, 1, 5)
+plt.scatter(
+ [i[1] for i in spikes_out_spin], [i[0] for i in spikes_out_spin], s=1)
+plt.xlim([0, runtime])
+
+plt.show()
diff --git a/examples/icub_vor_env/icub_vor_env_test_200_inputs.py b/examples/icub_vor_env/icub_vor_env_test_200_inputs.py
new file mode 100644
index 00000000..ceeeb123
--- /dev/null
+++ b/examples/icub_vor_env/icub_vor_env_test_200_inputs.py
@@ -0,0 +1,113 @@
+# Copyright (c) 2021 The University of Manchester
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+import pyNN.spiNNaker as p
+import spinn_gym as gym
+
+import numpy as np
+import spinn_gym.games.icub_vor_env.icub_utilities as icub_util
+
+
+# Parameter definition
+runtime = 5000
+# Build input SSP and output population
+input_size = 200 # neurons
+output_size = 200 # neurons
+gain = 20.0
+
+head_pos, head_vel = icub_util.generate_head_position_and_velocity(1)
+
+# perfect eye positions and velocities are exactly out of phase with head
+perfect_eye_pos = np.concatenate((head_pos[500:], head_pos[:500]))
+perfect_eye_vel = np.concatenate((head_vel[500:], head_vel[:500]))
+
+error_window_size = 10 # ms
+npc_limit = 50
+input_spike_times = [[] for _ in range(input_size)]
+
+for i in range(5):
+ input_spike_times[i * 2] = [250 + (10 * 2 * i) for _ in range(1)]
+ input_spike_times[2 * i + 1] = [500 + (10 * (2 * i + 1)) for _ in range(1)]
+ input_spike_times[50 + i * 2] = [750 + (10 * 2 * i) for _ in range(10 + i)]
+ input_spike_times[100 + 2 * i + 1] = [
+ 1000 + (10 * (2 * i + 1)) for _ in range(10 + i)]
+ input_spike_times[150 + i * 2] = [
+ 1250 + (10 * 2 * i) for _ in range(100 + i)]
+ input_spike_times[150 + 2 * i + 1] = [
+ 1500 + (10 * (2 * i + 1)) for _ in range(100 + i)]
+
+# Setup
+p.setup(timestep=1.0)
+p.set_number_of_neurons_per_core(p.SpikeSourcePoisson, 50)
+p.set_number_of_neurons_per_core(p.SpikeSourceArray, npc_limit)
+input_pop = p.Population(input_size,
+ p.SpikeSourceArray(spike_times=input_spike_times))
+
+output_pop = p.Population(output_size, p.SpikeSourcePoisson(rate=0))
+
+# Instantiate venv
+icub_vor_env_model = gym.ICubVorEnv(
+ head_pos, head_vel, perfect_eye_vel, perfect_eye_pos, error_window_size,
+ output_size)
+icub_vor_env_pop = p.Population(
+ icub_util.ICUB_VOR_VENV_POP_SIZE, icub_vor_env_model)
+
+# Set recording for input and output pop (env pop records by default)
+input_pop.record('spikes')
+output_pop.record('spikes')
+
+# Input -> ICubVorEnv projection
+# i2a = p.Projection(input_pop, icub_vor_env_pop, p.AllToAllConnector())
+p.external_devices.activate_live_output_to(input_pop, icub_vor_env_pop)
+
+# ICubVorEnv -> output, setup live output to the SSP vertex
+p.external_devices.activate_live_output_to(
+ icub_vor_env_pop, output_pop, "CONTROL")
+
+# Run the simulation
+p.run(runtime)
+
+# Get the data from the ICubVorEnv pop
+results = icub_util.retrieve_and_package_results(icub_vor_env_pop)
+
+# get the spike data from input and output
+spikes_in_spin = input_pop.spinnaker_get_data('spikes')
+spikes_out_spin = output_pop.spinnaker_get_data('spikes')
+
+# end simulation
+p.end()
+
+remapped_vn_spikes = icub_util.remap_odd_even(spikes_in_spin, input_size)
+remapped_cf_spikes = icub_util.remap_second_half_descending(
+ spikes_out_spin, output_size)
+
+simulation_parameters = {
+ 'runtime': runtime,
+ 'error_window_size': error_window_size,
+ 'vn_spikes': remapped_vn_spikes,
+ 'cf_spikes': remapped_cf_spikes,
+ 'perfect_eye_pos': perfect_eye_pos,
+ 'perfect_eye_vel': perfect_eye_vel,
+ 'vn_size': input_size,
+ 'cf_size': output_size,
+ 'gain': gain
+}
+
+# plot the data from the ICubVorEnv pop
+icub_util.plot_results(results_dict=results,
+ simulation_parameters=simulation_parameters,
+ name="spinngym_icub_vor_test_200_inputs")
+
+print("Done")
diff --git a/examples/icub_vor_env/icub_vor_venv_test_perfect_motion.py b/examples/icub_vor_env/icub_vor_venv_test_perfect_motion.py
new file mode 100644
index 00000000..cf080f8c
--- /dev/null
+++ b/examples/icub_vor_env/icub_vor_venv_test_perfect_motion.py
@@ -0,0 +1,125 @@
+# Copyright (c) 2021 The University of Manchester
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+import pyNN.spiNNaker as p
+import spinn_gym as gym
+
+import numpy as np
+import spinn_gym.games.icub_vor_env.icub_utilities as icub_util
+
+# Parameter definition
+runtime = 3000
+# Build input SSP and output population
+input_size = 200 # neurons
+output_size = 200 # neurons
+gain = 20.0
+
+head_pos, head_vel = icub_util.generate_head_position_and_velocity(1)
+
+# perfect eye positions and velocities are exactly out of phase with head
+perfect_eye_pos = np.concatenate((head_pos[500:], head_pos[:500]))
+perfect_eye_vel = np.concatenate((head_vel[500:], head_vel[:500]))
+
+input_spike_times = [[] for _ in range(input_size)]
+# the constant number (0.000031) is the effect of a single spike on the head
+# position
+# assert (np.isclose(np.abs(np.diff(head_pos)[0]),
+# no_required_spikes_per_chunk * 0.000031), 0.001)
+sub_head_pos = np.diff(head_pos)
+head_movement_per_spike = 2 ** (-15) * gain
+sub_eye_pos = np.diff(np.concatenate((perfect_eye_pos, [perfect_eye_pos[0]])))
+
+# no_required_spikes_per_chunk = 200
+no_required_spikes_per_chunk = np.ceil(
+ np.abs(sub_head_pos[0]) / head_movement_per_spike)
+
+# build ICubVorEnv model
+error_window_size = 10 # ms
+npc_limit = 200 # 25
+no_input_cores = int(input_size / npc_limit)
+input_spike_times = [[] for _ in range(input_size)]
+for ts in range(runtime - 1):
+ # if 1000 <= ts < 2000:
+ # continue
+ sgn = np.sign(sub_eye_pos[ts % 1000])
+ spikes_during_chunk = np.ceil(
+ np.abs(sub_eye_pos[ts % 1000]) / head_movement_per_spike)
+ for i in range(int(spikes_during_chunk)):
+ x = int(sgn <= 0)
+ input_spike_times[(i % no_input_cores) * npc_limit + x].append(ts)
+
+# Setup
+p.setup(timestep=1.0)
+p.set_number_of_neurons_per_core(p.SpikeSourcePoisson, 50)
+p.set_number_of_neurons_per_core(p.SpikeSourceArray, npc_limit)
+input_pop = p.Population(input_size,
+ p.SpikeSourceArray(spike_times=input_spike_times))
+
+output_pop = p.Population(output_size, p.SpikeSourcePoisson(rate=0))
+
+# Instantiate venv
+icub_vor_env_model = gym.ICubVorEnv(
+ head_pos, head_vel, perfect_eye_vel, perfect_eye_pos, error_window_size,
+ output_size)
+icub_vor_env_pop = p.Population(
+ icub_util.ICUB_VOR_VENV_POP_SIZE, icub_vor_env_model)
+
+# Set recording for input and output pop (env pop records by default)
+input_pop.record('spikes')
+output_pop.record('spikes')
+
+# Input -> ICubVorEnv projection
+# i2a = p.Projection(input_pop, icub_vor_env_pop, p.AllToAllConnector())
+p.external_devices.activate_live_output_to(input_pop, icub_vor_env_pop)
+
+# ICubVorEnv -> output, setup live output to the SSP vertex
+p.external_devices.activate_live_output_to(
+ icub_vor_env_pop, output_pop, "CONTROL")
+
+# Run the simulation
+p.run(runtime)
+
+# Get the data from the ICubVorEnv pop
+results = icub_util.retrieve_and_package_results(icub_vor_env_pop)
+
+# get the spike data from input and output
+spikes_in_spin = input_pop.spinnaker_get_data('spikes')
+spikes_out_spin = output_pop.spinnaker_get_data('spikes')
+
+# end simulation
+p.end()
+
+remapped_vn_spikes = icub_util.remap_odd_even(spikes_in_spin, input_size)
+remapped_cf_spikes = icub_util.remap_second_half_descending(
+ spikes_out_spin, output_size)
+
+simulation_parameters = {
+ 'runtime': runtime,
+ 'error_window_size': error_window_size,
+ 'vn_spikes': remapped_vn_spikes,
+ 'cf_spikes': remapped_cf_spikes,
+ 'perfect_eye_pos': perfect_eye_pos,
+ 'perfect_eye_vel': perfect_eye_vel,
+ 'vn_size': input_size,
+ 'cf_size': output_size,
+ 'gain': gain
+}
+
+# plot the data from the ICubVorEnv pop
+icub_util.plot_results(results_dict=results,
+ simulation_parameters=simulation_parameters,
+ name="spinngym_icub_vor_test_perfect")
+
+print("Done")
diff --git a/examples/icub_vor_env/normalised_head_positions_1000.csv b/examples/icub_vor_env/normalised_head_positions_1000.csv
new file mode 100644
index 00000000..a66f167a
--- /dev/null
+++ b/examples/icub_vor_env/normalised_head_positions_1000.csv
@@ -0,0 +1,1000 @@
+5.000000000000000000e-01
+4.968584280172205769e-01
+4.937169800583237067e-01
+4.905757801422959141e-01
+4.874349522783312239e-01
+4.842946204609358540e-01
+4.811549086650327434e-01
+4.780159408410675770e-01
+4.748778409101152009e-01
+4.717407327589877020e-01
+4.686047402353433200e-01
+4.654699871427970814e-01
+4.623365972360336529e-01
+4.592046942159212497e-01
+4.560744017246283755e-01
+4.529458433407428375e-01
+4.498191425743925387e-01
+4.466944228623700996e-01
+4.435718075632591462e-01
+4.404514199525650930e-01
+4.373333832178478708e-01
+4.342178204538587050e-01
+4.311048546576810025e-01
+4.279946087238739594e-01
+4.248872054396214404e-01
+4.217827674798845239e-01
+4.186814174025581536e-01
+4.155832776436330644e-01
+4.124884705123619821e-01
+4.093971181864313191e-01
+4.063093427071376995e-01
+4.032252659745698686e-01
+4.001450097427964869e-01
+3.970686956150593638e-01
+3.939964450389726869e-01
+3.909283793017287456e-01
+3.878646195253094286e-01
+3.848052866617047152e-01
+3.817505014881376613e-01
+3.787003846022963249e-01
+3.756550564175726303e-01
+3.726146371583089478e-01
+3.695792468550515575e-01
+3.665490053398122172e-01
+3.635240322413374470e-01
+3.605044469803853624e-01
+3.574903687650119455e-01
+3.544819165858640875e-01
+3.514792092114825128e-01
+3.484823651836130298e-01
+3.454915028125263299e-01
+3.425067401723476124e-01
+3.395281950963952022e-01
+3.365559851725287155e-01
+3.335902277385066617e-01
+3.306310398773543158e-01
+3.276785384127414713e-01
+3.247328399043704628e-01
+3.217940606433745687e-01
+3.188623166477271287e-01
+3.159377236576610404e-01
+3.130203971310997479e-01
+3.101104522390994434e-01
+3.072080038613017594e-01
+3.043131665813987863e-01
+3.014260546826096898e-01
+2.985467821431686541e-01
+2.956754626318254808e-01
+2.928122095033579009e-01
+2.899571357940968763e-01
+2.871103542174636702e-01
+2.842719771595204614e-01
+2.814421166745335601e-01
+2.786208844805492801e-01
+2.758083919549839114e-01
+2.730047501302266255e-01
+2.702100696892560938e-01
+2.674244609612708157e-01
+2.646480339173337692e-01
+2.618808981660304402e-01
+2.591231629491423383e-01
+2.563749371373338914e-01
+2.536363292258542179e-01
+2.509074473302546071e-01
+2.481883991821196012e-01
+2.454792921248143411e-01
+2.427802331092467902e-01
+2.400913286896452226e-01
+2.374126850193521987e-01
+2.347444078466329742e-01
+2.320866025105016717e-01
+2.294393739365621077e-01
+2.268028266328654674e-01
+2.241770646857849103e-01
+2.215621917559060239e-01
+2.189583110739347360e-01
+2.163655254366217418e-01
+2.137839372027045548e-01
+2.112136482888661848e-01
+2.086547601657119666e-01
+2.061073738537634592e-01
+2.035715899194703860e-01
+2.010475084712405880e-01
+1.985352291554876580e-01
+1.960348511526972815e-01
+1.935464731735118127e-01
+1.910701934548328373e-01
+1.886061097559437183e-01
+1.861543193546497665e-01
+1.837149190434377577e-01
+1.812880051256551828e-01
+1.788736734117077898e-01
+1.764720192152779144e-01
+1.740831373495606293e-01
+1.717071221235217382e-01
+1.693440673381740869e-01
+1.669940662828741373e-01
+1.646572117316399964e-01
+1.623335959394877348e-01
+1.600233106387904114e-01
+1.577264470356556925e-01
+1.554430958063257595e-01
+1.531733470935975339e-01
+1.509172905032637180e-01
+1.486750151005754306e-01
+1.464466094067262691e-01
+1.442321613953573278e-01
+1.420317584890844753e-01
+1.398454875560465327e-01
+1.376734349064766827e-01
+1.355156862892942238e-01
+1.333723268887200553e-01
+1.312434413209130624e-01
+1.291291136306304266e-01
+1.270294272879089748e-01
+1.249444651847701759e-01
+1.228743096319481060e-01
+1.208190423556390614e-01
+1.187787444942760284e-01
+1.167534965953250653e-01
+1.147433786121053456e-01
+1.127484699006330721e-01
+1.107688492164882882e-01
+1.088045947117059764e-01
+1.068557839316905400e-01
+1.049224938121548489e-01
+1.030048006760823920e-01
+1.011027802307144785e-01
+9.921650756456172615e-02
+9.734605714443907154e-02
+9.549150281252624661e-02
+9.365291778345302687e-02
+9.183037464140800243e-02
+9.002394533727385573e-02
+8.823370118578630072e-02
+8.645971286271911249e-02
+8.470205040209372038e-02
+8.296078319341440577e-02
+8.123597997892917366e-02
+7.952770885091546560e-02
+7.783603724899244847e-02
+7.616103195745842214e-02
+7.450275910265410917e-02
+7.286128415035245109e-02
+7.123667190317387043e-02
+6.962898649802817808e-02
+6.803829140358236272e-02
+6.646464941775495627e-02
+6.490812266523718344e-02
+6.336877259503992388e-02
+6.184665997806815252e-02
+6.034184490472188633e-02
+5.885438678252336020e-02
+5.738434433377237465e-02
+5.593177559322773384e-02
+5.449673790581609223e-02
+5.307928792436814036e-02
+5.167948160738213004e-02
+5.029737421681453047e-02
+4.893302031589857881e-02
+4.758647376699023934e-02
+4.625778772944157125e-02
+4.494701465750219893e-02
+4.365420629824860732e-02
+4.237941368954126209e-02
+4.112268715800941610e-02
+3.988407631706485101e-02
+3.866363006494261123e-02
+3.746139658277095053e-02
+3.627742333266931185e-02
+3.511175705587434026e-02
+3.396444377089455346e-02
+3.283552877169401696e-02
+3.172505662590377473e-02
+3.063307117306297844e-02
+2.955961552288728644e-02
+2.850473205356779394e-02
+2.746846241009757994e-02
+2.645084750262781392e-02
+2.545192750485272826e-02
+2.447174185242324829e-02
+2.351032924139059843e-02
+2.256772762667849652e-02
+2.164397422058469966e-02
+2.073910549131210979e-02
+1.985315716152846743e-02
+1.898616420695706242e-02
+1.813816085499513064e-02
+1.730918058336305965e-02
+1.649925611878252929e-02
+1.570841943568448973e-02
+1.493670175494711538e-02
+1.418413354266304105e-02
+1.345074450893671281e-02
+1.273656360671143739e-02
+1.204161903062633820e-02
+1.136593821590328734e-02
+1.070954783726395243e-02
+1.007247380787654190e-02
+9.454741278332942644e-03
+8.856374635655694938e-03
+8.277397502335151480e-03
+7.717832735397306410e-03
+7.177702425500975814e-03
+6.657027896065995098e-03
+6.155829702431114825e-03
+5.674127631042982789e-03
+5.211940698674547012e-03
+4.769287151674406200e-03
+4.346184465246691331e-03
+3.942649342761062048e-03
+3.558697715093164793e-03
+3.194344739995830240e-03
+2.849604801500524309e-03
+2.524491509349885421e-03
+2.219017698460029608e-03
+1.933195428413733707e-03
+1.667035982985051734e-03
+1.420549869693005229e-03
+1.193746819387400682e-03
+9.866357858642066381e-04
+7.992249455125027824e-04
+6.315216969912662570e-04
+4.835326609376605633e-04
+3.552636797053698725e-04
+2.467198171342277480e-04
+1.579053583500300562e-04
+8.882380959550351118e-05
+3.947789809194413024e-05
+9.869571931456211367e-06
+0.000000000000000000e+00
+9.869571931456211367e-06
+3.947789809194413024e-05
+8.882380959550351118e-05
+1.579053583500300562e-04
+2.467198171342277480e-04
+3.552636797053698725e-04
+4.835326609376605633e-04
+6.315216969912662570e-04
+7.992249455125027824e-04
+9.866357858642066381e-04
+1.193746819387400682e-03
+1.420549869693005229e-03
+1.667035982985051734e-03
+1.933195428413733707e-03
+2.219017698460029608e-03
+2.524491509349885421e-03
+2.849604801500524309e-03
+3.194344739995830240e-03
+3.558697715093164793e-03
+3.942649342761131437e-03
+4.346184465246691331e-03
+4.769287151674406200e-03
+5.211940698674547012e-03
+5.674127631043052178e-03
+6.155829702431184214e-03
+6.657027896065995098e-03
+7.177702425500975814e-03
+7.717832735397306410e-03
+8.277397502335220869e-03
+8.856374635655694938e-03
+9.454741278332942644e-03
+1.007247380787654190e-02
+1.070954783726395243e-02
+1.136593821590328734e-02
+1.204161903062626882e-02
+1.273656360671143739e-02
+1.345074450893671281e-02
+1.418413354266304105e-02
+1.493670175494704599e-02
+1.570841943568442034e-02
+1.649925611878245990e-02
+1.730918058336299026e-02
+1.813816085499506126e-02
+1.898616420695706242e-02
+1.985315716152846743e-02
+2.073910549131204040e-02
+2.164397422058469966e-02
+2.256772762667849652e-02
+2.351032924139059843e-02
+2.447174185242317890e-02
+2.545192750485265887e-02
+2.645084750262781392e-02
+2.746846241009751055e-02
+2.850473205356772455e-02
+2.955961552288728644e-02
+3.063307117306290905e-02
+3.172505662590377473e-02
+3.283552877169394757e-02
+3.396444377089455346e-02
+3.511175705587434026e-02
+3.627742333266931185e-02
+3.746139658277095053e-02
+3.866363006494254184e-02
+3.988407631706478162e-02
+4.112268715800934671e-02
+4.237941368954119270e-02
+4.365420629824853793e-02
+4.494701465750219893e-02
+4.625778772944157125e-02
+4.758647376699023934e-02
+4.893302031589864820e-02
+5.029737421681439169e-02
+5.167948160738199126e-02
+5.307928792436807097e-02
+5.449673790581602284e-02
+5.593177559322773384e-02
+5.738434433377237465e-02
+5.885438678252336020e-02
+6.034184490472188633e-02
+6.184665997806829130e-02
+6.336877259503999327e-02
+6.490812266523718344e-02
+6.646464941775495627e-02
+6.803829140358229333e-02
+6.962898649802817808e-02
+7.123667190317387043e-02
+7.286128415035245109e-02
+7.450275910265410917e-02
+7.616103195745842214e-02
+7.783603724899251786e-02
+7.952770885091539621e-02
+8.123597997892910427e-02
+8.296078319341440577e-02
+8.470205040209365099e-02
+8.645971286271911249e-02
+8.823370118578630072e-02
+9.002394533727385573e-02
+9.183037464140807182e-02
+9.365291778345316565e-02
+9.549150281252624661e-02
+9.734605714443900215e-02
+9.921650756456158737e-02
+1.011027802307144091e-01
+1.030048006760822532e-01
+1.049224938121547102e-01
+1.068557839316904706e-01
+1.088045947117059070e-01
+1.107688492164882882e-01
+1.127484699006330721e-01
+1.147433786121053456e-01
+1.167534965953250653e-01
+1.187787444942759590e-01
+1.208190423556389920e-01
+1.228743096319480366e-01
+1.249444651847701759e-01
+1.270294272879088915e-01
+1.291291136306304266e-01
+1.312434413209130624e-01
+1.333723268887200553e-01
+1.355156862892942793e-01
+1.376734349064765439e-01
+1.398454875560464772e-01
+1.420317584890843365e-01
+1.442321613953572446e-01
+1.464466094067261859e-01
+1.486750151005754306e-01
+1.509172905032637180e-01
+1.531733470935975339e-01
+1.554430958063258150e-01
+1.577264470356556092e-01
+1.600233106387903559e-01
+1.623335959394877348e-01
+1.646572117316399131e-01
+1.669940662828741373e-01
+1.693440673381740869e-01
+1.717071221235218215e-01
+1.740831373495606849e-01
+1.764720192152779144e-01
+1.788736734117077343e-01
+1.812880051256550995e-01
+1.837149190434377577e-01
+1.861543193546497110e-01
+1.886061097559437183e-01
+1.910701934548328373e-01
+1.935464731735118127e-01
+1.960348511526973647e-01
+1.985352291554877413e-01
+2.010475084712406435e-01
+2.035715899194703304e-01
+2.061073738537633759e-01
+2.086547601657119666e-01
+2.112136482888661848e-01
+2.137839372027046381e-01
+2.163655254366217973e-01
+2.189583110739347638e-01
+2.215621917559060794e-01
+2.241770646857850491e-01
+2.268028266328653841e-01
+2.294393739365620521e-01
+2.320866025105016717e-01
+2.347444078466329742e-01
+2.374126850193521987e-01
+2.400913286896453336e-01
+2.427802331092468457e-01
+2.454792921248144522e-01
+2.481883991821197399e-01
+2.509074473302545516e-01
+2.536363292258542179e-01
+2.563749371373336694e-01
+2.591231629491422273e-01
+2.618808981660303292e-01
+2.646480339173336027e-01
+2.674244609612707047e-01
+2.702100696892560383e-01
+2.730047501302265700e-01
+2.758083919549838559e-01
+2.786208844805492246e-01
+2.814421166745335601e-01
+2.842719771595203504e-01
+2.871103542174635592e-01
+2.899571357940967653e-01
+2.928122095033578454e-01
+2.956754626318254253e-01
+2.985467821431686541e-01
+3.014260546826096898e-01
+3.043131665813987863e-01
+3.072080038613017594e-01
+3.101104522390993323e-01
+3.130203971310996369e-01
+3.159377236576608738e-01
+3.188623166477270732e-01
+3.217940606433745687e-01
+3.247328399043704628e-01
+3.276785384127414713e-01
+3.306310398773543158e-01
+3.335902277385067727e-01
+3.365559851725286045e-01
+3.395281950963952022e-01
+3.425067401723475013e-01
+3.454915028125262189e-01
+3.484823651836130298e-01
+3.514792092114825128e-01
+3.544819165858640875e-01
+3.574903687650120010e-01
+3.605044469803854179e-01
+3.635240322413375025e-01
+3.665490053398121617e-01
+3.695792468550514465e-01
+3.726146371583088923e-01
+3.756550564175725748e-01
+3.787003846022963249e-01
+3.817505014881376613e-01
+3.848052866617047707e-01
+3.878646195253094842e-01
+3.909283793017288566e-01
+3.939964450389725759e-01
+3.970686956150593083e-01
+4.001450097427964869e-01
+4.032252659745698686e-01
+4.063093427071376995e-01
+4.093971181864314302e-01
+4.124884705123620376e-01
+4.155832776436331755e-01
+4.186814174025583202e-01
+4.217827674798844684e-01
+4.248872054396214404e-01
+4.279946087238739594e-01
+4.311048546576810025e-01
+4.342178204538588160e-01
+4.373333832178477598e-01
+4.404514199525650375e-01
+4.435718075632590351e-01
+4.466944228623699331e-01
+4.498191425743925387e-01
+4.529458433407427820e-01
+4.560744017246284865e-01
+4.592046942159210277e-01
+4.623365972360335419e-01
+4.654699871427969704e-01
+4.686047402353432645e-01
+4.717407327589876465e-01
+4.748778409101152009e-01
+4.780159408410675215e-01
+4.811549086650327434e-01
+4.842946204609359095e-01
+4.874349522783311128e-01
+4.905757801422958031e-01
+4.937169800583235957e-01
+4.968584280172204104e-01
+4.999999999999999445e-01
+5.031415719827794231e-01
+5.062830199416762378e-01
+5.094242198577040304e-01
+5.125650477216687761e-01
+5.157053795390640349e-01
+5.188450913349671456e-01
+5.219840591589323120e-01
+5.251221590898846880e-01
+5.282592672410122425e-01
+5.313952597646567355e-01
+5.345300128572029186e-01
+5.376634027639664026e-01
+5.407953057840788613e-01
+5.439255982753714580e-01
+5.470541566592570515e-01
+5.501808574256074058e-01
+5.533055771376299559e-01
+5.564281924367407983e-01
+5.595485800474349070e-01
+5.626666167821521292e-01
+5.657821795461412950e-01
+5.688951453423191085e-01
+5.720053912761261516e-01
+5.751127945603784486e-01
+5.782172325201153651e-01
+5.813185825974417353e-01
+5.844167223563669911e-01
+5.875115294876379624e-01
+5.906028818135686809e-01
+5.936906572928624115e-01
+5.967747340254302424e-01
+5.998549902572036796e-01
+6.029313043849405807e-01
+6.060035549610273131e-01
+6.090716206982712544e-01
+6.121353804746906269e-01
+6.151947133382953403e-01
+6.182494985118623942e-01
+6.212996153977038416e-01
+6.243449435824275362e-01
+6.273853628416912187e-01
+6.304207531449484980e-01
+6.334509946601877273e-01
+6.364759677586625530e-01
+6.394955530196146931e-01
+6.425096312349881655e-01
+6.455180834141360791e-01
+6.485207907885176537e-01
+6.515176348163871367e-01
+6.545084971874738367e-01
+6.574932598276524987e-01
+6.604718049036047978e-01
+6.634440148274712845e-01
+6.664097722614933383e-01
+6.693689601226456842e-01
+6.723214615872585842e-01
+6.752671600956295928e-01
+6.782059393566255423e-01
+6.811376833522730934e-01
+6.840622763423390706e-01
+6.869796028689002521e-01
+6.898895477609005011e-01
+6.927919961386982406e-01
+6.956868334186012692e-01
+6.985739453173903657e-01
+7.014532178568314569e-01
+7.043245373681746857e-01
+7.071877904966422657e-01
+7.100428642059033457e-01
+7.128896457825363298e-01
+7.157280228404795386e-01
+7.185578833254665510e-01
+7.213791155194507754e-01
+7.241916080450162552e-01
+7.269952498697735965e-01
+7.297899303107441282e-01
+7.325755390387289623e-01
+7.353519660826660642e-01
+7.381191018339694487e-01
+7.408768370508574952e-01
+7.436250628626661641e-01
+7.463636707741456711e-01
+7.490925526697452819e-01
+7.518116008178801213e-01
+7.545207078751854368e-01
+7.572197668907529877e-01
+7.599086713103545554e-01
+7.625873149806478013e-01
+7.652555921533669148e-01
+7.679133974894982728e-01
+7.705606260634378923e-01
+7.731971733671345604e-01
+7.758229353142149787e-01
+7.784378082440938096e-01
+7.810416889260651807e-01
+7.836344745633780917e-01
+7.862160627972953897e-01
+7.887863517111337597e-01
+7.913452398342879501e-01
+7.938926261462365686e-01
+7.964284100805296696e-01
+7.989524915287593565e-01
+8.014647708445121754e-01
+8.039651488473026353e-01
+8.064535268264880763e-01
+8.089298065451669961e-01
+8.113938902440561707e-01
+8.138456806453501224e-01
+8.162850809565621590e-01
+8.187119948743448727e-01
+8.211263265882923212e-01
+8.235279807847220024e-01
+8.259168626504392874e-01
+8.282928778764780953e-01
+8.306559326618259131e-01
+8.330059337171258349e-01
+8.353427882683600592e-01
+8.376664040605121819e-01
+8.399766893612095053e-01
+8.422735529643443630e-01
+8.445569041936741295e-01
+8.468266529064023551e-01
+8.490827094967362543e-01
+8.513249848994244307e-01
+8.535533905932737309e-01
+8.557678386046426722e-01
+8.579682415109154414e-01
+8.601545124439535783e-01
+8.623265650935232340e-01
+8.644843137107056652e-01
+8.666276731112798615e-01
+8.687565586790868544e-01
+8.708708863693694902e-01
+8.729705727120909975e-01
+8.750555348152296853e-01
+8.771256903680518802e-01
+8.791809576443607721e-01
+8.812212555057239438e-01
+8.832465034046749208e-01
+8.852566213878946266e-01
+8.872515300993668586e-01
+8.892311507835117812e-01
+8.911954052882939958e-01
+8.931442160683092935e-01
+8.950775061878452066e-01
+8.969951993239174692e-01
+8.988972197692854937e-01
+9.007834924354382045e-01
+9.026539428555609978e-01
+9.045084971874736146e-01
+9.063470822165471397e-01
+9.081696253585920253e-01
+9.099760546627261304e-01
+9.117662988142136715e-01
+9.135402871372807487e-01
+9.152979495979064462e-01
+9.170392168065855110e-01
+9.187640200210709374e-01
+9.204722911490844650e-01
+9.221639627510076487e-01
+9.238389680425416195e-01
+9.254972408973460851e-01
+9.271387158496476877e-01
+9.287633280968260463e-01
+9.303710135019718219e-01
+9.319617085964176928e-01
+9.335353505822452380e-01
+9.350918773347628443e-01
+9.366312274049601871e-01
+9.381533400219318475e-01
+9.396581550952782802e-01
+9.411456132174766953e-01
+9.426156556662276254e-01
+9.440682244067722939e-01
+9.455032620941838939e-01
+9.469207120756319984e-01
+9.483205183926179949e-01
+9.497026257831855389e-01
+9.510669796841014767e-01
+9.524135262330098994e-01
+9.537422122705585537e-01
+9.550529853424978288e-01
+9.563457937017514343e-01
+9.576205863104587657e-01
+9.588773128419906255e-01
+9.601159236829351906e-01
+9.613363699350575553e-01
+9.625386034172290772e-01
+9.637225766673307437e-01
+9.648882429441257846e-01
+9.660355562291054188e-01
+9.671644712283061773e-01
+9.682749433740961420e-01
+9.693669288269370909e-01
+9.704403844771127829e-01
+9.714952679464323726e-01
+9.725315375899025172e-01
+9.735491524973722832e-01
+9.745480724951474105e-01
+9.755282581475768211e-01
+9.764896707586095959e-01
+9.774322723733215312e-01
+9.783560257794152726e-01
+9.792608945086878069e-01
+9.801468428384715326e-01
+9.810138357930427988e-01
+9.818618391450048000e-01
+9.826908194166369404e-01
+9.835007438812174430e-01
+9.842915805643155380e-01
+9.850632982450530095e-01
+9.858158664573369867e-01
+9.865492554910632039e-01
+9.872634363932886181e-01
+9.879583809693737173e-01
+9.886340617840967404e-01
+9.892904521627360337e-01
+9.899275261921234303e-01
+9.905452587216669880e-01
+9.911436253643443051e-01
+9.917226024976647514e-01
+9.922821672646027213e-01
+9.928222975744990242e-01
+9.933429721039339633e-01
+9.938441702975688852e-01
+9.943258723689569756e-01
+9.947880593013255224e-01
+9.952307128483256493e-01
+9.956538155347532948e-01
+9.960573506572389935e-01
+9.964413022849069046e-01
+9.968056552600041975e-01
+9.971503951984994618e-01
+9.974755084906501423e-01
+9.977809823015399981e-01
+9.980668045715862524e-01
+9.983329640170148789e-01
+9.985794501303070225e-01
+9.988062531806126687e-01
+9.990133642141357795e-01
+9.992007750544875666e-01
+9.993684783030087893e-01
+9.995164673390624088e-01
+9.996447363202946024e-01
+9.997532801828658000e-01
+9.998420946416499699e-01
+9.999111761904044826e-01
+9.999605221019081114e-01
+9.999901304280686132e-01
+1.000000000000000000e+00
+9.999901304280686132e-01
+9.999605221019081114e-01
+9.999111761904044826e-01
+9.998420946416499699e-01
+9.997532801828658000e-01
+9.996447363202946024e-01
+9.995164673390624088e-01
+9.993684783030087893e-01
+9.992007750544875666e-01
+9.990133642141357795e-01
+9.988062531806126687e-01
+9.985794501303070225e-01
+9.983329640170148789e-01
+9.980668045715862524e-01
+9.977809823015399981e-01
+9.974755084906501423e-01
+9.971503951984994618e-01
+9.968056552600041975e-01
+9.964413022849069046e-01
+9.960573506572389935e-01
+9.956538155347532948e-01
+9.952307128483256493e-01
+9.947880593013255224e-01
+9.943258723689569756e-01
+9.938441702975688852e-01
+9.933429721039340743e-01
+9.928222975744990242e-01
+9.922821672646027213e-01
+9.917226024976649734e-01
+9.911436253643443051e-01
+9.905452587216669880e-01
+9.899275261921234303e-01
+9.892904521627360337e-01
+9.886340617840967404e-01
+9.879583809693737173e-01
+9.872634363932886181e-01
+9.865492554910632039e-01
+9.858158664573369867e-01
+9.850632982450530095e-01
+9.842915805643155380e-01
+9.835007438812176650e-01
+9.826908194166369404e-01
+9.818618391450048000e-01
+9.810138357930429098e-01
+9.801468428384715326e-01
+9.792608945086879180e-01
+9.783560257794151616e-01
+9.774322723733215312e-01
+9.764896707586093738e-01
+9.755282581475768211e-01
+9.745480724951472995e-01
+9.735491524973721722e-01
+9.725315375899024062e-01
+9.714952679464322616e-01
+9.704403844771126719e-01
+9.693669288269370909e-01
+9.682749433740962530e-01
+9.671644712283059553e-01
+9.660355562291056408e-01
+9.648882429441255626e-01
+9.637225766673307437e-01
+9.625386034172289662e-01
+9.613363699350574443e-01
+9.601159236829350796e-01
+9.588773128419905145e-01
+9.576205863104588767e-01
+9.563457937017513233e-01
+9.550529853424979398e-01
+9.537422122705583316e-01
+9.524135262330097884e-01
+9.510669796841012547e-01
+9.497026257831855389e-01
+9.483205183926177728e-01
+9.469207120756318874e-01
+9.455032620941840049e-01
+9.440682244067721829e-01
+9.426156556662276254e-01
+9.411456132174764733e-01
+9.396581550952781692e-01
+9.381533400219317365e-01
+9.366312274049600761e-01
+9.350918773347627333e-01
+9.335353505822452380e-01
+9.319617085964176928e-01
+9.303710135019719329e-01
+9.287633280968261573e-01
+9.271387158496476877e-01
+9.254972408973461961e-01
+9.238389680425418415e-01
+9.221639627510077597e-01
+9.204722911490845760e-01
+9.187640200210711594e-01
+9.170392168065856220e-01
+9.152979495979064462e-01
+9.135402871372808598e-01
+9.117662988142138936e-01
+9.099760546627261304e-01
+9.081696253585921363e-01
+9.063470822165472507e-01
+9.045084971874737256e-01
+9.026539428555611089e-01
+9.007834924354383155e-01
+8.988972197692857158e-01
+8.969951993239175803e-01
+8.950775061878453176e-01
+8.931442160683095155e-01
+8.911954052882942179e-01
+8.892311507835118922e-01
+8.872515300993669696e-01
+8.852566213878948487e-01
+8.832465034046749208e-01
+8.812212555057241659e-01
+8.791809576443609942e-01
+8.771256903680521022e-01
+8.750555348152296853e-01
+8.729705727120912195e-01
+8.708708863693698232e-01
+8.687565586790870764e-01
+8.666276731112800835e-01
+8.644843137107057762e-01
+8.623265650935235671e-01
+8.601545124439533563e-01
+8.579682415109157745e-01
+8.557678386046426722e-01
+8.535533905932737309e-01
+8.513249848994247637e-01
+8.490827094967363653e-01
+8.468266529064027992e-01
+8.445569041936742405e-01
+8.422735529643444741e-01
+8.399766893612095053e-01
+8.376664040605122930e-01
+8.353427882683600592e-01
+8.330059337171258349e-01
+8.306559326618262462e-01
+8.282928778764783173e-01
+8.259168626504395094e-01
+8.235279807847221134e-01
+8.211263265882923212e-01
+8.187119948743448727e-01
+8.162850809565622701e-01
+8.138456806453500114e-01
+8.113938902440562817e-01
+8.089298065451674402e-01
+8.064535268264882983e-01
+8.039651488473028573e-01
+8.014647708445123975e-01
+7.989524915287595785e-01
+7.964284100805296696e-01
+7.938926261462366796e-01
+7.913452398342879501e-01
+7.887863517111338707e-01
+7.862160627972956117e-01
+7.836344745633783138e-01
+7.810416889260654028e-01
+7.784378082440940316e-01
+7.758229353142152007e-01
+7.731971733671344493e-01
+7.705606260634380034e-01
+7.679133974894981618e-01
+7.652555921533671368e-01
+7.625873149806478013e-01
+7.599086713103547774e-01
+7.572197668907534318e-01
+7.545207078751855478e-01
+7.518116008178805654e-01
+7.490925526697452819e-01
+7.463636707741457821e-01
+7.436250628626659420e-01
+7.408768370508576062e-01
+7.381191018339694487e-01
+7.353519660826662863e-01
+7.325755390387292953e-01
+7.297899303107437952e-01
+7.269952498697734855e-01
+7.241916080450159221e-01
+7.213791155194507754e-01
+7.185578833254663289e-01
+7.157280228404795386e-01
+7.128896457825362187e-01
+7.100428642059031237e-01
+7.071877904966422657e-01
+7.043245373681744637e-01
+7.014532178568313459e-01
+6.985739453173901437e-01
+6.956868334186012692e-01
+6.927919961386981296e-01
+6.898895477609005011e-01
+6.869796028688999190e-01
+6.840622763423389596e-01
+6.811376833522728713e-01
+6.782059393566253203e-01
+6.752671600956295928e-01
+6.723214615872583622e-01
+6.693689601226456842e-01
+6.664097722614931163e-01
+6.634440148274711735e-01
+6.604718049036045757e-01
+6.574932598276523876e-01
+6.545084971874738367e-01
+6.515176348163868036e-01
+6.485207907885174317e-01
+6.455180834141357460e-01
+6.425096312349881655e-01
+6.394955530196144711e-01
+6.364759677586625530e-01
+6.334509946601875052e-01
+6.304207531449484980e-01
+6.273853628416911077e-01
+6.243449435824276472e-01
+6.212996153977037306e-01
+6.182494985118626163e-01
+6.151947133382956734e-01
+6.121353804746907379e-01
+6.090716206982716985e-01
+6.060035549610274241e-01
+6.029313043849410247e-01
+5.998549902572035686e-01
+5.967747340254303534e-01
+5.936906572928624115e-01
+5.906028818135689029e-01
+5.875115294876379624e-01
+5.844167223563671021e-01
+5.813185825974421794e-01
+5.782172325201154761e-01
+5.751127945603787817e-01
+5.720053912761261516e-01
+5.688951453423193305e-01
+5.657821795461412950e-01
+5.626666167821523512e-01
+5.595485800474347959e-01
+5.564281924367410204e-01
+5.533055771376302889e-01
+5.501808574256075168e-01
+5.470541566592574956e-01
+5.439255982753715690e-01
+5.407953057840789723e-01
+5.376634027639662916e-01
+5.345300128572030296e-01
+5.313952597646566245e-01
+5.282592672410124646e-01
+5.251221590898850211e-01
+5.219840591589325340e-01
+5.188450913349675897e-01
+5.157053795390641460e-01
+5.125650477216689982e-01
+5.094242198577040304e-01
+5.062830199416764598e-01
+5.031415719827794231e-01
diff --git a/examples/icub_vor_env/normalised_head_velocities_1000.csv b/examples/icub_vor_env/normalised_head_velocities_1000.csv
new file mode 100644
index 00000000..f215b6ad
--- /dev/null
+++ b/examples/icub_vor_env/normalised_head_velocities_1000.csv
@@ -0,0 +1,1000 @@
+0.000000000000000000e+00
+9.869571931439562087e-06
+3.947789809190699632e-05
+8.882380959548627237e-05
+1.579053583499612364e-04
+2.467198171342090997e-04
+3.552636797053673788e-04
+4.835326609376300430e-04
+6.315216969912583423e-04
+7.992249455125140581e-04
+9.866357858641615353e-04
+1.193746819387333461e-03
+1.420549869692992653e-03
+1.667035982985024412e-03
+1.933195428413718962e-03
+2.219017698460000985e-03
+2.524491509349872410e-03
+2.849604801500486579e-03
+3.194344739995816362e-03
+3.558697715093159155e-03
+3.942649342761002200e-03
+4.346184465246665310e-03
+4.769287151674420945e-03
+5.211940698674534002e-03
+5.674127631042969779e-03
+6.155829702431123499e-03
+6.657027896065956935e-03
+7.177702425500961068e-03
+7.717832735397246562e-03
+8.277397502335116786e-03
+8.856374635655587385e-03
+9.454741278332920093e-03
+1.007247380787648638e-02
+1.070954783726390906e-02
+1.136593821590326132e-02
+1.204161903062620463e-02
+1.273656360671141137e-02
+1.345074450893671801e-02
+1.418413354266298380e-02
+1.493670175494710324e-02
+1.570841943568445503e-02
+1.649925611878251541e-02
+1.730918058336302495e-02
+1.813816085499507860e-02
+1.898616420695698956e-02
+1.985315716152841886e-02
+2.073910549131204387e-02
+2.164397422058470313e-02
+2.256772762667843060e-02
+2.351032924139054292e-02
+2.447174185242324135e-02
+2.545192750485270050e-02
+2.645084750262781739e-02
+2.746846241009755912e-02
+2.850473205356769679e-02
+2.955961552288726563e-02
+3.063307117306297844e-02
+3.172505662590380943e-02
+3.283552877169400308e-02
+3.396444377089454653e-02
+3.511175705587420148e-02
+3.627742333266925634e-02
+3.746139658277095746e-02
+3.866363006494259735e-02
+3.988407631706478162e-02
+4.112268715800936753e-02
+4.237941368954127597e-02
+4.365420629824853793e-02
+4.494701465750217118e-02
+4.625778772944151573e-02
+4.758647376699020465e-02
+4.893302031589858575e-02
+5.029737421681453047e-02
+5.167948160738201208e-02
+5.307928792436815424e-02
+5.449673790581603672e-02
+5.593177559322771303e-02
+5.738434433377238159e-02
+5.885438678252330469e-02
+6.034184490472183082e-02
+6.184665997806816640e-02
+6.336877259503986837e-02
+6.490812266523718344e-02
+6.646464941775491464e-02
+6.803829140358234884e-02
+6.962898649802816420e-02
+7.123667190317387043e-02
+7.286128415035239558e-02
+7.450275910265402590e-02
+7.616103195745833887e-02
+7.783603724899246235e-02
+7.952770885091538233e-02
+8.123597997892911815e-02
+8.296078319341440577e-02
+8.470205040209359548e-02
+8.645971286271908474e-02
+8.823370118578624521e-02
+9.002394533727378634e-02
+9.183037464140793305e-02
+9.365291778345298523e-02
+9.549150281252624661e-02
+9.734605714443907154e-02
+9.921650756456158737e-02
+1.011027802307144785e-01
+1.030048006760823781e-01
+1.049224938121547657e-01
+1.068557839316905261e-01
+1.088045947117059348e-01
+1.107688492164882604e-01
+1.127484699006330582e-01
+1.147433786121053179e-01
+1.167534965953250237e-01
+1.187787444942760007e-01
+1.208190423556390197e-01
+1.228743096319480643e-01
+1.249444651847701482e-01
+1.270294272879089470e-01
+1.291291136306304266e-01
+1.312434413209131179e-01
+1.333723268887199720e-01
+1.355156862892941960e-01
+1.376734349064766549e-01
+1.398454875560465327e-01
+1.420317584890843643e-01
+1.442321613953572168e-01
+1.464466094067261859e-01
+1.486750151005754306e-01
+1.509172905032636069e-01
+1.531733470935975061e-01
+1.554430958063257318e-01
+1.577264470356556925e-01
+1.600233106387903836e-01
+1.623335959394877070e-01
+1.646572117316399408e-01
+1.669940662828741373e-01
+1.693440673381740591e-01
+1.717071221235217937e-01
+1.740831373495606849e-01
+1.764720192152778033e-01
+1.788736734117078453e-01
+1.812880051256551550e-01
+1.837149190434377577e-01
+1.861543193546498220e-01
+1.886061097559437738e-01
+1.910701934548328096e-01
+1.935464731735117017e-01
+1.960348511526972537e-01
+1.985352291554875470e-01
+2.010475084712405602e-01
+2.035715899194703027e-01
+2.061073738537634592e-01
+2.086547601657119388e-01
+2.112136482888661571e-01
+2.137839372027044993e-01
+2.163655254366217140e-01
+2.189583110739346805e-01
+2.215621917559059684e-01
+2.241770646857848825e-01
+2.268028266328654674e-01
+2.294393739365620244e-01
+2.320866025105016994e-01
+2.347444078466328909e-01
+2.374126850193520877e-01
+2.400913286896452226e-01
+2.427802331092467902e-01
+2.454792921248143966e-01
+2.481883991821195179e-01
+2.509074473302545516e-01
+2.536363292258542179e-01
+2.563749371373338359e-01
+2.591231629491423938e-01
+2.618808981660304402e-01
+2.646480339173337137e-01
+2.674244609612708712e-01
+2.702100696892560938e-01
+2.730047501302265700e-01
+2.758083919549837448e-01
+2.786208844805491691e-01
+2.814421166745335046e-01
+2.842719771595204614e-01
+2.871103542174636702e-01
+2.899571357940967653e-01
+2.928122095033578454e-01
+2.956754626318254253e-01
+2.985467821431686541e-01
+3.014260546826096898e-01
+3.043131665813987308e-01
+3.072080038613017039e-01
+3.101104522390994434e-01
+3.130203971310998035e-01
+3.159377236576609294e-01
+3.188623166477270732e-01
+3.217940606433746242e-01
+3.247328399043705183e-01
+3.276785384127414713e-01
+3.306310398773542603e-01
+3.335902277385066617e-01
+3.365559851725287710e-01
+3.395281950963952577e-01
+3.425067401723476124e-01
+3.454915028125262189e-01
+3.484823651836129743e-01
+3.514792092114825683e-01
+3.544819165858641430e-01
+3.574903687650118900e-01
+3.605044469803853624e-01
+3.635240322413374470e-01
+3.665490053398122727e-01
+3.695792468550516130e-01
+3.726146371583089478e-01
+3.756550564175725193e-01
+3.787003846022962139e-01
+3.817505014881376058e-01
+3.848052866617046597e-01
+3.878646195253094286e-01
+3.909283793017286346e-01
+3.939964450389726314e-01
+3.970686956150593083e-01
+4.001450097427964869e-01
+4.032252659745698131e-01
+4.063093427071376440e-01
+4.093971181864312636e-01
+4.124884705123619821e-01
+4.155832776436331200e-01
+4.186814174025580981e-01
+4.217827674798845239e-01
+4.248872054396214959e-01
+4.279946087238739594e-01
+4.311048546576810025e-01
+4.342178204538587050e-01
+4.373333832178479263e-01
+4.404514199525651486e-01
+4.435718075632592017e-01
+4.466944228623699886e-01
+4.498191425743925942e-01
+4.529458433407428375e-01
+4.560744017246284310e-01
+4.592046942159213052e-01
+4.623365972360336529e-01
+4.654699871427971369e-01
+4.686047402353432645e-01
+4.717407327589876465e-01
+4.748778409101152009e-01
+4.780159408410675770e-01
+4.811549086650326323e-01
+4.842946204609357985e-01
+4.874349522783312239e-01
+4.905757801422959141e-01
+4.937169800583236512e-01
+4.968584280172204659e-01
+5.000000000000000000e-01
+5.031415719827794231e-01
+5.062830199416763488e-01
+5.094242198577040304e-01
+5.125650477216686651e-01
+5.157053795390641460e-01
+5.188450913349672566e-01
+5.219840591589324230e-01
+5.251221590898846880e-01
+5.282592672410122425e-01
+5.313952597646566245e-01
+5.345300128572029186e-01
+5.376634027639662916e-01
+5.407953057840787503e-01
+5.439255982753716800e-01
+5.470541566592571625e-01
+5.501808574256075168e-01
+5.533055771376299559e-01
+5.564281924367407983e-01
+5.595485800474349070e-01
+5.626666167821522402e-01
+5.657821795461412950e-01
+5.688951453423189975e-01
+5.720053912761261516e-01
+5.751127945603785596e-01
+5.782172325201154761e-01
+5.813185825974417353e-01
+5.844167223563669911e-01
+5.875115294876380734e-01
+5.906028818135686809e-01
+5.936906572928624115e-01
+5.967747340254301314e-01
+5.998549902572035686e-01
+6.029313043849406917e-01
+6.060035549610274241e-01
+6.090716206982713654e-01
+6.121353804746906269e-01
+6.151947133382953403e-01
+6.182494985118623942e-01
+6.212996153977036196e-01
+6.243449435824273142e-01
+6.273853628416909967e-01
+6.304207531449482760e-01
+6.334509946601877273e-01
+6.364759677586625530e-01
+6.394955530196145821e-01
+6.425096312349880545e-01
+6.455180834141358570e-01
+6.485207907885174317e-01
+6.515176348163869147e-01
+6.545084971874736146e-01
+6.574932598276522766e-01
+6.604718049036046867e-01
+6.634440148274711735e-01
+6.664097722614933383e-01
+6.693689601226456842e-01
+6.723214615872584732e-01
+6.752671600956294817e-01
+6.782059393566253203e-01
+6.811376833522728713e-01
+6.840622763423389596e-01
+6.869796028689001410e-01
+6.898895477609005011e-01
+6.927919961386982406e-01
+6.956868334186012692e-01
+6.985739453173902547e-01
+7.014532178568313459e-01
+7.043245373681745747e-01
+7.071877904966421546e-01
+7.100428642059032347e-01
+7.128896457825364408e-01
+7.157280228404795386e-01
+7.185578833254663289e-01
+7.213791155194506644e-01
+7.241916080450160331e-01
+7.269952498697733745e-01
+7.297899303107439062e-01
+7.325755390387291843e-01
+7.353519660826662863e-01
+7.381191018339696708e-01
+7.408768370508577172e-01
+7.436250628626662751e-01
+7.463636707741457821e-01
+7.490925526697452819e-01
+7.518116008178803433e-01
+7.545207078751857699e-01
+7.572197668907533208e-01
+7.599086713103547774e-01
+7.625873149806479123e-01
+7.652555921533671368e-01
+7.679133974894983838e-01
+7.705606260634378923e-01
+7.731971733671345604e-01
+7.758229353142150897e-01
+7.784378082440940316e-01
+7.810416889260654028e-01
+7.836344745633783138e-01
+7.862160627972955007e-01
+7.887863517111338707e-01
+7.913452398342881722e-01
+7.938926261462365686e-01
+7.964284100805295585e-01
+7.989524915287592455e-01
+8.014647708445122865e-01
+8.039651488473026353e-01
+8.064535268264880763e-01
+8.089298065451671071e-01
+8.113938902440561707e-01
+8.138456806453501224e-01
+8.162850809565621590e-01
+8.187119948743448727e-01
+8.211263265882922102e-01
+8.235279807847220024e-01
+8.259168626504391764e-01
+8.282928778764780953e-01
+8.306559326618259131e-01
+8.330059337171259459e-01
+8.353427882683600592e-01
+8.376664040605122930e-01
+8.399766893612096164e-01
+8.422735529643444741e-01
+8.445569041936742405e-01
+8.468266529064024661e-01
+8.490827094967362543e-01
+8.513249848994244307e-01
+8.535533905932737309e-01
+8.557678386046427832e-01
+8.579682415109156635e-01
+8.601545124439534673e-01
+8.623265650935233451e-01
+8.644843137107056652e-01
+8.666276731112799725e-01
+8.687565586790869654e-01
+8.708708863693694902e-01
+8.729705727120909975e-01
+8.750555348152299073e-01
+8.771256903680519912e-01
+8.791809576443608831e-01
+8.812212555057239438e-01
+8.832465034046749208e-01
+8.852566213878946266e-01
+8.872515300993668586e-01
+8.892311507835116702e-01
+8.911954052882941069e-01
+8.931442160683095155e-01
+8.950775061878453176e-01
+8.969951993239176913e-01
+8.988972197692854937e-01
+9.007834924354383155e-01
+9.026539428555608868e-01
+9.045084971874738367e-01
+9.063470822165470286e-01
+9.081696253585921363e-01
+9.099760546627261304e-01
+9.117662988142137825e-01
+9.135402871372810818e-01
+9.152979495979065572e-01
+9.170392168065857330e-01
+9.187640200210708263e-01
+9.204722911490845760e-01
+9.221639627510074266e-01
+9.238389680425416195e-01
+9.254972408973460851e-01
+9.271387158496476877e-01
+9.287633280968261573e-01
+9.303710135019719329e-01
+9.319617085964179148e-01
+9.335353505822450160e-01
+9.350918773347628443e-01
+9.366312274049599651e-01
+9.381533400219316254e-01
+9.396581550952780582e-01
+9.411456132174766953e-01
+9.426156556662275143e-01
+9.440682244067721829e-01
+9.455032620941840049e-01
+9.469207120756318874e-01
+9.483205183926179949e-01
+9.497026257831856499e-01
+9.510669796841013657e-01
+9.524135262330096774e-01
+9.537422122705585537e-01
+9.550529853424978288e-01
+9.563457937017514343e-01
+9.576205863104587657e-01
+9.588773128419906255e-01
+9.601159236829353016e-01
+9.613363699350575553e-01
+9.625386034172290772e-01
+9.637225766673305216e-01
+9.648882429441256736e-01
+9.660355562291054188e-01
+9.671644712283059553e-01
+9.682749433740961420e-01
+9.693669288269369799e-01
+9.704403844771127829e-01
+9.714952679464322616e-01
+9.725315375899022952e-01
+9.735491524973720612e-01
+9.745480724951472995e-01
+9.755282581475767101e-01
+9.764896707586095959e-01
+9.774322723733215312e-01
+9.783560257794153836e-01
+9.792608945086879180e-01
+9.801468428384716436e-01
+9.810138357930430208e-01
+9.818618391450050220e-01
+9.826908194166369404e-01
+9.835007438812174430e-01
+9.842915805643155380e-01
+9.850632982450528985e-01
+9.858158664573368757e-01
+9.865492554910632039e-01
+9.872634363932887291e-01
+9.879583809693738283e-01
+9.886340617840968514e-01
+9.892904521627360337e-01
+9.899275261921235414e-01
+9.905452587216669880e-01
+9.911436253643443051e-01
+9.917226024976648624e-01
+9.922821672646028324e-01
+9.928222975744990242e-01
+9.933429721039341853e-01
+9.938441702975688852e-01
+9.943258723689569756e-01
+9.947880593013254114e-01
+9.952307128483255383e-01
+9.956538155347532948e-01
+9.960573506572389935e-01
+9.964413022849067936e-01
+9.968056552600040865e-01
+9.971503951984994618e-01
+9.974755084906502534e-01
+9.977809823015399981e-01
+9.980668045715863634e-01
+9.983329640170149899e-01
+9.985794501303070225e-01
+9.988062531806126687e-01
+9.990133642141358905e-01
+9.992007750544874556e-01
+9.993684783030087893e-01
+9.995164673390624088e-01
+9.996447363202946024e-01
+9.997532801828656890e-01
+9.998420946416499699e-01
+9.999111761904043716e-01
+9.999605221019081114e-01
+9.999901304280686132e-01
+1.000000000000000000e+00
+9.999901304280686132e-01
+9.999605221019081114e-01
+9.999111761904043716e-01
+9.998420946416499699e-01
+9.997532801828656890e-01
+9.996447363202946024e-01
+9.995164673390624088e-01
+9.993684783030087893e-01
+9.992007750544874556e-01
+9.990133642141358905e-01
+9.988062531806126687e-01
+9.985794501303070225e-01
+9.983329640170149899e-01
+9.980668045715863634e-01
+9.977809823015399981e-01
+9.974755084906502534e-01
+9.971503951984994618e-01
+9.968056552600040865e-01
+9.964413022849067936e-01
+9.960573506572389935e-01
+9.956538155347532948e-01
+9.952307128483255383e-01
+9.947880593013254114e-01
+9.943258723689569756e-01
+9.938441702975688852e-01
+9.933429721039340743e-01
+9.928222975744990242e-01
+9.922821672646028324e-01
+9.917226024976648624e-01
+9.911436253643443051e-01
+9.905452587216669880e-01
+9.899275261921235414e-01
+9.892904521627361447e-01
+9.886340617840968514e-01
+9.879583809693738283e-01
+9.872634363932885071e-01
+9.865492554910632039e-01
+9.858158664573368757e-01
+9.850632982450528985e-01
+9.842915805643155380e-01
+9.835007438812174430e-01
+9.826908194166369404e-01
+9.818618391450050220e-01
+9.810138357930430208e-01
+9.801468428384716436e-01
+9.792608945086879180e-01
+9.783560257794153836e-01
+9.774322723733215312e-01
+9.764896707586095959e-01
+9.755282581475767101e-01
+9.745480724951472995e-01
+9.735491524973720612e-01
+9.725315375899024062e-01
+9.714952679464321506e-01
+9.704403844771127829e-01
+9.693669288269369799e-01
+9.682749433740961420e-01
+9.671644712283059553e-01
+9.660355562291054188e-01
+9.648882429441256736e-01
+9.637225766673305216e-01
+9.625386034172290772e-01
+9.613363699350574443e-01
+9.601159236829353016e-01
+9.588773128419906255e-01
+9.576205863104587657e-01
+9.563457937017514343e-01
+9.550529853424978288e-01
+9.537422122705584426e-01
+9.524135262330098994e-01
+9.510669796841013657e-01
+9.497026257831854279e-01
+9.483205183926177728e-01
+9.469207120756318874e-01
+9.455032620941838939e-01
+9.440682244067721829e-01
+9.426156556662278474e-01
+9.411456132174766953e-01
+9.396581550952782802e-01
+9.381533400219318475e-01
+9.366312274049601871e-01
+9.350918773347629553e-01
+9.335353505822450160e-01
+9.319617085964179148e-01
+9.303710135019720440e-01
+9.287633280968262683e-01
+9.271387158496476877e-01
+9.254972408973460851e-01
+9.238389680425416195e-01
+9.221639627510076487e-01
+9.204722911490845760e-01
+9.187640200210708263e-01
+9.170392168065857330e-01
+9.152979495979065572e-01
+9.135402871372810818e-01
+9.117662988142137825e-01
+9.099760546627261304e-01
+9.081696253585921363e-01
+9.063470822165471397e-01
+9.045084971874738367e-01
+9.026539428555611089e-01
+9.007834924354383155e-01
+8.988972197692854937e-01
+8.969951993239178023e-01
+8.950775061878453176e-01
+8.931442160683095155e-01
+8.911954052882941069e-01
+8.892311507835118922e-01
+8.872515300993670806e-01
+8.852566213878947377e-01
+8.832465034046749208e-01
+8.812212555057239438e-01
+8.791809576443611052e-01
+8.771256903680519912e-01
+8.750555348152299073e-01
+8.729705727120912195e-01
+8.708708863693697122e-01
+8.687565586790869654e-01
+8.666276731112800835e-01
+8.644843137107058872e-01
+8.623265650935234561e-01
+8.601545124439534673e-01
+8.579682415109156635e-01
+8.557678386046427832e-01
+8.535533905932739529e-01
+8.513249848994246527e-01
+8.490827094967364763e-01
+8.468266529064025772e-01
+8.445569041936743515e-01
+8.422735529643444741e-01
+8.399766893612096164e-01
+8.376664040605122930e-01
+8.353427882683600592e-01
+8.330059337171259459e-01
+8.306559326618259131e-01
+8.282928778764783173e-01
+8.259168626504396205e-01
+8.235279807847220024e-01
+8.211263265882924323e-01
+8.187119948743448727e-01
+8.162850809565623811e-01
+8.138456806453501224e-01
+8.113938902440562817e-01
+8.089298065451674402e-01
+8.064535268264882983e-01
+8.039651488473028573e-01
+8.014647708445122865e-01
+7.989524915287594675e-01
+7.964284100805295585e-01
+7.938926261462365686e-01
+7.913452398342879501e-01
+7.887863517111338707e-01
+7.862160627972956117e-01
+7.836344745633782027e-01
+7.810416889260655138e-01
+7.784378082440939206e-01
+7.758229353142153117e-01
+7.731971733671344493e-01
+7.705606260634378923e-01
+7.679133974894981618e-01
+7.652555921533670258e-01
+7.625873149806475793e-01
+7.599086713103547774e-01
+7.572197668907533208e-01
+7.545207078751855478e-01
+7.518116008178805654e-01
+7.490925526697452819e-01
+7.463636707741457821e-01
+7.436250628626660530e-01
+7.408768370508576062e-01
+7.381191018339693377e-01
+7.353519660826662863e-01
+7.325755390387292953e-01
+7.297899303107437952e-01
+7.269952498697733745e-01
+7.241916080450160331e-01
+7.213791155194507754e-01
+7.185578833254663289e-01
+7.157280228404795386e-01
+7.128896457825361077e-01
+7.100428642059030127e-01
+7.071877904966422657e-01
+7.043245373681743526e-01
+7.014532178568313459e-01
+6.985739453173901437e-01
+6.956868334186012692e-01
+6.927919961386980185e-01
+6.898895477609005011e-01
+6.869796028689000300e-01
+6.840622763423388486e-01
+6.811376833522728713e-01
+6.782059393566252092e-01
+6.752671600956294817e-01
+6.723214615872583622e-01
+6.693689601226456842e-01
+6.664097722614931163e-01
+6.634440148274711735e-01
+6.604718049036044647e-01
+6.574932598276523876e-01
+6.545084971874737256e-01
+6.515176348163868036e-01
+6.485207907885174317e-01
+6.455180834141357460e-01
+6.425096312349884986e-01
+6.394955530196148041e-01
+6.364759677586629971e-01
+6.334509946601878383e-01
+6.304207531449488311e-01
+6.273853628416912187e-01
+6.243449435824276472e-01
+6.212996153977037306e-01
+6.182494985118625053e-01
+6.151947133382956734e-01
+6.121353804746907379e-01
+6.090716206982716985e-01
+6.060035549610274241e-01
+6.029313043849410247e-01
+5.998549902572035686e-01
+5.967747340254304644e-01
+5.936906572928623005e-01
+5.906028818135689029e-01
+5.875115294876379624e-01
+5.844167223563671021e-01
+5.813185825974421794e-01
+5.782172325201154761e-01
+5.751127945603787817e-01
+5.720053912761261516e-01
+5.688951453423192195e-01
+5.657821795461412950e-01
+5.626666167821522402e-01
+5.595485800474347959e-01
+5.564281924367410204e-01
+5.533055771376302889e-01
+5.501808574256075168e-01
+5.470541566592573846e-01
+5.439255982753716800e-01
+5.407953057840789723e-01
+5.376634027639664026e-01
+5.345300128572030296e-01
+5.313952597646566245e-01
+5.282592672410123535e-01
+5.251221590898850211e-01
+5.219840591589325340e-01
+5.188450913349674787e-01
+5.157053795390641460e-01
+5.125650477216689982e-01
+5.094242198577040304e-01
+5.062830199416764598e-01
+5.031415719827793120e-01
+5.000000000000001110e-01
+4.968584280172208545e-01
+4.937169800583237622e-01
+4.905757801422960807e-01
+4.874349522783312239e-01
+4.842946204609360206e-01
+4.811549086650326323e-01
+4.780159408410676880e-01
+4.748778409101150899e-01
+4.717407327589878685e-01
+4.686047402353435976e-01
+4.654699871427971369e-01
+4.623365972360338194e-01
+4.592046942159211942e-01
+4.560744017246285420e-01
+4.529458433407427265e-01
+4.498191425743926497e-01
+4.466944228623699331e-01
+4.435718075632592017e-01
+4.404514199525653706e-01
+4.373333832178479263e-01
+4.342178204538589270e-01
+4.311048546576808915e-01
+4.279946087238740704e-01
+4.248872054396213849e-01
+4.217827674798846904e-01
+4.186814174025580426e-01
+4.155832776436331200e-01
+4.124884705123622042e-01
+4.093971181864312636e-01
+4.063093427071379216e-01
+4.032252659745698131e-01
+4.001450097427966535e-01
+3.970686956150591973e-01
+3.939964450389727424e-01
+3.909283793017285236e-01
+3.878646195253094286e-01
+3.848052866617044376e-01
+3.817505014881376613e-01
+3.787003846022964360e-01
+3.756550564175725193e-01
+3.726146371583090033e-01
+3.695792468550513910e-01
+3.665490053398122727e-01
+3.635240322413371694e-01
+3.605044469803854179e-01
+3.574903687650116679e-01
+3.544819165858640320e-01
+3.514792092114826794e-01
+3.484823651836129188e-01
+3.454915028125263854e-01
+3.425067401723474458e-01
+3.395281950963952577e-01
+3.365559851725286045e-01
+3.335902277385066617e-01
+3.306310398773540937e-01
+3.276785384127414158e-01
+3.247328399043706293e-01
+3.217940606433745132e-01
+3.188623166477272397e-01
+3.159377236576608183e-01
+3.130203971310998035e-01
+3.101104522390992213e-01
+3.072080038613017039e-01
+3.043131665813985087e-01
+3.014260546826096343e-01
+2.985467821431687652e-01
+2.956754626318253698e-01
+2.928122095033579564e-01
+2.899571357940966543e-01
+2.871103542174636702e-01
+2.842719771595202394e-01
+2.814421166745335046e-01
+2.786208844805489471e-01
+2.758083919549838003e-01
+2.730047501302266810e-01
+2.702100696892559273e-01
+2.674244609612708712e-01
+2.646480339173335472e-01
+2.618808981660304402e-01
+2.591231629491421162e-01
+2.563749371373337804e-01
+2.536363292258538849e-01
+2.509074473302548292e-01
+2.481883991821196567e-01
+2.454792921248145632e-01
+2.427802331092467902e-01
+2.400913286896454168e-01
+2.374126850193525040e-01
+2.347444078466331130e-01
+2.320866025105019770e-01
+2.294393739365621077e-01
+2.268028266328657172e-01
+2.241770646857848825e-01
+2.215621917559061904e-01
+2.189583110739346805e-01
+2.163655254366218805e-01
+2.137839372027044993e-01
+2.112136482888663236e-01
+2.086547601657122442e-01
+2.061073738537635425e-01
+2.035715899194706080e-01
+2.010475084712405602e-01
+1.985352291554878246e-01
+1.960348511526973092e-01
+1.935464731735118959e-01
+1.910701934548327818e-01
+1.886061097559438571e-01
+1.861543193546500441e-01
+1.837149190434377855e-01
+1.812880051256553771e-01
+1.788736734117078453e-01
+1.764720192152779976e-01
+1.740831373495606016e-01
+1.717071221235218770e-01
+1.693440673381740036e-01
+1.669940662828742761e-01
+1.646572117316401629e-01
+1.623335959394878181e-01
+1.600233106387906057e-01
+1.577264470356556925e-01
+1.554430958063259538e-01
+1.531733470935974506e-01
+1.509172905032638012e-01
+1.486750151005753473e-01
+1.464466094067263247e-01
+1.442321613953575221e-01
+1.420317584890844753e-01
+1.398454875560466992e-01
+1.376734349064766549e-01
+1.355156862892944181e-01
+1.333723268887199720e-01
+1.312434413209131179e-01
+1.291291136306303433e-01
+1.270294272879090025e-01
+1.249444651847704119e-01
+1.228743096319480643e-01
+1.208190423556391585e-01
+1.187787444942760007e-01
+1.167534965953251902e-01
+1.147433786121053179e-01
+1.127484699006330998e-01
+1.107688492164881772e-01
+1.088045947117059348e-01
+1.068557839316906510e-01
+1.049224938121548073e-01
+1.030048006760824197e-01
+1.011027802307144785e-01
+9.921650756456176778e-02
+9.734605714443890501e-02
+9.549150281252624661e-02
+9.365291778345290197e-02
+9.183037464140793305e-02
+9.002394533727396675e-02
+8.823370118578624521e-02
+8.645971286271916800e-02
+8.470205040209359548e-02
+8.296078319341440577e-02
+8.123597997892903488e-02
+7.952770885091546560e-02
+7.783603724899237908e-02
+7.616103195745833887e-02
+7.450275910265394264e-02
+7.286128415035239558e-02
+7.123667190317387043e-02
+6.962898649802808093e-02
+6.803829140358244598e-02
+6.646464941775491464e-02
+6.490812266523718344e-02
+6.336877259503978510e-02
+6.184665997806816640e-02
+6.034184490472174062e-02
+5.885438678252330469e-02
+5.738434433377247179e-02
+5.593177559322771303e-02
+5.449673790581603672e-02
+5.307928792436806403e-02
+5.167948160738210228e-02
+5.029737421681435700e-02
+4.893302031589858575e-02
+4.758647376699011444e-02
+4.625778772944143247e-02
+4.494701465750217118e-02
+4.365420629824853793e-02
+4.237941368954127597e-02
+4.112268715800928426e-02
+3.988407631706478162e-02
+3.866363006494242388e-02
+3.746139658277095746e-02
+3.627742333266925634e-02
+3.511175705587420148e-02
+3.396444377089454653e-02
+3.283552877169391288e-02
+3.172505662590380943e-02
+3.063307117306288824e-02
+2.955961552288726563e-02
+2.850473205356760659e-02
+2.746846241009755912e-02
+2.645084750262772719e-02
+2.545192750485270050e-02
+2.447174185242324135e-02
+2.351032924139054292e-02
+2.256772762667843060e-02
+2.164397422058470313e-02
+2.073910549131204387e-02
+1.985315716152832866e-02
+1.898616420695698956e-02
+1.813816085499507860e-02
+1.730918058336302495e-02
+1.649925611878251541e-02
+1.570841943568445503e-02
+1.493670175494710324e-02
+1.418413354266298380e-02
+1.345074450893671801e-02
+1.273656360671149984e-02
+1.204161903062637984e-02
+1.136593821590326132e-02
+1.070954783726399753e-02
+1.007247380787648638e-02
+9.454741278333008564e-03
+8.856374635655587385e-03
+8.277397502335205257e-03
+7.717832735397246562e-03
+7.177702425501049539e-03
+6.657027896066045405e-03
+6.155829702431123499e-03
+5.674127631043058249e-03
+5.211940698674534002e-03
+4.769287151674420945e-03
+4.346184465246665310e-03
+3.942649342761090671e-03
+3.558697715093159155e-03
+3.194344739995816362e-03
+2.849604801500574616e-03
+2.524491509349872410e-03
+2.219017698460000985e-03
+1.933195428413718962e-03
+1.667035982985024412e-03
+1.420549869692992653e-03
+1.193746819387333461e-03
+9.866357858641615353e-04
+7.992249455125140581e-04
+6.315216969912583423e-04
+4.835326609376300430e-04
+3.552636797053673788e-04
+2.467198171342090997e-04
+1.579053583499612364e-04
+8.882380959548627237e-05
+3.947789809190699632e-05
+9.869571931439562087e-06
diff --git a/examples/icub_vor_env/spynnaker.cfg b/examples/icub_vor_env/spynnaker.cfg
new file mode 100644
index 00000000..c75c989f
--- /dev/null
+++ b/examples/icub_vor_env/spynnaker.cfg
@@ -0,0 +1,3 @@
+[Mapping]
+# ICubVor doesn't implement delay extensions, so avoid DelaySupportAdder
+delay_support_adder = None
\ No newline at end of file
diff --git a/examples/logic/logic_test.py b/examples/logic/logic_test.py
index 72a46e2a..738d1c6b 100644
--- a/examples/logic/logic_test.py
+++ b/examples/logic/logic_test.py
@@ -68,7 +68,7 @@
b_vertex = logic_pop._vertex # pylint: disable=protected-access
scores = b_vertex.get_recorded_data('score')
scores = scores.tolist()
-print(scores)
+print('scores:', scores)
spikes_in = input_pop.get_data('spikes').segments[0].spiketrains
spikes_out1 = output_pop1.get_data('spikes').segments[0].spiketrains
diff --git a/integration_tests/script_builder.py b/integration_tests/script_builder.py
index cace985e..810ce5ac 100644
--- a/integration_tests/script_builder.py
+++ b/integration_tests/script_builder.py
@@ -21,13 +21,15 @@ class ScriptBuilder(RootScriptBuilder):
This file will recreate the test_scripts.py file
"""
- def build_intro_labs_scripts(self):
+ def build_spinn_gym_scripts(self):
# create_test_scripts supports test that are too long or exceptions
self.create_test_scripts(["examples"],
# This is meant to run "forever"
- exceptions={"automated.py": "Runs forever"})
+ exceptions={
+ "automated.py": "Runs forever",
+ "icub_utilities.py": "Not a script"})
if __name__ == '__main__':
builder = ScriptBuilder()
- builder.build_intro_labs_scripts()
+ builder.build_spinn_gym_scripts()
diff --git a/integration_tests/test_scripts.py b/integration_tests/test_scripts.py
index 443d9976..3c4cc5fa 100644
--- a/integration_tests/test_scripts.py
+++ b/integration_tests/test_scripts.py
@@ -1,17 +1,16 @@
-# Copyright (c) 2019-2021 The University of Manchester
+# Copyright (c) 2019 The University of Manchester
#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
+# https://www.apache.org/licenses/LICENSE-2.0
#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
from spinnaker_testbase import ScriptChecker
@@ -28,8 +27,11 @@ class TestScripts(ScriptChecker):
"""
# flake8: noqa
- def test_examples_breakout_automated_bkout_play(self):
- self.check_script("examples/breakout/automated_bkout_play.py")
+ def test_examples_double_inverted_pendulum_double_inverted_pendulum_test(self):
+ self.check_script("examples/double_inverted_pendulum/double_inverted_pendulum_test.py")
+
+ def test_examples_logic_logic_test(self):
+ self.check_script("examples/logic/logic_test.py")
def test_examples_breakout_breakout_simple_connection(self):
self.check_script("examples/breakout/breakout_simple_connection.py")
@@ -40,17 +42,26 @@ def test_examples_breakout_breakout_simple_connection(self):
def test_examples_breakout_neuromodulated_bkout_play(self):
self.check_script("examples/breakout/neuromodulated_bkout_play.py")
- def test_examples_logic_logic_test(self):
- self.check_script("examples/logic/logic_test.py")
-
- def test_examples_double_inverted_pendulum_double_inverted_pendulum_test(self):
- self.check_script("examples/double_inverted_pendulum/double_inverted_pendulum_test.py")
+ def test_examples_breakout_automated_bkout_play(self):
+ self.check_script("examples/breakout/automated_bkout_play.py")
def test_examples_store_recall_store_recall_test(self):
self.check_script("examples/store_recall/store_recall_test.py")
- def test_examples_inverted_pendulum_inverted_pendulum_test(self):
- self.check_script("examples/inverted_pendulum/inverted_pendulum_test.py")
+ # Not testing file due to: Not a script
+ # examples/icub_vor_env/icub_utilities.py
+
+ def test_examples_icub_vor_env_icub_vor_env_test_200_inputs(self):
+ self.check_script("examples/icub_vor_env/icub_vor_env_test_200_inputs.py")
+
+ def test_examples_icub_vor_env_icub_vor_venv_test_perfect_motion(self):
+ self.check_script("examples/icub_vor_env/icub_vor_venv_test_perfect_motion.py")
+
+ def test_examples_icub_vor_env_icub_vor_env_test(self):
+ self.check_script("examples/icub_vor_env/icub_vor_env_test.py")
def test_examples_multi_arm_bandit_bandit_test(self):
self.check_script("examples/multi_arm_bandit/bandit_test.py")
+
+ def test_examples_inverted_pendulum_inverted_pendulum_test(self):
+ self.check_script("examples/inverted_pendulum/inverted_pendulum_test.py")
diff --git a/spinn_gym/__init__.py b/spinn_gym/__init__.py
index 4ae60e80..9a447ba5 100644
--- a/spinn_gym/__init__.py
+++ b/spinn_gym/__init__.py
@@ -20,6 +20,7 @@
from spinn_gym.games.store_recall.store_recall import Recall
from spinn_gym.games.double_inverted_pendulum.double_pendulum \
import DoublePendulum
+from spinn_gym.games.icub_vor_env.icub_vor_env import ICubVorEnv
import os
# Put model_binaries directory on path
@@ -28,4 +29,4 @@
SpynnakerDataView.register_binary_search_path(binary_path)
__all__ = ['Breakout', 'Bandit', 'Pendulum', 'Logic', 'Recall',
- 'DoublePendulum']
+ 'DoublePendulum', 'ICubVorEnv']
diff --git a/spinn_gym/games/icub_vor_env/__init__.py b/spinn_gym/games/icub_vor_env/__init__.py
new file mode 100644
index 00000000..be5735ba
--- /dev/null
+++ b/spinn_gym/games/icub_vor_env/__init__.py
@@ -0,0 +1,14 @@
+# Copyright (c) 2019-2021 The University of Manchester
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
diff --git a/spinn_gym/games/icub_vor_env/icub_utilities.py b/spinn_gym/games/icub_vor_env/icub_utilities.py
new file mode 100644
index 00000000..199ecfb7
--- /dev/null
+++ b/spinn_gym/games/icub_vor_env/icub_utilities.py
@@ -0,0 +1,241 @@
+# Copyright (c) 2021 The University of Manchester
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+import numpy as np
+import pylab as plt
+import matplotlib as mlib
+import copy
+
+# ensure we use viridis as the default cmap
+plt.viridis()
+
+mlib.use('Agg')
+# ensure we use the same rc parameters for all matplotlib outputs
+mlib.rcParams.update({'font.size': 24})
+mlib.rcParams.update({'errorbar.capsize': 5})
+mlib.rcParams.update({'figure.autolayout': True})
+viridis_cmap = mlib.cm.get_cmap('viridis')
+
+ICUB_VOR_VENV_POP_SIZE = 2
+POS_TO_VEL = 2 * np.pi * 0.001
+
+
+# Examples of get functions for variables
+def get_error(icub_vor_env_pop):
+ # pylint: disable=protected-access
+ b_vertex = icub_vor_env_pop._vertex
+ error = b_vertex.get_recorded_data('error')
+ return error.tolist()
+
+
+def get_l_count(icub_vor_env_pop):
+ # pylint: disable=protected-access
+ b_vertex = icub_vor_env_pop._vertex
+ left_count = b_vertex.get_recorded_data('l_count')
+ return left_count.tolist()
+
+
+def get_r_count(icub_vor_env_pop):
+ # pylint: disable=protected-access
+ b_vertex = icub_vor_env_pop._vertex
+ right_count = b_vertex.get_recorded_data('r_count')
+ return right_count.tolist()
+
+
+def get_eye_pos(icub_vor_env_pop):
+ # pylint: disable=protected-access
+ b_vertex = icub_vor_env_pop._vertex
+ eye_positions = b_vertex.get_recorded_data('eye_pos')
+ return eye_positions.tolist()
+
+
+def get_eye_vel(icub_vor_env_pop):
+ # pylint: disable=protected-access
+ b_vertex = icub_vor_env_pop._vertex
+ eye_velocities = b_vertex.get_recorded_data('eye_vel')
+ return eye_velocities.tolist()
+
+
+def generate_head_position_and_velocity(time, dt=0.001):
+ i = np.arange(0, time, dt)
+ pos = -np.sin(i * 2 * np.pi)
+ vel = -np.cos(i * 2 * np.pi)
+ return pos, vel
+
+
+def retrieve_and_package_results(icub_vor_env_pop):
+ # Get the data from the ICubVorEnv pop
+ errors = np.asarray(get_error(icub_vor_env_pop=icub_vor_env_pop)).ravel()
+ l_counts = get_l_count(icub_vor_env_pop=icub_vor_env_pop)
+ r_counts = get_r_count(icub_vor_env_pop=icub_vor_env_pop)
+ rec_eye_pos = np.asarray(
+ get_eye_pos(icub_vor_env_pop=icub_vor_env_pop)).ravel()
+ rec_eye_vel = np.asarray(
+ get_eye_vel(icub_vor_env_pop=icub_vor_env_pop)).ravel()
+ results = {
+ 'errors': errors,
+ 'l_counts': l_counts,
+ 'r_counts': r_counts,
+ 'rec_eye_pos': rec_eye_pos,
+ 'rec_eye_vel': rec_eye_vel,
+ }
+ return results
+
+
+def highlight_area(ax, runtime, start_nid, stop_nid):
+ ax.fill_between(
+ [0, runtime], start_nid, stop_nid,
+ color='grey', alpha=0.1,
+ )
+
+
+def plot_results(results_dict, simulation_parameters, name):
+ # unpacking results
+ errors = results_dict['errors']
+ l_counts = results_dict['l_counts']
+ r_counts = results_dict['r_counts']
+ rec_eye_pos = results_dict['rec_eye_pos']
+ rec_eye_vel = results_dict['rec_eye_vel']
+
+ # unpacking simulation params
+ runtime = simulation_parameters['runtime']
+ error_window_size = simulation_parameters['error_window_size']
+ vn_spikes = simulation_parameters['vn_spikes']
+ cf_spikes = simulation_parameters['cf_spikes']
+ perfect_eye_pos = simulation_parameters['perfect_eye_pos']
+ perfect_eye_vel = simulation_parameters['perfect_eye_vel']
+ vn_size = simulation_parameters['vn_size']
+ cf_size = simulation_parameters['cf_size']
+
+ # plot the data from the ICubVorEnv pop
+ x_plot = [(n) for n in range(0, runtime, error_window_size)]
+ fig = plt.figure(figsize=(15, 20), dpi=400)
+ # Spike raster plot
+ ax = plt.subplot(5, 1, 1)
+ highlight_area(ax, runtime, vn_size // 2, vn_size)
+ first_half_filter = vn_spikes[:, 0] < vn_size // 2
+ second_half_filter = ~first_half_filter
+ plt.scatter(
+ vn_spikes[second_half_filter, 1], vn_spikes[second_half_filter, 0],
+ s=1, color=viridis_cmap(.75))
+ plt.scatter(
+ vn_spikes[first_half_filter, 1], vn_spikes[first_half_filter, 0],
+ s=1, color=viridis_cmap(.25))
+
+ plt.xlim([0, runtime])
+ plt.ylim([-0.1, vn_size+0.1])
+ # L/R counts
+ plt.subplot(5, 1, 2)
+ plt.plot(x_plot, l_counts, 'o', color=viridis_cmap(.25), label="l_counts")
+ plt.plot(x_plot, r_counts, 'o', color=viridis_cmap(.75), label="r_counts")
+ plt.legend(loc="best")
+ plt.xlim([0, runtime])
+ # Positions and velocities
+ plt.subplot(5, 1, 3)
+ plt.plot(x_plot, rec_eye_pos, label="rec. eye position")
+ plt.plot(x_plot, rec_eye_vel, label="rec. eye velocity")
+ plt.plot(np.tile(perfect_eye_pos, runtime // 1000), label="eye position",
+ ls=':')
+ plt.plot(np.tile(perfect_eye_vel, runtime // 1000), label="eye velocity",
+ ls=':')
+ plt.legend(loc="best")
+ plt.xlim([0, runtime])
+ # Errors
+ plt.subplot(5, 1, 4)
+ plt.plot(x_plot, errors, label="recorded error")
+
+ eye_pos_diff = np.tile(
+ perfect_eye_pos[::error_window_size],
+ runtime // 1000) - rec_eye_pos.ravel()
+ eye_vel_diff = np.tile(
+ perfect_eye_vel[::error_window_size],
+ runtime // 1000) - rec_eye_vel.ravel()
+ reconstructed_error = eye_pos_diff + eye_vel_diff
+
+ plt.plot(x_plot, reconstructed_error, color='k', ls=":",
+ label="reconstructed error")
+ plt.plot(x_plot, eye_pos_diff,
+ label="eye position diff")
+ plt.plot(x_plot, eye_vel_diff,
+ label="eye velocity diff")
+ plt.legend(loc="best")
+ plt.xlim([0, runtime])
+ # Error spikes
+ ax2 = plt.subplot(5, 1, 5)
+ highlight_area(ax2, runtime, cf_size // 2, cf_size)
+ first_half_filter = cf_spikes[:, 0] < cf_size // 2
+ second_half_filter = ~first_half_filter
+ plt.scatter(
+ cf_spikes[second_half_filter, 1], cf_spikes[second_half_filter, 0],
+ s=1, color=viridis_cmap(.75))
+ plt.scatter(
+ cf_spikes[first_half_filter, 1], cf_spikes[first_half_filter, 0],
+ s=1, color=viridis_cmap(.25))
+ # plt.legend(loc="best")
+ plt.xlim([0, runtime])
+ plt.ylim([-0.1, cf_size+0.1])
+ plt.xlabel("Time (ms)")
+ save_figure(plt, name, extensions=[".png", ])
+ plt.close(fig)
+
+
+def remap_odd_even(original_spikes, size):
+ remapped_spikes = copy.deepcopy(original_spikes)
+ mapping = np.arange(size)
+ mapping[::2] = np.arange(0, size, 2) // 2
+ mapping[1::2] = size // 2 + np.arange(size - 1, 0, -2) // 2
+ remapped_spikes[:, 0] = mapping[remapped_spikes[:, 0].astype(int)]
+ return remapped_spikes
+
+
+def remap_second_half_descending(original_spikes, size):
+ remapped_spikes = copy.deepcopy(original_spikes)
+ mapping = np.arange(size)
+ mapping[:size // 2] = np.arange(0, size // 2, 1)
+ mapping[size // 2:] = np.arange(size, size // 2, -1)
+ remapped_spikes[:, 0] = mapping[remapped_spikes[:, 0].astype(int)]
+ return remapped_spikes
+
+
+def color_for_index(index, size, cmap=viridis_cmap):
+ return cmap(index / (size + 1))
+
+
+def write_sep():
+ print("=" * 80)
+
+
+def write_line():
+ print("-" * 80)
+
+
+def write_header(msg):
+ write_sep()
+ print(msg)
+ write_line()
+
+
+def write_short_msg(msg, value):
+ print("{:40}:{:39}".format(msg, str(value)))
+
+
+def write_value(msg, value):
+ print("{:60}:{:19}".format(msg, str(value)))
+
+
+def save_figure(plt_fig, name, extensions=(".png",), **kwargs):
+ for ext in extensions:
+ write_short_msg("Plotting", name + ext)
+ plt_fig.savefig(name + ext, **kwargs)
diff --git a/spinn_gym/games/icub_vor_env/icub_vor_env.py b/spinn_gym/games/icub_vor_env/icub_vor_env.py
new file mode 100644
index 00000000..17982458
--- /dev/null
+++ b/spinn_gym/games/icub_vor_env/icub_vor_env.py
@@ -0,0 +1,158 @@
+# Copyright (c) 2019-2021 The University of Manchester
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+import numpy
+
+from spinn_utilities.overrides import overrides
+
+from spinn_front_end_common.interface.ds import DataType
+from spinn_front_end_common.utilities import constants as \
+ front_end_common_constants
+from spinn_front_end_common.utilities.exceptions import ConfigurationException
+
+from spynnaker.pyNN.data import SpynnakerDataView
+
+from spinn_gym.games import SpinnGymApplicationVertex
+
+# ICubVorEnv imports
+from spinn_gym.games.icub_vor_env.icub_vor_env_machine_vertex \
+ import ICubVorEnvMachineVertex
+
+
+# ----------------------------------------------------------------------------
+# ICubVorEnv
+# ----------------------------------------------------------------------------
+class ICubVorEnv(SpinnGymApplicationVertex):
+
+ # not sure this is entirely necessary but keeping it for now
+ MAX_SIM_DURATION = 10000
+ RANDOM_SEED = [numpy.random.randint(10000),
+ numpy.random.randint(10000),
+ numpy.random.randint(10000),
+ numpy.random.randint(10000)]
+ # Probably better ways of doing this too, but keeping it for now
+ RECORDABLE_VARIABLES = [
+ "l_count", "r_count", "error", "eye_pos", "eye_vel"]
+ RECORDABLE_DTYPES = [
+ DataType.UINT32, DataType.UINT32, DataType.S1615, DataType.S1615,
+ DataType.S1615]
+
+ # magic multiplier to convert movement delta to speed
+ POS_TO_VEL = 1 / (0.001 * 2 * numpy.pi * 10)
+
+ def __init__(self, head_pos, head_vel, perfect_eye_pos, perfect_eye_vel,
+ error_window_size=10, output_size=200, gain=20,
+ pos_to_vel=POS_TO_VEL, wta_decision=False, low_error_rate=2,
+ high_error_rate=20, label="ICubVorEnv",
+ simulation_duration_ms=MAX_SIM_DURATION, random_seed=None):
+ """
+ :param head_pos: array of head positions
+ :param head_vel: array of head velocities
+ :param perfect_eye_pos: array of ideal eye positions to produce VOR
+ :param perfect_eye_vel: array of ideal eye velocities to produce VOR
+ :param error_window_size: how often the environment changes
+ :param output_size: numbers of neurons encoding the error transmitted \
+ via combing fibres
+ :param gain: boosts the effect of individual spikes
+ :param pos_to_vel: magic multiplier to convert movement delta to speed
+ :param wta_decision: whether eye movement takes into account the \
+ difference in number of spikes between L and R
+ :param constraints: usual sPyNNaker constraints
+ :param label: name of the population
+ :param simulation_duration_ms: maximum simulation duration for this \
+ application vertex
+ """
+ self._number_of_inputs = len(perfect_eye_pos)
+ if self._number_of_inputs != len(perfect_eye_vel):
+ raise ConfigurationException(
+ "The length of perfect_eye_pos {} is not the same as the "
+ "length of perfect_eye_vel {}".format(
+ self._number_of_inputs, len(perfect_eye_vel)))
+
+ if random_seed is None:
+ random_seed = list(self.RANDOM_SEED)
+
+ # n_neurons is the number of atoms in the network, which in this
+ # case only needs to be 2 (for receiving "left" and "right")
+ n_neurons = 2
+
+ # used to define size of recording region:
+ # record variables every error_window_size ms (same size each time)
+ self._n_recordable_variables = len(self.RECORDABLE_VARIABLES)
+
+ self._recording_size = int(
+ (simulation_duration_ms / error_window_size) *
+ front_end_common_constants.BYTES_PER_WORD)
+
+ # set up recording region IDs and data types
+ self._region_ids = dict()
+ self._region_dtypes = dict()
+ for n in range(self._n_recordable_variables):
+ self._region_ids[self.RECORDABLE_VARIABLES[n]] = n
+ self._region_dtypes[
+ self.RECORDABLE_VARIABLES[n]] = self.RECORDABLE_DTYPES[n]
+ self._m_vertex = None
+
+ # Superclasses
+ machine_vertex = ICubVorEnvMachineVertex(
+ label, self, n_neurons, simulation_duration_ms,
+ random_seed, head_pos, head_vel, perfect_eye_pos,
+ perfect_eye_vel, error_window_size, output_size, gain,
+ pos_to_vel, wta_decision, low_error_rate, high_error_rate)
+
+ super(ICubVorEnv, self).__init__(
+ machine_vertex, label, n_neurons)
+
+ # ------------------------------------------------------------------------
+ # Recording overrides
+ # ------------------------------------------------------------------------
+ @overrides(SpinnGymApplicationVertex.get_recorded_data)
+ def get_recorded_data(self, name):
+ if self._m_vertex is None:
+ self._m_vertex = self.machine_vertices.pop()
+ print('get_data from machine vertex ', self._m_vertex,
+ ' for variable ', name)
+ placement = SpynnakerDataView.get_placement_of_vertex(self._m_vertex)
+ buffer_manager = SpynnakerDataView.get_buffer_manager()
+
+ # Read the data recorded
+ data_values, _ = buffer_manager.get_data_by_placement(
+ placement, self._region_ids[name])
+ data = data_values
+
+ numpy_format = list()
+ output_format = list()
+ if self._region_dtypes[name] is DataType.S1615:
+ numpy_format.append((name, numpy.int32))
+ output_format.append((name, numpy.float32))
+ else:
+ numpy_format.append((name, numpy.int32))
+
+ output_data = numpy.array(data, dtype=numpy.uint8).view(numpy_format)
+ if self._region_dtypes[name] is DataType.S1615:
+ convert = numpy.zeros_like(
+ output_data, dtype=numpy.float32).view(output_format)
+ for i in range(output_data.size):
+ for j in range(len(numpy_format)):
+ convert[i][j] = float(
+ output_data[i][j]) / float(DataType.S1615.scale)
+ return convert
+ else:
+ return output_data
+
+ @property
+ @overrides(SpinnGymApplicationVertex.score_format)
+ def score_format(self):
+ return numpy.int32
diff --git a/spinn_gym/games/icub_vor_env/icub_vor_env_machine_vertex.py b/spinn_gym/games/icub_vor_env/icub_vor_env_machine_vertex.py
new file mode 100644
index 00000000..cf48b546
--- /dev/null
+++ b/spinn_gym/games/icub_vor_env/icub_vor_env_machine_vertex.py
@@ -0,0 +1,231 @@
+# Copyright (c) 2019-2021 The University of Manchester
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+from enum import Enum
+import numpy
+
+from spinn_utilities.overrides import overrides
+
+# PACMAN imports
+from pacman.model.resources import ConstantSDRAM
+from pacman.model.graphs.machine import MachineVertex
+
+# SpinnFrontEndCommon imports
+from spinn_front_end_common.interface.ds import DataType
+from spinn_front_end_common.utilities import helpful_functions
+from spinn_front_end_common.abstract_models.abstract_has_associated_binary \
+ import AbstractHasAssociatedBinary
+from spinn_front_end_common.interface.buffer_management \
+ import recording_utilities
+from spinn_front_end_common.abstract_models \
+ .abstract_generates_data_specification \
+ import AbstractGeneratesDataSpecification
+from spinn_front_end_common.interface.simulation import simulation_utilities
+from spinn_front_end_common.utilities import constants as \
+ front_end_common_constants
+from spinn_front_end_common.utilities.exceptions import ConfigurationException
+
+# sPyNNaker imports
+from spynnaker.pyNN.data import SpynnakerDataView
+from spynnaker.pyNN.utilities import constants
+
+# spinn_gym imports
+from spinn_gym.games.spinn_gym_machine_vertex import SpinnGymMachineVertex
+
+
+# ----------------------------------------------------------------------------
+# ICubVorEnvMachineVertex
+# ----------------------------------------------------------------------------
+class ICubVorEnvMachineVertex(SpinnGymMachineVertex):
+ ICUB_VOR_ENV_REGION_BYTES = 4
+ BASE_DATA_REGION_BYTES = 9 * 4
+ # Probably better ways of doing this too, but keeping it for now
+ RECORDABLE_VARIABLES = [
+ "l_count", "r_count", "error", "eye_pos", "eye_vel"]
+ RECORDABLE_DTYPES = [
+ DataType.UINT32, DataType.UINT32, DataType.S1615, DataType.S1615,
+ DataType.S1615]
+
+ _ICUB_VOR_ENV_REGIONS = Enum(
+ value="_ICUB_VOR_ENV_REGIONS",
+ names=[('SYSTEM', 0),
+ ('ICUB_VOR_ENV', 1),
+ ('RECORDING', 2),
+ ('DATA', 3)])
+
+ def __init__(self, label, app_vertex, n_neurons,
+ simulation_duration_ms, random_seed,
+ head_pos, head_vel, perfect_eye_pos,
+ perfect_eye_vel, error_window_size, output_size, gain,
+ pos_to_vel, wta_decision, low_error_rate, high_error_rate):
+
+ super(ICubVorEnvMachineVertex, self).__init__(
+ label, app_vertex, n_neurons,
+ self.ICUB_VOR_ENV_REGION_BYTES + self.BASE_DATA_REGION_BYTES,
+ simulation_duration_ms, random_seed)
+
+ # pass in variables
+ self._head_pos = head_pos
+ self._head_vel = head_vel
+ self._perfect_eye_pos = perfect_eye_pos
+ self._perfect_eye_vel = perfect_eye_vel
+ self._error_window_size = error_window_size
+ self._output_size = output_size
+ self._gain = gain
+ self._pos_to_vel = pos_to_vel
+ self._wta_decision = wta_decision
+ self._low_error_rate = low_error_rate
+ self._high_error_rate = high_error_rate
+ self._number_of_inputs = len(perfect_eye_pos)
+ if self._number_of_inputs != len(perfect_eye_vel):
+ raise ConfigurationException(
+ "The length of perfect_eye_pos {} is not the same as the "
+ "length of perfect_eye_vel {}".format(
+ self._number_of_inputs, len(perfect_eye_vel)))
+ self._n_recordable_variables = len(self.RECORDABLE_VARIABLES)
+
+ self._recording_size = int((simulation_duration_ms / error_window_size)
+ * front_end_common_constants.BYTES_PER_WORD)
+
+ self._sdram_required = ConstantSDRAM(
+ self.ICUB_VOR_ENV_REGION_BYTES + self.BASE_DATA_REGION_BYTES +
+ self._recording_size)
+
+ @property
+ @overrides(SpinnGymMachineVertex.sdram_required)
+ def sdram_required(self):
+ return self._sdram_required
+
+ # ------------------------------------------------------------------------
+ # AbstractGeneratesDataSpecification overrides
+ # ------------------------------------------------------------------------
+ @overrides(AbstractGeneratesDataSpecification.generate_data_specification)
+ def generate_data_specification(self, spec, placement):
+ vertex = placement.vertex
+
+ spec.comment("\n*** Spec for ICubVorEnv Instance ***\n\n")
+ spec.comment("\nReserving memory space for data regions:\n\n")
+
+ # Reserve memory:
+ spec.reserve_memory_region(
+ region=self._ICUB_VOR_ENV_REGIONS.SYSTEM.value,
+ size=front_end_common_constants.SYSTEM_BYTES_REQUIREMENT,
+ label='setup')
+ spec.reserve_memory_region(
+ region=self._ICUB_VOR_ENV_REGIONS.ICUB_VOR_ENV.value,
+ size=self.ICUB_VOR_ENV_REGION_BYTES, label='ICubVorEnvParams')
+ # reserve recording region
+ spec.reserve_memory_region(
+ self._ICUB_VOR_ENV_REGIONS.RECORDING.value,
+ recording_utilities.get_recording_header_size(
+ len(self.RECORDABLE_VARIABLES)))
+ spec.reserve_memory_region(
+ region=self._ICUB_VOR_ENV_REGIONS.DATA.value,
+ size=self.BASE_DATA_REGION_BYTES + (self._number_of_inputs * 16),
+ label='ICubVorEnvArms')
+
+ # Write setup region
+ spec.comment("\nWriting setup region:\n")
+ spec.switch_write_focus(
+ self._ICUB_VOR_ENV_REGIONS.SYSTEM.value)
+ spec.write_array(simulation_utilities.get_simulation_header_array(
+ vertex.get_binary_file_name()))
+
+ # Write icub_vor_env region containing routing key to transmit with
+ spec.comment("\nWriting icub_vor_env region:\n")
+ spec.switch_write_focus(
+ self._ICUB_VOR_ENV_REGIONS.ICUB_VOR_ENV.value)
+ routing_info = SpynnakerDataView.get_routing_infos()
+ spec.write_value(routing_info.get_first_key_from_pre_vertex(
+ vertex, constants.LIVE_POISSON_CONTROL_PARTITION_ID))
+
+ # Write recording region for score
+ spec.comment("\nWriting icub_vor_env recording region:\n")
+ spec.switch_write_focus(
+ self._ICUB_VOR_ENV_REGIONS.RECORDING.value)
+ recording_sizes = [
+ self._recording_size for _ in range(self._n_recordable_variables)]
+ spec.write_array(recording_utilities.get_recording_header_array(
+ recording_sizes))
+
+ # Write parameters for ICubVorEnv data
+ spec.comment("\nWriting icub_vor_env data region:\n")
+ float_scale = float(DataType.S1615.scale)
+ spec.switch_write_focus(
+ self._ICUB_VOR_ENV_REGIONS.DATA.value)
+ spec.write_value(self._error_window_size, data_type=DataType.UINT32)
+ spec.write_value(self._output_size, data_type=DataType.UINT32)
+ spec.write_value(self._number_of_inputs, data_type=DataType.UINT32)
+ spec.write_value(self.__round_to_nearest_accum(self._gain),
+ data_type=DataType.S1615)
+ spec.write_value(self.__round_to_nearest_accum(self._pos_to_vel),
+ data_type=DataType.S1615)
+ spec.write_value(int(self._wta_decision), data_type=DataType.UINT32)
+ spec.write_value(self.__round_to_nearest_accum(self._low_error_rate),
+ data_type=DataType.S1615)
+ spec.write_value(self.__round_to_nearest_accum(self._high_error_rate),
+ data_type=DataType.S1615)
+ # Write the data - Arrays must be 32-bit values, so convert
+ data = numpy.array(
+ [int(x * float_scale) for x in self._perfect_eye_pos],
+ dtype=numpy.uint32)
+ spec.write_array(data.view(numpy.uint32))
+ data = numpy.array(
+ [int(x * float_scale) for x in self._perfect_eye_vel],
+ dtype=numpy.uint32)
+ spec.write_array(data.view(numpy.uint32))
+
+ # End-of-Spec:
+ spec.end_specification()
+
+ def __round_to_nearest_accum(self, x):
+ eps = 2. ** (-15)
+ x_approx = numpy.floor((x / eps) + 0.5) * eps
+ return x_approx
+
+ @overrides(SpinnGymMachineVertex.get_recorded_region_ids)
+ def get_recorded_region_ids(self):
+ return [0, 1, 2, 3, 4]
+
+ def get_recording_region_base_address(self, placement):
+ return helpful_functions.locate_memory_region_for_placement(
+ placement, self._ICUB_VOR_ENV_REGIONS.RECORDING.value)
+
+ @overrides(AbstractHasAssociatedBinary.get_binary_file_name)
+ def get_binary_file_name(self):
+ return "icub_vor_env.aplx"
+
+ @overrides(MachineVertex.get_n_keys_for_partition)
+ def get_n_keys_for_partition(self, partition_id):
+ # If the vertex is controlling another vertex then the number of
+ # keys needed is related to that vertex!
+ if partition_id == constants.LIVE_POISSON_CONTROL_PARTITION_ID:
+ partitions = SpynnakerDataView.\
+ get_outgoing_edge_partitions_starting_at_vertex(
+ self.app_vertex)
+ n_keys = 0
+ for partition in partitions:
+ if partition.identifier == partition_id:
+ for edge in partition.edges:
+ if edge.pre_vertex is not edge.post_vertex:
+ for m_vert in edge.post_vertex.machine_vertices:
+ n_keys += (
+ m_vert.get_n_keys_for_partition(
+ partition))
+ return n_keys
+ else:
+ return (
+ super(ICubVorEnvMachineVertex, self).get_n_keys_for_partition(
+ partition_id))
diff --git a/spinn_gym/games/logic/logic.py b/spinn_gym/games/logic/logic.py
index d8575cd8..39482df9 100644
--- a/spinn_gym/games/logic/logic.py
+++ b/spinn_gym/games/logic/logic.py
@@ -46,7 +46,7 @@ class Logic(SpinnGymApplicationVertex):
def __init__(
self, truth_table, input_sequence, rate_on=20.0, rate_off=5.0,
score_delay=200.0, stochastic=1, label="Logic",
- simulation_duration_ms=ONE_DAY_IN_MS, random_seed=None):
+ simulation_duration_ms=ONE_DAY_IN_MS, random_seed=None):
if random_seed is None:
random_seed = list(self.RANDOM_SEED)