{ "cells": [ { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import numpy as np" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "class Island: \n", " def __init__(self, x, y, radius, sound_id, is_distractor=False):\n", " self.x = x # in meters\n", " self.y = y # in meters\n", " self.r = radius # in meters\n", " self.sound_id = sound_id\n", " self.is_distractor = is_distractor\n", "\n", " def __str__(self):\n", " return \",\".join([\"%.4f\" % x for x in (self.x, self.y, self.r)] + [str(self.sound_id), \"1\" if self.is_distractor else \"0\"]) " ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "class IslandFactory:\n", " \n", " def __init__(self, floor_radius, angle_corr, cfg_exp):\n", " # floor_radius in meters, angle_corr in deg\n", " self.floor_radius = floor_radius\n", " self.angle_corr = angle_corr\n", " self.cfg_exp = cfg_exp\n", "\n", " self.is_fixed = not (cfg_exp['target_angle'] == 'random')\n", " self.phi_initial = np.random.rand() * 2 * np.pi if not self.is_fixed else np.deg2rad(int(cfg_exp['target_angle']))\n", " self.rho = self.floor_radius - cfg_exp['target_radius'] # constant, in meters \n", " self.last_tgt_x, self.last_tgt_y = None, None\n", " \n", " def _correct_angle(self, phi):\n", " return (2*np.pi - phi) + np.deg2rad(self.angle_corr)\n", " \n", " def generate_islands(self, time_from_start):\n", " def get_fixed_island_position(time_from_start):\n", " # returns the angle of the island (in polar coordinates)\n", " # all angles are in radians\n", "\n", " # no change during light periods\n", " if time_from_start <= self.cfg_exp['timepoints'][0] or time_from_start >= self.cfg_exp['timepoints'][-1]:\n", " return self.phi_initial\n", "\n", " # max anglular conflict in the middle of the dark\n", " if time_from_start >= self.cfg_exp['timepoints'][1] and time_from_start <= self.cfg_exp['timepoints'][2]:\n", " return self.phi_initial + np.deg2rad(self.cfg_exp['phi_max'])\n", "\n", " # raising phase\n", " if time_from_start < self.cfg_exp['timepoints'][1]:\n", " p_dur = self.cfg_exp['timepoints'][1] - self.cfg_exp['timepoints'][0]\n", " t_in_p = time_from_start - self.cfg_exp['timepoints'][0]\n", " return self.phi_initial + np.deg2rad(self.cfg_exp['phi_max']) * (t_in_p/p_dur)\n", "\n", " # falling phase\n", " p_dur = self.cfg_exp['timepoints'][3] - self.cfg_exp['timepoints'][2]\n", " t_in_p = time_from_start - self.cfg_exp['timepoints'][2]\n", " return self.phi_initial + np.deg2rad(self.cfg_exp['phi_max']) * (1 - (t_in_p/p_dur)) \n", " \n", " def get_new_xy(new_islands):\n", " while True:\n", " # all in meters\n", " rho = self.rho if self.is_fixed else np.sqrt(np.random.rand()) * (self.floor_radius - self.cfg_exp['target_radius'])\n", " phi = np.random.rand() * 2 * np.pi\n", " x = rho * np.sin(phi)\n", " y = rho * np.cos(phi)\n", "\n", " too_close = False\n", " for island in new_islands:\n", " if (island.x - x)**2 + (island.y - y)**2 < (2*self.cfg_exp['target_radius'])**2:\n", " too_close = True\n", " break\n", "\n", " if too_close:\n", " continue\n", " return x, y\n", "\n", " # target island\n", " if self.is_fixed:\n", " phi = get_fixed_island_position(time_from_start)\n", " phi = self._correct_angle(phi) # correct for the camera orientation\n", " x, y = self.rho * np.sin(phi), self.rho * np.cos(phi)\n", " else:\n", " x, y = get_new_xy([])\n", " islands = [Island(x, y, self.cfg_exp['target_radius'], 2, False)] # sound 2 is always target\n", " self.last_tgt_x, self.last_tgt_y = x, y\n", "\n", " # distractors\n", " sound_ids = [3 + i for i in range(self.cfg_exp['distractor_islands'])]\n", " if self.cfg_exp['distractor_islands'] > 0:\n", " for i in range(self.cfg_exp['distractor_islands']):\n", " x, y = get_new_xy(islands)\n", " islands.append(Island(x, y, self.cfg_exp['target_radius'], sound_ids.pop(np.random.randint(0, len(sound_ids))), True))\n", "\n", " return islands # always a list of Islands" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "class IslandFactoryPR:\n", " \n", " def __init__(self, floor_radius, cfg_exp):\n", " self.floor_radius = floor_radius # floor_radius in meters\n", " self.cfg_exp = cfg_exp\n", " \n", " def _correct_angle(self, phi):\n", " return (2*np.pi - phi) + np.deg2rad(90)\n", " \n", " def generate_target(self, head_direction): # head_direction in deg\n", " segment = 360. / 8\n", " offset = 90.\n", " \n", " # check that head_direction is not None\n", " #phi = np.deg2rad(int(head_direction[0]/segment)*segment + offset)\n", " phi = self._correct_angle(np.deg2rad(90)) # TODO make a proper angle - FIXME\n", " rho = self.floor_radius - self.cfg_exp['target_radius'] # all in meters\n", " x, y = rho * np.sin(phi), rho * np.cos(phi)\n", "\n", " return [Island(x, y, self.cfg_exp['target_radius'], 2, False)]\n", " \n", " def generate_startpoint(self): # head_direction in deg\n", " x, y, r = self.cfg_exp['startpoint_x'], self.cfg_exp['startpoint_y'], self.cfg_exp['startpoint_r']\n", " return [Island(x, y, r, 1, False)]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.8" } }, "nbformat": 4, "nbformat_minor": 4 }