diff --git a/+eui/SignalsTest.m b/+eui/SignalsTest.m index 6a66a272..0567ace5 100644 --- a/+eui/SignalsTest.m +++ b/+eui/SignalsTest.m @@ -118,6 +118,16 @@ 'signals:test:copyPaths',... 'No paths file found. A template can be found in %s.', ... fullfile(fileparts(which('addRigboxPaths')), 'docs', 'setup')) + + % Check that the Psychophisics Toolbox is installed + toolboxes = ver; + isInstalled = strcmp('Psychtoolbox', {toolboxes.Name}); + if ~any(isInstalled) || str2double(toolboxes(isInstalled).Version(1)) < 3 + error('signals:test:toolboxRequired',... + ['Requires Psychtoolbox v3.0 or higher to be installed. '... + 'Follow the steps in the README to install.'],... + 'https://github.com/cortex-lab/Rigbox/tree/master#installing-psychtoolbox') + end obj.LastDir = getOr(dat.paths, 'expDefinitions'); if nargin > 0 % called with experiment function to run diff --git a/+exp/Parameters.m b/+exp/Parameters.m index 04efe1c8..18745912 100644 --- a/+exp/Parameters.m +++ b/+exp/Parameters.m @@ -38,6 +38,28 @@ end function set(obj, name, value, description, units) + % SET Set a named parameter value + % SET(OBJ, NAME, VALUE[, DESCRIPTION, UNITS]) sets the value of a + % parameter. If the parameter doesn't already exist, a new one is + % added. + % + % Inputs: + % name (char): The parameter name to set + % value: The value of the parameter. The number of columns must + % be 1 or equal to numTrialConditions (or for chars the number + % of rows) + % description (char): Optional. A description of the parameter + % units (char): Optional. The parameter units + % + % Example 1: Add a new parameter called targetAltitude + % description = 'Visual angle of target centre above horizon'; + % P.set('targetAltitude', 90, description, '°') + % + % Example 2: Set the values for a trial condition + % values = randsample(0:45:135, P.numTrialConditions, true); + % P.set('orientation', values) + % + % See also DESCRIPTION, NUMTRIALCONDITIONS % if size(value, 2) > 1 % % Attempting to set a conditional parameter so it should match the diff --git a/README.md b/README.md index 8099a059..b8d00952 100644 --- a/README.md +++ b/README.md @@ -3,27 +3,40 @@ ![Coverage badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fsilent-zebra-36.tunnel.datahub.at%2Fcoverage%2Frigbox%2Fmaster) ![Build status badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fsilent-zebra-36.tunnel.datahub.at%2Fstatus%2Frigbox%2Fmaster) -Rigbox is a high-performance, open-source MATLAB toolbox for managing behavioral neuroscience experiments. -Rigbox's main goals are to simplify hardware/software interfacing, behavioral task design, and visual and auditory stimuli presentation. Additionally, Rigbox can time-align datastreams from multiple sources and communicate with a remote database to manage experiment data. Rigbox is mostly object-oriented and highly modular, which simplifies the process of designing experiments. +Rigbox is a high-performance, open-source MATLAB toolbox for managing behavioral neuroscience experiments. Initially developed to probe mouse behavior for the [Steering Wheel Setup](https://www.ucl.ac.uk/cortexlab/tools/wheel), Rigbox simplifies hardware/software interfacing and creates a runtime environment in which an experiment's parameters can be easily monitored and manipulated. Its many features include synchronizing recordings, managing experimental data and a viewing model for visual stimuli. Rigbox is mostly object-oriented and highly modular, making designing and extending experiments much simpler. ## Requirements For exploring Rigbox's features and running test experiments, Rigbox only needs to be installed on a single computer. -For running experiments, we recommend installing Rigbox on two computers: one computer (which we refer to as the "Stimulus Computer" or "SC") communicates with an experiment rig's hardware and presents stimuli, and the other computer (which we refer to as the "Master Computer" or "MC") runs a GUI that the experimenter can use to start, monitor, parameterize, and stop the experiment. +Rigbox has the following software dependencies: +* **OS:** Windows 7 or later, 64-bit +* **MATLAB:** 2018b (v9.5) or later, with the Data Acquisition Toolbox +* **Libraries**: [Visual C++ Redistributable Packages for Visual Studio 2013](https://www.microsoft.com/en-us/download/details.aspx?id=40784) & [2015-2019](https://github.com/Psychtoolbox-3/Psychtoolbox-3/raw/master/Psychtoolbox/PsychContributed/vcredist_x64_2015-2019.exe) +* **MATLAB community toolboxes:** + * [GUI Layout Toolbox](https://uk.mathworks.com/matlabcentral/fileexchange/47982-gui-layout-toolbox) (v2 or later) + * [Psychophysics Toolbox](http://psychtoolbox.org/download.html) (v3 or later) + * [NI-DAQmx support package](https://uk.mathworks.com/hardware-support/nidaqmx.html) (Required if using an NI DAQ) + +Additionally, Rigbox works with a number of extra submodules (included with Rigbox): +* [signals](https://github.com/cortex-lab/signals) (for designing bespoke experiments in Signals) +* [alyx-matlab](https://github.com/cortex-lab/alyx-matlab) (for registering data to, and retrieving from, an [Alyx database](https://alyx.readthedocs.io/en/latest/)) +* [npy-matlab](https://github.com/kwikteam/npy-matlab) (for saving data in binary NPY format) +* [wheelAnalysis](https://github.com/cortex-lab/wheelAnalysis) (for analyzing data from the steering wheel task) ### Hardware -Below are the **minimum** computer hardware specs: -* CPU: 4 logical processors @ 3.0 GHz base speed (e.g. Intel Core i5-6500) -* RAM: DDR4 16 GB @ 2133 MHz (e.g. Corsair Vengeance 16 GB) -* GPU: 2 GB @ 1000 MHz base and memory speed (e.g. NVIDIA Quadro P400) +Below are a few minimum hardware requirements for both PCs. Precise requirements depend on the type of experiments you wish to run, however most contemporary PC with a dedicated graphics card should suffice. -For most experiments, typical, contemporary, factory-built desktops running Windows 10 with dedicated graphics cards should suffice. Specific requirements of a SC will depend on the complexity of the experiment. For example, running an audio-visual integration task on multiple screens will require quality graphics and sound cards. SCs may additionally require an i/o device to communicate with external rig hardware, of which only National Instruments Data Acquisition Devices (NI-DAQs, e.g. NI-DAQ USB 6211) are currently supported. +**Processor:** Intel Core i5-6500 @ 3.0 GHz (or similar) +**Graphics:** NVIDIA Quadro P400 (or similar) +**Memory:** DDR4 16 GB @ 2133 MHz (e.g. Corsair Vengeance 16 GB) ### Software -Below are the **minimum** computer software dependencies that must be installed before installing Rigbox: +Below are short instructions for installing Rigbox for users familiar with Git and MATLAB. For detailed instructions, please see the [installation guide](https://cortex-lab.github.io/Rigbox/install.html). + +Before starting, ensure the above toolboxes and packages are installed. PsychToobox can not be installed via the MATLAB AddOns browser. See [Installing PsychToobox](#Installing-PsychToolbox) for install instructions. * OS: 64 Bit Windows 7 or later * Libraries: Visual C++ Redistributable Packages for Visual Studio [2013](https://www.microsoft.com/en-us/download/details.aspx?id=40784) & [2015](https://www.microsoft.com/en-us/download/details.aspx?id=48145) @@ -32,30 +45,40 @@ Below are the **minimum** computer software dependencies that must be installed * [GUI Layout Toolbox](https://uk.mathworks.com/matlabcentral/fileexchange/47982-gui-layout-toolbox) (v2 or later) * [Psychophysics Toolbox](http://psychtoolbox.org/download.html#Windows) (v3 or later) -Similar to the hardware requirements, software requirements for a SC will depend on the experiment: if acquiring data through a NI-DAQ, the SC will require the MATLAB Data Acquisition Toolbox and MATLAB [NI-DAQmx support package](https://uk.mathworks.com/hardware-support/nidaqmx.html) +1. To install Rigbox, run the following commands in the Git Bash terminal to clone the repository from GitHub to your local machine. +``` +git clone --recurse-submodules https://github.com/cortex-lab/Rigbox +``` +2. Run the `addRigboxPaths.m` function in MATLAB (found in the Rigbox directory) then restart the program. This adds all required folders and functions to your MATLAB path**. __NB__: Do __not__ manually add all Rigbox folders and subfolders to the paths -## Installation +\* Accepting all installer defaults will suffice. +** To add the paths temporarily for testing, run `addRigboxPaths('SavePaths', false, 'Strict', false)` Before starting, ensure you have read and followed the above [requirements section](#requirements). Below we provide brief instructions for installing Rigbox via Git. For a detailed installation guide, including installing Rigbox's software dependencies, see [here](https://cortex-lab.github.io/Rigbox/detailed_installation.html). -1. Clone the repository from GitHub. In your git terminal, run: +1. Download and install a Subversion client. [SilkSVN](https://sliksvn.com/download/) is recommended. +2. Download and install the [64-Bit GStreamer-1.16.0 MSVC runtime](https://gstreamer.freedesktop.org/data/pkg/windows/1.16.0/gstreamer-1.0-msvc-x86_64-1.16.0.msi). Make sure all offered packages are installed. +3. Download the MATLAB [installer function](https://raw.githubusercontent.com/Psychtoolbox-3/Psychtoolbox-3/master/Psychtoolbox/DownloadPsychtoolbox.m) from the PsychToolbox GitHub page. +4. Call the function in MATLAB with the target install location (folder must exist) and follow the instructions: ``` git clone --recurse-submodules https://github.com/cortex-lab/Rigbox ``` -2. Add all required Rigbox folders and functions to your MATLAB path. In MATLAB, navigate to the Rigbox root directory (where Rigbox was cloned), and run: -`addRigboxPaths()`, OR `addRigboxPaths('SavePaths', false)` if you don't want to save the paths for future MATLAB sessions. -(*Note*: Do **not** manually add all Rigbox folders and subfolders to the paths.) - ## Getting started +After following the installation instructions you can start playing around with Rigbox and Signals. To run one of the example experiments, open MATLAB and run `eui.SignalsTest();`, then select 'advancedChoiceWorld.m'. + +![](https://github.com/cortex-lab/Rigbox/blob/master/docs/html/images/SignalsTest%20GUI%20Example.gif) + +Full Rigbox documentation can be found at [cortex-lab.github.io/Rigbox](https://cortex-lab.github.io/Rigbox/). + +To run the example experiments from the Rigbox paper, see [Running Paper Examples](https://cortex-lab.github.io/Rigbox/paper_examples.html). -Rigbox uses the *Signals* framework for programatically designing and running behavioral tasks. -See the *Signals* [docs](https://github.com/cortex-lab/signals/tree/master/docs) for more information on *Signals* and how to run example test experiments on a single computer via Rigbox's `+eui/SignalsTest.m` GUI. +For more infomation on using the Signals Test GUI see [this guide](https://cortex-lab.github.io/Rigbox/using_test_gui.html). -![](https://github.com/cortex-lab/Rigbox/blob/master/docs/html/SignalsTest%20GUI%20Example.gif) -(The above is an example of running the `signals/docs/examples/exp defs/advancedChoiceWorld.m` file in the `+eui/SignalsTest.m` GUI) +### Running an experiment +For running full experiments see the [Setting up experiments](https://cortex-lab.github.io/Rigbox/index.html#2) guide. This will guide you through configuring a visual viewing model, configuring audio devices and setting up hardware that requires a DAQ. For information on running experiments via MC and SC, see Rigbox's [index page](https://github.com/cortex-lab/Rigbox/blob/dev/docs/html/index.html). This page also contains information on setting up Rigbox (see also [`docs/setup`](https://github.com/cortex-lab/Rigbox/tree/master/docs/setup)) and using certain Rigbox features (see also [`docs/usage`](https://github.com/cortex-lab/Rigbox/tree/master/docs/setup)) after an MC and SC installation. Furthermore, this page gives an overview of the repository's organization. @@ -82,5 +105,4 @@ For further information, see [our publication](https://www.biorxiv.org/content/1 * [Psychophsics Toolbox](http://psychtoolbox.org) for code pertaining to visual stimulus presentation * [NI-DAQmx](https://uk.mathworks.com/hardware-support/nidaqmx.html) for code pertaining to inerfacing with a NI-DAQ device * [TooTallNate](https://github.com/TooTallNate/Java-WebSocket) for code pertaining to using Java Websockets -* [Andrew Janke](https://github.com/apjanke) for the `isWindowsAdmin` function -* [Timothy E. Holy](http://holylab.wustl.edu/) for the `distinguishable_colors` function +* [Timothy E. Holy](http://holylab.wustl.edu/) for the `distinguishable_colors` function \ No newline at end of file diff --git a/addRigboxPaths.m b/addRigboxPaths.m index 9825517f..c1689e1f 100644 --- a/addRigboxPaths.m +++ b/addRigboxPaths.m @@ -1,11 +1,10 @@ function addRigboxPaths(varargin) %ADDRIGBOXPATHS Adds the required paths for using Rigbox -% addRigboxPaths([savePaths, interactive, strict]) or -% addRigboxPaths('SavePaths', true, 'Interactive', true, 'Strict', true) +% addRigboxPaths([savePaths, strict]) or +% addRigboxPaths('SavePaths', true, 'Strict', true) % % Inputs (Optional): % savePaths (logical): If true, added paths are saved between sessions -% interactive (logical): If true, user may be prompted for input % strict (logical): Assert toolbox & system requirments are all met % % Part of the Rigging toolbox @@ -17,7 +16,6 @@ function addRigboxPaths(varargin) % Allow positional or Name-Value pairs p = inputParser; p.addOptional('savePaths', true) -p.addOptional('interactive', true) p.addOptional('strict', true) p.parse(varargin{:}); p = p.Results; @@ -47,8 +45,15 @@ function addRigboxPaths(varargin) 'Click here to install.'],... 'https://www.microsoft.com/en-us/download/details.aspx?id=48145') + % Microsoft Visual C++ Redistributable for Visual Studio 2013 must be + % installed, check for runtime dll file in system32 folder + assert(any(strcmpi('msvcr120.dll',{sys32.name})), 'Rigbox:setup:libraryRequired',... + ['Requires Microsoft Visual C++ Redistributable for Visual Studio 2013. ',... + 'Click here to install.'],... + 'https://www.microsoft.com/en-us/download/details.aspx?id=40784') + % Check MATLAB 2017b is running - assert(~verLessThan('matlab', '9.3'), 'Requires MATLAB 2017b or later') + assert(~verLessThan('matlab', '9.5'), 'Requires MATLAB 2018b or later') % Check essential toolboxes are installed (common to both master and % stimulus computers) @@ -74,7 +79,8 @@ function addRigboxPaths(varargin) info = matlabshared.supportpkg.getInstalled; if isempty(info) || ~any(contains({info.Name}, 'NI-DAQmx')) warning('Rigbox:setup:toolboxRequired',... - ['The stimulus computer requires the National Instruments support package to be installed. '... + ['To run full experiments, the stimulus computer requires '... + 'the National Instruments support package to be installed. '... 'Click here to install.'],... 'https://www.mathworks.com/hardware-support/nidaqmx.html') end @@ -133,7 +139,7 @@ function addRigboxPaths(varargin) %%% Remind user to copy paths file %%% if ~exist('+dat/paths','file') - template_paths = fullfile(root, 'docs', 'setup', 'paths_template.m'); + template_paths = fullfile(root, 'docs', 'scripts', 'paths_template.m'); new_loc = fullfile(root, '+dat', 'paths.m'); copied = copyfile(template_paths, new_loc); % Check that the file was copied @@ -157,42 +163,4 @@ function addRigboxPaths(varargin) warning('Rigbox:setup:javaNotSetup',... 'Cannot use java classes without saving new classpath'); end - -%%% Attempt to move dll file for signals %%% -MSVSC2013URL = 'https://www.microsoft.com/en-us/download/details.aspx?id=40784'; -fileName = fullfile(root, 'signals', 'msvcr120.dll'); -fileExists = any(strcmp('msvcr120.dll',{sys32.name})); -copied = false; -if isWindowsAdmin % If user has admin privileges, attempt to copy dll file - if fileExists && p.interactive % If there's already a dll file there prompt use to make backup - prompt = sprintf(['For signals to work propery, it is nessisary to copy ',... - 'the file \n', strrep(fileName, '\', '\\\\'), ' to ',... - 'C:\\\\Windows\\\\System32.\n',... - 'You may want to make a backup of your existing dll file before continuing.\n\n',... - 'Alternatively this file is installed with ',... - '',... - 'Visual C++ Redistributable Packages for Visual Studio 2013\n\n',... - 'Do you want to proceed with copying? Y/N [Y]: '], MSVSC2013URL); - str = input(prompt,'s'); if isempty(str); str = 'y'; end - if strcmpi(str, 'n'); return; end % Return without copying - end - copied = copyfile(fileName, 'C:\Windows\System32'); -end -% Check that the file was copied -if ~copied - warning('Rigbox:setup:libraryRequired', ['Please copy the file ',... - '%s to C:\\Windows\\System32 ',... - '\nor install ',... - 'Visual C++ Redistributable Packages for Visual Studio 2013'], ... - fileName, MSVSC2013URL) -end - -function out = isWindowsAdmin() -%ISWINDOWSADMIN True if this user is in admin role. -% 2011 Andrew Janke (https://github.com/apjanke) -if ~NET.isNETSupported; out = false; return; end -wi = System.Security.Principal.WindowsIdentity.GetCurrent(); -wp = System.Security.Principal.WindowsPrincipal(wi); -out = wp.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator); -end end \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 9133862d..6f9fcafa 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,5 @@ -This `docs` folder contains information on setting up and using Rigbox, as well as information on the organization of the repository. After installation, we recommend viewing and following the instructions in the main index page for getting started with Rigbox. To view the main index page, open `docs/html/index.html` in a web browser. E.g. to do so within MATLAB, run: +# Documentation: +This 'docs' folder contains files that are useful for learning how to use and set up Rigbox. To view the docs in HTML open `docs/html/index.html` in the MATLAB browser or visit [cortex-lab.github.io/Rigbox](https://cortex-lab.github.io/Rigbox/): ```matlab root = fileparts(which('addRigboxPaths')); url = ['file:///', fullfile(root, 'docs', 'html', 'index.html')]; @@ -6,11 +7,18 @@ web(url) ``` ## Contents: +The docs directory contains three things: -- `setup/` - information on how to set up Rigbox on a new rig after installation. -- `usage/` - information on how to use certain Rigbox features after setup. -- `html/` - .html files that correspond to the .m files in `setup/` and `usage/` -- `maintainers/` - files for maintainers which specify design and style choices and how to standardize maintenance and development of Rigbox. -- `index.m` - Rigbox's documentation index page as a .m file. Corresponds to the `html/index.html` file. -- `Rigbox UML.pdf` - a UML diagram of Rigbox. -- `Troubleshooting_and_FAQ.m` - information on troubleshooting errors which arise in Rigbox, and frequently asked questions. \ No newline at end of file +- `scripts/` - The scripts used to generate the html files. These are useful if you wish to run some of the code in the docs, particularly `hardware_config.m`. +- `html/` - The html docs and source images. +- 'maintainers/' - Guidelines for code maintainers. +- `Rigbox UML.pdf` - A UML diagram of the Rigbox class structure. + + +## Contributing +If you wish to make changes to the documentation, please follow the below steps: +1. Make your changes to the documentation scripts on the `documentation` branch. +2. Export all changed files to html using MATLAB's 'Publish' feature. Code execution can be disabled in the Publish Options. +3. Copy the files from `docs/scripts/html` to `docs/html`. +4. Run the `fixFiles` script to perform any post processing on the html files. +5. Once committed to the `documentation` branch, merge this branch onto the `gh-pages` branch and copy the files from `docs/scripts/html` to the repository's root directory. Commit these changes to the `gh-pages` branch. They will now show up on the documentation Website. diff --git a/docs/Troubleshooting_and_FAQ.m b/docs/Troubleshooting_and_FAQ.m deleted file mode 100644 index f2fd33ea..00000000 --- a/docs/Troubleshooting_and_FAQ.m +++ /dev/null @@ -1,378 +0,0 @@ -%% Troubleshooting -% Often finding the source of a problem seems daunghting when faced with a -% huge Rigbox error stack. Below are some tips on how to quickly get to -% the root of the issue and hopefully solve it. - - -%%% Update the code -% Check what version of the code you're using and that you're up-to-date: -git.runCmd('status'); % Tells me what branch I'm on -git.update(0); % Update now - -% If you're on a development or feature branch try moving to the master -% branch, which should be most stable. -git.runCmd('checkout master'); git.update(0); - - -%%% Examining the stack -% Don't be frightened by a wall of red text! Simply start from the top and -% work out what the errors might mean and what part of code they came from. -% The error at the top is the one that ultimately caused the crash. Try to -% determine if this is a MATLAB builtin function, e.g. -% -% Warning: Error occurred while executing the listener callback for event UpdatePanel defined for class eui.SignalsTest: -% Error using griddedInterpolant -% Interpolation requires at least two sample points in each dimension. -% -% Error in interp1 (line 151) -% F = griddedInterpolant(X,V,method); -% -% TODO Add better example of builtin errors -% -% If you're debugging a signals experiment definition, check for the line -% in your experiment where this particular builtin function was called. NB: -% You can check whether it is specific to your experiment by running one of -% the example experiment definitions such as advancedChoiceWorld.m, found -% in signals/docs/examples. If this runs without error then you're problem -% may be specific to your experiment. You should see the name of your -% definition function and exp.SignalsExp in the stack if they are involved. -% -% If you don't know what a function is, try checking the documentation. -% Consider the following: -% -% Error using open -% Invalid number of channels -% -% Error in audstream.fromSignal (line 16) -% id = audstream.open(sampleRate, nChannels, devIdx); -% [...] -% -% If you're unsure what `audstream.fromSignal` does, try typing `doc -% audstream`. This should tell you that the package deals with audio -% devices in signals. In this case the issue might be that your audio -% settings are incorrect. Take a look at the audio section of -% `docs\setup\hardware_config.m` and see if you can setup your audio -% devices differently. - - -%%% Paths -% By far the most common issue in Rigbox relates to problems with the -% MATLAB paths. Check the following: -% -% # Do you have a paths file in the +dat package? -% Check the location by running `which dat.paths`. Check that a file is -% on the paths and that it's the correct one. -% # Check the paths set in this file. -% Run `p = dat.paths` and inspect the output. Perhaps a path is set -% incorrectly for one of the fields. Note that custom rig paths overwrite -% those written in your paths file. More info found in -% `using_dat_package` and `paths_template`. -% # Do you have path conflicts? -% Make sure MATLAB's set paths don't include other functions that have the -% same name as Rigbox ones. Note that any functions in ~/Documents/MATLAB -% take precedence over others. If you keep seeing the following warning -% check that you've set the paths correctly: -% Warning: Function system has the same name as a MATLAB builtin. We -% suggest you rename the function to avoid a potential name conflict. -% This warning can occur if the tests folder has been added to the paths -% by mistake. Always set the paths by running `addRigboxPaths` and never -% set them manually as some folders should not be visible to MATLAB. -% # Check your working directory -% MATLAB prioritizes functions found in your working directory over any -% others in your path list so try to change into a 'safe' folder before -% re-running your code: -% pwd % display working directory -% cd ~/Documents/MATLAB -% # Check your variable names -% Make sure your variable names don't shadow a function or package in -% Rigbox, for instance if in an experiment definition you create a varible -% called `vis`, you will no longer be able to access functions in the +vis -% package from within the function: -% vis = 23; -% img = vis.image(t); -% Error: Reference to non-existent field 'image'. - - -%%% Reverting -% If these errors only started occuring after updating the code, -% particularly if you hadn't updated in a long time, try reverting to the -% previous version of the code. This can help determine if the update -% really was the culprit and will allow you to keep using the code on -% outdated machines. Previous stable releases can be found on the Github -% page under releases. NB: For the most recent stable code always pull -% directly from the master branch - - -%%% Posting an issue on Github -% If you're completely stumped, open an issue on the Rigbox Github page (or -% alyx-matlab if you think it's related to the Alyx database). When -% creating an issue, read the bug report template carefully and be sure to -% provide as much information as possible. -% -% If you tracked down the problem but found the error to be confusing or -% too vague, feel free to post a feature request describing how better to -% present the error. This is an area in need of improvment. You could also -% make a change yourself and submit a pull request. For more info see -% CONTRIBUTING.md - - -%% FAQ -% Below are some frequently asked questions and suggestions for fixing -% them. Note there are plenty of other FAQs in the various setup scripts -% with more specific information. - - -%% Error and warning IDs -% Below is a list of Rigbox error & warning IDs. This list is currently -% incomplete and there aren't yet very standard. Typically the ID has the -% following structure: module:package:function:error -% -% These are here for search convenience and may soon contain more detailed -% troubleshooting information. - -% ..:..:..:copyPaths -% Problem: -% In order to load various essential configuration files, and to load and -% save experimental data, user specific paths must be retrieved via calls -% to |dat.paths|. This error means the function is not on MATLAB's search -% path. -% -% Solution: -% Add your +dat\paths.m file to MATLAB's search path. A template is -% present in \docs\setup\paths_template.m. This file is automatically -% copied by addRigboxPaths to +dat\. If you haven't already done so, run -% |addRigboxPaths| to ensure all other paths have been correctly set. -% -% See also README.md for further setup information. -% -% IDs -% Rigbox:git:update:copyPaths -% signals:test:copyPaths - -% ..:..:noRemoteFile -% Problem: -% % TODO Add problem & solution for noRemoteFile error -% -% Solution: -% -% -% IDs -% Rigbox:mc:noRemoteFile - -% ..:..:..:notInTest -% Problem: -% This occurs when a mock function is called when the INTEST global -% variable is not set. These mock functions shadow Rigbox and builtin -% functions, meaning they have the same name. -% -% Solution: -% If this function was called during a test, add the following to the top -% of your test or in the constructor: -% global INTEST -% INTEST = true -% Ensure that this is cleared during the teardown: -% addteardown(@clear, INTEST) % If in a class -% mess = onCleanup(@clear, INTEST) % If in a function -% -% If the mock in question is a class, set the InTest flag instead of the -% global variable: -% mock = MockDialog; % An example using MockDialog class -% mock.InTest = true; -% addteardown(@clear, MockDialog) % Clear mock class when done -% mess = onCleanup(@clear, MockDialog) % If in a function -% -% If you are in not running tests, ensure that tests/fixtures is not in -% your MATLAB path and that you are in a different working directory. It -% is best to remove all Rigbox paths and readd them using `addRigboxPaths` -% -% IDs -% Rigbox:tests:system:notInTest -% Rigbox:tests:modDate:notInTest -% Rigbox:tests:paths:notInTest -% Rigbox:tests:pnet:notInTest -% Rigbox:tests:modDate:missingTestFlag % TODO change name -% Rigbox:MockDialog:newCall:InTestFalse - -% ..:..:..:behaviourNotSet -% Problem: -% A mock function was called while in a test, however the behaviour for -% this particular input has not been defined. -% -% Solution: -% If not testing a specific behavior for this function's output, simply -% supress the warning in your test, remembering to restore the warning -% state: -% origState = warning; -% addteardown(@warning, origState) % If in a class -% mess = onCleanup(@warning, origState) % If in a function -% warning('Rigbox:MockDialog:newCall:behaviourNotSet', 'off') -% -% If you're specifically testing the behavior when the mock returns a -% particular output then check that you've set the input-output map -% correctly: usually this is done by first calling the mock with input -% identical to function under test as well as the output you want to see. -% Check the input is formatted correctly. For more information see the -% help of the particular mock you are using. -% -% IDs -% Rigbox:tests:system:valueNotSet % TODO change name -% Rigbox:MockDialog:newCall:behaviourNotSet -% - -% ..:..:mkdirFailed -% Problem: -% MATLAB was unable to create a new folder on the system. -% -% Solution: -% In general Rigbox code only creates new folders when a new experiment is -% created. The folders are usually created in the localRepository and -% mainRepository locations that are set in your paths file. If either of -% these are remote (e.g. a server accessed via SMB) check that you can -% navigate to the location in Windows' File Explorer (sometimes the access -% credentials need setting first). If you can, next check the permissions -% of these locations. If the folders are read-only, MATLAB will not be -% able to create a new experiment folder there. Either change the -% permissions or set a different path in |dat.paths|. One final thing to -% check is that the folder names are valid: the presence of a folder that -% is not correctly numbered in the subject's date folder may lead to an -% invalid expRef. Withtin a date folder there should only be folders name -% '1', '2', '3', etc. -% -% IDs -% Alyx:newExp:mkdirFailed -% Rigbox:dat:newExp:mkdirFailed -% - -% ..:newExp:expFoldersAlreadyExist -% Problem: -% The folder structure for a newly generated experiment reference is -% already in place. -% -% Experiment references are generated based on subject name, today's date -% and the experiment number, which is found by looking at the folder -% structure of the main repository. In a subject's experiment folder for -% a given date there are numbered folders. When running a new experiment, -% the code takes the folder name with the largest number and adds 1. It -% then checks that this numbered folder doesn't exist in the other -% repositories. If it does, an error is thrown so that no previous -% experiment data is overwritten. -% -% Solution: -% Check the folder structure for all your repositories (namely the -% localRepository and mainRepository set in |dat.paths|). It may be that -% there is an empty experiment folder in the localRepository but not the -% mainRepository, in which case you can delete it. Alternatively, if you -% find a full experiment folder in the local but not the main, copy it -% over so that the two match. This will avoid a duplicate expRef being -% created (remember, new expRefs are created based on the folder structure -% of the mainRepository only). -% -% IDs -% Alyx:newExp:expFoldersAlreadyExist -% Rigbox:dat:newExp:expFoldersAlreadyExist -% - -% ..:..:expRefNotFound -% Problem: -% The experiment reference string does not correspond to the folder -% structure in your mainRepository path. Usually determined via a call to -% |dat.expExists|. -% -% Solution: -% Check that the mainRepository paths are the same on both the computer -% that creates the experiment (e.g. MC) and the one that loads the -% experiment (e.g. the one that runs |srv.expServer|). For an experiment -% to exist, the subject > date > sequence folder structure should exist in -% the mainRepository. To see the mainRepository location, run the -% following: -% getOr(dat.paths, 'mainRepository') -% For example if the output is '\\server\Subjects\' then for the expRef -% '2019-11-25_1_test' to exist, the following folder should exist: -% \\server\Subjects\test\2019-11-25\1 -% -% IDs -% Rigbox:srv:expServer:expRefNotFound - -% ----- ! PTB - ERROR: SYNCHRONIZATION FAILURE ! ---- -% Problem: -% To quote PsychToolbox: One or more internal checks indicate that -% synchronization of Psychtoolbox to the vertical retrace (VBL) is not -% working on your setup.This will seriously impair proper stimulus -% presentation and stimulus presentation timing! -% -% Solution: -% There are many, many reasons for this error. Here's a quick list of -% things to try, in order: -% -% # Simply re-trying a couple of times. Sometimes it happens -% sporadically. -% # Check the monitor(s) are on and plugged in. If you're using -% multiple monitors they should be of the same make and model. If they -% aren't, try with just one monitor first. -% # If you're using multiple screens in NVIDEA's 'Mosaic' mode, the -% settings may have changed: sometimes Mosiac becomes deactivated and you -% should set it up again. -% # If you're using a remote connection for that computer it may be -% interfering with the graphics settings. Examples of a remote -% connection include VNC servers, TeamViewer and Windows Remote Desktop. -% Try opening the PTB Window without any of these remote services. -% # Update the graphics card drivers and firmware. This often helps. -% # Read the PTB docs carefully and follow their suggestions. The docs -% can be found at http://psychtoolbox.org/docs/SyncTrouble. -% # If all else fails. You can skip these tests and check that there is -% no taring manually. This is not recommended but can be done by setting -% your stimWindow object's PtbSyncTests property to false: -% stimWindow = getOr(hw.devices([],false), 'stimWindow'); -% stimWindow.PtbSyncTests = false; -% hwPath = fullfile(getOr(dat.paths, 'rigConfig'), 'hardware.mat'); -% save(hwPath, 'stimWindow', '-append') - -%%% Undocumented IDs -% Below is a list of all error and warning ids. - -% Rigbox:git:runCmd:nameValueArgs -% Rigbox:git:runCmd:gitNotFound -% Rigbox:git:update:valueError -% -% Rigbox:hw:calibrate:noscales -% Rigbox:hw:calibrate:deadscale -% Rigbox:hw:calibrate:partialPVpair -% -% Rigbox:srv:unexpectedUDPResponse -% Rigbox:srv:unexpectedUDP -% Rigbox:srv:expServer:noHardwareConfig -% -% Rigbox:dat:expPath:NotEnoughInputs -% Rigbox:exp:SignalsExp:NoScreenConfig -% Rigbox:exp:Parameters:wrongNumberOfColumns -% -% Rigbox:dat:expFilePath:NotEnoughInputs -% -% Rigbox:MockDialog:newCall:EmptySeq -% -% Rigbox:exp:SignalsExp:noTokenSet -% -% Rigbox:eui:choiceExpPanel:toolboxRequired -% Rigbox:setup:toolboxRequired -% -% Alyx:newExp:subjectNotFound -% Alyx:registerFile:InvalidPath -% Alyx:registerFile:UnableToValidate -% Alyx:registerFile:EmptyDNSField -% Alyx:registerFile:InvalidRepoPath -% Alyx:registerFile:InvalidFileType -% Alyx:registerFile:InvalidFileName -% Alyx:registerFile:NoValidPaths -% Alyx:updateNarrative:UploadFailed -% -% Alyx:getFile:InvalidID -% Alyx:getExpRef:InvalidID -% Alyx:getFile:InvalidType -% Alyx:expFilePath:InvalidType -% Alyx:url2Eid:InvalidURL -% -% toStr:isstruct:Unfinished -% -% squeak.hw -% shape:error -% window:error diff --git a/docs/html/Burgess_hardware_setup.html b/docs/html/Burgess_hardware_setup.html new file mode 100644 index 00000000..0fdb4c0a --- /dev/null +++ b/docs/html/Burgess_hardware_setup.html @@ -0,0 +1 @@ +

Instructions for steering wheel setup: hardware

Version 1.0.0, 14 February 2020

Lauren E Wool*, Miles J Wells**, Hamish Forrest, and Matteo Carandini
*
l.wool@ucl.ac.uk, **miles.wells@ucl.ac.uk 
Cortical Processing Laboratory, University College London

Table of contents

Introduction

Master computer

Stimulus computer

Installing the video card

Installing the DAQ device

Frame and components

Assembling the frame

Preparing the screens

Attaching the Fresnel lenses

Installing the screens

Configuring the screens

Assembling the mouse holder

Adding the camera and speaker

Assembling the water-reward system

Connecting the water-reward system

Connecting the rotary encoder

Connecting the photodiode

Comments and suggestions

Appendix: Components list

Introduction

This document gives instructions on how to build a basic version of the steering wheel setup to probe mouse behavior, introduced by Burgess et al. (Cell Reports, 2017). The goal is to make it easy for other laboratories, including those that make the International Brain Laboratory, to replicate the task and extend it in various directions. To this end, these instructions rely entirely on materials that can be bought off the shelf, or ordered online based on 3-D drawings.

In this steering wheel setup, we place a steering wheel under the front paws of a head-fixed mouse, and we couple the wheel’s rotation to the horizontal position of a visual stimulus on the screens. Turning the wheel left or right moves the stimulus left or right. The mouse is then trained to decide whether a stimulus appears on its left or its right. Using the wheel, the mouse indicates its choice by moving the stimulus to the center. A correct decision is rewarded with a drop of water and short intertrial interval, while an incorrect decision is penalized with a longer timeout and auditory noise.  

We use this setup throughout our laboratory, and deploy it in training rigs and experimental rigs. Training rigs are used to train head-fixed mice on the steering-wheel task and acquire behavioral data. Experimental rigs have additional apparatus to collect electrophysiological and imaging data, measure eye movements and licking activity, provide optogenetic perturbations, and so on.

Up until recently, constructing these setups required a machine shop that could provide custom-made components. However, for the purposes of spreading this setup to other laboratories, we here describe a new version that does not require a machine shop: all components can be ordered online or 3D-printed.

NB: An improved frame design can be found on the IBL Website.  The improved frame and its components (mouse holder, etc.) may still be used with Rigbox.

rig_frontback.jpg

The behavioral rig. A basic behavioral setup with three iPad screens (with Fresnel lenses), a mouse holder (with steering wheel), a water-delivery system, a head-fixation assembly, and a photodiode.

The main components of the behavioral setup are a mouse holder with steering wheel encoder, a water-delivery system, and three iPad screens for stimulus presentation. These and other components are  held together by a “frame”. A “stimulus computer” controls all this apparatus. Additionally, a “master computer” controls the stimulus computer.

A 3D view of the rig is available here, and a detailed list of the components can be found in this spreadsheet. Note that this list was assembled in the UK; though we have aimed to use international vendors, you may need to pick different ones depending on your location (please let us know if you encounter difficulties). Place the orders as soon as possible, as some items will take time to arrive. Also, start planning how you will 3D-print the mouse holder.

Configuring the “stimulus computer” is more involved, and so it helps to have it in place first. This way you can use it to test other components as they arrive. The “master computer” can be configured once you are ready to run software.

Master computer

The “master computer” controls the stimulus computer and manages the experimental session, and monitors the mouse with a camera. It runs Windows 10. The computer should be connected to the network, ideally through a high-speed connection (not WiFi). Instructions for installing and managing experimental software for this computer can be found in the document "Software instructions for steering wheel setup." If you are not using our software, you do not necessarily need this computer.

Stimulus computer

The “stimulus computer” controls stimulus display and water delivery, and acquires the mouse’s movements on the steering wheel and the output of a photodiode to synchronize stimulus output with other measurements. It runs Windows 10. The computer should be connected to the network, ideally through a high-speed connection (not WiFi). Instructions for installing and managing experimental software for this computer can be found in the document "Software instructions for steering wheel setup."

Installing the video card

The required video card is the NVIDIA NVS 510. This card drives four monitors: a main display monitor and the three iPad screens. This is a typical installation that would apply to any card for a Windows machine; if you are not familiar with the process, detailed instructions are below.

  1. Ensure your main monitor is connected to the onboard graphics card
  2. If you are removing a currently graphics card, open 'Device Manager' and check the 'Display adapters' drill-down menu for the current graphics card
  3. Double-click the graphics device: under the 'Driver' tab, select 'Uninstall' to remove any drivers associated with the current card.
  4. After powering down and unplugging the computer, open the case and install the NVIDIA NVS 510 in the PCI slot. If you are replacing an existing card, remove it and replace it with the NVS 510.
  5. Power up the computer and open 'Device Manager' and check that the 'Display adapters' drill-down menu shows a new object: 'Microsoft Basic Display Adapter,' or similar
  6. Via your browser, find and download, then install, an appropriate driver for your new card. As of October 2017, the current driver for NVIDIA NVS 510 is the Quadro Desktop/Notebook Driver Release 387, Version R387 U1 (387.95).
  7. Back in Device Manager, check that 'Microsoft Basic Display Adapter' has changed to the name of your GPU ('NVIDIA NVS 510').
  8. Restart the computer for changes to take effect
  9. Migrate the main display monitor to an NVS graphics card port using a suitable mini-DisplayPort cable, and confirm that you have visual output

Installing the DAQ device

To acquire data from the steering wheel and from the photodiode and to deliver water rewards to the mouse, we use a DAQ (data acquisition) device, the NI-DAQ 6211.

  1. Plug in the device to a powered USB port on the stimulus computer
  2. Visit the Drivers page on the National Instruments website and select ‘NI DAQmx’ from the ‘Popular Drivers and Updates’ list, then download the latest version of the device driver (17.1.1, as of October 2017).
  3. Once installation is complete, restart the computer.
  4.  Launch ‘NI Device Monitor’ from the System Tray. The program should recognize that the NI-DAQ 6211 is connected, and a green light on the DAQ should flash

Frame and components

The setup itself comprises three iPad screens installed on posts, a mouse holder with a steering wheel encoder and head-fixation assembly, and a water-delivery system. Here we describe the assembly of the frame required to hold these and other components together.

RigFootprint_Updated.jpg

Rig footprint diagram. The steering-wheel setup is contained entirely within a frame made of Thorlabs components, all seated on a 300mm x 300mm aluminium breadboard (MB3030/M). Components can be secured to the breadboard using 16mm M6 cap screws. The screen/Fresnel assemblies are seated between two grooved screws on clamps (one bottom, one top) that are attached to 300mm posts. The mouse itself is seated on a 3D-printed holder (not shown) that attaches to a magnetic plate in the center of the frame. In order for the Fresnel lenses to collimate light properly, the mouse’s head position must be equidistant from the three screens (indicated by the yellow ‘x’). This requirement is fulfilled with proper attachment of the holder to the magnetic plate (described below).

Assembling the frame

The frame is composed chiefly of Thorlabs components.

  1. Assemble the three screen post mounts, by attaching each post holder (PH50/M) to a mounting base (BA2T2/M), then attach them to the breadboard (MB3030/M) as shown in the footprint diagram
  2. Insert and secure 1 TR300/M post into each of the mounts 
  3. Wrap the thread of six PCMV/M V-groove screws 2-3 times with a ~5mm-wide piece of thread-seal tape. (The tape enables fine positioning and better tightening)
  4. For each of six PMTR/M clamp arms, screw 1 PCMV/M into the first M6 tap (i.e., closest to the clamp) until the groove is perpendicular to the clamp arm. Rotate just until the screw is tight, and try not to reverse as this ruins the grip
  5. On each post, firmly secure 1 PMTR/M clamp directly above the PH50/M, with the PCMV/M V-groove screw facing up. Each clamp arm should be perpendicular to its BA2T2/M plate and facing the center of the breadboard
  6. On each post, attach 1 PMTR/M clamp ~20 cm above the lower clamp, facing the same direction, with the PCMV/M V-groove screw facing down. Tighten just to secure to the posts, as these will be readjusted

Preparing the screens

To protect the screens from damage, keep the plastic film on until you are ready to attach the Fresnel lenses

  1. On a soft surface, turn the iPad over so that the back is facing up and the input cable is running along the top
  2. Check that the cable input on the driver board has its locking mechanism (black plastic bar) pressed up
  3. Carefully connect a driver board to the input cable. There will be ~1mm of gold contacts left visible. DO NOT FORCE THE CABLE.
  4. Attach the driver to the back of the screen with some lab tape, ensuring the cable is not bending or shearing
  5. Check that each driver board switch is set to 'OFF'

Attaching the Fresnel lenses

The purpose of the Fresnel lenses is to ensure that the intensity is homogeneous across the screen when viewed from a specific location (marked by a yellow ‘x’ in the rig footprint diagram above). To avoid pixel aliasing, the iPad screen and Fresnel lens must be separated by ~1 mm, using silicone pads. Various brands of window film may have different application instructions, so you may need to adapt steps 2–13 below.

  1. Ensure the smooth side of each Fresnel lens is clean and dry, with no fingerprints (use an air duster if needed to remove debris)
  2. Lay the lens on a bed of paper towels, smooth-side up with the short edge nearest
  3. Cut a piece of window film that is slightly larger than the fresnel lens (~2 cm border)
  4. Carefully peel back the adhesive and lay the window film next to the lens, adhesive-side up with the short edge nearest
  5. Generously spray both the lens and the film with soap/water solution
  6. Lift the window film from a short edge, letting it hang orthogonally to the surface of the fresnel lens
  7. Slowly lower the film to the lens surface, allowing the bottommost short edges to begin contacting each other
  8. Continue lowering to make contact with the lens, meanwhile using the squeegee to press out extra bubbles and solution to the sides
  9. Continue working away from the bottom edge, lowering the film and using the squeegee to remove bubbles and solution
  10. Lifting the lens/film, replace the wet paper towels with some new dry ones
  11. Carefully flip the lens/film over so that the ridged side is now facing up
  12. Trim the film edges with a razor or scalpel blade
  13. Flip the lens over to remove any remaining bubbles with a squeegee, and further trim edges with a blade as needed. You may find there are white patches on the lens after applying the film. These will usually disappear after a few hours
  14. Carefully remove the plastic protective film from the iPad screen and lay it face up
  15. Cut four small pieces of silicone pad (~3mm x ~20mm) from the silicone rubber sheet, and apply them to each corner of the screen, atop the screen bezel, with the long dimension of the pad running along the long edges of the screen. The pads should not touch the screen display
  16. Center the fresnel lens over the screen, with the rough side facing in, adjusting the silicone pads so that they lie between the screen bezel and the edge of the lens
  17. Using four binder clips, clip the screen/Fresnel assembly together at each corner, centered over the pads (two clips on the top and two clips on the bottom). Ensure that the clips do not intrude on the viewable area of the screen, but only grip along the bezel where the pads are located.

Installing the screens

If you haven't already done so, ensure that the main monitor of the Stimulus computer is connected to the NVIDIA video card via a mini-DisplayPort cable, at port 4.

  1. For each screen, center the bottom edge into the V-groove screw of the lower PMTR/M clamp. The output cable and driver board should be at the top of the screen on the back
  2. While holding the screen assembly in place, lower the upper PMTR/M clamp down the post until its V-groove screw holds the top edge of the screen assembly, and then firmly secure its position with the thumbscrew
  3. After each screen assembly has been attached to a post, make minor adjustments at each BA2T2/M plate to ensure that the screens are perpendicular to each other and that the edges of the fresnel lenses are flush
  4. Once the screens are firmly in place and all connection points are secured tightly to the breadboard, plug in the AC power cable to each.
  5. Connect each screen to the remaining NVS ports via the miniDP-to-DP display cables. Facing the screens, the leftmost screen should connect to port 1, the center to port 2, and the rightmost to port 3. The main monitor should connect to port 4.
  6. Turn the driver board switches to 'ON'
  7. Check that visual output appears onscreen. It is possible that the screens are out of order or the 'main display' option defaults away from your main monitor. This can be reconfigured, below.

Configuring the screens

The three iPad screens must be designated as a single viewable output, separate from the main monitor. This is accomplished using the NVIDIA Control Panel.

  1. Launch the NVIDIA Control Panel
  2. In the left panel, select ‘Select a task…’ > ‘Workstation’ > ‘Set up Mosaic’
  3. Click ‘Create new configuration’
  4. Under the ‘1. Select topology’ tab, select ‘Number of displays’ as 3 and choose a 1 x 3 topology with landscape orientation.
  5. Check the box ‘I am using recommended connections for the selected topology’ and then click ‘Enable Mosaic’
  6. Under the ‘2. Select displays’ tab, check the three iPad screens. These should be numbered 1 (0,0), 2 (0,1), and 3 (0,2). If they are not, rearrange the connections at the ports until this is satisfied.
  7. Assign ‘Resolution per display’ to 1280 x 1024. If they are not already in the ‘Selected display sources’ box, drag them there and then click ‘Next’
  8. Under the ‘3. Arrange displays’ tab, arrange the screen configuration so that 1-3 are arranged left to right. Apply the changes and select ‘yes’ to the dialog box prompting to save. Note: The main monitor will switch off and your working window will move to the 3-screen arrangement. Click ‘Finish’ ( skip overlap and bezel correction).
  9. Return to the main control panel, this time choosing ‘Select a task…’ > ‘Displays’ > ‘Set up multiple displays’
  10. Of the available displays, check the remaining box corresponding to the main monitor. In addition to the mosaic screens (labeled ‘3’), it will appear in the configuration window next to the 3-screen mosaic (display ‘3’) as display ‘4.’
  11. Rearrange the screens in the preferred configuration, then right-click screen 4 and choose ‘make primary’. Apply and accept changes. The main monitor should now reactivate.
  12. Launch Windows 10 > Settings > Display
  13. For each of the displays, ensure that ‘Change the size of text, apps and other items’ is set to 100%

Assembling the mouse holder

The mouse holder comprises seating for the mouse, a steering wheel/encoder assembly, an articulated arm for delivering water rewards, and a head-fixation assembly.

MouseHolderAssembly_new.jpg

The mouse holder assembly. Left: The mouse holder, seen from the front, shows the center bore that will accommodate the wheel assembly, as well as key attachment points to the KBM1/M breadboard. Center: The front of the holder shows the attachment point for the Fisso arm. Right: The back of holder shows the attachment point for the head-fixation assembly.

  1. 3D-print the (a) mouse holder, (b) mouse cover, and (c) wheel coupler designs. This can be done in-house or can be outsourced to third parties. Use PLA plastic for best results. If desired, the mouse cover can be printed in clear PLA so as to better observe mouse body movements
  2. Connect the wheel coupler to the shaft of the rotary encoder. It should attach securely with a just strong push
  3. Feed the rotary encoder through the large center bore on the front plate of the mouse holder, so that the coupler is facing outward and the encoder body is housed on the underside of the mouse holder. The encoder cable should be oriented downward
  4. Feed three 5-mm M3 cap screws through the small bores on the front plate of the mouse holder, and then screw them into the threaded holes on the face of the encoder
  5. To the top plate of the two-piece KBM1/M kinematic breadboard, attach the larger Fisso articulated arm to the front center hole (row 1, hole 3) of the KBM1/M, and secure tightly with an adjustable wrench
  6. Connect the 3D-printed mouse holder to the KBM1/M top plate using four 45-mm M6 cap screws, as shown in the diagram above. The two front screws will be in row 1 (holes 1 and 7) and the two back screws will be in row 3 (holes 1 and 7). Ensure that the magnetic hex switch is oriented to one side for accessibility
  7. Once the mouse holder is in position, assemble the LEGO wheel and hub, then gently secure it to the front cross of the coupler. There should be 1-2 mm of space between the wheel and the front face of the mouse holder
  8. Rotate the KBM1/M hex screw to release the bottom plate from the mouse holder assembly
  9. With a 20-mm M6 set screw, attach the TR200/M post to the KBM1/M top plate at row 6, hole 7
  10. Attach the RA90/M right-angle clamp 2 mm below the top of the TR200/M post, with the second post bore pointed toward the back of the KBM1/M top plate.
  11. Attach the RA180/M end clamp to the base of the TR50/M post, then feed the assembly through the open bore of the RA90/M, so that the RA180/M is centered over the mouse holder and the RA180/M bore is parallel to the KBM1/M top plate. Secure the RA90/M thumb screw
  12. Attach the headplate holder to the base of the TR100/M post with a 16-mm M6 cap screw
  13. Feed the holder/post assembly through the bore of the RA180/M until the headplate holder screw points are centered over the steering wheel. Secure the RA180/M thumb screw
  14. Insert the two M3 thumb screws top-down into the headplate holder. These are to secure the animal’s headplate
  15. Screw the KBM1/M bottom plate to the MB3030/M breadboard at the positions shown on the footprint diagram, then attach the holder assembly to the plate via the magnetic switch. (To avoid damage or injury, always make sure the magnetic switch is OFF before attempting to add or remove the top plate.)
  16. Cut a 65mm x 35mm rectangle of silicone rubber sheeting, and use it to line the bore where the mouse will be seated. This adds a bit of padding for comfort, and can be washed with soap & warm water between sessions.

Adding the camera and speaker

A camera is essential for monitoring the mouse’s behavior during the task, and a speaker is necessary to transmit simple task-related sounds, like beeps and white noise.

  1. Place the camera atop the left corner of the screens, where the left and center screens meet. If needed, use small pieces of poster putty to keep it stable. This needs to be positioned to view the front of the mouse holder at the top of the wheel, where the mouse’s face will be located during the task
  2. Plug the camera into the Master computer
  3. The camera can be managed with freeware (such as WebcamViewer,  ManyCam, or the software that comes with the camera), which should be installed on the Master computer. This runs independently of any experimental software.
  4. Plug the USB speaker into the Stimulus computer, and place the speaker on one corner of the MB3030/M breadboard, facing the mouse holder

Assembling the water-reward system

copperspoutguide.jpg

Making a spout guide. Use a length of 16AWG copper wire to extend the reach of the Fisso arm and enable water delivery to the mouse.

  1. To make a spout guide, first cut an 8-cm length of copper wire. Using long-nose pliers, wrap the end into a 2-mm-diameter loop, then bend it to a right angle
  2. Wrap the other end of the wire around the free M6 screw shaft of the Fisso arm, and secure with an M6 hex nut
  3. Bend the spout guide so that it extends the length of the Fisso arm toward the top of the steering wheel
  4. Position the water valve on one corner of the MB3030/M breadboard.
  5. On each end of the tubing already in the pinch valve, connect the larger end of a 3/32" x 1/16 barbed reducing connector
  6. Cut 50 cm of 1/32" ID x 3/32" OD tubing, and attach one end to one of the barbed connectors
  7. Feed the tubing along the back of the Fisso arm and through the 2-mm loop, and adjust the tubing so ~5 mm extends. Gently secure the tubing to the Fisso with a piece of laboratory tape
  8. Adjust the Fisso arm and spout guide so that the tube tip is centered in the bore of the mouse holder. Make sure the Fisso does not obstruct free movement of the wheel
  9. Additional 1/32" ID x 3/32" OD tubing will connect to the other barbed connector. This length should be cut in order to reach a nearby water reservoir (use a graduated cylinder or other vessel with milliliter precision)

Connecting the water-reward system

Before troubleshooting, always power off the valve system by unplugging the power supply directly.

  1. Cut two lengths each of red and black hookup wire. One red/black pair will connect the power supply and the other the DAQ board, so cut the lengths accordingly.
  2. Strip 5mm of insulation from both ends of each wire
  3. Connect the DC cable mount to the red/black wire pair that will supply power. Insert the red wire into the ‘+’ terminal and the black wire into the ‘’ terminal. Secure the wires in the terminals by using a screwdriver to tighten the set screws. Ensure that no exposed wire is outside the mount housing.
  4. Insert the CoolDrive valve controller driver into the prototyping mini-breadboard, so that its pins span multiple rows, not columns (i.e., the driver should run parallel to the center dividing well on the breadboard). The orientation of the driver is reversible, and pin information is twinned at each end (i.e., position 1 = position 9; position 2 = position 8, etc.). However, there is a LED trigger indicator on the driver, so consider its visibility when installing.
  5. Connect the red (+) and black (GND) power-supply wires at position 1 and 2 on the breadboard, respectively.
  6. Connect the two wires of the valve at position 3 and 5. Note that these leads are interchangeable.
  7. Connect the red (+) and black (GND) DAQ wires at positions 4 and 8, respectively.
  8. Using a piece of electrical tape, tape over all the breadboard connections to avoid short-circuiting or injury.
  9. On the back of the power-supply plug, adjust the voltage of the power supply to the 12V by rotating the switch position with a flathead screwdriver
  10. Connect the 5.5mm DC (male) plug to the two-pin output of the power-supply lead. Ensure the correct polarity by matching up the ‘+’ symbols between the plug and the lead
  11. Connect the red DAQ (+) wire at position 4 to the NI DAQ 6211 at port ‘AO0.’ Insert the wire into the port, and using a 2-mm flathead screwdriver, tighten the port’s set screw until the wire is secure
  12. Connect the black DAQ (GND) wire at position 8 to the NI DAQ 6211 at port ‘AOGND.’ Insert the wire into the port, and using a 2-mm flathead screwdriver, tighten the port’s set screw until the wire is secure
  13. Connect the male and female DC connectors for the power supply
  14. Power the breadboard by plugging in the power supply to the wall socket
  15. To test for valve function, launch ‘NI Device Monitor’ from the System Tray on the stimulus computer. The program should recognize the NI-6211, and a green light on the DAQ should flash
  16. Select the ‘NI USB-6211:Dev1’ icon, and then select ‘Test this device’
  17. In the Test Panels dialog box, migrate to the ‘Analog Output’ tab, then select ‘Mode: Voltage DC’
  18. Alternate the ‘Output Value’ between (+) and (-) 5 V in the right pane, clicking the Update button each time.
  19. The state of the valve (open or closed) will itself alternate with the alternating +/- 5V outputs—this will be evidenced by a small click and illumination of the green LED light on the driver board.

Connecting the rotary encoder

  1. Isolate the gray, green, brown, and white wires in the cable output of the rotary encoder.
  2. Connect the wires to the NI DAQ 6211 at positions PFI0 (gray), PFI1 (green), +5V (brown), GND (white) by inserting the exposed wire into the correct DAQ socket and securing it with a 2-mm flathead screwdriver until tight
  3. Ensure the other, loose wires don’t short one another by trimming them or insulating each one with electrical tape
  4. To test for encoder function, launch ‘NI Device Monitor’ from the System Tray.
  5. Select the ‘NI USB-6211:Dev1’ icon, and then select ‘Test this device’
  6. In the Test Panels dialog box, migrate to the ‘Counter I/O’ tab, then select ‘Mode: Edge Counting’ and ‘Pulse Terminal: /Dev1/PF10’
  7. Click the Start button, then manually spin the wheel on the mouse holder. If the encoder is working properly, the counter value will increase quickly, irrespective of wheel direction.

Connecting the photodiode

A photodiode is critical for gamma-correcting the luminance output of the screens, and is important for measuring stimulus timing. However, it is not required for starting basic behavioral training and can be added at a later stage.

  1. Attach the photodiode horizontally to the TR50/M post via the M4 screw
  2. Insert the TR300/M post into the PH50E/M post holder
  3. Place the PH50E/M on the breadboard so that the TR300/M post is near the rightmost edge of the right screen
  4. Mount the PH50E/M to the breadboard using a CF125 clamping fork and M6 cap screw
  5. Use the RA90/M right-angle clamp to connect the TR50/M and TR300/M post so that the photodiode lens is facing the screen
  6. Adjust the clamp and post positions so that the photodiode lens is flush with the iPad screen and as far into the top righthand corner of the screen as possible
  7. Connect the photodiode’s power supply and a male-male BNC coaxial cable to the photodiode output port.
  8. Connect the open end of the coaxial cable to the female BNC socket with test leads
  9. Strip 5mm of insulation from both ends of each wire
  10. Connect the red BNC (+) wire to the NI DAQ 6211 at port ‘AI1.’ Insert the wire into the port, and using a 2-mm flathead screwdriver, tighten the port’s set screw until the wire is secure
  11. Connect the black BNC (GND) wire to the NI DAQ 6211 at port ‘AI9.’ Insert the wire into the port, and using a 2-mm flathead screwdriver, tighten the port’s set screw until the wire is secure
  12. Power on the photodiode (there are switches at both the photodiode housing and power supply)
  13. To test for photodiode function, launch ‘NI Device Monitor’ from the System Tray on the stimulus computer. The program should recognize the NI-6211, and a green light on the DAQ should flash
  14. Select the ‘NI USB-6211:Dev1’ icon, and then select ‘Test this device’
  15. In the Test Panels dialog box, migrate to the ‘Analog Input’ tab, then select Channel Name: Dev1/ai1,’ ‘Mode: On Demand,’ and ‘Input Configuration: Differential’
  16. Click the ‘Start’ button.
  17. Free the photodiode slightly from its position near the screen so the sensor is visible. Without touching the sensor, carefully use your hand or a piece of cardstock to perturb the amount of light reaching it. This will cause the voltage reading to fluctuate, which will be visible on the onscreen graph.

Comments and suggestions

Now that you have your behavioral setup, you will want to place it in a sound insulation box or other quiet place to train your mice, or somewhere else in your lab, where you can acquire physiological data.

In following these instructions, you certainly will find that parts of this document can be improved. By all means, please make those improvement, by using the “suggest” feature if you are reading this in Google Docs, or by sending an email to Lauren or Miles.

An example of a steering-wheel setup used in a 2-photon imaging rig

Appendix: Components list

Category

QTY

Product

Specifications

Supplier

Notes

Stimulus computer

1

Computer

Processor: Intel Core i3 7100, 3.9 GHz

Memory: 16 GB (2 x 8 GB) Corsair 2133MHz DDR4 RAM, 1.2 V

Storage: 1TB WD Blue WD10EZEX, 7200rpm, 64MB Cache

OS: Windows 10 64-bit

Scan V10i

This computer controls the rig. For more details, see the document: "Software Instructions for Steering Wheel Setup". Note: When building multiple rigs, EACH rig needs its own Stimulus Computer, but these can all be controlled by one Master Computer

1

Graphics card

NVIDIA NVS 510

Insight Cat# VCNVS510VGA-PB

1

Keyboard & mouse

1

Monitor

1

mini-DP display cable

Connects the monitor to the video card

1

USB stereo speaker

Adafruit 3369

Master computer

1

Computer

Processor: Intel Core i3 4170, 3.70 GHz

Memory: 4 GB (2 x 2 GB) DDR3/DDR3L

OS: Windows 10 64-bit

Graphics Card: On-board graphics support

HP ProDesk 400 G2.5 (or similar)

This computer controls the Stimulus Computer. For more details, see the document: "Software Instructions for Steering Wheel Setup". Note: When building multiple rigs, EACH rig needs its own Stimulus Computer, but can all be controlled by one Master Computer. If you are not using our software, you do not necessarily need this machine.

1

Keyboard & mouse

1

Monitor

1

USB camera

Logitech C270

Stimulus displays

3

iPad 3/4 Retina display

LP097QX1

Adafruit 1751

3

Qualia bare driver board

Adafruit 1716

3

Mini DP-to DP cable

DisplayPort 1.2, 2m length

StarTech MDP2DPMM2M

3

9V DC, 1A power supply

9V DC, 1A, 1 output

RS 720-3726 (UK) / 720-3720 (USA/Japan) / 720-3739 (EU)

3

Fresnel lens

Size: 200 x 160 mm

Thickness: 2mm

Material: PMMA

Groove pitch: 0.5mm

Focal length: 220mm

Wuxi Bohai Optics (BHLens.com) BHPA220-2-5 (request the listed specifications)

Cortexlab have a number of these lenses cut to spec; please contact us if you are interested in obtaining some for your build

1

Roll adhesive window film (50 cm x 5 m)

Smooth surface, frosted-effect, adhesive (not self-adhesive/static)

The Window Film Company "Frostbrite" (or similar)

12

Binder clips

19mm

Staples 831594

1

Roll silicone rubber sheet

600mm x 600mm x 1.5mm

RS 840-5541

Mouse holder

1

Incremental rotary encoder

24mm, push-pull, 5V, 1024 PPR

Kubler 05.2400.1122.1024

1

USB data acquisition (DAQ) I/O device

Interface for rotary encoder and water reward system

National Instruments USB-6211

1

LEGO wheel/axle hub

Wheel 62.4 x 20 with Short Axle Hub, with Black Tire 62.4 x 20 (86652 / 32019)

LEGO parts 86652 & 32019 (www.bricklink.com)

1

Mouse holder block

3D printed: [link]

1

Mouse holder block cover

3D printed: [link]

1

Wheel/encoder coupler

3D printed: [link]

3

5mm M3 screw

Thorlabs SH3M5 (or part of HW-KIT5/M)

SH3M5 is a pack of 50, but only 3 total are required

4

45mm M6 cap screw

RS 293-397 (or part of Thorlabs HW-KIT2/M)

RS 293-397 is a pack of 50, but only 4 total are required

1

Post

Thorlabs TR200/M

1

Post

Thorlabs TR50/M

1

Post

Thorlabs TR100/M

1

Right-angle clamp

Thorlabs RA90/M

1

Right-angle end clamp

Thorlabs RA180/M

1

20mm M6 set screw

Thorlabs SS6MS20 (or part of HW-KIT2/M)

SS6MS20 is a pack of 25, but only 1 is required

1

Magnetic breadboard

Thorlabs KBM1/M

1

Aluminium Headplate Holder

STP file: [link]

Thread size for the 2 thumbscrews: M3

Material: Aluminium 6082 - T651 Grey Aluminium

ProtoLabs.com

On ProtoLabs.com, click 'Get a quote', select 'CNC Machining' and upload the STL file.

2

Stainless thread M3 thumb screw

6mm shaft

Mechanical Components P0480.030-006-A4

1

Stainless steel headplate

Specs: [link]

1

Articulated arm

Strato XS-13 130 mm with M6 mounts (arm only)

Fisso 4.000

http://fisso.com/pdf/FISSO_StratoLine_E.pdf

1

Roll copper wire

Solid core, bare, 16 AWG

RS 357-794

1

M6 hex nut

RS 525-919 (or part of Thorlabs HW-KIT2/M)

RS 525-919 is a pack of 250, but only 1 is required

Reward system

1

Pinch valve

1-tube, normally closed, 12V DC

NResearch 225P011-21

1

Valve controller driver

NResearch specifications (May 2017)

Nresearch CoolDriveSolo CDS-V01 (UK), CoolDriveSolo CDS-US (USA)

Confirm the linked specifications, as part numbers can be inconsistent

1

Tubing

1/32" ID x 3/32" OD, 50 ft

Cole Parmer WZ-95702-00

2

Tube connector

Barbed Reducing Connector 3/32" x 1/16"

Cole Parmer WZ-41518-22

1

Power supply

1.5–12 V DC, 1A linear power supply

RS 615-8919

1

Mini breadboard

Pimoroni COM0101

1

Cable mount

2.1 x 5.5 mm DC (female), 2-pin

RS 810-4605

1

Roll red hookup wire

300V 22AWG, solid core

Alpha Wire 3051/1 RD005

1

Roll black hookup wire

300V 22AWG, solid core

Alpha Wire 3051/1 BK005

Rig frame

1

Breadboard

Thorlabs MB3030/M

3

Post

Thorlabs TR300/M

3

Post holder

Thorlabs PH50/M

3

Adjustable mounting base

Thorlabs BA2T2/M

6

Component clamp

Thorlabs PMTR/M

6

V-groove base adapter

Thorlabs PCMV/M

1

USB camera

Logitech C270

1

USB stereo speaker

Adafruit 3369

12

16mm M6 cap screw

RS 281-114 (or part of HW-KIT2/M)

RS 281-114 is a pack of 50, but only 12 screws total are required

Photo-

diode

1

Post

Thorlabs TR300/M

1

Post

Thorlabs TR50/M

1

Right-angle clamp

Thorlabs RA90/M

1

Post holder

Thorlabs PH50E/M

1

Clamping fork

Thorlabs CF125

1

Photodiode

Thorlabs PDA100A-EC

1

Power supply

Thorlabs LDS1212

1

Coaxial cable

50 Ω, Male BNC to Male BNC, 1m

RS 284-3792

1

Coaxial socket with test leads

Female BNC

Pomona 4969

Tools

1

Scissors

1

Razor blade

1

Squeegee/straightedge

This is to remove bubbles during film application, and usually comes with the film

1

Roll of write-on lab tape

Cole Parmer WZ-06530-21

1

Spray bottle with ~10% soap solution

~9:1 water:soap. The solution should be lightly coloured

Any regular dish detergent (e.g., Dawn, Fairy)

Mix gently until the soap is dissolved but the solution is not frothy

1

Air Duster 200 mL

Office Depot, Staples, etc.

1

5mm hex key

Thorlabs BD-5M

Ensure this is long enough for the bores of the mouse holder

1

2mm flathead screwdriver

1

Wire stripper/cutter

1

Long-nose pliers

1

Adjustable wrench

1

Roll electrical tape

1

Roll PTFE thread seal tape

12mm wide x 0.075mm thick (or similar)

RS 512-238

1

Pack poster putty

Bostik 'blu tack', Elmer's 'poster tack', etc.

Page

\ No newline at end of file diff --git a/docs/html/Fig7_timeline.png b/docs/html/Fig7_timeline.png new file mode 100644 index 00000000..4f184685 Binary files /dev/null and b/docs/html/Fig7_timeline.png differ diff --git a/docs/html/using_parameters.html b/docs/html/Parameters.html similarity index 90% rename from docs/html/using_parameters.html rename to docs/html/Parameters.html index 44e94646..e31e4ebf 100644 --- a/docs/html/using_parameters.html +++ b/docs/html/Parameters.html @@ -6,7 +6,7 @@ Introduction

Introduction

This document contains information on how experiment parameters work in Rigbox. How to create them, edit them and save them.

NB: Not all uncommented lines will run without error, particularly when a specific hardware configuration is required. Always read the preceeding text before running each line.

Contents

Parameters

Parameters are structures that contain experiment and session specific variables that may be set via a GUI and stored for each session. Parameters are stored as structures saved MAT files and may also be saved as JSON. They typically end in '_parameters' and are saved when creating a new experiment using the dat.newExp function or Alyx/newExp method. You can generate and retrieve paths for experiment parameter files using the dat package:

expRef = dat.constructExpRef('fake', now, 1); % Example experiment reference
+  

Parameters

This document contains information on how experiment parameters work in Rigbox. How to create them, edit them and save them.

NB: Not all uncommented lines will run without error, particularly when a specific hardware configuration is required. Always read the preceeding text before running each line.

Contents

Loading parameters

Parameters are structures that contain experiment and session specific variables that may be set via a GUI and stored for each session. Parameters are stored as structures saved MAT files and may also be saved as JSON. They typically end in '_parameters' and are saved when creating a new experiment using the dat.newExp function or Alyx/newExp method. You can generate and retrieve paths for experiment parameter files using the dat package:

expRef = dat.constructExpRef('fake', now, 1); % Example experiment reference
 paramPath = dat.expFilePath(expRef, 'parameters') % Generate path for saving
 
 % Parameters can be loaded using an experiment reference via DAT.EXPPARAMS:
 paramStruct = dat.expParams(expRef); % Returns empty if params don't exist
 
 % More info on generating paths can be found in USING_DAT_PACKAGE:
-open(fullfile(getOr(dat.paths,'rigbox'), 'docs', 'using_dat_package.m'))
+root = getOr(dat.paths,'rigbox');
+open(fullfile(root, 'docs', 'scripts', 'using_dat_package.m'))
 

Parameter structures

In signals a set of parameters may be extracted using EXP.INFERPARAMETERS (see note 1).

defFunction should be either an experiment definition function handle, or if the function isn't on MATLAB's search path, a char of the full path to such a definition function.

defFunction = fullfile(getOr(dat.paths,'rigbox'), 'tests', ...
   'fixtures', 'expDefinitions', 'advancedChoiceWorld.m');
 paramStruct = exp.inferParameters(defFunction);
@@ -193,10 +194,8 @@
 % c.f. [~, ~, trialParams] = parameters.toConditionServer(false)
 % See section below for more details on randomizing.
 

The ParamEditor GUI

The easiest way to modify parameters is via the ParamEditor GUI, managed by the eui.ParamEditor class. A ParamEditor object is embedded into MC and can also be instantiated via the Experiment Panels.

To instantiate a standalone editor, call EUI.PARAMEDITOR with a Parameters object. Additionally a parent figure handle may be provided.

There are two panels that make up the editor. On the left are the global parameters and on the right is the trial conditions table, containing the conditional parameters.

PE = eui.ParamEditor(parameters)
-
- -

Global panel

The global panel is pretty simple. Each parameter is represented by the parameter name (formatted as a title, see above section) and an input field. When a field is modified the title turns red. For numrical and string parameters, vectors may be added by inputting values separated by commas. For instance typing '1, 3, 5' (without quotes) would set the value of that parameter to [1; 3; 5]. For numrical parameters spaces alone will suffice, e.g. '1 3 5'.

To make a parameter conditional, right-clicking on the input field or title and select 'Make conditional'. The parameter will now appear in the conditions table to the right.

Conditions panel

Here each parameter is represented as a table column, and its conditions (i.e. the columns of the parameter) as table rows. The rows may be re-ordered by dragging the field name of the column you with to move.

New blank conditions (i.e. rows) can be added by clicking the 'New condition' button at the bottom of the table.

Individual cells can be selected and edited as expected. To select multiple cells, hold down the ctrl key while clicking. To select multiple conditions in a row, hold the shift key. Once you've selected a cell in at least one column, the other buttons become available:

'Delete condition' allows you to delete the table rows of the selected cells (i.e. the selected trial conditions).

'Globalise parameter' makes the columns of the selected cells global parameters, whereby they are moved to the left panel. The value in the last selected cell for that parameter is used as the new parameter value. This may also be done via the context menu.

'Set values' allows you can set multiple cells are once. One clicked a small dialog appears with am input field for each selected column. The number of selected cells for each column is shown in brackets. Entering a single value will set each cell to that value. Entering a semicolon-separated list will assign each cell one value going from top to bottom. For example by selecting three cells in a column and typing '4; 5; 6' (without quotes) the top most cell will take the value '4' and so forth.

This is particularly useful for more involved stimulus sets with many conditions.

By right-clicking anywhere in the condition table you get two extra options:

'Sort by selected column' will sort the columns by whichever column the selected cell is in. Currently only sorting by one column is supported.

'Randomise conditions' is a checkbox that sets the underlying hidden parameter of the same name. By default this is checked. When unchecked, the rows of the table are given an index, indicating the set order trial conditions.

Once your parameters have been modified via the GUI they can be saved by extracting the underlying parameter stuct and saving to a file:

dat.saveParamProfile('custom', 'variant_2', PE.Parameters.Struct)
-

Advanced trial conditions

Let's look at some ways you can set trial condition parameters for different sorts of experiments. In the below examples imagine you have a signals experiment definition with three conditional parameters, A, B and C (see note 6).

By default all conditions are presented in a random order n times, where n is defined by the numRepeats parameter. If numRepeats is made a global parameter, then all conditions are presented the same number of times.

% Example 1: An illustration of how the trial order may turn out when
+

Global panel

The global panel is pretty simple. Each parameter is represented by the parameter name (formatted as a title, see above section) and an input field. When a field is modified the title turns red. For numrical and string parameters, vectors may be added by inputting values separated by commas. For instance typing '1, 3, 5' (without quotes) would set the value of that parameter to [1; 3; 5]. For numrical parameters spaces alone will suffice, e.g. '1 3 5'.

To make a parameter conditional, right-clicking on the input field or title and select 'Make conditional'. The parameter will now appear in the conditions table to the right.

Conditions panel

Here each parameter is represented as a table column, and its conditions (i.e. the columns of the parameter) as table rows. The rows may be re-ordered by dragging the field name of the column you with to move.

New blank conditions (i.e. rows) can be added by clicking the 'New condition' button at the bottom of the table.

Individual cells can be selected and edited as expected. To select multiple cells, hold down the ctrl key while clicking. To select multiple conditions in a row, hold the shift key. Once you've selected a cell in at least one column, the other buttons become available:

'Delete condition' allows you to delete the table rows of the selected cells (i.e. the selected trial conditions).

'Globalise parameter' makes the columns of the selected cells global parameters, whereby they are moved to the left panel. The value in the last selected cell for that parameter is used as the new parameter value. This may also be done via the context menu.

'Set values' allows you can set multiple cells are once. One clicked a small dialog appears with am input field for each selected column. The number of selected cells for each column is shown in brackets. Entering a single value will set each cell to that value. Entering a semicolon-separated list will assign each cell one value going from top to bottom. For example by selecting three cells in a column and typing '4; 5; 6' (without quotes) the top most cell will take the value '4' and so forth.

This is particularly useful for more involved stimulus sets with many conditions.

By right-clicking anywhere in the condition table you get two extra options:

'Sort by selected column' will sort the columns by whichever column the selected cell is in. Currently only sorting by one column is supported.

'Randomise conditions' is a checkbox that sets the underlying hidden parameter of the same name. By default this is checked. When unchecked, the rows of the table are given an index, indicating the set order trial conditions.

Once your parameters have been modified via the GUI they can be saved by extracting the underlying parameter stuct and saving to a file:

dat.saveParamProfile('custom', 'variant_2', PE.Parameters.Struct)
+

Advanced trial conditions

Let's look at some ways you can set trial condition parameters for different sorts of experiments. In the below examples imagine you have a signals experiment definition with three conditional parameters, A, B and C (see note 6).

By default all conditions are presented in a random order n times, where n is defined by the numRepeats parameter. If numRepeats is made a global parameter, then all conditions are presented the same number of times.

% Example 1: An illustration of how the trial order may turn out when
 % 'randomiseConditions' is false and 'numRepeats' is a conditional parameter:
 
 % +---+---+---+-------------+
@@ -269,7 +268,7 @@ 

Global panel

The global panel is pretty simple. Each paramet % 4 | 3 | 3 | 4 | % 5 | 3 | 3 | 4 | % +---+---+---+ -

Using Set values

For more involved stimulus sets, we can use Set Values to conveniently set the values of multiple cells at once. This is particularly useful for experiments with many conditions.

% Example 4: Say you want to present each condition twice in a row, and the
+

Using Set values

For more involved stimulus sets, we can use Set Values to conveniently set the values of multiple cells at once. This is particularly useful for experiments with many conditions.

% Example 4: Say you want to present each condition twice in a row, and the
 % entire set two times, e.g.
 %
 % #  | A | B | C |
@@ -320,7 +319,7 @@ 

Global panel

The global panel is pretty simple. Each paramet % 11 | 6 | 4 | 4 | % 12 | 6 | 1 | 4 | % +---+---+---+ -

Notes and warning suppressions

(1) To load default parameters for legacy experiments, there are simple functions that return these paramteters. NB: The below are no longer used as signals provides more flexbility in running experiments.

choiceParams = exp.choiceWorldParams; % For the original Burgess task
+

Notes and warning suppressions

(1) To load default parameters for legacy experiments, there are simple functions that return these paramteters. NB: The below are no longer used as signals provides more flexbility in running experiments.

choiceParams = exp.choiceWorldParams; % For the original Burgess task
 diskParams = exp.discWorldParams; % For a similar orientation-based protocol
 rangeParams = exp.rangeParams; % A Burgess task prototype experiment
 % Various visual field mapping experiment parameteres
@@ -404,14 +403,12 @@ 

Global panel

The global panel is pretty simple. Each paramet % Author: Miles Wells % -% v1.0.0 +% v1.1.1 -% INTERNAL: -% ln209 ParamEditor.png %#ok<*NOPTS,*ASGLU,*NASGU>

Introduction

Introduction

Timeline manages the acquisition and generation of experimental timing data using a NI-DAQ. The main timing signal, 'chrono', is a digital square wave that flips each time a new chunk of data is available from the DAQ. A callback function to this flip event collects the DAQ timestamp of the scan where each flip occured. The difference between this timestamp and the system time recorded when the flip command was given is recorded as the offset time and can be used to unify all timestamps across computers during an experiment. Thus, all event timestamps across all computers for a given experiment are recorded in times relative to the DAQ's clock. These timestamps can be interchanged with MATLAB and system times during an experiment. Timeline can acquire any number of hardware events and record their values with respect to this offset; for example, Timeline can use a photodiode to record the times at which the screen updates.

- -

NB: Not all uncommented lines will run without error, particularly when a specific hardware configuration is required. Always read the preceeding text before running each line.








Contents

Using Timeline

For more details on setting up Timeline, see hardware_config:

opentoline(fullfile(getOr(dat.paths,'rigbox'), ...
+  

Timeline

Timeline manages the acquisition and generation of experimental timing data using a NI-DAQ. The main timing signal, 'chrono', is a digital square wave that flips each time a new chunk of data is available from the DAQ. A callback function to this flip event collects the DAQ timestamp of the scan where each flip occured. The difference between this timestamp and the system time recorded when the flip command was given is recorded as the offset time and can be used to unify all timestamps across computers during an experiment. Thus, all event timestamps across all computers for a given experiment are recorded in times relative to the DAQ's clock. These timestamps can be interchanged with MATLAB and system times during an experiment. Timeline can acquire any number of hardware events and record their values with respect to this offset; for example, Timeline can use a photodiode to record the times at which the screen updates.

NB: Not all uncommented lines will run without error, particularly when a specific hardware configuration is required. Always read the preceeding text before running each line.

Contents

Using Timeline

For more details on setting up Timeline, see hardware_config:

opentoline(fullfile(getOr(dat.paths,'rigbox'), ...
   'docs', 'setup', 'hardware_config.m'), 58)
-
-% NB: Not all uncommented lines will run without error, particularly when a
-% specific hardware configuration is required.  Always read the preceeding
-% text before running each line.
-
-% Let's set up a timeline object:
+

NB : Not all uncommented lines will run without error, particularly when a specific hardware configuration is required. Always read the preceeding text before running each line.

% Let's set up a timeline object:
 timeline = hw.Timeline;
-
-% To set up a new timeline object using setting from a previous experiment,
-% call the constructor with the variable saved in *_Timeline.mat for that
-% experiment:
-%   ref = dat.constructExpRef('example', now - 10, 2); % Example experiment
-%   hwPath = dat.expFilePath(ref, 'timeline', 'master');
-%   timeline = hw.Timeline(loadVar(hwPath, 'hw')); % Load and instantiate
-
-% A JSON file is also saved after each experiment, currently with the name
-% TimelineHW.json:
-%   hwPath = fullfile(dat.expPath(ref,'main','master'), 'TimelineHW.json');
-%   timeline = hw.Timeline(jsondecode(fileread(hwPath)));
-

Inputs

The Inputs property contains a structure for configuring which channels to aquire data from.

timeline.Inputs
-
-% You can add a channel by adding directly to the Inputs property or by
-% using ADDINPUT:
-name = 'rotary encoder'; % Name of the device or signal you're acquiring
+

Using settings from a previous experiment

To set up a new timeline object using setting from a previous experiment, call the constructor with the variable saved in *_Timeline.mat for that experiment:

ref = dat.constructExpRef('example', now - 10, 2); % Example experiment
+hwPath = dat.expFilePath(ref, 'timeline', 'master'); % Path to timeline MAT
+timeline = hw.Timeline(loadVar(hwPath, 'hw')); % Load and instantiate
+

A JSON file is also saved after each experiment, currently with the name TimelineHW.json:

hwPath = fullfile(dat.expPath(ref,'main','master'), 'TimelineHW.json');
+timeline = hw.Timeline(jsondecode(fileread(hwPath))); % Load from JSON copy
+

Inputs

The Inputs property contains a structure for configuring which channels to aquire data from.

timeline.Inputs
+
ans =
+
   struct with fields:
               name: 'chrono'
+        arrayColumn: -1
+       daqChannelID: 'ai0'
+        measurement: 'Voltage'
+     terminalConfig: 'SingleEnded'
+          axesScale: 1

You can add a channel by adding directly to the Inputs property or by using addInput:

name = 'rotary encoder'; % Name of the device or signal you're acquiring
 channel = 'ctr0'; % The channel the device is connected to
 measurement = 'Position'; % The measurement type, i.e. 'volts', 'pos', 'edge'
 timeline.addInput(name, channel, measurement)
-
-% Once an input is added you can view the wiring information with
-% WIRINGINFO:
-timeline.wiringInfo(name)
-
-% Extra parameters include terminal configuration (Differential or
-% SingleEnded, otherwise the channel default is used), axes scale, and a
-% flag indicating whether to use the input (true by default):
-timeline.addInput('lick detecter', 'ctr1', 'EdgeCount', [], 2, false)
-
-% The axes scale (set to 2 above) sets the plot scale when the Timeline
-% property LivePlot is set to true.
-timeline.LivePlot = 'on'; % Plot input data during acquisition
-
-% The UseInputs property contains a cellstring of the input names to be
-% acquired.  This allows one to set up mutiple inputs that aren't
-% necessarily acquired every experiment.
-timeline.UseInputs % 'lick detecter' missing as we set the use arg to false
+

Timeline input 'rotary encoder' successfully added.

Extra parameters include terminal configuration (Differential or SingleEnded, otherwise the channel default is used), axes scale, and a flag indicating whether to use the input (true by default):

timeline.addInput('lick detecter', 'ctr1', 'EdgeCount', [], 2, false)
+

The axes scale (set to 2 above) sets the vertical plot scale when the Timeline property LivePlot is set to true (more on this later).

Activating Inputs

The 'UseInputs' property contains a cellstring of the input names to be acquired. This allows one to set up mutiple inputs that aren't necessarily acquired every experiment. The 'use' flag of addInput can set whether an input is added to UseInputs upon adding. The default is true.

timeline.UseInputs % 'lick detecter' missing as we set the use arg to false above
 % To activate an input again simply add it to UseInputs again:
 timeline.UseInputs{end+1} = 'lick detecter';
-
-% Note that the order of channels in the UseInputs array determines the
-% order in which the channels are added to the DAQ session and thus the
-% order in which they are scanned during acquisition (see next section).
-

Dealing with ghosting

Multiplexing NI DAQ boards (as opposed simultaneously sampling boards) can be susceptible to 'ghosting', whereby weak differential channels (those with a small current source) are corrupted by neighbouring channels. A solution to this is to isolate the channel of interest by adding one dummy channel either side of it. This is a page on NI website explaining how to avoid ghosting: https://knowledge.ni.com/KnowledgeArticleDetails?id=kA00Z0000019KzzSAE

For instance consider that we want to acquire the p.d. of a passive piezo:

timeline.addInput('piezoLickDetector', 'ai5', 'Volts', 'Differential',1,0)
+

Note that the order of channels in the UseInputs array determines the order in which the channels are added to the DAQ session and thus the order in which they are scanned during acquisition (see next section).

Dealing with ghosting

Multiplexing NI DAQ boards (as opposed simultaneously sampling boards) can be susceptible to 'ghosting', whereby weak differential channels (those with a small current source) are corrupted by neighbouring channels. A solution to this is to isolate the channel of interest by adding one dummy channel either side of it. This is a page on NI website explaining how to avoid ghosting: https://knowledge.ni.com/KnowledgeArticleDetails?id=kA00Z0000019KzzSAE

For instance consider that we want to acquire the p.d. of a passive piezo:

timeline.addInput('piezoLickDetector', 'ai5', 'Volts', 'Differential',1,0)
 % Now we can isolate this channel to prevent bleed-through by adding a
 % couple of 'dummy' channels that are scanned before and after our channel:
 timeline.addInput('dummy1', 'ai4', 'Volts',[],1,0)
@@ -130,13 +99,12 @@
 % Add them to UseInputs in the following order:
 use = [timeline.UseInputs {'dummy1', 'piezoLickDetector', 'dummy2'}]
 timeline.UseInputs = use;
-
-% NB: Channel names beginning with the word 'dummy' are not extracted as
-% ALF files.  For more info see alyx-matlab:
-open(fullfile(getOr(dat.paths,'rigbox'), ...
+

NB : Channel names beginning with the word 'dummy' are not extracted as ALF files . For more info see alyx-matlab:

open(fullfile(getOr(dat.paths,'rigbox'), ...
   'alyx-matlab', 'docs', 'AlyxMatlabPrimer.m'))
 web('https://github.com/cortex-lab/ALF')
-

Outputs

Timeline outputs are for setting up pulses for triggering external hadware acquisition devices. The main output class for timeline is HW.TLOUTPUT

doc hw.TLOutput
+

Wiring information

Once an input is added you can view the wiring information with the wiringInfo method:

name = 'rotary encoder';
+timeline.wiringInfo(name)
+

Connect rotary encoder to terminal ctr0 of the DAQ

Outputs

Timeline outputs are for setting up pulses for triggering external hadware acquisition devices. The main output class for timeline is hw.TLOutput

doc hw.TLOutput
 
 % An array of configured outputs are stored in the Outputs property of
 % timeline:
@@ -156,7 +124,7 @@
 % The Verbose switch when 'on' will print extra information to the command
 % window during the experiment:
 timeline.Outputs(1).Verbose = true;
-

Acquire Live

% Let's add another output:
+

Acquire Live

% Let's add another output:
 timeline.Outputs(2) = hw.TLOutputAcqLive;
 
 % The Acquire Live output by default outputs HIGH for the entire time an
@@ -180,7 +148,7 @@
 %   _                         _
 % _| |__________...__________| |_
 % ^ start()                  ^ stop()
-

Output Clock

timeline.Outputs(end+1) = hw.TLOutputClock;
+

Output Clock

timeline.Outputs(end+1) = hw.TLOutputClock;
 
 % The output clock object will produce a regular pulse troughout the
 % experiment, useful for triggaring frame acquisitions of a camera:
@@ -203,12 +171,13 @@
 % For custom output signals that are not configurable with the current
 % TLOutput classes, simply create a new subclass with your desired
 % implementation.
-

Acquisitions

Timeline may be run automatically on the stimulus computer, or on a separate computer that's triggred by the stimulus computer via UDPs (for more info see using_services:

open(fullfile(getOr(dat.paths,'rigbox'), 'docs', 'using_services.m'))
+

Acquisitions

Timeline may be run automatically on the stimulus computer, or on a separate computer that's triggred by the stimulus computer via UDPs (for more info see using_services):

% Open the 'Using Services' script
+open(fullfile(getOr(dat.paths,'rigbox'), 'docs', 'using_services.m'))
 
 % You can also start Timeline manually from the command prompt with
 % HW.TIMELINE/START.  An experiment reference string is required:
 ref = dat.newExp('default'); % Create an experiment for subject 'default'
-timeline.start(ref) % Start acquisition
+timeline.start(ref, Alyx('','')) % Start acquisition
 timeline.IsRunning % true
 
 % In order to register Timeline file to the alyx database, an alyx object
@@ -241,7 +210,11 @@
 % binary files during acquisition.  This ensures that data aren't lost in
 % the even of MATLAB crashes.
 timeline.WriteBufferToDisk = true; % Save data as they're collected
-

Clocks

doc hw.Clock
+

Live plotting

During acquisition you can plot the inputs live by setting the 'LivePlot' property to true / 'on'. The default plot figure position(1) can be set using the 'FigureScale' property. The values are in normalized units and is set as fullscreen by default. NB: This must be set before calling start.

timeline.LivePlot = 'on'; % Plot input data during acquisition
+timeline.FigureScale = [0 0 0.5 1]; % Take up half screen width and full height
+

The axes scale for individual inputs can be set be changing the 'axesScale' of the Inputs struct. This field controls the vertical scaling of each trace (multiplicative) and can be set when adding an input with the addInput method (see Inputs section). Below we change it manually:

I = strcmp('rotary encoder', {timeline.Inputs.name})
+timeline.Inputs(I).axesScale = 2; % 2x vertical scaling
+

Clocks

doc hw.Clock
 
 % While timeline is running, timestampts can be returned using the TIME
 % method:
@@ -269,10 +242,15 @@
 % reference time:
 clock.zero()
 clock.now()
-

Etc.

Author: Miles Wells

v1.0.0

%#ok<*NOPTS>
-
\ No newline at end of file diff --git a/docs/html/glossary.html b/docs/html/glossary.html new file mode 100644 index 00000000..70fdf16e --- /dev/null +++ b/docs/html/glossary.html @@ -0,0 +1,164 @@ + + + + + Glossary

Glossary

Below is a list of terms and their meaning, along with some links for finding out more information.

Contents

Block file

The 'block' file is a MAT file that contains most of the data acquired during an experiment. It is saved by the Experiment class upon experiment quit and follows the following file name pattern: yyyy-mm-dd_n_subject_Block.mat.

See also dat.paths, loading_experiment_data

Experiment Definition (expDef)

The experiment definition function (expDef) is a user-created function that the Signals Experiment class uses to map the hardware inputs to the outputs. The function has the following signature:

function exampleWorld(t, evts, p, vs, in, out, audio)
+    [...]
+end
+

See also SignalsPrimer2?

Experiment Framework

The 'Experiment Framework' is everything defined by the exp.Experiment base class. This class defines some basic methods (e.g. run, quit, saveDave, useRig) and 'experiment phases' (experimentInit, experimentStarted, experimentEnded) within which stuff happens and updates are broadcast to any listener such as MC. An Experiment object stores and uses various objects throughout the experiment, for instance an exp.ConditionServer object that manages the trial parameter conditions and an io.Communicator that manages the sending of updates to remote listeners. All experiments run in Rigbox (i.e. via mc and/or srv.expServer) use this framework.

exp.SignalsExp extends this framework to use Signals for implementing a user defined experiment function (expDef). NB: Signals can be set up and used outside of this framework. For an example of this, see signals/docs/example/ringach98.m

For more info, see the Experiment package:

helpwin +exp
+

Experiment Reference String (expRef)

An 'experiment reference string' or 'expRef' (sometimes just 'ref') is a char array of the form yyyy_mm_dd_n_subject. These are unique, human-readable references to an experiment session. Whenever an experiment is started in mc, a new expRef is created, reflecting the folder structure of the main repository, where the parameter set is saved.

See The Data Package

expServer

srv.expServer is the function that loads rig hardware and allows users to run experiments either locally or via MC.

Main Repository

The 'main experiment repository' or 'main repo' is the primary location where your experiment data is saved. It is the 'mainRepository' field returned by dat.paths (defined in your +dat/paths.m file). When new experiments are created, a parameter set is saved into this location according to the following directory structure: subject/date/number. srv.expServer looks in this location when loading parameters for a given experiment, and saves the main data files here.

See also dat_package, dat.expExists

Master Computer (MC)

The computer that controls the starting and stopping of experiments. This computer runs the mc function, which creates a GUI for doing this.

mc

mc is the function used for logging, parameterizing and creating new experiments.

Stimulus Computer (SC)

The 'stimulus computer', 'stim server' or 'SC' is the computer that runs srv.expServer and produces visual and auditory stimuli. All hardware devices used during an experiment are configured for this computer.

Etc.

Home

Author: Miles Wells

v1.0.0

\ No newline at end of file diff --git a/docs/html/hardware_config.html b/docs/html/hardware_config.html index 0f8575d8..4783675a 100644 --- a/docs/html/hardware_config.html +++ b/docs/html/hardware_config.html @@ -6,7 +6,7 @@ hardware_config

Contents

Configuring hardware devices

When running SRV.EXPSERVER the hardware settings are loaded from a MAT file and initialized before an experiment. The MC computer may also have a hardware file, though this isn't essential. The below script is a guide for setting up a new hardware file, with examples mostly pertaining to replicating the Burgess steering wheel task(1). Not all uncommented lines will run without error, particularly when a specific hardware configuration is required. Always read the preceeding text before running each line.

It is recommended that you copy this file and keep it as a way of versioning your hardware configurations. In this way the script can easily be re-run when after any unintended changes are made to your hardware file. If you do this, make sure you save a copy of the calibration strutures or re-run the calibrations.

Note that the variable names saved to the hardware file must be the same as those below in order for various Rigbox functions to recognize them, namely these variables:

  • stimWindow - The hw.Window object for PsychToolbox parameters
  • stimViewingModel - A viewing model used by legacy experiments
  • mouseInput - The rotary encoder device
  • lickDetector - A lick detector device
  • timeline - The Timeline object
  • daqController - NI DAQ output settings for use during an experiment
  • scale - A weighing scale device for use by the MC computer
  • screens - Parameters for the Signals viewing model
  • audioDevices - Struct of parameters for each audio device
% Many of these classes for are found in the HW package:
-doc hw
-

Retrieving hardware file path

The location of the configuration file is set in DAT.PATHS. If running this on the stimulus computer you can use the following syntax:

hardware = fullfile(getOr(dat.paths, 'rigConfig'), 'hardware.mat');
+  

Introduction

When running srv.expServer the hardware settings are loaded from a MAT file and initialized before an experiment. The MC computer may also have a hardware file, though this isn't essential. The below script is a guide for setting up a new hardware file, with examples mostly pertaining to replicating the Burgess steering wheel task(1). Not all uncommented lines will run without error, particularly when a specific hardware configuration is required. Always read the preceeding text before running each line.

It is recommended that you copy this file and keep it as a way of versioning your hardware configurations. In this way the script can easily be re-run when after any unintended changes are made to your hardware file. If you do this, make sure you save a copy of the calibration strutures or re-run the calibrations.

Note that the variable names saved to the hardware file must be the same as those below in order for various Rigbox functions to recognize them, namely these variables:

  • stimWindow - The hw.Window object for PsychToolbox parameters
  • stimViewingModel - A viewing model used by legacy experiments
  • mouseInput - The rotary encoder device
  • lickDetector - A lick detector device
  • timeline - The Timeline object
  • daqController - NI DAQ output settings for use during an experiment
  • scale - A weighing scale device for use by the MC computer
  • screens - Parameters for the Signals viewing model
  • audioDevices - Struct of parameters for each audio device

NB: Not all uncommented lines will run without error, particularly when a specific hardware configuration is required. Always read the preceeding text before running each line.

Contents

The +hw packages

Many of these classes for are found in the HW package. This package contains all of the code that interfaces with lower-level hardware code (e.g. PsychToolbox's OpenGL functions, the NI +daq package):

doc hw
+

Retrieving hardware file path

The location of the configuration file is set in DAT.PATHS. If running this on the stimulus computer you can use the following syntax:

hardware = fullfile(getOr(dat.paths, 'rigConfig'), 'hardware.mat');
 
 % For more info on setting the paths and using the DAT package:
 rigbox = getOr(dat.paths, 'rigbox'); % Location of Rigbox code
-open(fullfile(rigbox, 'docs', 'setup', 'paths_config.m'))
-open(fullfile(rigbox, 'docs', 'using_dat_package.m'))
-

Configuring the stimulus window

The +hw Window class is the main class for configuring the visual stimulus window. It contains the attributes and methods for interacting with the lower level functions that interact with the graphics drivers. Currently the only concrete implementation is support for the Psychophysics Toolbox, the HW.PTB.WINDOW class.

doc hw.ptb.Window
+open(fullfile(rigbox, 'docs', 'scripts', 'paths_config.m'))
+open(fullfile(rigbox, 'docs', 'scripts', 'using_dat_package.m'))
+

Configuring the stimulus window

The +hw Window class is the main class for configuring the visual stimulus window. It contains the attributes and methods for interacting with the lower level functions that interact with the graphics drivers. Currently the only concrete implementation is support for the Psychophysics Toolbox, the hw.ptb.Window class.

doc hw.ptb.Window
 stimWindow = hw.ptb.Window;
 
 % Most of the properties directly mirror PsychToolbox parameters, therefore
@@ -133,21 +132,21 @@
 stimWindow.PtbVerbosity = 2;
 

ColourRange, White, Black, etc.

These properties are set by the object iteself after running OPEN, based on the colour depth of the screen. For more info see these docs:

help WhiteIndex
 help BlackIndex
-

- Performing gamma calibration from command window

Calibration

This stores the gamma correction tables (See Below) The simplist way to to run the calibration is through SRV.EXPSEERVER once the rest of the hardware is configures, however it can also be done via the command window, assuming you have an NI DAQ installed:

lightIn = 'ai0'; % The input channel of the photodiode used to measure screen
+

Calibration (performing gamma calibration from command window)

This stores the gamma correction tables (See Below) The simplist way to to run the calibration is through srv.expServer once the rest of the hardware is configured, however it can also be done via the command window, assuming you have an NI DAQ installed:

lightIn = 'ai0'; % The input channel of the photodiode used to measure screen
 clockIn = 'ai1'; % The clocking pulse input channel
 clockOut = 'port1/line0 (PFI4)'; % The clocking pulse output channel
 % Connect the photodiode to `lightIn` and user a jumper to bridge a
 % connection between `clockIn` and `clockOut`.
 
 % Make sure the photodiode is placed against the screen before running
-stimWindow.Calibration = stimWindow.calibration(DaqDev); % calibration
-
+stimWindow.Calibration = ...
+  stimWindow.calibration(DaqDev, lightIn, clockIn, clockOut);
 
 save(hardware, 'stimWindow', '-append') % Save the stimWindow to file
-

Using the Window object

Let's check the Window object is set up correctly and explore some of the methods...

- Setting the background colour

stimWindow.open() % Open the window
+

Using the Window object

Let's check the Window object is set up correctly and explore some of the methods...

- Setting the background colour

stimWindow.open() % Open the window
 stimWindow.BackgroundColour = stimWindow.Green; % Change the background
 stimWindow.flip(); % Whoa!
-

- Displaying a Gabor patch

Make a texture and draw it to the screen with MAKETEXTURE and DRAWTEXTURE Let's make a Gabor patch as an example:

sz = 1000; % size of texture matrix
+

- Displaying a Gabor patch

Make a texture and draw it to the screen with makeTexture and drawTexture Let's make a Gabor patch as an example:

sz = 1000; % size of texture matrix
 [xx, yy] = deal(linspace(-sz/2,sz/2,sz)');
 phi = 2*pi*rand; % randomised cosine phase
 sigma = 100; % size of Gaussian window
@@ -166,9 +165,9 @@
 stimWindow.drawTexture(tex)
 % Flip the buffer:
 stimWindow.flip;
-

- Clearing the window

To clear the window, the use CLEAR method:

stimWindow.clear % Re-draw background colour
+

- Clearing the window

To clear the window, the use the clear method:

stimWindow.clear % Re-draw background colour
 stimWindow.flip; % Flip to screen
-

- Drawing text to the screen

Drawing text to the screen can be done with the DRAWTEXT method:

[x, y] = deal('center'); % Render the text to the center
+

- Drawing text to the screen

Drawing text to the screen can be done with the drawText method:

[x, y] = deal('center'); % Render the text to the center
 [nx, ny] = stimWindow.drawText('Hello World', x, y, stimWindow.Red);
 stimWindow.flip;
 
@@ -176,9 +175,9 @@
 [nx, ny] = stimWindow.drawText('Hello World', x, y, stimWindow.Red);
 stimWindow.drawText('! What''s up?', nx, ny, stimWindow.Red);
 stimWindow.flip;
-

- Closing a window

Finally lets clear and close the window:

stimWindow.clear
+

- Closing a window

Finally lets clear and close the window:

stimWindow.clear
 stimWindow.close
-

Viewing models

The viewing model classes allow one to configure the relationship between physical dimentions and pixel space. The viewing model classes contain methods for converting between visual degrees, pixels and physical dimentions. Note: The viewing model classes are currently only implemented in legacy experiments such as ChoiceWorld. See below section for configuring the viewing model in Signals.

There are currently two viewing model classes to choose from...

- Basic screen viewing model

The basic viewing model class deals with single screens positioned straight in front of an observer (^):| ___ | ^

doc hw.BasicScreenViewingModel
+

Viewing models

The viewing model classes allow one to configure the relationship between physical dimentions and pixel space. The viewing model classes contain methods for converting between visual degrees, pixels and physical dimentions. Note: The viewing model classes are currently only implemented in legacy experiments such as ChoiceWorld. See below section for configuring the viewing model in Signals.

There are currently two viewing model classes to choose from...

Basic screen viewing model

The basic viewing model class deals with single screens positioned straight in front of an observer (^):| ___ | ^

doc hw.BasicScreenViewingModel
 
 % Let's set this up:
 stimViewingModel = hw.BasicScreenViewingModel;
@@ -200,7 +199,7 @@
 stimViewingModel.ScreenWidthMetres = 0.4750;
 
 save(hardware, 'stimViewingModel', '-append')
-

-- Using the model

The object contains useful methods for converting between visual and graphics space:

% Visual field coordinates of a specified pixel.  The presumed
+

Using the model

The object contains useful methods for converting between visual and graphics space:

% Visual field coordinates of a specified pixel.  The presumed
 % 'straight-ahead' view pixel should map to the centre of the visual field
 % (zero polar and visual angles)
 x = 0; y = 100; % Convert this pixel coordinate to visual angle
@@ -229,10 +228,10 @@
 % d(t) = zPx*tan(t)
 % Derivative w.r.t. t yields pixel density at a given visual angle:
 % d'(t) = zPx*sec(t)^2
-

- Pseudo-Circular screen viewing model

doc hw.PseudoCircularScreenViewingModel
+

Pseudo-Circular screen viewing model

doc hw.PseudoCircularScreenViewingModel
 
 stimViewingModel = hw.PseudoCircularScreenViewingModel
-

- Signals viewing model

Signals currently only supports a single viewing odel. For now the function VIS.SCREEN is used to configure this. Below is an example of configuring the viewing model for the Burgess wheel task, where there are three small screens located at right-angles to one another:

help vis.screen
+

Signals viewing model

Signals currently only supports a single viewing odel. For now the function VIS.SCREEN is used to configure this. Below is an example of configuring the viewing model for the Burgess wheel task, where there are three small screens located at right-angles to one another:

help vis.screen
 % Below is a schematic of the screen configuration (top-down view).
 % ^ represents the observer:
 %   _____
@@ -257,7 +256,7 @@
 screens(3) = vis.screen(centerPt(3,:), angle(3), screenDimsCm, [2*pxW  0 3*pxW pxH]); % right screen
 
 save(hardware, 'screens', '-append');
-

Hardware inputs

In this example we will add two inputs, a DAQ rotatary encoder and a beam lick detector.

- DAQ rotary encoder

Create a input for the Burgess LEGO wheel using the HW.DAQROTARYENCODER class:

doc hw.DaqRotaryEncoder % More details for this class
+

Hardware inputs

In this example we will add two inputs, a DAQ rotatary encoder and a beam lick detector.

DAQ rotary encoder

Create a input for the Burgess LEGO wheel using the HW.DAQROTARYENCODER class:

doc hw.DaqRotaryEncoder % More details for this class
 mouseInput = hw.DaqRotaryEncoder;
 
 % To deteremine what devices you have installed and their IDs:
@@ -280,7 +279,7 @@
 mouseInput.EncoderResolution = 1024
 % Diameter of the wheel in mm
 mouseInput.WheelDiameter = 62
-

- Lick detector

A beam lick detector may be configured to work with an edge counter channel. We can use the HW.DAQEDGECOUNTER class for this:

lickDetector = hw.DaqEdgeCounter;
+

Lick detector

A beam lick detector may be configured to work with an edge counter channel. We can use the HW.DAQEDGECOUNTER class for this:

lickDetector = hw.DaqEdgeCounter;
 
 % This is actually a subclass of the HW.DAQROTARYENCODER class, and
 % therefore has a few irrelevant properties such as WheelDiameter.  These
@@ -294,7 +293,7 @@
 
 % Save these two into our hardware file
 save(hardware, 'stimWindow', 'lickDetector', '-append')
-

Hardware outputs

HW.DAQCONTROLLER

doc hw.DaqController
+

Hardware outputs

HW.DAQCONTROLLER

doc hw.DaqController
 daqController = hw.DaqController;
 
 % This class deals with creating DAQ sessions, assigning output
@@ -324,7 +323,7 @@
 
 % Save your hardware file
 save(hardware, 'daqController', '-append');
-

Timeline

Timeline unifies various hardware and software times using a DAQ device.

doc hw.Timeline
+

Timeline

Timeline unifies various hardware and software times using a DAQ device. There is a separate guide for Timeline here.

doc hw.Timeline
 
 % Let's create a new object and configure some channels
 timeline = hw.Timeline
@@ -345,18 +344,12 @@
 % They may be changed by setting the above fields, e.g.
 timeline.Outputs(1).DaqChannelID = 'port1/line1';
 timeline.wiringInfo('chrono'); % New port # displayed
-
-% INPUTS
-% Add the rotary encoder
-timeline.addInput('rotaryEncoder', 'ctr0', 'Position');
+

Inputs

Add the rotary encoder

timeline.addInput('rotaryEncoder', 'ctr0', 'Position');
 % For a lick detector
 timeline.addInput('lickDetector', 'ctr1', 'EdgeCount');
 % For a photodiode (see 'Configuring the visual stimuli' above)
 timeline.addInput('photoDiode', 'ai2', 'Voltage', 'SingleEnded');
-
-% OUTPUTS
-% Say we wanted to trigger camera aquisition at a given frame rate:
-clockOut = hw.TLOutputClock;
+

Outputs

Say we wanted to trigger camera aquisition at a given frame rate:

clockOut = hw.TLOutputClock;
 clockOut.DaqChannelID = 'ctr2'; % Set channal
 clockOut.Name = 'Cam-Trigger'; % A memorable name
 clockOut.Frequency = 180; % Hz
@@ -367,9 +360,9 @@
 save(hardware, 'timeline', '-append')
 
 % For more information on configuring and using Timeline, see
-% USING_TIMELINE:
-open(fullfile(getOr(dat.paths,'rigbox'), 'docs', 'using_timeline.m'))
-

Weigh scale

MC allows you to log weights through the GUI by interfacing with a digital scale connected via a COM port. This is the only object of use in the MC computer's hardware file.

scale = hw.WeighingScale
+% TIMELINE:
+open(fullfile(getOr(dat.paths,'rigbox'), 'docs', 'scripts', 'Timeline.m'))
+

Weigh scale

MC allows you to log weights through the GUI by interfacing with a digital scale connected via a COM port. This is the only object of use in the MC computer's hardware file.

scale = hw.WeighingScale
 
 % The Name field should be set to the name or product code of the scale you
 % connect.
@@ -379,7 +372,8 @@
 % Device Manager (Win + X, then M).  Under Universal Serial Bus, you can
 % see all current USB and serial ports.  If you right-click and select
 % 'Properties' you can view the port number and even reassign them (under
-% Advanced)
+% Advanced).  You can also list all available ports by running |seriallist|
+% (|serialportlistt("available")| for >2019b).
 scaleComPort = 'COM4'; % Set to a different port
 % The TareCommand and FormatSpec fields should be set based on your scale's
 % input and output configurations.  Check the manual.
@@ -391,7 +385,7 @@
 
 %Save your hardware.mat file
 save(hardware, 'scale', '-append')
-

- Using the scale

The methods are rather self-explanatory. To use the scale the port must first be opened using the INIT method:

scale.init()
+

Using the scale

The methods are rather self-explanatory. To use the scale the port must first be opened using the INIT method:

scale.init()
 
 % To tare (zero) the scale, use the TARE method:
 scale.tare()
@@ -406,8 +400,9 @@
 
 % To clean up you can simply clear the object from the workspace:
 clear scale lh
-

Audio devices

InitializePsychSound
+

Audio devices

On MS-Windows you'll have the choice between up to 5 different audio subsystems: WASAPI (on Windows-Vista and later), or WDMKS (on Windows-2000/XP) should provide ok latency. DirectSound is the next worst choice if you have hardware with DirectSound support. If everything else fails, you'll be left with MME, a completely unusable API for precise or low latency timing.

InitializePsychSound
 devs = PsychPortAudio('GetDevices')
+
 % Sanitize the names
 names = matlab.lang.makeValidName({devs.DeviceName}, 'ReplacementStyle', 'delete');
 names = iff(ismember('default', names), names, @()[{'default'} names(2:end)]);
@@ -415,7 +410,11 @@
 audioDevices = devs;
 
 save(hardware, 'audioDevices', '-append')
-

Loading your hardware file

To load your rig hardware objects for testing at a rig, you can use HW.DEVICES:

rig = hw.devices;
+
+% @TODO Substantiate
+% @body Info on PTB support, mention the helper for testing devices,
+% mention how audio device naming works
+

Loading your hardware file

To load your rig hardware objects for testing at a rig, you can use hw.devices:

rig = hw.devices;
 
 % To load the hardware file or a different rig, you can input the rig name.
 % Note HW.DEVICES initializes some of the hardware by default, including
@@ -424,7 +423,7 @@
 rigName = 'ZREDONE';
 initialize = false;
 rig = hw.devices(rigName, initialize);
-

FAQ

I tried loading an old hardware file but the variables are not objects.

This was probably accompanied with an error such as: * % Warning: Variable 'rewardController' originally saved as a hw.DaqRewardValve cannot be instantiated as an object and will be read in as a uint32. *

% This usually means that there has been a substantial change in the code
+

FAQ

I tried loading an old hardware file but the variables are not objects.

This was probably accompanied with an error such as: * % Warning: Variable 'rewardController' originally saved as a hw.DaqRewardValve cannot be instantiated as an object and will be read in as a uint32. *

% This usually means that there has been a substantial change in the code
 % since the object was last saved and MATLAB can no longer load it into the
 % workspace.  One solution is to revert your code to a release dated around
 % the time of the hardware file's modified date:
@@ -433,10 +432,10 @@
 
 % Once you have the previous parameters, create a new object with the
 % current code version, assign the parameters and resave.
-

I'm missing the time of the first flip only, why?

Perhaps the first flip is always too dark a colour. Try reversing the order stimWindow.SyncColourCycle:

scc = stimWindow.SyncColourCycle;
+

I'm missing the time of the first flip only, why?

Perhaps the first flip is always too dark a colour. Try reversing the order stimWindow.SyncColourCycle:

scc = stimWindow.SyncColourCycle;
 scc = iff(size(scc,1) > size(scc,2), @() flipud(scc), @() fliplr(scc));
 stimWindow.SyncColourCycle = scc;
-

The PsychToolbox window covers the wrong monitors when I run the experiment server

Make sure Mosaic is still running (sometimes if the computer loses a monitor input the graphics card disables Mosaic). One indication of this is that the task bar should stretch across all three of the stimulus screens. Also check that the stimWindow.ScreenNum is correct in the hardware.mat file. When set to 0, PsychToolbox uses all screens available to Windows; 1 means Windows’ primary screen (see the Display Settings); 2 means Windows’ secondary screen, etc.

I get a ‘PTB synchronization error’ when I run the experiment server.

This happens from time-to-time. When a PsychToolbox window is opened it runs some synchronization to retrace tests, checking whether buffer flips are properly synchronized to the vertical retrace signal of your display. Synchronization failiures indicate that there tareing or flickering may occur during stimulus presentation. More info on this may be found here :

web('http://psychtoolbox.org/docs/SyncTrouble')
+

The PsychToolbox window covers the wrong monitors when I run the experiment server

Make sure Mosaic is still running (sometimes if the computer loses a monitor input the graphics card disables Mosaic). One indication of this is that the task bar should stretch across all three of the stimulus screens. Also check that the stimWindow.ScreenNum is correct in the hardware.mat file. When set to 0, PsychToolbox uses all screens available to Windows; 1 means Windows' primary screen (see the Display Settings); 2 means Windows' secondary screen, etc.

I get a ‘PTB synchronization error’ when I run the experiment server.

This happens from time-to-time. When a PsychToolbox window is opened it runs some synchronization to retrace tests, checking whether buffer flips are properly synchronized to the vertical retrace signal of your display. Synchronization failiures indicate that there tareing or flickering may occur during stimulus presentation. More info on this may be found here :

web('http://psychtoolbox.org/docs/SyncTrouble')
 % The problem may be exacerbated if you're running other programs that
 % interfere with the graphics, such as remote window viewers (VNC, Remote
 % Desktpo, etc.), or if you are running multiple monitors that do not have
@@ -444,19 +443,17 @@
 % If you know what you're doing and are confident that things are working,
 % you can skip the tests by setting the following property:
 stimWindow.PtbSyncTests = false;
-

Error using hw.DaqRotaryEncoder/readAbsolutePosition (line 143)

NI Error -88709 ?or Error using hw.DaqRotaryEncoder/createDaqChannel (line 81): The requested subsystem 'CounterInput' does not exist on this device.

% This happens from time to time, particularly after the computer has gone
+

Error using hw.DaqRotaryEncoder/readAbsolutePosition (line 143)

NI Error -88709 ?or Error using hw.DaqRotaryEncoder/createDaqChannel (line 81): The requested subsystem 'CounterInput' does not exist on this device.

% This happens from time to time, particularly after the computer has gone
 % to sleep. Unplugging the DAQ USB cable and plugging it back in helps.
 % Restart MATLAB. If the error persists, restart the computer with the DAQ
 % unplugged.
-

The experiment server is unable to open my DAQ on ‘Dev1’

If you have multiple NI devices on this computer, set the DaqIds properties to the correct id in your hardware.mat file, i.e. daqController.DaqIds, mouseInput.DaqId, rewardController.DaqId

d = daq.getDevices % Availiable devices and their info
-

My rotary encoder has a different resolution, how do I change the hardware config?

Change the mouseInput.EncoderResolution peroperty to the value found at the end of your rotary encoder’s product number: e.g. 05.2400.1122.1024 means EncoderResolution = 1024.

Notes

(1) DOI:10.1016/j.celrep.2017.08.047

Etc.

%#ok<*NOPTS>
-%#ok<*NASGU>
-%#ok<*ASGLU>
-
\ No newline at end of file diff --git a/docs/html/id_index.html b/docs/html/id_index.html new file mode 100644 index 00000000..29c6faac --- /dev/null +++ b/docs/html/id_index.html @@ -0,0 +1,453 @@ + + + + + Error and warning IDs

Error and warning IDs

Below is a list of Rigbox error & warning IDs. This list is currently incomplete and there aren't yet very standard. Typically the ID has the following structure: module:package:function:error

These are here for search convenience and may soon contain more detailed troubleshooting information.

Contents

copyPaths

Problem:

In order to load various essential configuration files, and to load and save experimental data, user specific paths must be retrieved via calls to dat.paths. This error means the function is not on MATLAB's search path.

Solution:

Add your +dat\paths.m file to MATLAB's search path. A template is present in docs\setup\paths_template.m. This file is automatically copied by addRigboxPaths to +dat\. If you haven't already done so, run addRigboxPaths to ensure all other paths have been correctly set.

See also README.md for further setup information.

IDs

Rigbox:git:update:copyPaths
+signals:test:copyPaths

noRemoteFile

Problem: % TODO Add problem & solution for noRemoteFile error

Solution:

IDs

Rigbox:mc:noRemoteFile

notInTest

Problem:

This occurs when a mock function is called when the INTEST global variable is not set. These mock functions shadow Rigbox and builtin functions, meaning they have the same name.

Solution:

If this function was called during a test, add the following to the top of your test or in the constructor:

global INTEST
+INTEST = true
+

Ensure that this is cleared during the teardown:

addteardown(@clear, INTEST) % If in a class
+mess = onCleanup(@clear, INTEST) % If in a function
+

If the mock in question is a class, set the InTest flag instead of the global variable:

mock = MockDialog; % An example using MockDialog class
+mock.InTest = true;
+addteardown(@clear, MockDialog) % Clear mock class when done
+mess = onCleanup(@clear, MockDialog) % If in a function
+

If you are in not running tests, ensure that tests/fixtures is not in your MATLAB path and that you are in a different working directory. It is best to remove all Rigbox paths and readd them using `addRigboxPaths`

IDs

Rigbox:tests:system:notInTest
+Rigbox:tests:modDate:notInTest
+Rigbox:tests:paths:notInTest
+Rigbox:tests:pnet:notInTest
+Rigbox:tests:modDate:notInTest
+Rigbox:MockDialog:newCall:notInTest

behaviourNotSet

Problem:

A mock function was called while in a test, however the behaviour for this particular input has not been defined.

Solution:

If not testing a specific behavior for this function's output, simply supress the warning in your test, remembering to restore the warning state:

origState = warning;
+addteardown(@warning, origState) % If in a class
+mess = onCleanup(@warning, origState) % If in a function
+warning('Rigbox:MockDialog:newCall:behaviourNotSet', 'off')
+

If you're specifically testing the behavior when the mock returns a particular output then check that you've set the input-output map correctly: usually this is done by first calling the mock with input identical to function under test as well as the output you want to see. Check the input is formatted correctly. For more information see the help of the particular mock you are using.

IDs

Rigbox:tests:system:valueNotSet % TODO change name
+Rigbox:MockDialog:newCall:behaviourNotSet

mkdirFailed

Problem:

MATLAB was unable to create a new folder on the system.

Solution:

In general Rigbox code only creates new folders when a new experiment is created. The folders are usually created in the localRepository and mainRepository locations that are set in your paths file. If either of these are remote (e.g. a server accessed via SMB) check that you can navigate to the location in Windows' File Explorer (sometimes the access credentials need setting first). If you can, next check the permissions of these locations. If the folders are read-only, MATLAB will not be able to create a new experiment folder there. Either change the permissions or set a different path in dat.paths. One final thing to check is that the folder names are valid: the presence of a folder that is not correctly numbered in the subject's date folder may lead to an invalid expRef. Withtin a date folder there should only be folders name '1', '2', '3', etc.

IDs

Alyx:newExp:mkdirFailed
+Rigbox:dat:newExp:mkdirFailed

newExp:expFoldersAlreadyExist

Problem:

The folder structure for a newly generated experiment reference is already in place.

Experiment references are generated based on subject name, today's date and the experiment number, which is found by looking at the folder structure of the main repository. In a subject's experiment folder for a given date there are numbered folders. When running a new experiment, the code takes the folder name with the largest number and adds 1. It then checks that this numbered folder doesn't exist in the other repositories. If it does, an error is thrown so that no previous experiment data is overwritten.

Solution:

Check the folder structure for all your repositories (namely the localRepository and mainRepository set in dat.paths). It may be that there is an empty experiment folder in the localRepository but not the mainRepository, in which case you can delete it. Alternatively, if you find a full experiment folder in the local but not the main, copy it over so that the two match. This will avoid a duplicate expRef being created (remember, new expRefs are created based on the folder structure of the mainRepository only).

IDs

Alyx:newExp:expFoldersAlreadyExist
+Rigbox:dat:newExp:expFoldersAlreadyExist
% ..:..:expRefNotFound
+% *Problem*:
+%
+% The experiment reference string does not correspond to the folder
+% structure in your mainRepository path.  Usually determined via a call to
+% |dat.expExists|.
+%
+% *Solution*:
+%
+% Check that the mainRepository paths are the same on both the computer
+% that creates the experiment (e.g. MC) and the one that loads the
+% experiment (e.g. the one that runs |srv.expServer|).  For an experiment
+% to exist, the subject > date > sequence folder structure should exist in
+% the mainRepository.  To see the mainRepository location, run the
+% following:
+%
+%   getOr(dat.paths, 'mainRepository')
+%
+

For example if the output is \\server\Subjects\ then for the expRef '2019-11-25_1_test' to exist, the following folder should exist: \\server\Subjects\test\2019-11-25\1

IDs

Rigbox:srv:expServer:expRefNotFound

----- ! PTB - ERROR: SYNCHRONIZATION FAILURE ! ----

Problem:

To quote PsychToolbox: One or more internal checks indicate that synchronization of Psychtoolbox to the vertical retrace (VBL) is not working on your setup.This will seriously impair proper stimulus presentation and stimulus presentation timing!

Solution:

There are many, many reasons for this error. Here's a quick list of things to try, in order:

  1. Simply re-trying a couple of times. Sometimes it happens sporadically.
  2. Check the monitor(s) are on and plugged in. If you're using multiple monitors they should be of the same make and model. If they aren't, try with just one monitor first.
  3. If you're using multiple screens in NVIDEA's 'Mosaic' mode, the settings may have changed: sometimes Mosiac becomes deactivated and you should set it up again.
  4. If you're using a remote connection for that computer it may be interfering with the graphics settings. Examples of a remote connection include VNC servers, TeamViewer and Windows Remote Desktop. Try opening the PTB Window without any of these remote services.
  5. Update the graphics card drivers and firmware. This often helps.
  6. Read the PTB docs carefully and follow their suggestions. The docs can be found at http://psychtoolbox.org/docs/SyncTrouble.
  7. If all else fails. You can skip these tests and check that there is no taring manually. This is not recommended but can be done by setting your stimWindow object's PtbSyncTests property to false:
stimWindow = getOr(hw.devices([],false), 'stimWindow');
+stimWindow.PtbSyncTests = false;
+hwPath = fullfile(getOr(dat.paths, 'rigConfig'), 'hardware.mat');
+save(hwPath, 'stimWindow', '-append')
+

Undocumented IDs

Below is a list of all other error and warning ids.
% Rigbox:git:runCmd:nameValueArgs
+% Rigbox:git:runCmd:gitNotFound
+% Rigbox:git:update:valueError
+%
+% Rigbox:hw:calibrate:noscales
+% Rigbox:hw:calibrate:deadscale
+% Rigbox:hw:calibrate:partialPVpair
+%
+% Rigbox:srv:unexpectedUDPResponse
+% Rigbox:srv:unexpectedUDP
+% Rigbox:srv:expServer:noHardwareConfig
+%
+% Rigbox:dat:expPath:NotEnoughInputs
+% Rigbox:exp:SignalsExp:NoScreenConfig
+% Rigbox:exp:Parameters:wrongNumberOfColumns
+%
+% Rigbox:dat:expFilePath:NotEnoughInputs
+%
+% Rigbox:MockDialog:newCall:EmptySeq
+%
+% Rigbox:exp:SignalsExp:noTokenSet
+%
+% Rigbox:eui:choiceExpPanel:toolboxRequired
+% Rigbox:setup:toolboxRequired
+%
+% Alyx:newExp:subjectNotFound
+% Alyx:registerFile:InvalidPath
+% Alyx:registerFile:UnableToValidate
+% Alyx:registerFile:EmptyDNSField
+% Alyx:registerFile:InvalidRepoPath
+% Alyx:registerFile:InvalidFileType
+% Alyx:registerFile:InvalidFileName
+% Alyx:registerFile:NoValidPaths
+% Alyx:updateNarrative:UploadFailed
+%
+% Alyx:getFile:InvalidID
+% Alyx:getExpRef:InvalidID
+% Alyx:getFile:InvalidType
+% Alyx:expFilePath:InvalidType
+% Alyx:url2Eid:InvalidURL
+%
+% toStr:isstruct:Unfinished
+%
+% squeak.hw
+% shape:error
+% window:error
+
\ No newline at end of file diff --git a/docs/html/SignalsTest GUI Example.gif b/docs/html/images/SignalsTest GUI Example.gif similarity index 100% rename from docs/html/SignalsTest GUI Example.gif rename to docs/html/images/SignalsTest GUI Example.gif diff --git a/docs/html/images/image1.jpg b/docs/html/images/image1.jpg new file mode 100644 index 00000000..efc679a9 Binary files /dev/null and b/docs/html/images/image1.jpg differ diff --git a/docs/html/images/image10.jpg b/docs/html/images/image10.jpg new file mode 100644 index 00000000..5e06e76a Binary files /dev/null and b/docs/html/images/image10.jpg differ diff --git a/docs/html/images/image11.jpg b/docs/html/images/image11.jpg new file mode 100644 index 00000000..f42f4d71 Binary files /dev/null and b/docs/html/images/image11.jpg differ diff --git a/docs/html/images/image12.jpg b/docs/html/images/image12.jpg new file mode 100644 index 00000000..22365644 Binary files /dev/null and b/docs/html/images/image12.jpg differ diff --git a/docs/html/images/image2.jpg b/docs/html/images/image2.jpg new file mode 100644 index 00000000..ef8e2c97 Binary files /dev/null and b/docs/html/images/image2.jpg differ diff --git a/docs/html/images/image3.png b/docs/html/images/image3.png new file mode 100644 index 00000000..2dd89fec Binary files /dev/null and b/docs/html/images/image3.png differ diff --git a/docs/html/images/image4.jpg b/docs/html/images/image4.jpg new file mode 100644 index 00000000..7c9201c3 Binary files /dev/null and b/docs/html/images/image4.jpg differ diff --git a/docs/html/images/image5.jpg b/docs/html/images/image5.jpg new file mode 100644 index 00000000..19e41207 Binary files /dev/null and b/docs/html/images/image5.jpg differ diff --git a/docs/html/images/image6.jpg b/docs/html/images/image6.jpg new file mode 100644 index 00000000..c9280575 Binary files /dev/null and b/docs/html/images/image6.jpg differ diff --git a/docs/html/images/image7.jpg b/docs/html/images/image7.jpg new file mode 100644 index 00000000..47b98e51 Binary files /dev/null and b/docs/html/images/image7.jpg differ diff --git a/docs/html/images/image8.jpg b/docs/html/images/image8.jpg new file mode 100644 index 00000000..a749b900 Binary files /dev/null and b/docs/html/images/image8.jpg differ diff --git a/docs/html/images/image9.jpg b/docs/html/images/image9.jpg new file mode 100644 index 00000000..55fc837e Binary files /dev/null and b/docs/html/images/image9.jpg differ diff --git a/docs/html/index.html b/docs/html/index.html index 7b1598e8..361daf00 100644 --- a/docs/html/index.html +++ b/docs/html/index.html @@ -6,7 +6,7 @@ Rigbox Documentation

Rigbox Documentation

Below is a list of useful topics:

@todo Further files to add to docs @body Burgess config, setting up shared paths

Contents

Code organization

Below is a list of Rigbox's subdirectories and an overview of their respective contents. For more details, see the REAME.md and Contents.m files for each package folder.

+dat

The 'data' package contains code pertaining to the organization and logging of data. It contains functions that generate and parse unique experiment reference ids, and return file paths where subject data and rig configuration information is stored. Other functions include those that manage experimental log entries and parameter profiles. A nice metaphor for this package is a lab notebook.

doc +dat
-

+eui

The 'experiment user interface' package contains code pertaining to the Rigbox user interface. It contains code for constructing the mc GUI (MControl.m), and for plotting live experiment data or generating tables for viewing experiment parameters and subject logs.

This package is exclusively used by the master computer.

doc +eui
-

+exp

The 'experiment' package is for the initialization and running of behavioural experiments. It contains code that define a framework for event- and state-based experiments. Actions such as visual stimulus presentation or reward delivery can be controlled by experiment phases, and experiment phases are managed by an event-handling system (e.g. ResponseEventInfo).

The package also triggers auxiliary services (e.g. starting remote acquisition software), and loads parameters for presentation for each trial. The principle two base classes that control these experiments are 'Experiment' and its 'signals package' counterpart, 'SignalsExp'.

helpwin +exp
-

+hw

The 'hardware' package is for configuring, and interfacing with, hardware (such as screens, DAQ devices, weighing scales and lick detectors). Within this is the '+ptb' package which contains classes for interacting with PsychToolbox.

hw.devices loads and initializes all the hardware for a specific experimental rig. There are also classes for unifying system and hardware clocks.

doc hw
-

+psy

The 'psychometrics' package contains simple functions for processing and plotting psychometric data.

doc psy
-

+srv

The 'stim server' package contains the 'expServer' function as well as classes that manage communications between rig computers.

The 'Service' base class allows the stimulus computer to start and stop auxiliary acquisition systems at the beginning and end of experiments.

The 'StimulusControl' class is used by the master computer to manage the stimulus computer.

Note: Lower-level communication protocol code is found in the 'cortexlab/+io' package.

doc +srv
-

cb-tools/burgbox

'Burgbox' contains many simple helper functions that are used by the main packages. Within this directory are additional packages:

  • +bui --- Classes for managing graphics objects such as axes
  • +aud --- Functions for interacting with PsychoPortAudio
  • +file --- Functions for simplifying directory and file management, for instance returning the modified dates for specified folders or filtering an array of directories by those that exist
  • +fun --- Convenience functions for working with function handles in MATLAB, e.g. functions similar cellfun that are agnostic of input type, or ones that cache function outputs
  • +img --- Classes that deal with image and frame data (DEPRECATED)
  • +io --- Lower-level communications classes for managing UDP and TCP/IP Web sockets
  • +plt --- A few small plotting functions (DEPRECATED)
  • +vis --- Functions for returning various windowed visual stimuli (i.g. gabor gratings)
  • +ws --- An early Web socket package using SuperWebSocket (DEPRECATED)

cortexlab

The 'cortexlab' directory is intended for functions and classes that are rig or CortexLab specific, for example, code that allows compatibility with other stimulus presentation packages used by CortexLab (e.g. MPEP)

tests

The 'tests' directory contains code for running unit tests within Rigbox.

docs

Contains various guides for how to configure and use Rigbox.

submodules

Additional information on the alyx-matlab, npy-matlab, signals and wheelAnalysis submodules can be found in their respective github repositories.

Etc.

Author: Miles Wells

v0.1.0

Welcome to the main Rigging Toolbox (Rigbox) documentation. Here you can find detailed documentation and guides on how to set up Rigbox, including writing new experiments, setting up recording devices, running experiments and processing the resulting data.

Contents

Installing Rigbox

Below are some instructions for installing Rigbox. There are two guides, the first is a thorough guide for users unfarmilliar with MATLAB and Git. The second is for 'power users' who have a basic understanding of these things.

Setting up experiments

Below is a set of steps for setting up a full experiment in Rigbox. A full experiment being one where you record quality, reliable data that gets saved into the main experiment repository.

Briefly, before you can run a full experiment you must 1) set up your paths so that Rigbox knows from where to load rig settings and parameters, 2) save a hardware configuration file so that Rigbox can properly initialize its hardware, and 3) locate or create an experiment definition function to define your experiment.

Running full experiments

Before you can run a complete experiment, you must set up Rigbox (see above section). Once this is done there you can follow on of the below sections to run a full experiment.

Creating experiments

The principle way to create a new is experiment (i.e. passive stimulation or behaviour task) is write an expDef. Below will be a set of guides for how to write an expDef, and how to test it.

Working with Rigbox Experiment data

Below are some guides on how to work with the experimental data saved by Rigbox. These guides instruduce some functions for loading and processing these data, and explain the forms in which data are saved.

Troubleshooting

Rigbox is a mountain of code and there are many things that can go wrong when using it. Below are a few guides for how to fix problems that arise in Rigbox.

  • Basic MATLAB troubleshooting - this guide is for users that are unfamiliar with MATLAB.
  • General troubleshooting - this guide gives a list of steps to follow when an error is encountered.
  • ID index - A list of Rigbox error/warning IDs along with the a detailed description of what they mean and an exhastive list of causes and solutions.
  • FAQ - A list of frequently asked questions regarding problems and pointers to the solutions.

User guides

Below is a list of in-depth guides for users who want to learn the ins-and-outs of various packages and classes in Rigbox.

  • The Data Package - How to query data locations and log experiments using the +dat package.
  • How Signals works - An in-depth guide to how Signals works. This shows you how to work with Signals outside of the Experiment Framework and gives demonstrations of all Signals methods ( scan, etc.)
  • Parameters - How to create and edit experiment parameters.
  • Alyx - How to interact with an Alyx database
  • Timeline - Using Timeline for time alignment

Miscellaneous

Below is a list of useful topics:

Etc.

Author: Miles Wells

v0.1.1

\ No newline at end of file diff --git a/docs/html/install.html b/docs/html/install.html new file mode 100644 index 00000000..57f6aea2 --- /dev/null +++ b/docs/html/install.html @@ -0,0 +1,231 @@ + + + + + Installing Rigbox

Installing Rigbox

Below are some easy step-by-step instructions for installing Rigbox without any prior knowledge of Git or MATLAB. For more succinct installation instructions, see the Rigbox README. The first section lists the requirements. NB: Please read this section carefully before attempting to install anything.

Contents

Requirements

For exploring Rigbox's features and running test experiments, Rigbox only needs to be installed on a single computer.

For running full experiments, we recommend running Rigbox on two PCs: one is used for presenting stimuli and communicating with rig hardware, and the other runs a GUI which the user interacts with to monitor the experiment. Currently only National Instruments DAQs are supported for acquiring data from hardware devices.

Software

Rigbox reqquires the following software to work properly:

  • Windows Operating System (7 or later, 64-bit)
  • MATLAB (2018b or later, also known as version 9.5)
  • Visual C++ Redistributable Packages for Visual Studio 2013 & 2015-2019 (free)
  • The MATLAB Data Acquisition Toolbox
  • If using an NI DAQ the NI-DAQmx support package (free)
  • The GUI Layout Toolbox (v2 or later, free)
  • Psychophysics Toolbox (v3 or later, free)

Hardware

Below are a few minimum hardware requirements for both PCs.

  • Processor: Intel Core i5-6500 @ 3.0 GHz (or similar)
  • Graphics: NVIDIA Quadro P400 (or similar)
  • Memory: DDR4 16 GB @ 2133 MHz (e.g. Corsair Vengeance 16 GB)

Install steps

Below are detailed steps on installing all required software. If you already have software installed for a particular step, feel free to skip that step. Unless you are installing Rigbox on a computer which will use a NI-DAQ for data acquistion, you can skip step 5.

  1. Install Windows 7 or later (Windows 10 is recommended). Windows must be must be 64-bit (sometimes called x64, x86_64, AMD64 or Intel 64).
  2. Download and install https://uk.mathworks.com/downloads/ MATLAB> by following their installation guide (see note 1). At step 9, make sure to check the box for the Data Acquisition Toolbox, along with any other MATLAB Mathworks toolboxes you want, though for testing Rigbox, no other toolboxes are required (See note 2). NB: This step may take a while.
  3. Once downloaded, open MATLAB by double-clicking on the MATLAB icon in the start menu.
  4. Within MATLAB, install the GUI Layout Toolbox (See note 2). Make sure the version number is greater than 2.
  5. Within MATLAB, install the NI-DAQmx Support Package (See note 2). NB: This step may take a while.
  6. Download and install the Microsoft Visual C++ Redistributable Packages for Visual Studio 2013 installer (See note 3).
  7. Download and install the Microsoft Visual C++ Redistributable Packages for Visual Studio 2015-2019 installer (See note 4). NB: This is 2015-2019; the previous step was for 2013. Both are required.
  8. Download and install SilkSVN (See note 5).
  9. Download and install the 64-Bit GStreamer-1.16.0 MSVC runtime, making sure to install all offered packages (See note 6).
  10. Download the PsychToolbox installer function and save it into your Documents/MATLAB folder.
  11. In the MATLAB Command Window (see note 7), type DownloadPsychtoolbox(userpath) (no quotes) and press enter. This will download and install PsychToolbox to MATLAB folder. At certain points in the installation it will print stuff to the Command Window and ask you to press any key to continue. Do this until the two angled brackes ('|>>|') reappear.
  12. Close MATLAB by pressing the '|X|' in the top right corner of the window.
  13. Download and install Git Bash for Windows (See note 8). Use all defaults.
  14. Launch Git Bash (See note 9). A black command line window should appear.
  15. Type the following line into Git Bash (or copy/paste): cd ~/Documents/Github
  16. Copy this line and paste it into Git Bash (use right click for pasting): git clone --recurse-submodules https://github.com/cortex-lab/Rigbox
  17. Launch MATLAB and navigate to the following folder (See note 10): Documents\Github\Rigbox
  18. Type the following into the MATLAB Command Window and press enter (See note 11): addRigboxPaths
  19. You should be done now. To check this, type eui.SignalsTest; into the MATLAB Command Window and select signalsPong.m. Then click Start. Your mouse controls the right paddle.

Notes

  1. MATLAB is not free and requires a MATLAB account in order to download. If you are part of an academic institution you may be able to get MATLAB for free. If in doubt ask your lab supervisor or institute IT department. For more information see MATLAB's install guide.
  2. Once MATLAB is installed, toolboxes can be downloaded and installed directly within MATLAB via the "Add-Ons" button in the "Home" top toolstrip. This opens the MATLAB 'AddOn Explorer' where you can search and install toolboxes.
  3. To install download and install, follow the link and click the orange 'Download' button. A 'Choose the download you want' window will come up. Select 'vcredist_x64.exe' and click 'Next'. A download window will pop up; click 'Save file'. Once downloaded, double-click the installer and follow the steps.
  4. To download and install the MSVC 2015-2019 libraries, follow the link and click 'Save file'. You can then run the file and follow the installation steps.
  5. To download and install SilkSVN, follow the link and click the blue button that says 'SVN 1.12.0, 64 bit' on the left-hand side. The numbers might be slightly different but the important thing is that you choose the one that says '64 bit'. Click 'OK' in the pop-up window to save the installer zip file. Once downloaded double-click the zip file and open the exe file contained. Follow all the steps in the installer.
  6. To download and install the 64-Bit GStreamer-1.16.0 MSVC runtime, follow the link and clock 'Save file'. Then open the file and follow the installation steps. Choose the full/complete installation with all packages selected.
  7. The MATLAB Command Window is usually at the bottom of the MATLAB window and has a '|>>|' in it. For more information, please read the MATLAB documentation about the Command Window.
  8. To download and install Git Bash for Windows, follow the link and click 'Save file' when the download window pops up. Open the installer file and click 'Next' repeatedly until the end, then click 'Finish'.
  9. There might be more than one program installed that has 'Git' in the name. Make sure the one you open is called 'Git Bash'.
  10. To navigate to a folder in MATLAB, either use the Address Field or type the following into the MATLAB Command Window, replacing USER with the name of the Windows user that's currently logged in: cd('C:\Users\USER\Documents\Github\rigbox\')
  11. If you've followed the above steps you can safely ignore any warnings you may see for trying out Rigbox.

Etc.

Authors: Jai Bhagat, Matteo Caranini, Miles Wells

v0.1.0

\ No newline at end of file diff --git a/docs/html/packages.html b/docs/html/packages.html new file mode 100644 index 00000000..e4b7916c --- /dev/null +++ b/docs/html/packages.html @@ -0,0 +1,203 @@ + + + + + Code organization

Code organization

Rigbox is organized into various MATLAB packages(1). Functions and classes within a package have their own namespace. We seperate our functions based broadly on what part of Rigbox they're for. For example files in the +eui folder are part of the 'Experiment UI' package and are all related to GUIs in Rigbox (e.g. the MC GUI or Parameter Editor GUI).

Fig. 1 - An overview of the packages and their loose relationships to one another

Below is a list of Rigbox's subdirectories and an overview of their general purpose. Shown is the command for viewing the package overview doc, which lists the package contents. For further details, see the REAME.md and Contents.m files for each package folder.

Contents

+dat

The 'data' package contains code pertaining to the organization and logging of data. It contains functions that generate and parse unique experiment reference ids, and return file paths where subject data and rig configuration information is stored. Other functions include those that manage experimental log entries and parameter profiles. A nice metaphor for this package is a lab notebook.

doc +dat
+

+eui

The 'experiment user interface' package contains code pertaining to the Rigbox user interface. It contains code for constructing the mc GUI (MControl.m), and for plotting live experiment data or generating tables for viewing experiment parameters and subject logs.

This package is exclusively used by the master computer.

doc +eui
+

+exp

The 'experiment' package is for the initialization and running of behavioural experiments. It contains code that define a framework for event- and state-based experiments. Actions such as visual stimulus presentation or reward delivery can be controlled by experiment phases, and experiment phases are managed by an event-handling system (e.g. ResponseEventInfo).

The package also triggers auxiliary services (e.g. starting remote acquisition software), and loads parameters for presentation for each trial. The principle two base classes that control these experiments are 'Experiment' and its 'signals package' counterpart, 'SignalsExp'.

helpwin +exp
+

+hw

The 'hardware' package is for configuring, and interfacing with, hardware (such as screens, DAQ devices, weighing scales and lick detectors). Within this is the '+ptb' package which contains classes for interacting with PsychToolbox.

hw.devices loads and initializes all the hardware for a specific experimental rig. There are also classes for unifying system and hardware clocks.

doc hw
+

+psy

The 'psychometrics' package contains simple functions for processing and plotting psychometric data.

doc psy
+

+srv

The 'stim server' package contains the 'expServer' function as well as classes that manage communications between rig computers.

The 'Service' base class allows the stimulus computer to start and stop auxiliary acquisition systems at the beginning and end of experiments.

The 'StimulusControl' class is used by the master computer to manage the stimulus computer.

Note: Lower-level communication protocol code is found in the 'cortexlab/+io' package.

doc +srv
+

cb-tools/burgbox

'Burgbox' contains many simple helper functions that are used by the main packages. Within this directory are additional packages:

  • +bui --- Classes for managing graphics objects such as axes
  • +aud --- Functions for interacting with PsychoPortAudio
  • +file --- Functions for simplifying directory and file management, for instance returning the modified dates for specified folders or filtering an array of directories by those that exist
  • +fun --- Convenience functions for working with function handles in MATLAB, e.g. functions similar cellfun that are agnostic of input type, or ones that cache function outputs
  • +img --- Classes that deal with image and frame data (DEPRECATED)
  • +io --- Lower-level communications classes for managing UDP and TCP/IP Web sockets
  • +plt --- A few small plotting functions (DEPRECATED)
  • +vis --- Functions for returning various windowed visual stimuli (i.g. gabor gratings)
  • +ws --- An early Web socket package using SuperWebSocket (DEPRECATED)

cortexlab

The 'cortexlab' directory is intended for functions and classes that are rig or CortexLab specific, for example, code that allows compatibility with other stimulus presentation packages used by CortexLab (e.g. MPEP)

tests

The 'tests' directory contains code for running unit tests within Rigbox.

docs

Contains various guides for how to configure and use Rigbox.

submodules

Additional information on the alyx-matlab, npy-matlab, signals and wheelAnalysis submodules can be found in their respective github repositories.

Notes

(1) For more information about using packages in MATLAB, see Scoping Classes With Packages

Etc.

Author: Miles Wells

v0.0.2

\ No newline at end of file diff --git a/docs/html/timeline.png b/docs/html/timeline.png deleted file mode 100644 index 917dff30..00000000 Binary files a/docs/html/timeline.png and /dev/null differ diff --git a/docs/html/troubleshooting.html b/docs/html/troubleshooting.html index 2ae9a329..3c2fd024 100644 --- a/docs/html/troubleshooting.html +++ b/docs/html/troubleshooting.html @@ -6,7 +6,7 @@ Troubleshooting

Troubleshooting

Often finding the source of a problem seems daunghting when faced with a huge Rigbox error stack. Below are some tips on how to quickly get to the root of the issue and hopefully solve it.

Contents

Update the code

Check what version of the code you're using and that you're up-to-date:

git.runCmd('status'); % Tells me what branch I'm on
+  

Troubleshooting

Often finding the source of a problem seems daunghting when faced with a huge Rigbox error stack. Below are some tips on how to quickly get to the root of the issue and hopefully solve it.

Contents

Update the code

Check what version of the code you're using and that you're up-to-date:

git.runCmd('status'); % Tells me what branch I'm on
 git.update(0); % Update now
 
 % If you're on a development or feature branch try moving to the master
@@ -81,248 +81,8 @@
 

If you're debugging a signals experiment definition, check for the line in your experiment where this particular builtin function was called. NB: You can check whether it is specific to your experiment by running one of the example experiment definitions such as advancedChoiceWorld.m, found in signals/docs/examples. If this runs without error then you're problem may be specific to your experiment. You should see the name of your definition function and exp.SignalsExp in the stack if they are involved.

If you don't know what a function is, try checking the documentation. Consider the following:

Error using open
 Invalid number of channels
Error in audstream.fromSignal (line 16)
   id = audstream.open(sampleRate, nChannels, devIdx);
-[...]

If you're unsure what `audstream.fromSignal` does, try typing `doc audstream`. This should tell you that the package deals with audio devices in signals. In this case the issue might be that your audio settings are incorrect. Take a look at the audio section of `docs\setup\hardware_config.m` and see if you can setup your audio devices differently.

Paths

By far the most common issue in Rigbox relates to problems with the MATLAB paths. Check the following:

  1. Do you have a paths file in the +dat package? Check the location by running `which dat.paths`. Check that a file is on the paths and that it's the correct one.
  2. Check the paths set in this file. Run `p = dat.paths` and inspect the output. Perhaps a path is set incorrectly for one of the fields. Note that custom rig paths overwrite those written in your paths file. More info found in `using_dat_package` and `paths_template`.
  3. Do you have path conflicts? Make sure MATLAB's set paths don't include other functions that have the same name as Rigbox ones. Note that any functions in ~/Documents/MATLAB take precedence over others. If you keep seeing the following warning check that you've set the paths correctly: Warning: Function system has the same name as a MATLAB builtin. We suggest you rename the function to avoid a potential name conflict. This warning can occur if the tests folder has been added to the paths by mistake. Always set the paths by running `addRigboxPaths` and never set them manually as some folders should not be visible to MATLAB.
  4. Check your working directory MATLAB prioritizes functions found in your working directory over any others in your path list so try to change into a 'safe' folder before re-running your code: pwd % display working directory cd ~/Documents/MATLAB
  5. Check your variable names Make sure your variable names don't shadow a function or package in Rigbox, for instance if in an experiment definition you create a varible called `vis`, you will no longer be able to access functions in the +vis package from within the function: vis = 23; img = vis.image(t); Error: Reference to non-existent field 'image'.

Reverting

If these errors only started occuring after updating the code, particularly if you hadn't updated in a long time, try reverting to the previous version of the code. This can help determine if the update really was the culprit and will allow you to keep using the code on outdated machines. Previous stable releases can be found on the Github page under releases. NB: For the most recent stable code always pull directly from the master branch

Posting an issue on Github

If you're completely stumped, open an issue on the Rigbox Github page (or alyx-matlab if you think it's related to the Alyx database). When creating an issue, read the bug report template carefully and be sure to provide as much information as possible.

If you tracked down the problem but found the error to be confusing or too vague, feel free to post a feature request describing how better to present the error. This is an area in need of improvment. You could also make a change yourself and submit a pull request. For more info see CONTRIBUTING.md

FAQ

Below are some frequently asked questions and suggestions for fixing them. Note there are plenty of other FAQs in the various setup scripts with more specific information.

Error and warning IDs

Below is a list of Rigbox error & warning IDs. This list is currently incomplete and there aren't yet very standard. Typically the ID has the following structure: module:package:function:error

These are here for search convenience and may soon contain more detailed troubleshooting information.

% ..:..:..:copyPaths
-% Problem:
-%  In order to load various essential configuration files, and to load and
-%  save experimental data, user specific paths must be retrieved via calls
-%  to |dat.paths|.  This error means the function is not on MATLAB's search
-%  path.
-%
-% Solution:
-%  Add your +dat\paths.m file to MATLAB's search path.  A template is
-%  present in \docs\setup\paths_template.m.  This file is automatically
-%  copied by addRigboxPaths to +dat\.  If you haven't already done so, run
-%  |addRigboxPaths| to ensure all other paths have been correctly set.
-%
-%  See also README.md for further setup information.
-%
-% IDs
-%  Rigbox:git:update:copyPaths
-%  signals:test:copyPaths
-
-% ..:..:noRemoteFile
-% Problem:
-%  % TODO Add problem & solution for noRemoteFile error
-%
-% Solution:
-%
-%
-% IDs
-%  Rigbox:mc:noRemoteFile
-
-% ..:..:..:notInTest
-% Problem:
-%  This occurs when a mock function is called when the INTEST global
-%  variable is not set.  These mock functions shadow Rigbox and builtin
-%  functions, meaning they have the same name.
-%
-% Solution:
-%  If this function was called during a test, add the following to the top
-%  of your test or in the constructor:
-%    global INTEST
-%    INTEST = true
-%  Ensure that this is cleared during the teardown:
-%    addteardown(@clear, INTEST) % If in a class
-%    mess = onCleanup(@clear, INTEST) % If in a function
-%
-%  If the mock in question is a class, set the InTest flag instead of the
-%  global variable:
-%    mock = MockDialog; % An example using MockDialog class
-%    mock.InTest = true;
-%    addteardown(@clear, MockDialog) % Clear mock class when done
-%    mess = onCleanup(@clear, MockDialog) % If in a function
-%
-%  If you are in not running tests, ensure that tests/fixtures is not in
-%  your MATLAB path and that you are in a different working directory.  It
-%  is best to remove all Rigbox paths and readd them using `addRigboxPaths`
-%
-% IDs
-%  Rigbox:tests:system:notInTest
-%  Rigbox:tests:modDate:notInTest
-%  Rigbox:tests:paths:notInTest
-%  Rigbox:tests:pnet:notInTest
-%  Rigbox:tests:modDate:missingTestFlag % TODO change name
-%  Rigbox:MockDialog:newCall:InTestFalse
-
-% ..:..:..:behaviourNotSet
-% Problem:
-%  A mock function was called while in a test, however the behaviour for
-%  this particular input has not been defined.
-%
-% Solution:
-%  If not testing a specific behavior for this function's output, simply
-%  supress the warning in your test, remembering to restore the warning
-%  state:
-%    origState = warning;
-%    addteardown(@warning, origState) % If in a class
-%    mess = onCleanup(@warning, origState) % If in a function
-%    warning('Rigbox:MockDialog:newCall:behaviourNotSet', 'off')
-%
-%  If you're specifically testing the behavior when the mock returns a
-%  particular output then check that you've set the input-output map
-%  correctly: usually this is done by first calling the mock with input
-%  identical to function under test as well as the output you want to see.
-%  Check the input is formatted correctly.  For more information see the
-%  help of the particular mock you are using.
-%
-% IDs
-%  Rigbox:tests:system:valueNotSet % TODO change name
-%  Rigbox:MockDialog:newCall:behaviourNotSet
-%
-
-% ..:..:mkdirFailed
-% Problem:
-%  MATLAB was unable to create a new folder on the system.
-%
-% Solution:
-%  In general Rigbox code only creates new folders when a new experiment is
-%  created.  The folders are usually created in the localRepository and
-%  mainRepository locations that are set in your paths file.  If either of
-%  these are remote (e.g. a server accessed via SMB) check that you can
-%  navigate to the location in Windows' File Explorer (sometimes the access
-%  credentials need setting first).  If you can, next check the permissions
-%  of these locations.  If the folders are read-only, MATLAB will not be
-%  able to create a new experiment folder there.  Either change the
-%  permissions or set a different path in |dat.paths|.  One final thing to
-%  check is that the folder names are valid: the presence of a folder that
-%  is not correctly numbered in the subject's date folder may lead to an
-%  invalid expRef.  Withtin a date folder there should only be folders name
-%  '1', '2', '3', etc.
-%
-% IDs
-%  Alyx:newExp:mkdirFailed
-%  Rigbox:dat:newExp:mkdirFailed
-%
-
-% ..:newExp:expFoldersAlreadyExist
-% Problem:
-%  The folder structure for a newly generated experiment reference is
-%  already in place.
-%
-%  Experiment references are generated based on subject name, today's date
-%  and the experiment number, which is found by looking at the folder
-%  structure of the main repository.  In a subject's experiment folder for
-%  a given date there are numbered folders.  When running a new experiment,
-%  the code takes the folder name with the largest number and adds 1.  It
-%  then checks that this numbered folder doesn't exist in the other
-%  repositories.  If it does, an error is thrown so that no previous
-%  experiment data is overwritten.
-%
-% Solution:
-%  Check the folder structure for all your repositories (namely the
-%  localRepository and mainRepository set in |dat.paths|).  It may be that
-%  there is an empty experiment folder in the localRepository but not the
-%  mainRepository, in which case you can delete it.  Alternatively, if you
-%  find a full experiment folder in the local but not the main, copy it
-%  over so that the two match.  This will avoid a duplicate expRef being
-%  created (remember, new expRefs are created based on the folder structure
-%  of the mainRepository only).
-%
-% IDs
-%  Alyx:newExp:expFoldersAlreadyExist
-%  Rigbox:dat:newExp:expFoldersAlreadyExist
-%
-
-% ..:..:expRefNotFound
-% Problem:
-%  The experiment reference string does not correspond to the folder
-%  structure in your mainRepository path.  Usually determined via a call to
-%  |dat.expExists|.
-%
-% Solution:
-%  Check that the mainRepository paths are the same on both the computer
-%  that creates the experiment (e.g. MC) and the one that loads the
-%  experiment (e.g. the one that runs |srv.expServer|).  For an experiment
-%  to exist, the subject > date > sequence folder structure should exist in
-%  the mainRepository.  To see the mainRepository location, run the
-%  following:
-%    getOr(dat.paths, 'mainRepository')
-%  For example if the output is '\\server\Subjects\' then for the expRef
-%  '2019-11-25_1_test' to exist, the following folder should exist:
-%  \\server\Subjects\test\2019-11-25\1
-%
-% IDs
-%  Rigbox:srv:expServer:expRefNotFound
-
-% ----- ! PTB - ERROR: SYNCHRONIZATION FAILURE ! ----
-% Problem:
-%   To quote PsychToolbox: One or more internal checks indicate that
-%   synchronization of Psychtoolbox to the vertical retrace (VBL) is not
-%   working on your setup.This will seriously impair proper stimulus
-%   presentation and stimulus presentation timing!
-%
-% Solution:
-%   There are many, many reasons for this error.  Here's a quick list of
-%   things to try, in order:
-%
-%   # Simply re-trying a couple of times.  Sometimes it happens
-%   sporadically.
-%   # Check the monitor(s) are on and plugged in.  If you're using
-%   multiple monitors they should be of the same make and model.  If they
-%   aren't, try with just one monitor first.
-%   # If you're using multiple screens in NVIDEA's 'Mosaic' mode, the
-%   settings may have changed: sometimes Mosiac becomes deactivated and you
-%   should set it up again.
-%   # If you're using a remote connection for that computer it may be
-%   interfering with the graphics settings.  Examples of a remote
-%   connection include VNC servers, TeamViewer and Windows Remote Desktop.
-%   Try opening the PTB Window without any of these remote services.
-%   # Update the graphics card drivers and firmware.  This often helps.
-%   # Read the PTB docs carefully and follow their suggestions.  The docs
-%   can be found at http://psychtoolbox.org/docs/SyncTrouble.
-%   # If all else fails.  You can skip these tests and check that there is
-%   no taring manually.  This is not recommended but can be done by setting
-%   your stimWindow object's PtbSyncTests property to false:
-%     stimWindow = getOr(hw.devices([],false), 'stimWindow');
-%     stimWindow.PtbSyncTests = false;
-%     hwPath = fullfile(getOr(dat.paths, 'rigConfig'), 'hardware.mat');
-%     save(hwPath, 'stimWindow', '-append')
-

Undocumented IDs

Below is a list of all error and warning ids.
% Rigbox:git:runCmd:nameValueArgs
-% Rigbox:git:runCmd:gitNotFound
-% Rigbox:git:update:valueError
-%
-% Rigbox:hw:calibrate:noscales
-% Rigbox:hw:calibrate:deadscale
-% Rigbox:hw:calibrate:partialPVpair
-%
-% Rigbox:srv:unexpectedUDPResponse
-% Rigbox:srv:unexpectedUDP
-% Rigbox:srv:expServer:noHardwareConfig
-%
-% Rigbox:dat:expPath:NotEnoughInputs
-% Rigbox:exp:SignalsExp:NoScreenConfig
-% Rigbox:exp:Parameters:wrongNumberOfColumns
-%
-% Rigbox:dat:expFilePath:NotEnoughInputs
-%
-% Rigbox:MockDialog:newCall:EmptySeq
-%
-% Rigbox:exp:SignalsExp:noTokenSet
-%
-% Rigbox:eui:choiceExpPanel:toolboxRequired
-% Rigbox:setup:toolboxRequired
-%
-% Alyx:newExp:subjectNotFound
-% Alyx:registerFile:InvalidPath
-% Alyx:registerFile:UnableToValidate
-% Alyx:registerFile:EmptyDNSField
-% Alyx:registerFile:InvalidRepoPath
-% Alyx:registerFile:InvalidFileType
-% Alyx:registerFile:InvalidFileName
-% Alyx:registerFile:NoValidPaths
-% Alyx:updateNarrative:UploadFailed
-%
-% Alyx:getFile:InvalidID
-% Alyx:getExpRef:InvalidID
-% Alyx:getFile:InvalidType
-% Alyx:expFilePath:InvalidType
-% Alyx:url2Eid:InvalidURL
-%
-% toStr:isstruct:Unfinished
-%
-% squeak.hw
-% shape:error
-% window:error
+[...]

If you're unsure what `audstream.fromSignal` does, try typing `doc audstream`. This should tell you that the package deals with audio devices in signals. In this case the issue might be that your audio settings are incorrect. Take a look at the audio section of `docs\setup\hardware_config.m` and see if you can setup your audio devices differently.

Paths

By far the most common issue in Rigbox relates to problems with the MATLAB paths. Check the following:

  1. Do you have a paths file in the +dat package? Check the location by running `which dat.paths`. Check that a file is on the paths and that it's the correct one.
  2. Check the paths set in this file. Run `p = dat.paths` and inspect the output. Perhaps a path is set incorrectly for one of the fields. Note that custom rig paths overwrite those written in your paths file. More info found in `using_dat_package` and `paths_template`.
  3. Do you have path conflicts? Make sure MATLAB's set paths don't include other functions that have the same name as Rigbox ones. Note that any functions in ~/Documents/MATLAB take precedence over others. If you keep seeing the following warning check that you've set the paths correctly: Warning: Function system has the same name as a MATLAB builtin. We suggest you rename the function to avoid a potential name conflict. This warning can occur if the tests folder has been added to the paths by mistake. Always set the paths by running `addRigboxPaths` and never set them manually as some folders should not be visible to MATLAB.
  4. Check your working directory MATLAB prioritizes functions found in your working directory over any others in your path list so try to change into a 'safe' folder before re-running your code: pwd % display working directory cd ~/Documents/MATLAB
  5. Check your variable names Make sure your variable names don't shadow a function or package in Rigbox, for instance if in an experiment definition you create a varible called `vis`, you will no longer be able to access functions in the +vis package from within the function: vis = 23; img = vis.image(t); Error: Reference to non-existent field 'image'.

Reverting

If these errors only started occuring after updating the code, particularly if you hadn't updated in a long time, try reverting to the previous version of the code. This can help determine if the update really was the culprit and will allow you to keep using the code on outdated machines. Previous stable releases can be found on the Github page under releases. NB: For the most recent stable code always pull directly from the master branch

Posting an issue on Github

If you're completely stumped, open an issue on the Rigbox Github page (or alyx-matlab if you think it's related to the Alyx database). When creating an issue, read the bug report template carefully and be sure to provide as much information as possible.

If you tracked down the problem but found the error to be confusing or too vague, feel free to post a feature request describing how better to present the error. This is an area in need of improvment. You could also make a change yourself and submit a pull request. For more info see CONTRIBUTING.md

FAQ

Below are some frequently asked questions and suggestions for fixing them. Note there are plenty of other FAQs in the various setup scripts with more specific information.

Etc.

Author: Miles Wells

v0.1.0

% INTERNAL
+% execute off
 
\ No newline at end of file diff --git a/docs/html/using_dat_package.html b/docs/html/using_dat_package.html index 9564e76f..5d1f8199 100644 --- a/docs/html/using_dat_package.html +++ b/docs/html/using_dat_package.html @@ -6,7 +6,7 @@ Introduction

Introduction

The 'data' package contains code pertaining to the organization and logging of data. It contains functions that generate and parse unique experiment reference ids, and return file paths where subject data and rig configuration information is stored. Other functions include those that manage experimental log entries and parameter profiles. A nice metaphor for this package is a lab notebook.

Contents

Setting up the paths

In order to use Rigbox, a 'paths' file must be placed in a +dat folder somewhere in the MATLAB path. You can copy docs/setup/paths_template.m to +dat/paths.m, then customise the file according to your setup. The paths used by the wider Rigbox code are found in the 'essential paths' section of the paths_template.m file. These paths are required to run experiments. Any number of custom repositories may be set, allowing them to be queried using functions such as DAT.REPOSPATH and DAT.EXPPATH (see below).

Using expRefs

Experiment reference strings are human-readable labels constructed from the subject name, date and sequence (i.e. session number). Many of the following functions take one or experiment references as inputs and an experiment reference is constructed each time your create an experiment.

ref = dat.constructExpRef('subject', now, 2); % subject's 2nd session today
+  

The Data Package

The 'data' package contains code pertaining to the organization and logging of data. It contains functions that generate and parse unique experiment reference ids, and return file paths where subject data and rig configuration information is stored. Other functions include those that manage experimental log entries and parameter profiles. A nice metaphor for this package is a lab notebook.

Contents

Setting up the paths

In order to use Rigbox, a 'paths' file must be placed in a +dat folder somewhere in the MATLAB path. You can copy docs/setup/paths_template.m to +dat/paths.m, then customise the file according to your setup. The paths used by the wider Rigbox code are found in the 'essential paths' section of the paths_template.m file. These paths are required to run experiments. Any number of custom repositories may be set, allowing them to be queried using functions such as DAT.REPOSPATH and DAT.EXPPATH (see below).

It may be prefereable to keep the paths file in a shared network drive where all rigs can access it. This way only one file needs updating when a path gets changed. You can also override and add to the fields set by the paths file in a rig specific manner. To do this, create your paths as a struct with the name `paths` and save this to a MAT file called `paths` in your rig specific config folder:

rigConfig = getOr(dat.paths('exampleRig'), 'rigConfig');
+customPathsFile = fullfile(rigConfig, 'paths.mat');
+paths.mainRepository = 'overide/path'; % Overide main repo for `exampleRig`
+paths.addedRepository = 'new/custom/path'; % Add novel repo
+
+save(customPathsFile, 'paths') % Save your new custom paths file.
+
+% More info in the paths template:
+root = getOr(dat.paths, 'rigbox');
+opentoline(fullfile(root, 'docs', 'scripts', 'paths_template.m'), 75)
+

Using expRefs

Experiment reference strings are human-readable labels constructed from the subject name, date and sequence (i.e. session number). Many of the following functions take one or experiment references as inputs and an experiment reference is constructed each time your create an experiment.

ref = dat.constructExpRef('subject', now, 2); % subject's 2nd session today
 [subjectRef, expDate, expSequence] = dat.parseExpRef(ref);
 

Loading experiments

Below are some common ways to query data and paths.

% Listing all subjects
 subjects = dat.listSubjects;
@@ -114,13 +124,13 @@
 dat.delParamProfile(expType, profileName);
 
 % More info on how parameters work can be found in USING_PARAMETERS:
-open(fullfile(getOr(dat.paths,'rigbox'), 'docs', 'using_parameters.m'))
+open(fullfile(getOr(dat.paths,'rigbox'), 'docs', 'scripts', 'using_parameters.m'))
 

Using the log

The log object, is primarily dealt with through MC, however you can also use it from the command line:

e = dat.addLogEntry(subject, timestamp, type, value, comments, AlyxInstance);
 p = dat.logPath(subject, 'all');
 e = dat.logEntries(subject);
 e = dat.updateLogEntry(subject, id, newEntry);
 

Setting custom paths

Some people keep the paths file in a shared remote location that all rigs can access. This reduces the number of files to change when a repository path needs updating to one. In this case, rig-specific paths may be set using a custom paths file that overrides any paths set in DAT.PATHS:

opentoline(fullfile(getOr(dat.paths,'rigbox'), ...
-  'docs', 'setup', 'paths_template.m'), 78, 1)
+  'docs', 'scripts', 'paths_template.m'), 78, 1)
 
 % The paths file, 'paths.mat', must contain a variable `paths` that is a
 % struct of custom paths.  The file should be located in the location set
@@ -133,10 +143,10 @@
 paths.expDefinitions = 'C:\ExpDefinitions';
 customPathsFile = fullfile(getOr(dat.paths('ZREDONE'), 'rigConfig'), 'paths');
 save(customPathsFile, 'paths', '-mat')
-

Etc.

Author: Miles Wells

v1.0.0

%#ok<*NASGU,*ASGLU,*ASGLU>
-
\ No newline at end of file diff --git a/docs/html/using_services.html b/docs/html/using_services.html index 60444996..83eb9580 100644 --- a/docs/html/using_services.html +++ b/docs/html/using_services.html @@ -6,7 +6,7 @@ Introduction

Running experiments on a single computer

Running experiments with two PCs has two major advantages:

  1. An MC computer can control and monitor multiple stimulus computers in parallel.
  2. Using mc on a separate computer frees up the stimulus computer's resources. A dedicated experiment computer is likely to have lower latencies.

Nevertheless, it is possible to run experiments using a single computer. The first way is by using srv.expServer's 'single-shot' mode to run an experiment without running mc. The second way is by running mc on the same computer, in a different instance of MATLAB.

Contents

Without MC

Running experiments on a single computer without MC is simple, however live monitoring of the experiment is not possible. First a new experiment is created, then srv.expServer should be called the experiment reference string. The below code shows how to create and run a ChoiceWorld Experiment using the default parameters, without using Alyx:

ref = dat.newExp('test', now, exp.choiceWorldParams);
+srv.expServer('expRef', ref, 'preDelay', 10) % Ten second delay before start
+

Below is an example of modifying parameters for a Signals Experiment, then create an experiment in Alyx and run it:

% Get the parameter list using inferParameters
+paramStruct = exp.inferParameters(@advancedChoiceWorld);
+
+% Modify the parameters using the exp.Parameters object
+P = exp.Parameters(paramStruct); %
+P.makeTrialSpecific('rewardSize')
+P.set('rewardSize', linspace(1,3,P.numTrialConditions))
+
+% Parameters can also be manipulated in the Parameter Editor GUI
+PE = eui.ParamEditor(P);
+paramStruct = PE.Parameters.Struct;
+
+% Save parameters and register session to Alyx
+ai = Alyx;
+ref = newExp(ai, 'test', now, P.Struct);
+srv.expServer('expRef', ref, 'alyx', ai)
+

With MC

It is also possible to run mc on the same computer as srv.expServer. This requires that the computer has at least 2 monitors connected.

To do this set up the remote file according to the Configuring WebSockets guide, however, instead of using the hostname or external IP as the URI, use the localhost address (normally 127.0.0.1). Below is the code for setting up the remote file this way:

% The stimulus controllers are loaded from a MAT file with the name
+% 'remote' in the globalConfig directory, defined in dat.paths:
+p = fullfile(getOr(dat.paths, 'globalConfig'), 'remote.mat');
+
+% Let's create a stimulus controller for this PC
+stimulusControllers = srv.StimulusControl.create(hostname, '127.0.0.1');
+
+% Save your new configuration.  Note the variable name must be as below:
+save(p, 'stimulusControllers')
+

Now simply open another instance of MATLAB and in one, run mc. In the other instance, run srv.expServer.

Etc.

Author: Miles Wells

v0.0.1

\ No newline at end of file diff --git a/docs/html/using_test_gui.html b/docs/html/using_test_gui.html index d73a1119..59d0986d 100644 --- a/docs/html/using_test_gui.html +++ b/docs/html/using_test_gui.html @@ -6,7 +6,7 @@ using_test_gui

Contents

Introduction

This document demonstrates how to test Signals Experiment Definition (expDef) functions in the test GUI. The GUI opens a PTB window and a Parameter Editor for live-updating parameters. Before opening the test GUI, loading the debug settings for PTB will make the window transparent. This is particularly useful on small screens(1).

PsychDebugWindowConfiguration
+  

Contents

Introduction

This document demonstrates how to test Signals Experiment Definition (expDef) functions in the test GUI. The GUI opens a PTB window and a Parameter Editor for live-updating parameters. Before opening the test GUI, loading the debug settings for PTB will make the window transparent. This is particularly useful on small screens(1).

PsychDebugWindowConfiguration
 

Opening your expDef in the GUI

Upon calling the eui.SignalsTest class with no inputs you will be prompted to select your function from the file browser. As with MC, the default folder location is set by the 'expDefinitions' field in dat.paths.

You can also call the function with the function name or function handle. The function must be on the MATLAB path. Let's run one of the example expDef functions: the Burgess wheel task(2) implemented in Signals.

PsychDebugWindowConfiguration % Make window transparant and turn of blocking
 root = fileparts(which('addRigboxPaths')); % Location of Rigbox root dir
 cd(fullfile(root, 'signals', 'docs', 'examples')) % Change to examples folder
@@ -75,13 +75,14 @@
 % e = eui.SignalsTest() % Opens a file navigator
 % e = eui.SignalsTest(@advancedChoiceWorld) % Function handle
 % e = eui.SignalsTest('full/path/to/expDef.m') % Absolute file path
-
+
PTB-INFO: Using modified PortAudio V19.6.0-devel, revision unknown
+
 e = 
 
   SignalsTest with properties:
 
           Hardware: [1×1 struct]
-               Ref: '2020-01-30_1_test'
+               Ref: '2020-02-19_1_test'
     LoggingDisplay: [1×1 UIControl]
           LivePlot: off
       ShowExpPanel: on
@@ -109,7 +110,6 @@
                     zero: @nop
 
 

Testing different hardware

A hardware structure can be assigned to the Hardware property of the test object (see configuring hardware devices):

e.Hardware = hw.devices;  % Assign a rig's actual hardware settings
-
Warning: hardware config not found for hostname desktop-c6p85d3 
 

Editing parameters

Parameters are shown in the eui.ParamEditor which is in the 'Parameters' box. When you select an expDef, the default parameters are loaded. These are the names and values defined in the try-catch block at the end of the expDef. Parameters can be edited before pressing start, and saved/loaded using the 'saved sets' section. Saved sets are located in the mainRepository (set in your dat.paths file), in a file called 'parameterProfiles.mat'. For more info see Using Parameters. The parameters can be updated live during the experiment. In order to do this, check 'Post new parameters on edit' in the options dialog.

Live plotting

The values of the event Signals can be plotted live by checking the LivePlot option in the Options popup.

Clicking on each subplot will cycle through the three plot modes. The default mode (0) creates a stair plot with each value update marked with an x. Mode 1 plots each value as a discrete point. Mode 2 plots a simple line, with now markers to indicate value updates. Note, if a Signal takes a vector or matrix as its value, the mode is switched to 1 and the size of the array is added as an text annotation. If the value is a charecter array, the mode is switched to 1 and the value is plotted as a text annotation. For more details on the plotting function see sig.test.timeplot.

For more about options see the help for the setOptions method.

e.setOptions % Open Options dialog
 help eui.SignalsTest/setOptions
 
  SETOPTIONS callback for 'Options' button
@@ -131,13 +131,10 @@
  
   See also SIG.TEST.TIMEPLOT, EUI.SIGNALSEXPPANEL
 
-

Experiment panel

The 'Show experiment panel' option is on by default and instantiates an experiment panel (ExpPanel) that displays Signals updates after the experiment has started. A custom ExpPanel can be defined via your expDef's 'expPanelFun' parameter, otherwise eui.SignalsExpPanel is used. For more info, see Using ExpPanel.

- -

Debugging

A number of features make debugging a little easier:

  1. The expDef is re-loaded each time you start the experiment, so you can make changes without having to reload the GUI.
  2. The parameters can be updated live during the experiment (see Editing Parmeters).
  3. You can pause and resume the experiment at any time by pressing the esc key. While paused, no Signals are updated. Note that while the experiment is running you can not use the command prompt, even when paused.
  4. Signals is run in debug mode, so the error messages printed give more informative information about the exact cause of the error. Below is an example of a typical Signals error thrown. The top of the stack gives the name of the function that threw the error, the error message and the line at which it occured. The 'Caused by' section gives the node ids involved (e.g. node 61 -> node 62), their values at the time of the error (e.g. bombWorld/timeSampler([0; 0.1; 0.09]) ), and the name and line of problem Signal in your expDef, e.g. 'Error in [...]bombWorld.m (line 22)'; pars.preStimulusDelay.map(@bombWorld/timeSampler). NB: If you call eui.SignalsTest with a function handle, the line number of your expDef can not be determined.

Error using bombWorld/timeSampler (line 183) Expected char; was double instead.

[...]

Caused by:
Error in Net 1 mapping Node 61 to 62:
function call 'bombWorld/timeSampler' with input [0; 0.1; 0.09] produced an error:
Expected char; was double instead.
Error in C:\Users\User\Documents\Github\rigbox\signals\docs\examples\bombWorld.m (line 22)
pars.preStimulusDelay.map(@bombWorld/timeSampler)

Notes

(1) These settings can be cleared by calling the Screen function:

clear Screen
+

Experiment panel

The 'Show experiment panel' option is on by default and instantiates an experiment panel (ExpPanel) that displays Signals updates after the experiment has started. A custom ExpPanel can be defined via your expDef's 'expPanelFun' parameter, otherwise eui.SignalsExpPanel is used. Note that unlike in MC, the comments box is hidden from the panel. For more info, see Using ExpPanel.

Debugging

A number of features make debugging a little easier:

  1. The expDef is re-loaded each time you start the experiment, so you can make changes without having to reload the GUI.
  2. The parameters can be updated live during the experiment (see Editing Parmeters).
  3. You can pause and resume the experiment at any time by pressing the esc key. While paused, no Signals are updated. Note that while the experiment is running you can not use the command prompt, even when paused.
  4. Signals is run in debug mode, so the error messages printed give more informative information about the exact cause of the error. Below is an example of a typical Signals error thrown. The top of the stack gives the name of the function that threw the error, the error message and the line at which it occured. The 'Caused by' section gives the node ids involved (e.g. node 61 -> node 62), their values at the time of the error (e.g. bombWorld/timeSampler([0; 0.1; 0.09]) ), and the name and line of problem Signal in your expDef, e.g. 'Error in [...]bombWorld.m (line 22)'; pars.preStimulusDelay.map(@bombWorld/timeSampler). NB: If you call eui.SignalsTest with a function handle, the line number of your expDef can not be determined.

Error using bombWorld/timeSampler (line 183) Expected char; was double instead.

[...]

Caused by:
Error in Net 1 mapping Node 61 to 62:
function call 'bombWorld/timeSampler' with input [0; 0.1; 0.09] produced an error:
Expected char; was double instead.
Error in C:\Users\User\Documents\Github\rigbox\signals\docs\examples\bombWorld.m (line 22)
pars.preStimulusDelay.map(@bombWorld/timeSampler)

Notes

(1) These settings can be cleared by calling the Screen function:

clear Screen
 % (2) <https://doi.org/10.1016/j.celrep.2017.08.047 DOI:10.1016/j.celrep.2017.08.047>
-

Etc.

Author: Miles Wells

v0.1.0

% INTERNAL:
-%  ln79 ExpPanel.png
-%  ln103-114 make red
+

Etc.

Author: Miles Wells

v0.1.0

% INTERNAL:
+%  execute code
 %#ok<*NOPTS,*NASGU,*ASGLU>
 
Visual stimuli in Signals

Visual stimuli in Signals

Signals uses the OpenGL MEX wrapper functions provided by PsychToolbox to render the visual stimuli.

In order to build up an enviroment we need to know a few things:

  1. Where are the objects (stimuli) with respect to one another in the world
  2. Where are the objects with respect to the viewer
  3. How to do these coordinates map to a 2D surface (a screen)

Thus when we define a stimulus in visual space it is transformed by our model into physical space by the model (or world-to-camera) matrix then to projected 2D space by our projection matrix. These transformations are done in the shader.

Contents

The visual stimulus object

The visual stimulus object is the 4th input to an experiment definition. It is a StructRef object, which like a structure, can be assigned fields.

vis.screen

The model produced by vis.screen is a matrix (known as the world-to-camera matrix) that transforms our world coordinates (visual degrees) to camera coodinates (the physical location of the viewer). It technically does two transforms in one: object-to-world the world-to-camera, however in our viewing model the the camera IS the world, so the object-to-world matrix is identity. See also hardware configuration:

root = fileparts(which('addRigboxPaths'));
+opentoline(fullfile(root, 'docs', 'scripts', 'hardware_config.m'), 344, 1)
+

vis.init

Loads the shader (slimshady) and initializes a projection matrix with default viewing parameters.

The viewing model is 'pseudo-circular'. An inverted spherical mesh is created using vis.uniSphereTriangles onto which all textures are painted. This is designed to compensate for the fact that the screen edges are further away than the centre when the viewer is facing the middle of the screen. As textures move further along the azimuth, they enlarge.

Plane projection

A 4x4 plane projection matrix when multiplied by a 3D coordinates in camera space gives you the 2D coordinates on the screen/projection surface. This maxtrix allows us to map 3D coordinates to images that follow the rules of perspective. Clipping happens here.

The shader

This is the job of the vertex shader. The shader's job is to transform our vertices from camera space (visual degrees) to clip space. The shader returns 'gl_Position' (an OpenGL global variable) which is the result of multiplying vertex postion by the plane projection and world-to-camera matrices. The shader applies all nessesary transformations (scaling, rotating and translating). The shader converts the vertices to homogeneous coordinates (vec4), i.e. position = [position 1]; See slimshady.vert

[Projection matrix] [World-to-camera matrix]
+       \                      /
+        \                    /
+         \                  /
+          \                /
+           \              /
+            \            /
+             \          /
+              \        /
+-------------------------------------GPU----
+                \    /
+                 \  /
+                  \/
+            [Vertex shader]

Once in clip space, the fragment shader defines its appearence (i.e. colour).

Clip space

After this plane projection we are in clip space. Here points have homogeneous (4D) coordinates.

NDC space

After the projection is divided by Clip.W leaving us in Normalized Device Space (NDC). The resulting matrix has values between [-1, 1]. Values outside of this range are outside the clipping space. In OpenGL (c.f. Direct3D) this matrix is cubic. NDC coordinates are agnostic to screen shape and always [-1, 1].

Rasterization

This step uses the view port and depth range to translate everything to fragment locations in screen/window space. This is done on the GPU.

vis.draw

  • vis.init
  • vis.screen
  • vis.loadLayerTextures
  • vis.reloadLayerTextures

Viewing model

  • vis.planeProjection
  • vis.uniSphereTriangles
  • vis.quadToTriangles

Layers

Current layers functions:

  • gaussianLayer
  • circLayer
  • rectLayer
  • crossLayer
  • sinusoidLayer
  • squareWaveLayer
  • emptyLayer
%VIS.EMPTYLAYER Template texture layer for rendering in Signals
+%  Returns a struct of paramters and their defaults used by VIS.DRAW to
+%  load a visual stimulus layer.  If n > 1 a non-scalar struct is returned
+%  of length n (default 1).
+%
+%  TODO Document viewAngle, texAngle and pos
+%  @body There is currently no information on how these three parameters
+%  are used by the viewing model.  For example, what is the practical
+%  difference between `texOffset` and `pos`, or `viewAngle` and `texAngle`?
+%
+%  See also VIS.DRAW, VIS.RGBA
+
+% Create an empty structure
+layer = struct;
+% SHOW a logical indicating whether or not the stimulus is visible
+layer.show = false;
+% TEXTUREID a char array used by VIS.DRAW to identify the texture layer.
+% Layers with unique texture data (i.e. the data stored in rgba) must have
+% unique IDs in order to be loaded into the buffer seperately.  Preceeding
+% the ID with '~' indicates that it is a dynamic texture to be loaded anew
+% each time. Dynamic textures are those where the underlying image array
+% changes.
+layer.textureId = [];
+% POS
+layer.pos = [0 0]';
+% SIZE array of the form [azimuth altitude] defining the size of the
+% texture in visual degrees
+layer.size = [0 0]';
+% VIEWANGLE The view angle in degrees
+layer.viewAngle = 0;
+% TEXANGLE the texture angle in degrees
+layer.texAngle = 0;
+% TEXOFFSET an array of the form [azimuth altitude] indicating the texture
+% offset from the centre of the viewer's visual field in visual degrees
+layer.texOffset = [0 0]';
+% ISPERIODIC logical - when true the texture is replicated across the
+% entire visual space
+layer.isPeriodic = true;
+% BLENDING char array defining the type of blending used.
+% Options:
+%  'none' (/ ''),
+%  'source' (/ 'src'),
+%  'destination' (/ 'dst'),
+%  '1-source' (/'1-src')
+layer.blending = 'source';
+% MINCOLOUR & MAXCOLOUR arrays of the form [R G B A] indicating the min
+% (max) intensity of the red, green and blue channels, along with the amout
+% of opacity (alpha).  Values must be between 0 and 1.
+layer.minColour = [0 0 0 0]';
+layer.maxColour = [1 1 1 1]';
+% COLOURMASK logical array indicating whether the red, green, blue and
+% alpha channels may be written to the frame buffer.  When any of these
+% channels are set to false no change is made to that component of any
+% pixel in any of the color buffers, regardless of any changes to the
+% texture image
+layer.colourMask = [true true true true]';
+% INTERPOLATION char array indicating the type of interpolation applied.
+% Options:
+%  'nearest' - Nearest neighbour interpolation
+%  'linear' - linear interpolation
+layer.interpolation = 'linear';
+% RGBA Column array of uint8 RGBA values for each pixel (left to right, top
+% to bottom) in the texture image. The values must be between 0 and 255.
+% For example take a matrix.  See also VIS.RGBA
+layer.rgba = [];
+% RGBASIZE array of the form [m n] where m and n are the sizes of the first
+% two dimentions of the texture image
+layer.rgbaSize = [0 0]';
+

Stimuli

Images

The function for making image textures is vis.image. Images can be arrays with values between 0-1 (MATLAB-style) or 0-255. They may be monochromatic ([m,n,1]) or be RGB(A) ([m,n,3-4]). Images can be loaded in a few different ways. If you don't intend for the underlying image to change you can pass in a path to the image:

srcImg = which('cell.tif'); % Path to image
+img = vis.image(t, srcImg);
+% The source image may be a MAT file or an image file (tiff, png, etc.)
+% If an alpha layer is present it will used.  This can be overridden by
+% providing an alpha layer as a positional argument:
+img = vis.image(t, srcImg, 1); % alpha may be scalar or array the size of img.
+% If creating more than one visual element (e.g. you have two images you
+% want to show at the same time) and are providing a source path, the names
+% of the image files must be unique.  This is because the file name is used
+% as the texture ID, which is ID used by Signals to distinguish textures.
+
+% The source image may be loaded separately and passed in the same way:
+images = load('imdemos.mat');
+img = vis.image(t, images.circles);
+
+% Finally the input may be a Signal whose value is the image array.  When
+% the source image is a Signal it is loaded as a dynamic texture (the
+% layer's textureId field starts with a '~').  This allows the source image
+% to change throughout the experiment, however if you don't intend for your
+% source image to change, consider pre-loading it like the above examples
+% as it is more efficient.
+
+% You can optionally add a Gaussian window over the image:
+img.window = 'gauss';
+img.sigma = [10 10];
+
+% The image position and size may be set as expected:
+img.dims = [40 20];
+img.orientation = 180; % upside-down
+img.azimuth = 0; % centred in x
+img.altitude = 10; % slightly elevated
+
+% The image may also be tiled across the screen by setting the repeat flag:
+img.repeat = true; % cover the whole screen with image tiles
+

Checker / sparse noise

Gabor patch & gratings

Shapes

Dynamic textures

vis.rgba & vis.rgbaFromUint8

%VIS.GRATING Returns a Signals grating stimulus defining a grating texture
+%  Produces a visual element for parameterizing the presentation of a
+%  grating. Produces a grating that can be either sinusoidal or
+%  square-wave, and may be windowed by a Gaussian stencil, producing a
+%  Gabor patch.
+%
+%  Inputs:
+%    't' - The "time" signal. Used to obtain the Signals network ID.
+%      (Could be any signal within the network - 't' is chosen by
+%      convention).
+%    'grating' - A char array defining the nature of the grating. Options
+%      are 'sinusoid' (default) or 'squarewave'.
+%    'window' - A char array defining the type of windowing applied.
+%      Options are 'gaussian' (default) or 'none'.
+%
+%  Outputs:
+%    'elem' - a subscriptable signal containing fields which parametrize
+%      the stimulus, and a field containing the processed texture layer.
+%      Any of the fields may be a signal.
+%
+%  Stimulus parameters (fields belonging to 'elem'):
+%    'grating' - see above
+%    'window' - see above
+%    'azimuth' - the azimuth of the image (position of the centre pixel in
+%     visual degrees).  Default 0
+%    'altitude' - the altitude of the image (position of the centre pixel
+%     in visual degrees). Default 0
+%    'sigma' - if window is Gaussian, the size of the window in visual
+%      degrees. Must be an array of the form [width height].
+%      Default [10 10]
+%    'phase' - the phase of the grating in visual degrees.  Default 0
+%    'spatialFreq' - the spatial frequency of the grating in cycles per
+%      visual degree.  Default 1/15
+%    'orientation' - the orientation of the grating in degrees. Default 0
+%    'colour' - an array defining the intensity of the red, green and blue
+%      channels respectively. Values must be between 0 and 1.
+%      Default [1 1 1]
+%    'contrast' - the normalized contrast of the grating (between 0 and 1).
+%      Default 1
+%    'show' - a logical indicating whether or not the stimulus is visible.
+%      Default false
+%
+%  See Also VIS.EMPTYLAYER, VIS.PATCH, VIS.IMAGE, VIS.CHECKER6, VIS.GRID
+
+
+% Map the visual element signal through the below function 'makeLayers' and
+% assign it to the 'layers' field.  When any of the above parameters takes
+% a new value, 'makeLayer' is called, returning the texture layer.
+% 'flattenStruct' returns the same texture layer but with all fields
+% containing signals replaced by their current value. The 'layers' field
+% is loaded by VIS.DRAW
+

Notes

  1. Like MATLAB OpenGl uses column-major order
  2. Camera space may also be referred to as view space
  3. In the unit cube, 1 means the object is at the far clipping plane (right up against the back-drop as it were) and -1, the near clipping plane (right up against the screen). All points visible to the camera have a negative z-component.
  4. In OpenGL (GLUT more precisely), the FOV corresponds to the vertical angle
  5. https://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/projection-matrix-introduction

Etc.

Author: Miles Wells

v0.0.1

%#ok<*NASGU,*NOPTS>
+
\ No newline at end of file diff --git a/docs/html/using_wheel.html b/docs/html/using_wheel.html new file mode 100644 index 00000000..d5e26f45 --- /dev/null +++ b/docs/html/using_wheel.html @@ -0,0 +1,272 @@ + + + + + Working with wheel data

Working with wheel data

In the Burgess wheel task a visual stimulus is yoked to LEGO wheel via a rotary encoder. Below are some things to consider when designing or modifying a wheel task. For information on setting up the rotary encoder, see Hardware Configuration: DAQ rotary encoder. For information on wiring a rotary encoder for the Burgess steering wheel task, see the Burgess hardware setup instructions .

Contents

The wheel input in Signals

There are currently three wheel-related inputs used by the Signals Experiment class. These can be accessed via a subscripted reference(1) to the 'inputs' argument of an experiment definition function (expDef) :

  1. wheel - the raw value of the rotary encoder, polled on every iteration of the main experiment loop. Each time the rotary encoder moves suffeciently it sends out a pulse. These are integrated by a counter channel and the output is seen in the wheel signal. This Signal is zero'd at the beginning of the experiment.
  2. wheelMM - the wheel movement in units of centimetres linear displacement. That is the distance the wheel would have rolled along a flat surface. This Signal is zero'd at the beginning of the experiment.
  3. wheelDeg - the wheel movement in degrees. This Signal is zero'd at the beginning of the experiment.

The wheelMM and wheelDeg signals simply map the values of wheel through a function based on information found in the hardware file's mouseInput object, namely the 'WheelDiameter' and 'EncoderResolution' properties.

Load information about the wheel from the hardware file

For a given experiment you may wish to load the hardware used, and to view the settings for the rotary encoder. Each experiment, a JSON copy of the hardware file is saved to the main repository. This preserves the settings as they were at the time the experiment ran. The below code searches for this JSON file and tries to load it. If it doesn't exist, the current hardware file is loaded instead. Some information about the rotary encoder settings are the printed.

expRef = '2019-03-28_1_default'; % Example experiment
+jsonPath = dat.expFilePath(expRef, 'hw-info', 'master', 'json');
+if exist(jsonPath, 'file') % Check is hardware JSON exists
+  % If the JSON file exists load that as the wheel may have sinced changed
+  rig = jsondecode(fileread(jsonPath));
+else
+  % Otherwise load the existing harware file
+  rigName = 'exampleRig';
+  rig = hw.devices(rigName, false);
+end
+
+% Print some info:
+D = rig.mouseInput.WheelDiameter;
+res = rig.mouseInput.EncoderResolution;
+a = rig.mouseInput.MillimetresFactor;
+fprintf(['Details for experiment <strong>%s</strong>:\n'...
+  'Wheel diameter (mm): %.1f, '...
+  'encoder resolution: %d, '...
+  'calculated millimetres factor: %.4f\n'], expRef, D, res, a)
+

Load the wheel data

If availiable, load the auto-extracted ALF file as the data is quicker to load, in centimeters linear displacment units and resampled evenly at 1000Hz.

expPath = dat.expPath(expRef, 'main', 'master');
+files = dir(expPath);
+Fs = 1000; % Frequency to resample at
+if any(endsWith({files.name}, 'wheel.position.npy'))
+  fullFileFn = @(nm) readNPY(fullfile(expPath, endsWith({files.name}, nm)));
+  pos = fullFileFn('wheel.position.npy'); % in cm
+  rawT = fullFileFn('wheel.timestamps.npy'); % in sec
+  vel = fullFileFn('wheel.velocity.npy'); % in cm/sec
+  t = (rawT(1,2):1/Fs:rawT(2,2))';
+else % Otherwise load from block file and preprocess
+  data = dat.loadBlock(expRef);
+  pos = data.inputs.wheelValues; % in samples
+  tRaw = data.inputs.wheelTimes; % in sec
+  % Resample values
+  t = 0:1/Fs:tRaw(end);
+  pos = interp1(tRaw, pos, t);
+  % Correct for over-/underflow
+  pos = wheel.correctCounterDiscont(pos);
+end
+

Convert to linear displacement (cm)

If the units are in samples (i.e. loaded from inputs.wheel or inputSensorPos), convert to units of centimetres linear displacement. That is the distance the wheel would have rolled along a flat surface.

posCM = (rig.mouseInput.MillimetresFactor/10) .* pos; %#ok<*NASGU>
+% or alternatively
+res = rig.mouseInput.EncoderResolution*4; % Resolution * 4 for '4X' encoders
+D = rig.mouseInput.WheelDiameter/10; % Converted to cm from mm
+posCM = pos./res * pi * D;
+
+% The velocity is the derivative of this, so it's the tangential velocity
+% in cm/sec
+smoothSize = 0.03; % Gaussian smoothing window
+[vel, acc] = wheel.computeVelocity2(pos, smoothSize, Fs);
+

Convert to angular displacement (rad)

For angular displacement / velocity, just divide by the wheel radius

posRad = posCM / 0.5*D; % in radians
+velAng = vel / 0.5*D; % in rad/sec
+

Convert to angular displacement (RPM)

Convert this to the more intuitive revolutions per minute:

RPM = velAng*60 / 2*pi;
+

Convert to angular displacement (deg)

For displacement in degrees:

posDeg = rad2deg(posRad);
+velDeg = rad2deg(velAng);
+% or...
+posDeg = pos / res*360;
+

Convert to azimuth (visual degrees)

If you know the response threshold in visual degrees, you can convert this to visual degrees.

thresh = 35; % visual degrees azimuth
+% Position relative to interactive on
+pos = pos - pos(1);
+% Distance moved in whatever units
+dist = diff([pos(1) pos(end)]);
+% Convert to visual degrees moved, assuming correct is an element of [-1 0
+% 1]
+posAzi = (pos/abs(dist) * thresh) - (sign(dist) * sign(correct) * thresh);
+velAzi = (vel/abs(dist) * thresh) - (sign(dist) * sign(correct) * thresh);
+

Notes

(1) e.g. 'inputs.foo'. This is know as dot notation. More info here .

Etc.

Author: Miles Wells

v1.0.0

\ No newline at end of file diff --git a/docs/html/websocket_config.html b/docs/html/websocket_config.html index f6a7fbaa..1b65dc72 100644 --- a/docs/html/websocket_config.html +++ b/docs/html/websocket_config.html @@ -6,7 +6,7 @@ Introduction

Introduction

Once the hardware files are set up for srv.expServer and mc, it is necessary to configure the websockets so that the two computers can connect to one another. This connection serves a few purposes:

  1. To start and stop experiments via the MC GUI (currently the only way to do so).
  2. To monitor the experiment, e.g. the current parameters, trial number, reward total, etc.
  3. To send an Alyx instance so that the stimulus computer can register its files to the database.

Contents

Configuring WebSockets

In order for the two computers to communicate...

% The stimulus controllers are loaded from a MAT file with the name
+  

Introduction

Once the hardware files are set up for srv.expServer and mc, it is necessary to configure the websockets so that the two computers can connect to one another. This connection serves a few purposes:

  1. To start and stop experiments via the MC GUI (currently the only way to do so).
  2. To monitor the experiment, e.g. the current parameters, trial number, reward total, etc.
  3. To send an Alyx instance so that the stimulus computer can register its files to the database.

Contents

Configuring WebSockets

This section demonstrates how to configure WebSockets so that MC can connect to the Stimulus computer. See this guide if you wish to configure things for running mc and srv.expServer on the same computer (not recommended).

% The stimulus controllers are loaded from a MAT file with the name
 % 'remote' in the globalConfig directory, defined in dat.paths:
 p = fullfile(getOr(dat.paths, 'globalConfig'), 'remote.mat');
 
@@ -91,7 +91,13 @@
 rig2 = strcmp('rig2', {stimulusControllers.Name});
 stimulusControllers(rig2).DefaultPort % *2014
 stimulusControllers(rig2).Uri % 'ws://192.168.0.1:5000'
-

Experiment delays

Setting default delays is sometimes useful. These can also be changed in the 'rig options' dialog in MC. The ExpPreDelay property is the time in seconds to wait between starting the services and initializing the experiment object, and actually beginning the experiment (for a Signals experiment this means updating the 'events.expStart' signal). Hence if the pre-delay is 5 seconds then the inputs, parameters and time signals are updated in the main loop for 5 seconds before the first trial officially begins. This can be useful when an auxiliary recording device takes some time to initialize, or if you want to record some sort of baseline activity before the first stimulus appears. It also ensures that everything is running smoothly before the first trial (sometimes there are suspect timings on the first propogation through the network).

stimulusControllers(end).ExpPreDelay = 10; % Initialize then wait 10s
+

The port set in the URI of a rig's StrimulusControl object must be the same as the port used by that rig's srv.expServer. When expServer is started it listens on the default port (normally 2014). If you wish to set a port that is different to the default port, you must save a Communicator object into the rig's hardware file and set it there. Below is some code for setting the default port to 3000 on a Stimulus Computer:

% Create a communicator object (var name must be 'communicator')
+communicator = io.WSJCommunicator.server(3000);
+
+% Save into the hardware file
+hardware = fullfile(getOr(dat.paths, 'rigConfig'), 'hardware.mat');
+save(hardware, 'communicator', '-append') % append to the hardware file
+

Experiment delays

Setting default delays is sometimes useful. These can also be changed in the 'rig options' dialog in MC. The ExpPreDelay property is the time in seconds to wait between starting the services and initializing the experiment object, and actually beginning the experiment (for a Signals experiment this means updating the 'events.expStart' signal). Hence if the pre-delay is 5 seconds then the inputs, parameters and time signals are updated in the main loop for 5 seconds before the first trial officially begins. This can be useful when an auxiliary recording device takes some time to initialize, or if you want to record some sort of baseline activity before the first stimulus appears. It also ensures that everything is running smoothly before the first trial (sometimes there are suspect timings on the first propogation through the network).

stimulusControllers(end).ExpPreDelay = 10; % Initialize then wait 10s
 
 % Likewise the ExpPostDelay is the time in seconds between the experiment
 % ending (i.e. the events.expStop signal updating), and the stop command
@@ -103,18 +109,17 @@
 % Trigger ExperimentEnded event, wait 30s then trigger the
 % ExperimentCleanup event:
 stimulusControllers(end).ExpPostDelay = 30;
-

Saving & loading

% Save your new configuration.  Note the variable name must be as below:
+

Saving & loading

% Save your new configuration.  Note the variable name must be as below:
 save(p, 'stimulusControllers')
 
 % The stimulus controllers can be loaded using the srv.stimulusControllers
 % function.  If no remote file exists, a default StimulusControl object is
 % returned.
 sc = srv.stimulusControllers;
-

Using Websockets

The stimulusControllers list will appear in the 'rig' drop-down list in MC, allowing you to choose which one to connect to and where to start an experiment. In this way you can manage multiple experiments from one computer.

The Websockets are set up automatically when you run MC and srv.expServer, however you can use these for your own code if you wish. Below is some information on using the Websockets and the +io package.

The srv.StimulusControl object builds on the io.WSJCommunicator object by adding extra events and useful properties such as the Status property. Let's look at the lower level classes first:

One computer should be running as a server and another as a client. The relationship is many-to-one in that a client may connect to only one server at a time, while a server may broadcast to any number of clients. Hence an number of MC computers (clients) can listen for experiment updates from a particular rig (server).

You can test this class by running the two on the same computer. Thi must be done in two different instances of MATLAB.

- Server

server = io.WSJCommunicator.server()
+

Using Websockets

The stimulusControllers list will appear in the 'rig' drop-down list in MC, allowing you to choose which one to connect to and where to start an experiment. In this way you can manage multiple experiments from one computer.

The Websockets are set up automatically when you run MC and srv.expServer, however you can use these for your own code if you wish. Below is some information on using the Websockets and the +io package.

The srv.StimulusControl object builds on the io.WSJCommunicator object by adding extra events and useful properties such as the Status property. Let's look at the lower level classes first:

One computer should be running as a server and another as a client. The relationship is many-to-one in that a client may connect to only one server at a time, while a server may broadcast to any number of clients. Hence an number of MC computers (clients) can listen for experiment updates from a particular rig (server).

You can test this class by running the two on the same computer. Thi must be done in two different instances of MATLAB.

- Server

server = io.WSJCommunicator.server()
 
 server.open() % Start listening on default port 2014
-server.wtf % Get status of socker, e.g. OPEN
-server.WebSocket.isOpen % Similar status but as a bool
+server.wtf % Get status of socket, e.g. OPEN
 
 % When EventMode is set to false (default), the message is kept in the
 % buffer.  Checking for messages can be done by looking at the
@@ -132,7 +137,7 @@
   'Message with id %s from %s with the following data %s', ...
   evt.Id, evt.Sender, toStr(evt.Data));
 el = event.listener(server, 'MessageReceived', callback); % Display message ids
-

- Client

ip = ipaddress; % This computer's IP
+

- Client

ip = ipaddress; % This computer's IP
 client = io.WSJCommunicator.client(ip)
 
 client.open() % Open the connection
@@ -140,9 +145,9 @@
 client.WebSocket.isOpen % Similar status but as a bool
 client.send('test message', randi(100,1,5))
 % Sending uses the function hlp_serialize
-

- Close connections

client.close()
+

- Close connections

client.close()
 server.close()
-

Stimulus Controller

The srv.StimulusControl class methods are pretty self explanatory...

  • create - As seen above this is the constructor
  • connect - Bind web socket. Calls io.WSJCommunicator/open()
  • disconnect - Unbind. Sends 'goodbye' message then calls io.WSJCommunicator/close()
  • startExperiment - Called with an expRef and, optionally, an Alyx instance. Sends both to the remote host with the message id 'run'
  • quitExperiment - Called with a flag to indicate an abort or not. If true the experiment 'aborts', otherwise it's end status is set to 'end'. Currently the behaviours of these two are identical. It may be that in the future this flag will determine whether expServer waits for the trial to end before quitting. Sends 'quit' message id

expServer messages

When a new messages arrives it is expected to be one of the IDs mentioned below. These usually leads to listeners to one of the events being notfied. The listener callbacks are called with an event object of the class srv.ExpEvent, which are like regular event objects but have three properties: Name, Ref and Data, which may be used by the callback functions.

The following IDs are expected:

- signals

This id means an experiment update from a currently running signals object (exp.SignalsExp) has arrived. Listeners to the ExpUpdate event are notified with a 'signals' ExpEvent. In MC the listeners to this are obejects of the eui.ExpPanel class, e.g. eui.squeakExpPanel. These panel objects plot and display the update data.

- status

Messages with this id are usually sent before and after an experiment or in the case of 'update' messages, they indicate a new phase of the experiment (in legacy experiments such as exp.ChoiceWorld only. The data object is expected to be a cell array with at least two elements. The first is the status, which may be one of the following:

  1. starting - Indicates that expServer received the message and is able to begin the experiment. data{2} contains the expRef of the experiment. Listeners of the ExpStarting event are notified with a 'starting' ExpEvent.
  2. completed - Indicates that the experiment stopped without any exceptions. data{2} contains the expRef of the experiment. Listeners of the ExpStopped event are notified with a 'completed' ExpEvent.
  3. expException - Indicates that the experiment stopped because of an uncaught error. data{2} contains the expRef of the experiment; data{3} contains the error message from the MException object. Listeners of the ExpStopped event are notfied with an 'exception' ExpEvent. The event object's Data field contains the error message.
  4. update - Indicates a new phase of the experiment. data{2} contains the expRef of the experiment; data{3} contains a cell array. This may be the name of the new phase (e.g. 'feedback', 'interactive'), in which case listeners of the ExpUpdate event are notified with an 'update' ExpEvent. One special case is when data{3} contains the string 'event', iindicating that the experiment has finished initializing and has now officially started (sent after the experiment pre-delay has ended). In this case the ExpUpdate event listeners are notified with a 'started' ExpEvent.

- AlyxRequest

expServer requested the AlyxInstance. Data = an experiment reference string. The object will return whatever is in the AlyxInstance property at that time and notify listeners of the AlyxRequest event.

Schematic

Below is a schematic of the messages between MC and srv.expServer. The words within the dashed lines are the message ids. The works in brackets to the right of the '<<' arrows are the messages / data that are sent alongside the message id. The words on the left in brackets are the actions that cause, or are a response to, a message.

%       MC                                           srv.expServer
+

Stimulus Controller

The srv.StimulusControl class methods are pretty self explanatory...

  • create - As seen above this is the constructor
  • connect - Bind web socket. Calls io.WSJCommunicator/open()
  • disconnect - Unbind. Sends 'goodbye' message then calls io.WSJCommunicator/close()
  • startExperiment - Called with an expRef and, optionally, an Alyx instance. Sends both to the remote host with the message id 'run'
  • quitExperiment - Called with a flag to indicate an abort or not. If true the experiment 'aborts', otherwise it's end status is set to 'end'. Currently the behaviours of these two are identical. It may be that in the future this flag will determine whether expServer waits for the trial to end before quitting. Sends 'quit' message id

expServer messages

When a new messages arrives it is expected to be one of the IDs mentioned below. These usually leads to listeners to one of the events being notfied. The listener callbacks are called with an event object of the class srv.ExpEvent, which are like regular event objects but have three properties: Name, Ref and Data, which may be used by the callback functions.

The following IDs are expected:

- signals

This id means an experiment update from a currently running signals object (exp.SignalsExp) has arrived. Listeners to the ExpUpdate event are notified with a 'signals' ExpEvent. In MC the listeners to this are objects of the eui.ExpPanel class, e.g. eui.SignalsExpPanel. These panel objects plot and display the update data.

- status

Messages with this id are usually sent before and after an experiment or in the case of 'update' messages, they indicate a new phase of the experiment (in legacy experiments such as exp.ChoiceWorld only. The data object is expected to be a cell array with at least two elements. The first is the status, which may be one of the following:

  1. starting - Indicates that expServer received the message and is able to begin the experiment. data{2} contains the expRef of the experiment. Listeners of the ExpStarting event are notified with a 'starting' ExpEvent.
  2. completed - Indicates that the experiment stopped without any exceptions. data{2} contains the expRef of the experiment. Listeners of the ExpStopped event are notified with a 'completed' ExpEvent.
  3. expException - Indicates that the experiment stopped because of an uncaught error. data{2} contains the expRef of the experiment; data{3} contains the error message from the MException object. Listeners of the ExpStopped event are notfied with an 'exception' ExpEvent. The event object's Data field contains the error message.
  4. update - Indicates a new phase of the experiment. data{2} contains the expRef of the experiment; data{3} contains a cell array. This may be the name of the new phase (e.g. 'feedback', 'interactive'), in which case listeners of the ExpUpdate event are notified with an 'update' ExpEvent. One special case is when data{3} contains the string 'event', iindicating that the experiment has finished initializing and has now officially started (sent after the experiment pre-delay has ended). In this case the ExpUpdate event listeners are notified with a 'started' ExpEvent.

- AlyxRequest

expServer requested the AlyxInstance. Data = an experiment reference string. The object will return whatever is in the AlyxInstance property at that time and notify listeners of the AlyxRequest event.

Schematic

Below is a schematic of the messages between MC and srv.expServer. The words within the dashed lines are the message ids. The works in brackets to the right of the '<<' arrows are the messages / data that are sent alongside the message id. The words on the left in brackets are the actions that cause, or are a response to, a message.

%       MC                                           srv.expServer
 % -------------------------------------------------------------------------
 % [rig selected]-------------status------> +    [check if exp running]
 %                                          |               | <false>
@@ -181,8 +186,8 @@
 % [notify user]
 %
 %   [quit mc]-------------------goodbye--> +       [log: disconnected]
-

UDP communication & Services

You can also add a list of auxiliary service ids to the Services property of your StimulusControl objects. This list will show up in the 'rig options' dialog in MC, allowing you to select which services to activate for a given experiment. For information on controlling auxiliary software devices during an experiment see using_services

Debugging

University networks are often quite complicated and operating within various firewalls and workgroups or within an intranet can cause problems. These Websockets just use a basic TCP/IP protocol and therefore you (or your IT administrator) should be able to diagnose any issues with the below information.

If you can get your computers to show up in each other's Windows network list then there's a very good chance the Websockets will work. Sometimes Windows fails to resolve a given hostname (i.e. computer name) so trying the IP address first is more reliable. You can find your computer's IP address by searching 'what is my IP' online.

Sometimes the defualt port of 2014 is in use by another program, in which case you may see the following error:

Error using io.WSJCommunicator/startClient (line 194)
-Could not connect to 'ws://128.40.198.177:2014'

Try setting a different port (anthing between 1024-49151 should be safe). This is done by either adding/changing the port to the end of the Uri property, after a colon, or by setting the DefaultPort property. The latter is only used in the Uri doesn't already have a port.

Sometimes when you can't connect to a remote computer it's because the remote computer failed to start the connection. When this happens the following may be printed to the command window:

onError: java.net.BindException: Address already in use: bind

This usually means that the previous time you opened a socket it was not closed properly. Restarting MATLAB and/or clearing java may resolve the issue.

- Stimulus server

clear all; clear java % Make sure everything is cleared
+

UDP communication & Services

You can also add a list of auxiliary service ids to the Services property of your StimulusControl objects. This list will show up in the 'rig options' dialog in MC, allowing you to select which services to activate for a given experiment. For information on controlling auxiliary software devices during an experiment see using_services

Debugging

University networks are often quite complicated and operating within various firewalls and workgroups or within an intranet can cause problems. These Websockets just use a basic TCP/IP protocol and therefore you (or your IT administrator) should be able to diagnose any issues with the below information.

If you can get your computers to show up in each other's Windows network list then there's a very good chance the Websockets will work. Sometimes Windows fails to resolve a given hostname (i.e. computer name) so trying the IP address first is more reliable. You can find your computer's IP address by searching 'what is my IP' online.

Sometimes the defualt port of 2014 is in use by another program, in which case you may see the following error:

Error using io.WSJCommunicator/startClient (line 194)
+Could not connect to 'ws://128.40.198.177:2014'

Try setting a different port (anthing between 1024-49151 should be safe). This is done by either adding/changing the port to the end of the Uri property, after a colon, or by setting the DefaultPort property. The latter is only used in the Uri doesn't already have a port.

Sometimes when you can't connect to a remote computer it's because the remote computer failed to start the connection. When this happens the following may be printed to the command window:

onError: java.net.BindException: Address already in use: bind

This usually means that the previous time you opened a socket it was not closed properly. Restarting MATLAB and/or clearing java may resolve the issue.

- Stimulus server

clear all; clear java % Make sure everything is cleared
 system('netstat -nao | find ":2014"'); % Should return nothing
 com = io.WSJCommunicator.server; % Create server object
 com.EventMode = true; % Allows us to create callback listeners
@@ -193,7 +198,7 @@
 % Example:
 %  TCP    0.0.0.0:2014           0.0.0.0:0              LISTENING       26756
 %  TCP    [::]:2014              [::]:0                 LISTENING       26756
-

- MC computer

clear all; clear java % Make sure everything is cleared
+

- MC computer

clear all; clear java % Make sure everything is cleared
 system('netstat -nao | find ":2014"'); % Should return nothing
 % Check this matches exactly to computer name in
 % Control Panel --> All Control Panel Items --> System
@@ -205,9 +210,9 @@
 %  TCP    128.40.198.140:2014    128.40.198.162:49458   ESTABLISHED     6640
 
 com.send('hello', []) % Should display 'hello' on stimulus computer
-

- Clean up

close(com); delete(com); clear all; clear java
-

Etc.

Author: Miles Wells v1.0.0

%#ok<*NOPTS,*ASGLU,*NASGU,*CLJAVA,*CLALL>
-
'; +pos = 17; + +T = readFile(filename); +T = insert(T, subStr, pattern, pos); +writeFile(filename, T) + +%% using_test_gui.html +% Colour error text +filename = 'using_test_gui.html'; +pattern = '

Error using bombWorld/timeSampler'; +subStr = '

';
+
+T = readFile(filename);
+T = insert(T, subStr, pattern, 'before');
+T = insert(T, '
', 'timeSampler)

', 'after'); +% Add breaks +lines = {... + '

Caused by:'... + 'mapping Node 61 to 62:'... + 'input [0; 0.1; 0.09] produced an error:'... + ' Expected char; was double instead.'... + 'examples\bombWorld.m (line 22)'}; +for l = lines + T = insert(T, '
', l, 'after', 1); +end +writeFile(filename, T) + + +%% Helpers +function T = readFile(filename) +% Load file +fid = fopen(filename,'r'); +i = 1; +tline = fgetl(fid); +T{i} = tline; +while true + i = i+1; + tline = fgetl(fid); + if tline == -1 + break + else + T{i} = tline; + end +end +fclose(fid); +end + +function T = insert(T, subStr, pattern, pos, n) +% INSERT Insert text into one line +% Inputs: +% T (cellstr): A cell array of lines from a file +% subStr (char): The str to insert +% pattern (char): The search pattern +% pos (int|char): The postion with respect to the search pattern where +% to insert subStr. Either an index location in pattern, or 'first' +% / 'last'. +% n (int): The number in the order of pattern matches to insert subStr. +% Default assumes only one instance of pattern. +if nargin < 4 || isempty(pos), pos = 'after'; end +if nargin < 5, n = 1; end + +% Find line +idx = strfind(T, pattern); +if nargin < 5 + assert(sum(cellfun(@numel,idx)) == 1) +else + assert(sum(cellfun(@numel,idx)) >= n) +end +ln = find(~cellfun('isempty', idx), n, 'first'); + +% Modify +switch pos + case 'before' + T{ln(n)} = insertBefore(T{ln(n)}, pattern, subStr); + case 'after' + T{ln(n)} = insertAfter(T{ln(n)}, pattern, subStr); + otherwise + startIdx = cell2mat(idx) + pos; + T{ln(n)} = [T{ln(n)}(1:startIdx-1) subStr T{ln(n)}(startIdx:end)]; +end + +end + +function writeFile(filename, T) +% Write back into file +fid = fopen(filename, 'w'); +for i = 1:numel(T) + if i == numel(T) + fprintf(fid,'%s', T{i}); + break + else + fprintf(fid,'%s\n', T{i}); + end +end +end \ No newline at end of file diff --git a/docs/scripts/glossary.m b/docs/scripts/glossary.m new file mode 100644 index 00000000..06da87dc --- /dev/null +++ b/docs/scripts/glossary.m @@ -0,0 +1,93 @@ +%% Glossary +% Below is a list of terms and their meaning, along with some links for +% finding out more information. + +%% ALF +% ALF stands for 'ALyx File'. + +%% Alyx +% + +%% Block file +% The 'block' file is a MAT file that contains most of the data acquired +% during an experiment. It is saved by the Experiment class upon +% experiment quit and follows the following file name pattern: +% |yyyy-mm-dd_n_subject_Block.mat|. +% +% See also dat.paths, loading_experiment_data + +%% Experiment Definition (expDef) +% The experiment definition function (expDef) is a user-created function +% that the Signals Experiment class uses to map the hardware inputs to the +% outputs. The function has the following signature: +% +% function exampleWorld(t, evts, p, vs, in, out, audio) +% [...] +% end +% +% See also SignalsPrimer2? + +%% Experiment Framework +% The 'Experiment Framework' is everything defined by the |exp.Experiment| +% base class. This class defines some basic methods (e.g. run, quit, +% saveDave, useRig) and 'experiment phases' (experimentInit, +% experimentStarted, experimentEnded) within which stuff happens and +% updates are broadcast to any listener such as MC. An Experiment object +% stores and uses various objects throughout the experiment, for instance +% an |exp.ConditionServer| object that manages the trial parameter +% conditions and an |io.Communicator| that manages the sending of updates +% to remote listeners. All experiments run in Rigbox (i.e. via mc and/or +% srv.expServer) use this framework. +% +% |exp.SignalsExp| extends this framework to use Signals for implementing a +% user defined experiment function (expDef). NB: Signals can be set up and +% used outside of this framework. For an example of this, see +% |signals/docs/example/ringach98.m| +% +% For more info, see the Experiment package: +helpwin +exp + +%% Experiment Reference String (expRef) +% An 'experiment reference string' or 'expRef' (sometimes just 'ref') is +% a char array of the form |yyyy_mm_dd_n_subject|. These are unique, +% human-readable references to an experiment session. Whenever an +% experiment is started in |mc|, a new expRef is created, reflecting the +% folder structure of the main repository, where the parameter set is +% saved. +% +% See <./using_dat_package.html The Data Package> + +%% expServer +% |srv.expServer| is the function that loads rig hardware and allows users +% to run experiments either locally or via MC. + +%% Main Repository +% The 'main experiment repository' or 'main repo' is the primary location +% where your experiment data is saved. It is the 'mainRepository' field +% returned by |dat.paths| (defined in your |+dat/paths.m| file). When new +% experiments are created, a parameter set is saved into this location +% according to the following directory structure: subject/date/number. +% |srv.expServer| looks in this location when loading parameters for a +% given experiment, and saves the main data files here. +% +% See also dat_package, dat.expExists + +%% Master Computer (MC) +% The computer that controls the starting and stopping of experiments. +% This computer runs the |mc| function, which creates a GUI for doing this. + +%% mc +% |mc| is the function used for logging, parameterizing and creating new +% experiments. + +%% Stimulus Computer (SC) +% The 'stimulus computer', 'stim server' or 'SC' is the computer that runs +% |srv.expServer| and produces visual and auditory stimuli. All hardware +% devices used during an experiment are configured for this computer. + +%% Etc. +% <./index.html Home> +% +% Author: Miles Wells +% +% v1.0.0 diff --git a/docs/setup/hardware_config.m b/docs/scripts/hardware_config.m similarity index 98% rename from docs/setup/hardware_config.m rename to docs/scripts/hardware_config.m index 640cc7db..b6882cd5 100644 --- a/docs/setup/hardware_config.m +++ b/docs/scripts/hardware_config.m @@ -46,8 +46,8 @@ % For more info on setting the paths and using the DAT package: rigbox = getOr(dat.paths, 'rigbox'); % Location of Rigbox code -open(fullfile(rigbox, 'docs', 'setup', 'paths_config.m')) -open(fullfile(rigbox, 'docs', 'using_dat_package.m')) +open(fullfile(rigbox, 'docs', 'scripts', 'paths_config.m')) +open(fullfile(rigbox, 'docs', 'scripts', 'using_dat_package.m')) %% Configuring the stimulus window % The +hw Window class is the main class for configuring the visual @@ -455,7 +455,7 @@ %% Timeline % Timeline unifies various hardware and software times using a DAQ device. -% There is a separate guide for Timeline <./using_timeline.html here>. +% There is a separate guide for Timeline <./Timeline.html here>. doc hw.Timeline % Let's create a new object and configure some channels @@ -499,8 +499,8 @@ save(hardware, 'timeline', '-append') % For more information on configuring and using Timeline, see -% USING_TIMELINE: -open(fullfile(getOr(dat.paths,'rigbox'), 'docs', 'using_timeline.m')) +% TIMELINE: +open(fullfile(getOr(dat.paths,'rigbox'), 'docs', 'scripts', 'Timeline.m')) %% Weigh scale % MC allows you to log weights through the GUI by interfacing with a @@ -661,6 +661,6 @@ %% Etc. % Author: Miles Wells % -% v1.1.0 +% v1.1.1 %#ok<*NOPTS,*NASGU,*ASGLU> diff --git a/docs/scripts/id_index.m b/docs/scripts/id_index.m new file mode 100644 index 00000000..b2f84c54 --- /dev/null +++ b/docs/scripts/id_index.m @@ -0,0 +1,301 @@ +%% Error and warning IDs +% Below is a list of Rigbox error & warning IDs. This list is currently +% incomplete and there aren't yet very standard. Typically the ID has the +% following structure: module:package:function:error +% +% These are here for search convenience and may soon contain more detailed +% troubleshooting information. + +%% copyPaths +% +% *Problem*: +% +% In order to load various essential configuration files, and to load and +% save experimental data, user specific paths must be retrieved via calls +% to |dat.paths|. This error means the function is not on MATLAB's search +% path. +% +% *Solution*: +% +% Add your |+dat\paths.m| file to MATLAB's search path. A template is +% present in |docs\setup\paths_template.m|. This file is automatically +% copied by addRigboxPaths to |+dat\|. If you haven't already done so, run +% |addRigboxPaths| to ensure all other paths have been correctly set. +% +% See also README.md for further setup information. +% +% *IDs* +% +% Rigbox:git:update:copyPaths +% signals:test:copyPaths +% + + +%% noRemoteFile +% *Problem*: +% % TODO Add problem & solution for noRemoteFile error +% +% *Solution*: +% +% +% *IDs* +% +% Rigbox:mc:noRemoteFile + +%% notInTest +% *Problem*: +% +% This occurs when a mock function is called when the INTEST global +% variable is not set. These mock functions shadow Rigbox and builtin +% functions, meaning they have the same name. +% +% *Solution*: +% +% If this function was called during a test, add the following to the top +% of your test or in the constructor: +% +% global INTEST +% INTEST = true +% +%% +% Ensure that this is cleared during the teardown: +% +% addteardown(@clear, INTEST) % If in a class +% mess = onCleanup(@clear, INTEST) % If in a function +% +%% +% If the mock in question is a class, set the InTest flag instead of the +% global variable: +% +% mock = MockDialog; % An example using MockDialog class +% mock.InTest = true; +% addteardown(@clear, MockDialog) % Clear mock class when done +% mess = onCleanup(@clear, MockDialog) % If in a function +% +%% +% If you are in not running tests, ensure that tests/fixtures is not in +% your MATLAB path and that you are in a different working directory. It +% is best to remove all Rigbox paths and readd them using `addRigboxPaths` +% +% *IDs* +% +% Rigbox:tests:system:notInTest +% Rigbox:tests:modDate:notInTest +% Rigbox:tests:paths:notInTest +% Rigbox:tests:pnet:notInTest +% Rigbox:tests:modDate:notInTest +% Rigbox:MockDialog:newCall:notInTest + +%% behaviourNotSet +% *Problem*: +% +% A mock function was called while in a test, however the behaviour for +% this particular input has not been defined. +% +% *Solution*: +% +% If not testing a specific behavior for this function's output, simply +% supress the warning in your test, remembering to restore the warning +% state: +% +% origState = warning; +% addteardown(@warning, origState) % If in a class +% mess = onCleanup(@warning, origState) % If in a function +% warning('Rigbox:MockDialog:newCall:behaviourNotSet', 'off') +% +%% +% If you're specifically testing the behavior when the mock returns a +% particular output then check that you've set the input-output map +% correctly: usually this is done by first calling the mock with input +% identical to function under test as well as the output you want to see. +% Check the input is formatted correctly. For more information see the +% help of the particular mock you are using. +% +% *IDs* +% +% Rigbox:tests:system:valueNotSet % TODO change name +% Rigbox:MockDialog:newCall:behaviourNotSet +% + +%% mkdirFailed +% *Problem*: +% +% MATLAB was unable to create a new folder on the system. +% +% *Solution*: +% +% In general Rigbox code only creates new folders when a new experiment is +% created. The folders are usually created in the localRepository and +% mainRepository locations that are set in your paths file. If either of +% these are remote (e.g. a server accessed via SMB) check that you can +% navigate to the location in Windows' File Explorer (sometimes the access +% credentials need setting first). If you can, next check the permissions +% of these locations. If the folders are read-only, MATLAB will not be +% able to create a new experiment folder there. Either change the +% permissions or set a different path in |dat.paths|. One final thing to +% check is that the folder names are valid: the presence of a folder that +% is not correctly numbered in the subject's date folder may lead to an +% invalid expRef. Withtin a date folder there should only be folders name +% '1', '2', '3', etc. +% +% *IDs* +% +% Alyx:newExp:mkdirFailed +% Rigbox:dat:newExp:mkdirFailed +% + +%% newExp:expFoldersAlreadyExist +% *Problem*: +% +% The folder structure for a newly generated experiment reference is +% already in place. +% +% Experiment references are generated based on subject name, today's date +% and the experiment number, which is found by looking at the folder +% structure of the main repository. In a subject's experiment folder for +% a given date there are numbered folders. When running a new experiment, +% the code takes the folder name with the largest number and adds 1. It +% then checks that this numbered folder doesn't exist in the other +% repositories. If it does, an error is thrown so that no previous +% experiment data is overwritten. +% +% *Solution*: +% +% Check the folder structure for all your repositories (namely the +% localRepository and mainRepository set in |dat.paths|). It may be that +% there is an empty experiment folder in the localRepository but not the +% mainRepository, in which case you can delete it. Alternatively, if you +% find a full experiment folder in the local but not the main, copy it +% over so that the two match. This will avoid a duplicate expRef being +% created (remember, new expRefs are created based on the folder structure +% of the mainRepository only). +% +% *IDs* +% +% Alyx:newExp:expFoldersAlreadyExist +% Rigbox:dat:newExp:expFoldersAlreadyExist +% + +% ..:..:expRefNotFound +% *Problem*: +% +% The experiment reference string does not correspond to the folder +% structure in your mainRepository path. Usually determined via a call to +% |dat.expExists|. +% +% *Solution*: +% +% Check that the mainRepository paths are the same on both the computer +% that creates the experiment (e.g. MC) and the one that loads the +% experiment (e.g. the one that runs |srv.expServer|). For an experiment +% to exist, the subject > date > sequence folder structure should exist in +% the mainRepository. To see the mainRepository location, run the +% following: +% +% getOr(dat.paths, 'mainRepository') +% +%% +% For example if the output is |\\server\Subjects\| then for the expRef +% '2019-11-25_1_test' to exist, the following folder should exist: +% |\\server\Subjects\test\2019-11-25\1| +% +% *IDs* +% +% Rigbox:srv:expServer:expRefNotFound + +%% ----- ! PTB - ERROR: SYNCHRONIZATION FAILURE ! ---- +% *Problem*: +% +% To quote PsychToolbox: One or more internal checks indicate that +% synchronization of Psychtoolbox to the vertical retrace (VBL) is not +% working on your setup.This will seriously impair proper stimulus +% presentation and stimulus presentation timing! +% +% *Solution*: +% +% There are many, many reasons for this error. Here's a quick list of +% things to try, in order: +% +% # Simply re-trying a couple of times. Sometimes it happens +% sporadically. +% # Check the monitor(s) are on and plugged in. If you're using +% multiple monitors they should be of the same make and model. If they +% aren't, try with just one monitor first. +% # If you're using multiple screens in NVIDEA's 'Mosaic' mode, the +% settings may have changed: sometimes Mosiac becomes deactivated and you +% should set it up again. +% # If you're using a remote connection for that computer it may be +% interfering with the graphics settings. Examples of a remote +% connection include VNC servers, TeamViewer and Windows Remote Desktop. +% Try opening the PTB Window without any of these remote services. +% # Update the graphics card drivers and firmware. This often helps. +% # Read the PTB docs carefully and follow their suggestions. The docs +% can be found at http://psychtoolbox.org/docs/SyncTrouble. +% # If all else fails. You can skip these tests and check that there is +% no taring manually. This is not recommended but can be done by setting +% your stimWindow object's PtbSyncTests property to false: + +stimWindow = getOr(hw.devices([],false), 'stimWindow'); +stimWindow.PtbSyncTests = false; +hwPath = fullfile(getOr(dat.paths, 'rigConfig'), 'hardware.mat'); +save(hwPath, 'stimWindow', '-append') + +%% Undocumented IDs +% Below is a list of all other error and warning ids. + +% Rigbox:git:runCmd:nameValueArgs +% Rigbox:git:runCmd:gitNotFound +% Rigbox:git:update:valueError +% +% Rigbox:hw:calibrate:noscales +% Rigbox:hw:calibrate:deadscale +% Rigbox:hw:calibrate:partialPVpair +% +% Rigbox:srv:unexpectedUDPResponse +% Rigbox:srv:unexpectedUDP +% Rigbox:srv:expServer:noHardwareConfig +% +% Rigbox:dat:expPath:NotEnoughInputs +% Rigbox:exp:SignalsExp:NoScreenConfig +% Rigbox:exp:Parameters:wrongNumberOfColumns +% +% Rigbox:dat:expFilePath:NotEnoughInputs +% +% Rigbox:MockDialog:newCall:EmptySeq +% +% Rigbox:exp:SignalsExp:noTokenSet +% +% Rigbox:eui:choiceExpPanel:toolboxRequired +% signals:test:toolboxRequired +% Rigbox:setup:toolboxRequired +% +% Alyx:newExp:subjectNotFound +% Alyx:registerFile:InvalidPath +% Alyx:registerFile:UnableToValidate +% Alyx:registerFile:EmptyDNSField +% Alyx:registerFile:InvalidRepoPath +% Alyx:registerFile:InvalidFileType +% Alyx:registerFile:InvalidFileName +% Alyx:registerFile:NoValidPaths +% Alyx:updateNarrative:UploadFailed +% +% Alyx:getFile:InvalidID +% Alyx:getExpRef:InvalidID +% Alyx:getFile:InvalidType +% Alyx:expFilePath:InvalidType +% Alyx:url2Eid:InvalidURL +% +% toStr:isstruct:Unfinished +% +% squeak.hw +% shape:error +% window:error + +%% Etc. +% Author: Miles Wells +% +% v0.1.0 +% + +% INTERNAL +% execute off \ No newline at end of file diff --git a/docs/scripts/index.m b/docs/scripts/index.m new file mode 100644 index 00000000..866c9762 --- /dev/null +++ b/docs/scripts/index.m @@ -0,0 +1,101 @@ +%% Rigging Toolbox Documentation +% Welcome to the main Rigging Toolbox (Rigbox) documentation. Here you can +% find detailed documentation and guides on how to set up Rigbox, including +% writing new experiments, setting up recording devices, running +% experiments and processing the resulting data. +% + +%% Installing Rigbox +% Below are some instructions for installing Rigbox. There are two guides, +% the first is a thorough guide for users unfarmilliar with MATLAB and Git. +% The second is for 'power users' who have a basic understanding of these +% things. +% +% # <./install.html Full install instructions> +% # +% + +%% Setting up experiments +% Below is a set of steps for setting up a full experiment in Rigbox. A +% full experiment being one where you record quality, reliable data that +% gets saved into the <./glossary.html main experiment repository>. +% +% Briefly, before you can run a full experiment you must 1) set up your +% paths so that Rigbox knows from where to load rig settings and +% parameters, 2) save a hardware configuration file so that Rigbox can +% properly initialize its hardware, and 3) locate or create an experiment +% definition function to define your experiment. +% +% # <./paths_config.html Setting up dat.paths> +% # <./hardware_config.html How to configure hardware on the stimulus computer> +% # <./websocket_config.html Setting up communication between the stimulus computer and MC> +% # <./using_single_rig.html Setting up |mc| and |srv.expServer| on the +% same computer> + +%% Running full experiments +% Before you can run a complete experiment, you must set up Rigbox (see +% above section). Once this is done there you can follow on of the below +% sections to run a full experiment. + +%% Creating experiments +% The principle way to create a new is experiment (i.e. passive stimulation +% or behaviour task) is write an <./glossary.html expDef>. Below will be a +% set of guides for how to write an expDef, and how to test it. +% +% * <./using_test_gui.html Playing around with Signals Experiment Definitions> +% + +%% Working with Rigbox Experiment data +% Below are some guides on how to work with the experimental data saved by +% Rigbox. These guides instruduce some functions for loading and +% processing these data, and explain the forms in which data are saved. +% +% * +% * Working with block files +% * Working with ALF files +% + +%% Troubleshooting +% Rigbox is a mountain of code and there are many things that can go wrong +% when using it. Below are a few guides for how to fix problems that arise +% in Rigbox. +% +% * Basic MATLAB troubleshooting - this guide is for users that are +% unfamiliar with MATLAB. +% * - this guide gives a +% list of steps to follow when an error is encountered. +% * <./id_index.html ID index> - A list of Rigbox error/warning IDs along +% with the a detailed description of what they mean and an exhastive list +% of causes and solutions. +% * FAQ - A list of frequently asked questions regarding problems and +% pointers to the solutions. + +%% User guides +% Below is a list of in-depth guides for users who want to learn the +% ins-and-outs of various packages and classes in Rigbox. +% +% * <./using_dat_package.html The Data Package> - How to query data locations +% and log experiments using the |+dat| package. +% * <./SignalsPrimer.html How Signals works> - An in-depth guide to how +% Signals works. This shows you how to work with Signals outside of the +% and gives demonstrations of all +% Signals methods ( |scan|, etc.) +% * <./Parameters.html Parameters> - How to create and edit +% experiment parameters. +% * <./AlyxMatlabPrimer.html Alyx> - How to interact with an Alyx database +% * <./Timeline.html Timeline> - Using Timeline for time alignment +% +% +%% Miscellaneous +% Below is a list of useful topics: +% +% * <./using_services.html Setting up auxiliary services> +% * <./using_ExpPanel.html How to create a custom Experiment Panel> +% * <./glossary.html Glossary of Rigbox terminology> +% + +%% Etc. +% Author: Miles Wells +% +% v0.1.1 diff --git a/docs/scripts/install.m b/docs/scripts/install.m new file mode 100644 index 00000000..710bd226 --- /dev/null +++ b/docs/scripts/install.m @@ -0,0 +1,158 @@ +%% Installing Rigbox +% Below are some easy step-by-step instructions for installing Rigbox +% without any prior knowledge of Git or MATLAB. For more succinct +% installation instructions, see the Rigbox +% . The +% first section lists the requirements. NB: Please read this section +% carefully before attempting to install anything. + +%% Requirements +% For exploring Rigbox's features and running test experiments, +% Rigbox only needs to be installed on a single computer. +% +% For running full experiments, we recommend running Rigbox on two PCs: one +% is used for presenting stimuli and communicating with rig hardware, and +% the other runs a GUI which the user interacts with to monitor the +% experiment. Currently only +% are supported for acquiring data from hardware +% devices. +% +%%% Software +% Rigbox reqquires the following software to work properly: +% +% * Windows Operating System (7 or later, 64-bit) +% * MATLAB (2018b or later, also known as version 9.5) +% * Visual C++ Redistributable Packages for Visual Studio 2013 & 2015-2019 +% (_free_) +% * The MATLAB Data Acquisition Toolbox +% * _If using an NI DAQ_ the NI-DAQmx support package (_free_) +% * The GUI Layout Toolbox (v2 or later, _free_) +% * Psychophysics Toolbox (v3 or later, _free_) +% +%%% Hardware +% +% Below are a few minimum hardware requirements for both PCs. +% +% * *Processor*: Intel Core i5-6500 @ 3.0 GHz (or similar) +% * *Graphics*: NVIDIA Quadro P400 (or similar) +% * *Memory*: DDR4 16 GB @ 2133 MHz (e.g. Corsair Vengeance 16 GB) +% +% +%% Install steps +% Below are detailed steps on installing all required software. If you +% already have software installed for a particular step, feel free to skip +% that step. Unless you are installing Rigbox on a computer which will use +% a NI-DAQ for data acquistion, you can skip step 5. +% +% # Install Windows 7 or later (Windows 10 is recommended). Windows must +% be must be 64-bit (sometimes called x64, x86_64, AMD64 or Intel 64). +% # Download and install https://uk.mathworks.com/downloads/ MATLAB> by +% following their +% (see note 1). At +% , make sure to check the box for the Data Acquisition Toolbox, +% along with any other MATLAB Mathworks toolboxes you want, though for +% testing Rigbox, no other toolboxes are required (See note 2). NB: This +% step may take a while. +% # Once downloaded, open MATLAB by double-clicking on the MATLAB icon in +% the start menu. +% # Within MATLAB, install the GUI Layout Toolbox (See note 2). Make sure +% the version number is greater than 2. +% # Within MATLAB, install the NI-DAQmx Support Package (See note 2). NB: +% This step may take a while. +% # Download and install the Microsoft +% installer (See note +% 3). +% # Download and install the Microsoft +% +% installer (See note 4). NB: This is 2015-2019; the previous step was for +% 2013. Both are required. +% # Download and install (See note +% 5). +% # Download and install the +% , making sure to install all offered +% packages (See note 6). +% # Download the +% and save it into your |Documents/MATLAB| folder. +% # In the MATLAB Command Window (see note 7), type +% |DownloadPsychtoolbox(userpath)| (no quotes) and press enter. This will +% download and install PsychToolbox to MATLAB folder. At certain points in +% the installation it will print stuff to the Command Window and ask you to +% press any key to continue. Do this until the two angled brackes ('|>>|') +% reappear. +% # Close MATLAB by pressing the '|X|' in the top right corner of the window. +% # Download and install (See note 8). Use all defaults. +% # Launch Git Bash (See note 9). A black command line window should appear. +% # Type the following line into Git Bash (or copy/paste): |cd +% ~/Documents/Github| +% # Copy this line and paste it into Git Bash (use right click for +% pasting): |git clone --recurse-submodules +% https://github.com/cortex-lab/Rigbox| +% # Launch MATLAB and navigate to the following folder (See note 10): +% |Documents\Github\Rigbox| +% # Type the following into the MATLAB Command Window and press enter (See +% note 11): |addRigboxPaths| +% # You should be done now. To check this, type |eui.SignalsTest;| into the +% MATLAB Command Window and select |signalsPong.m|. Then click Start. Your +% mouse controls the right paddle. + +%% Notes +% # MATLAB is not free and requires a MATLAB account in order to +% download. If you are part of an academic institution you may be able to +% get MATLAB for free. If in doubt ask your lab supervisor or institute IT +% department. For more information see +% . +% # Once MATLAB is installed, toolboxes can be downloaded and installed +% directly within MATLAB via the "Add-Ons" button in the "Home" top +% toolstrip. This opens the MATLAB 'AddOn Explorer' where you can search +% and install toolboxes. +% # To install download and install, follow the link and click the orange +% 'Download' button. A 'Choose the download you want' window will come up. +% Select 'vcredist_x64.exe' and click 'Next'. A download window will pop +% up; click 'Save file'. Once downloaded, double-click the installer and +% follow the steps. +% # To download and install the +% libraries, follow the link and click 'Save file'. You +% can then run the file and follow the installation steps. +% # To download and install , +% follow the link and click the blue button that says 'SVN 1.12.0, 64 bit' +% on the left-hand side. The numbers might be slightly different but the +% important thing is that you choose the one that says '64 bit'. Click +% 'OK' in the pop-up window to save the installer zip file. Once +% downloaded double-click the zip file and open the exe file contained. +% Follow all the steps in the installer. +% # To download and install the , follow the link and clock 'Save +% file'. Then open the file and follow the installation steps. Choose the +% full/complete installation with all packages selected. +% # The MATLAB Command Window is usually at the bottom of the MATLAB +% window and has a '|>>|' in it. For more information, please read the +% . +% # To download and install , follow the link and click 'Save file' when the download window +% pops up. Open the installer file and click 'Next' repeatedly until the +% end, then click 'Finish'. +% # There might be more than one program installed that has 'Git' in the +% name. Make sure the one you open is called 'Git Bash'. +% # To navigate to a folder in MATLAB, either use the +% or type the following into the MATLAB Command Window, +% replacing |USER| with the name of the Windows user that's currently +% logged in: |cd('C:\Users\USER\Documents\Github\rigbox\')| +% # If you've followed the above steps you can safely ignore any warnings +% you may see for trying out Rigbox. + +%% Etc. +% Authors: Jai Bhagat, Matteo Caranini, Miles Wells +% +% v0.1.0 +% diff --git a/docs/index.m b/docs/scripts/packages.m similarity index 80% rename from docs/index.m rename to docs/scripts/packages.m index 0d4582d3..d943b49c 100644 --- a/docs/index.m +++ b/docs/scripts/packages.m @@ -1,26 +1,22 @@ -%% Rigbox Documentation -% Below is a list of useful topics: +%% Code organization +% Rigbox is organized into various MATLAB packages(1). Functions and +% classes within a package have their own namespace. We seperate our +% functions based broadly on what part of Rigbox they're for. For example +% files in the |+eui| folder are part of the 'Experiment UI' package and +% are all related to GUIs in Rigbox (e.g. the MC GUI or Parameter Editor +% GUI). +% +% <> % -% * <./paths_config.html Setting up dat.paths> -% * <./hardware_config.html How to configure hardware on the stimulus computer> -% * <./using_dat_package.html How to query data locations and log experiments> -% * <./websocket_config.html Setting up communication between the stimulus computer and MC> -% * <./using_test_gui.html Playing around with Signals Experiment Definitions> -% * <./SignalsPrimer.html How to create experiments in signals> -% * <./using_parameters.html How to create and edit experiment parameters> -% * <./using_timeline.html Using Timeline for time alignment> -% * <./using_services.html Setting up auxiliary services> -% * <./AlyxMatlabPrimer.html How to interact with an Alyx database> -% * <./using_ExpPanel.html How to create a custom Experiment Panel> -% * <./troubleshooting.html Troubleshooting Rigbox errors> +% _Fig. 1_ - An overview of the packages and their loose relationships to +% one another % -% @todo Further files to add to docs -% @body Burgess config, setting up shared paths - -%% Code organization % Below is a list of Rigbox's subdirectories and an overview of their -% respective contents. For more details, see the REAME.md and Contents.m -% files for each package folder. +% general purpose. Shown is the command for viewing the package overview +% doc, which lists the package contents. For further details, see the +% REAME.md and Contents.m files for each package folder. +% + %%% +dat % The 'data' package contains code pertaining to the organization and @@ -117,7 +113,13 @@ % submodules % can be found in their respective github repositories. +%% Notes +% (1) For more information about using packages in MATLAB, see +% +% + %% Etc. % Author: Miles Wells % -% v0.1.0 +% v0.0.2 \ No newline at end of file diff --git a/docs/setup/paths_config.m b/docs/scripts/paths_config.m similarity index 100% rename from docs/setup/paths_config.m rename to docs/scripts/paths_config.m diff --git a/docs/setup/paths_template.m b/docs/scripts/paths_template.m similarity index 100% rename from docs/setup/paths_template.m rename to docs/scripts/paths_template.m diff --git a/docs/scripts/troubleshooting.m b/docs/scripts/troubleshooting.m new file mode 100644 index 00000000..dbb10775 --- /dev/null +++ b/docs/scripts/troubleshooting.m @@ -0,0 +1,132 @@ +%% Troubleshooting +% Often finding the source of a problem seems daunghting when faced with a +% huge Rigbox error stack. Below are some tips on how to quickly get to +% the root of the issue and hopefully solve it. + + +%%% Update the code +% Check what version of the code you're using and that you're up-to-date: +git.runCmd('status'); % Tells me what branch I'm on +git.update(0); % Update now + +% If you're on a development or feature branch try moving to the master +% branch, which should be most stable. +git.runCmd('checkout master'); git.update(0); + + +%%% Examining the stack +% Don't be frightened by a wall of red text! Simply start from the top and +% work out what the errors might mean and what part of code they came from. +% The error at the top is the one that ultimately caused the crash. Try to +% determine if this is a MATLAB builtin function, e.g. +% +% Warning: Error occurred while executing the listener callback for event UpdatePanel defined for class eui.SignalsTest: +% Error using griddedInterpolant +% Interpolation requires at least two sample points in each dimension. +% +% Error in interp1 (line 151) +% F = griddedInterpolant(X,V,method); +% +% TODO Add better example of builtin errors +% +% If you're debugging a signals experiment definition, check for the line +% in your experiment where this particular builtin function was called. NB: +% You can check whether it is specific to your experiment by running one of +% the example experiment definitions such as advancedChoiceWorld.m, found +% in signals/docs/examples. If this runs without error then you're problem +% may be specific to your experiment. You should see the name of your +% definition function and exp.SignalsExp in the stack if they are involved. +% +% If you don't know what a function is, try checking the documentation. +% Consider the following: +% +% Error using open +% Invalid number of channels +% +% Error in audstream.fromSignal (line 16) +% id = audstream.open(sampleRate, nChannels, devIdx); +% [...] +% +% If you're unsure what `audstream.fromSignal` does, try typing `doc +% audstream`. This should tell you that the package deals with audio +% devices in signals. In this case the issue might be that your audio +% settings are incorrect. Take a look at the audio section of +% `docs\setup\hardware_config.m` and see if you can setup your audio +% devices differently. + + +%%% Paths +% By far the most common issue in Rigbox relates to problems with the +% MATLAB paths. Check the following: +% +% # Do you have a paths file in the +dat package? +% Check the location by running `which dat.paths`. Check that a file is +% on the paths and that it's the correct one. +% # Check the paths set in this file. +% Run `p = dat.paths` and inspect the output. Perhaps a path is set +% incorrectly for one of the fields. Note that custom rig paths overwrite +% those written in your paths file. More info found in +% `using_dat_package` and `paths_template`. +% # Do you have path conflicts? +% Make sure MATLAB's set paths don't include other functions that have the +% same name as Rigbox ones. Note that any functions in ~/Documents/MATLAB +% take precedence over others. If you keep seeing the following warning +% check that you've set the paths correctly: +% Warning: Function system has the same name as a MATLAB builtin. We +% suggest you rename the function to avoid a potential name conflict. +% This warning can occur if the tests folder has been added to the paths +% by mistake. Always set the paths by running `addRigboxPaths` and never +% set them manually as some folders should not be visible to MATLAB. +% # Check your working directory +% MATLAB prioritizes functions found in your working directory over any +% others in your path list so try to change into a 'safe' folder before +% re-running your code: +% pwd % display working directory +% cd ~/Documents/MATLAB +% # Check your variable names +% Make sure your variable names don't shadow a function or package in +% Rigbox, for instance if in an experiment definition you create a varible +% called `vis`, you will no longer be able to access functions in the +vis +% package from within the function: +% vis = 23; +% img = vis.image(t); +% Error: Reference to non-existent field 'image'. + + +%%% Reverting +% If these errors only started occuring after updating the code, +% particularly if you hadn't updated in a long time, try reverting to the +% previous version of the code. This can help determine if the update +% really was the culprit and will allow you to keep using the code on +% outdated machines. Previous stable releases can be found on the Github +% page under releases. NB: For the most recent stable code always pull +% directly from the master branch + + +%%% Posting an issue on Github +% If you're completely stumped, open an issue on the Rigbox Github page (or +% alyx-matlab if you think it's related to the Alyx database). When +% creating an issue, read the bug report template carefully and be sure to +% provide as much information as possible. +% +% If you tracked down the problem but found the error to be confusing or +% too vague, feel free to post a feature request describing how better to +% present the error. This is an area in need of improvment. You could also +% make a change yourself and submit a pull request. For more info see +% CONTRIBUTING.md + + +%% FAQ +% Below are some frequently asked questions and suggestions for fixing +% them. Note there are plenty of other FAQs in the various setup scripts +% with more specific information. + + +%% Etc. +% Author: Miles Wells +% +% v0.1.0 +% + +% INTERNAL +% execute off \ No newline at end of file diff --git a/docs/usage/using_ExpPanel.m b/docs/scripts/using_ExpPanel.m similarity index 100% rename from docs/usage/using_ExpPanel.m rename to docs/scripts/using_ExpPanel.m diff --git a/docs/usage/using_dat_package.m b/docs/scripts/using_dat_package.m similarity index 95% rename from docs/usage/using_dat_package.m rename to docs/scripts/using_dat_package.m index 6a74c8a1..0284c368 100644 --- a/docs/usage/using_dat_package.m +++ b/docs/scripts/using_dat_package.m @@ -1,4 +1,4 @@ -%% Introduction +%% The Data Package % The 'data' package contains code pertaining to the organization and % logging of data. It contains functions that generate and parse unique % experiment reference ids, and return file paths where subject data and @@ -31,7 +31,7 @@ % More info in the paths template: root = getOr(dat.paths, 'rigbox'); -opentoline(fullfile(root, 'docs', 'setup', 'paths_template.m'), 75) +opentoline(fullfile(root, 'docs', 'scripts', 'paths_template.m'), 75) %% Using expRefs % Experiment reference strings are human-readable labels constructed from @@ -92,14 +92,14 @@ %% Loading parameters % The dat package allows you to load both session specific and experiment -% specific <./using_parameters.html parameters> . +% specific <./Parameters.html parameters> . expType = 'custom'; % signals experiments have the type 'custom' p = dat.loadParamProfiles(expType); dat.saveParamProfile(expType, profileName, params); dat.delParamProfile(expType, profileName); % More info on how parameters work can be found in USING_PARAMETERS: -open(fullfile(getOr(dat.paths,'rigbox'), 'docs', 'using_parameters.m')) +open(fullfile(getOr(dat.paths,'rigbox'), 'docs', 'scripts', 'Parameters.m')) %% Using the log % The log object, is primarily dealt with through MC, however you can also @@ -115,7 +115,7 @@ % path needs updating to one. In this case, rig-specific paths may be set % using a custom paths file that overrides any paths set in DAT.PATHS: opentoline(fullfile(getOr(dat.paths,'rigbox'), ... - 'docs', 'setup', 'paths_template.m'), 78, 1) + 'docs', 'scripts', 'paths_template.m'), 78, 1) % The paths file, 'paths.mat', must contain a variable `paths` that is a % struct of custom paths. The file should be located in the location set @@ -132,6 +132,6 @@ %% Etc. % Author: Miles Wells % -% v1.0.0 +% v1.0.1 %#ok<*NASGU,*ASGLU,*ASGLU> diff --git a/docs/usage/using_services.m b/docs/scripts/using_services.m similarity index 99% rename from docs/usage/using_services.m rename to docs/scripts/using_services.m index 82df406a..f2b33534 100644 --- a/docs/usage/using_services.m +++ b/docs/scripts/using_services.m @@ -232,8 +232,8 @@ % More information can be found in the <./websocket_config.html % websocket_config> script: -open(fullfile(getOr(dat.paths,'rigbox'), ... - 'docs', 'setup', 'websocket_config.m')) +root = getOr(dat.paths, 'rigbox'); +open(fullfile(root, 'docs', 'scripts', 'websocket_config.m')) %% Conclusion % Ultimately the way you configure your services will be idiosyncratic as @@ -251,6 +251,6 @@ %% Etc. % Author: Miles Wells % -% v1.1.0 +% v1.1.1 %#ok<*FINS,*NASGU,*NOPTS> \ No newline at end of file diff --git a/docs/scripts/using_single_rig.m b/docs/scripts/using_single_rig.m new file mode 100644 index 00000000..5dcfccf9 --- /dev/null +++ b/docs/scripts/using_single_rig.m @@ -0,0 +1,73 @@ +%% Running experiments on a single computer +% Running experiments with two PCs has two major advantages: +% +% # An MC computer can control and monitor multiple stimulus computers in +% parallel. +% # Using |mc| on a separate computer frees up the stimulus computer's +% resources. A dedicated experiment computer is likely to have lower +% latencies. +% +% Nevertheless, it is possible to run experiments using a single computer. +% The first way is by using |srv.expServer|'s 'single-shot' mode to run an +% experiment without running |mc|. The second way is by running |mc| on +% the same computer, in a different instance of MATLAB. + +%% Without MC +% Running experiments on a single computer without MC is simple, however +% live monitoring of the experiment is not possible. First a new +% experiment is created, then |srv.expServer| should be called the +% experiment reference string. The below code shows how to create and run +% a ChoiceWorld Experiment using the default parameters, without using +% <./glossary.html Alyx>: +ref = dat.newExp('test', now, exp.choiceWorldParams); +srv.expServer('expRef', ref, 'preDelay', 10) % Ten second delay before start + +%% +% Below is an example of modifying parameters for a Signals Experiment, +% then create an experiment in Alyx and run it: + +% Get the parameter list using inferParameters +paramStruct = exp.inferParameters(@advancedChoiceWorld); + +% Modify the parameters using the exp.Parameters object +P = exp.Parameters(paramStruct); % +P.makeTrialSpecific('rewardSize') +P.set('rewardSize', linspace(1,3,P.numTrialConditions)) + +% Parameters can also be manipulated in the Parameter Editor GUI +PE = eui.ParamEditor(P); +paramStruct = PE.Parameters.Struct; + +% Save parameters and register session to Alyx +ai = Alyx; +ref = newExp(ai, 'test', now, P.Struct); +srv.expServer('expRef', ref, 'alyx', ai) + +%% With MC +% It is also possible to run |mc| on the same computer as |srv.expServer|. +% This requires that the computer has at least 2 monitors connected. +% +% To do this set up the remote file according to the +% <./websocket_config.html Configuring WebSockets> guide, however, instead +% of using the hostname or external IP as the URI, use the localhost +% address (normally |127.0.0.1|). Below is the code for setting up the +% remote file this way: + +% The stimulus controllers are loaded from a MAT file with the name +% 'remote' in the globalConfig directory, defined in dat.paths: +p = fullfile(getOr(dat.paths, 'globalConfig'), 'remote.mat'); + +% Let's create a stimulus controller for this PC +stimulusControllers = srv.StimulusControl.create(hostname, '127.0.0.1'); + +% Save your new configuration. Note the variable name must be as below: +save(p, 'stimulusControllers') + +%% +% Now simply open another instance of MATLAB and in one, run |mc|. In the +% other instance, run |srv.expServer|. + +%% Etc. +% Author: Miles Wells +% +% v0.0.1 diff --git a/docs/scripts/using_test_gui.m b/docs/scripts/using_test_gui.m new file mode 100644 index 00000000..d4cfccfb --- /dev/null +++ b/docs/scripts/using_test_gui.m @@ -0,0 +1,136 @@ +%% Introduction +% This document demonstrates how to test Signals Experiment Definition +% (expDef) functions in the test GUI. The GUI opens a PTB window and a +% Parameter Editor for live-updating parameters. Before opening the test +% GUI, loading the debug settings for PTB will make the window transparent. +% This is particularly useful on small screens(1). +PsychDebugWindowConfiguration + +%% Opening your expDef in the GUI +% Upon calling the |eui.SignalsTest| class with no inputs you will be +% prompted to select your function from the file browser. As with |MC|, +% the default folder location is set by the 'expDefinitions' field in +% dat.paths. +% +% You can also call the function with the function name or function handle. +% The function must be on the MATLAB path. Let's run one of the example +% expDef functions: the Burgess wheel task(2) implemented in Signals. +PsychDebugWindowConfiguration % Make window transparant and turn of blocking +root = fileparts(which('addRigboxPaths')); % Location of Rigbox root dir +cd(fullfile(root, 'signals', 'docs', 'examples')) % Change to examples folder + +e = eui.SignalsTest('advancedChoiceWorld') % Start GUI and loaded expDef +% e = eui.SignalsTest() % Opens a file navigator +% e = eui.SignalsTest(@advancedChoiceWorld) % Function handle +% e = eui.SignalsTest('full/path/to/expDef.m') % Absolute file path + +%% Default settings +% The hardware wheel input is simulated in the experiment GUI by the +% position of the cursor over the stimulus window. Upon clicking start the +% 'expStart' event updates with the the experiment ref string. The ref +% string can be changed by editing the Ref property before pressing start: +e.Ref = dat.constructExpRef('subject', now-7, 2); + +% Moving the cursor over the window will move the visual stimulus in the +% stimulus window. +e.Hardware.mouseInput % Uses the eui.SignalsTest/getMouse method + +%% Testing different hardware +% A hardware structure can be assigned to the Hardware property of the test +% object (see <../hardware_config.html#1 configuring hardware devices>): +e.Hardware = hw.devices; % Assign a rig's actual hardware settings + +%% Editing parameters +% Parameters are shown in the |eui.ParamEditor| which is in the +% 'Parameters' box. When you select an expDef, the default parameters are +% loaded. These are the names and values defined in the try-catch block at +% the end of the expDef. Parameters can be edited before pressing start, +% and saved/loaded using the 'saved sets' section. Saved sets are located +% in the mainRepository (set in your |dat.paths| file), in a file called +% 'parameterProfiles.mat'. For more info see <./using_parameters.html +% Using Parameters>. The parameters can be updated live during the +% experiment. In order to do this, check 'Post new parameters on edit' in +% the options dialog. + +%% Live plotting +% The values of the event Signals can be plotted live by checking the +% LivePlot option in the Options popup. +% +% Clicking on each subplot will cycle through the three plot modes. The +% default mode (0) creates a stair plot with each value update marked with +% an x. Mode 1 plots each value as a discrete point. Mode 2 plots a +% simple line, with now markers to indicate value updates. Note, if a +% Signal takes a vector or matrix as its value, the mode is switched to 1 +% and the size of the array is added as an text annotation. If the value +% is a charecter array, the mode is switched to 1 and the value is plotted +% as a text annotation. For more details on the plotting function see +% |sig.test.timeplot|. +% +% For more about options see the help for the |setOptions| method. +e.setOptions % Open Options dialog +help eui.SignalsTest/setOptions + +%% Experiment panel +% The 'Show experiment panel' option is on by default and instantiates an +% experiment panel (ExpPanel) that displays Signals updates after the +% experiment has started. A custom ExpPanel can be defined via your +% expDef's 'expPanelFun' parameter, otherwise |eui.SignalsExpPanel| is +% used. Note that unlike in |MC|, the comments box is hidden from the +% panel. For more info, see <./using_ExpPanel.html Using ExpPanel>. +%% +% +% <> +% + + +%% Debugging +% A number of features make debugging a little easier: +% +% # The expDef is re-loaded each time you start the experiment, so you can +% make changes without having to reload the GUI. +% # The parameters can be updated live during the experiment (see <#5 +% Editing Parmeters>). +% # You can pause and resume the experiment at any time by pressing the +% |esc| key. While paused, no Signals are updated. Note that while the +% experiment is running you can not use the command prompt, even when +% paused. +% # Signals is run in debug mode, so the error messages printed give more +% informative information about the exact cause of the error. Below is an +% example of a typical Signals error thrown. The top of the stack gives +% the name of the function that threw the error, the error message and the +% line at which it occured. The 'Caused by' section gives the node ids +% involved (e.g. node 61 -> node 62), their values at the time of the error +% (e.g. bombWorld/timeSampler([0; 0.1; 0.09]) ), and the name and line of +% problem Signal in your expDef, e.g. 'Error in [...]bombWorld.m (line +% 22)'; pars.preStimulusDelay.map(@bombWorld/timeSampler). NB: If you call +% |eui.SignalsTest| with a function handle, the line number of your expDef +% can not be determined. +% +% Error using bombWorld/timeSampler (line 183) +% Expected char; was double instead. +% +% [...] +% +% Caused by: +% Error in Net 1 mapping Node 61 to 62: +% function call 'bombWorld/timeSampler' with input [0; 0.1; 0.09] produced an error: +% Expected char; was double instead. +% Error in C:\Users\User\Documents\Github\rigbox\signals\docs\examples\bombWorld.m (line 22) +% pars.preStimulusDelay.map(@bombWorld/timeSampler) +% + + +%% Notes +% (1) These settings can be cleared by calling the Screen function: +clear Screen +%% +% (2) + +%% Etc. +% Author: Miles Wells +% +% v0.1.1 + +% INTERNAL: +% execute code +%#ok<*NOPTS,*NASGU,*ASGLU> diff --git a/docs/scripts/using_visual_stimuli.m b/docs/scripts/using_visual_stimuli.m new file mode 100644 index 00000000..039b1535 --- /dev/null +++ b/docs/scripts/using_visual_stimuli.m @@ -0,0 +1,308 @@ +%% Visual stimuli in Signals +% Signals uses the OpenGL MEX wrapper functions provided by PsychToolbox to +% render the visual stimuli. +% +% In order to build up an enviroment we need to know a few things: +% +% # Where are the objects (stimuli) with respect to one another in the +% world +% # Where are the objects with respect to the viewer +% # How to do these coordinates map to a 2D surface (a screen) +% +% Thus when we define a stimulus in visual space it is transformed by our +% model into physical space by the model (or world-to-camera) matrix then +% to projected 2D space by our projection matrix. These transformations +% are done in the shader. + +%% The visual stimulus object +% The visual stimulus object is the 4th input to an experiment definition. +% It is a |StructRef| object, which like a structure, can be assigned +% fields. + + + +%% vis.screen +% The model produced by vis.screen is a matrix (known as the +% world-to-camera matrix) that transforms our world coordinates (visual +% degrees) to camera coodinates (the physical location of the viewer). It +% technically does two transforms in one: object-to-world the +% world-to-camera, however in our viewing model the the camera IS the +% world, so the object-to-world matrix is identity. See also +% <./hardware_config.html#27 hardware configuration>: +root = fileparts(which('addRigboxPaths')); +opentoline(fullfile(root, 'docs', 'scripts', 'hardware_config.m'), 344, 1) + +%% vis.init +% Loads the shader (slimshady) and initializes a projection matrix with +% default viewing parameters. +% +% The viewing model is 'pseudo-circular'. An inverted spherical mesh is +% created using |vis.uniSphereTriangles| onto which all textures are +% painted. This is designed to compensate for the fact that the screen +% edges are further away than the centre when the viewer is facing the +% middle of the screen. As textures move further along the azimuth, they +% enlarge. + +%% Plane projection +% A 4x4 plane projection matrix when multiplied by a 3D coordinates in +% camera space gives you the 2D coordinates on the screen/projection +% surface. This maxtrix allows us to map 3D coordinates to images that +% follow the rules of perspective. Clipping happens here. + +%% The shader +% This is the job of the vertex shader. The shader's job is to transform +% our vertices from camera space (visual degrees) to clip space. The +% shader returns 'gl_Position' (an OpenGL global variable) which is the +% result of multiplying vertex postion by the plane projection and +% world-to-camera matrices. The shader applies all nessesary +% transformations (scaling, rotating and translating). The shader converts +% the vertices to homogeneous coordinates (vec4), i.e. |position = +% [position 1];| See |slimshady.vert| + +%% +% [Projection matrix] [World-to-camera matrix] +% \ / +% \ / +% \ / +% \ / +% \ / +% \ / +% \ / +% \ / +% -------------------------------------GPU---- +% \ / +% \ / +% \/ +% [Vertex shader] + +%% +% Once in clip space, the fragment shader defines its appearence (i.e. +% colour). + +%% Clip space +% After this plane projection we are in clip space. Here points have +% homogeneous (4D) coordinates. + +%% NDC space +% After the projection is divided by Clip.W leaving us in Normalized Device +% Space (NDC). The resulting matrix has values between [-1, 1]. Values +% outside of this range are outside the clipping space. In OpenGL (c.f. +% Direct3D) this matrix is cubic. NDC coordinates are agnostic to screen +% shape and always [-1, 1]. + +%% Rasterization +% This step uses the view port and depth range to translate everything to +% fragment locations in screen/window space. This is done on the GPU. + +%% vis.draw +% * vis.init +% * vis.screen +% * vis.loadLayerTextures +% * vis.reloadLayerTextures + +%% Viewing model +% * vis.planeProjection +% * vis.uniSphereTriangles +% * vis.quadToTriangles + +%% Layers +% Current layers functions: +% +% * gaussianLayer +% * circLayer +% * rectLayer +% * crossLayer +% * sinusoidLayer +% * squareWaveLayer +% * emptyLayer + +%VIS.EMPTYLAYER Template texture layer for rendering in Signals +% Returns a struct of paramters and their defaults used by VIS.DRAW to +% load a visual stimulus layer. If n > 1 a non-scalar struct is returned +% of length n (default 1). +% +% TODO Document viewAngle, texAngle and pos +% @body There is currently no information on how these three parameters +% are used by the viewing model. For example, what is the practical +% difference between `texOffset` and `pos`, or `viewAngle` and `texAngle`? +% +% See also VIS.DRAW, VIS.RGBA + +% Create an empty structure +layer = struct; +% SHOW a logical indicating whether or not the stimulus is visible +layer.show = false; +% TEXTUREID a char array used by VIS.DRAW to identify the texture layer. +% Layers with unique texture data (i.e. the data stored in rgba) must have +% unique IDs in order to be loaded into the buffer seperately. Preceeding +% the ID with '~' indicates that it is a dynamic texture to be loaded anew +% each time. Dynamic textures are those where the underlying image array +% changes. +layer.textureId = []; +% POS +layer.pos = [0 0]'; +% SIZE array of the form [azimuth altitude] defining the size of the +% texture in visual degrees +layer.size = [0 0]'; +% VIEWANGLE The view angle in degrees +layer.viewAngle = 0; +% TEXANGLE the texture angle in degrees +layer.texAngle = 0; +% TEXOFFSET an array of the form [azimuth altitude] indicating the texture +% offset from the centre of the viewer's visual field in visual degrees +layer.texOffset = [0 0]'; +% ISPERIODIC logical - when true the texture is replicated across the +% entire visual space +layer.isPeriodic = true; +% BLENDING char array defining the type of blending used. +% Options: +% 'none' (/ ''), +% 'source' (/ 'src'), +% 'destination' (/ 'dst'), +% '1-source' (/'1-src') +layer.blending = 'source'; +% MINCOLOUR & MAXCOLOUR arrays of the form [R G B A] indicating the min +% (max) intensity of the red, green and blue channels, along with the amout +% of opacity (alpha). Values must be between 0 and 1. +layer.minColour = [0 0 0 0]'; +layer.maxColour = [1 1 1 1]'; +% COLOURMASK logical array indicating whether the red, green, blue and +% alpha channels may be written to the frame buffer. When any of these +% channels are set to false no change is made to that component of any +% pixel in any of the color buffers, regardless of any changes to the +% texture image +layer.colourMask = [true true true true]'; +% INTERPOLATION char array indicating the type of interpolation applied. +% Options: +% 'nearest' - Nearest neighbour interpolation +% 'linear' - linear interpolation +layer.interpolation = 'linear'; +% RGBA Column array of uint8 RGBA values for each pixel (left to right, top +% to bottom) in the texture image. The values must be between 0 and 255. +% For example take a matrix. See also VIS.RGBA +layer.rgba = []; +% RGBASIZE array of the form [m n] where m and n are the sizes of the first +% two dimentions of the texture image +layer.rgbaSize = [0 0]'; + +%% Stimuli + +%%% Images +% The function for making image textures is |vis.image|. Images can be +% arrays with values between 0-1 (MATLAB-style) or 0-255. They may be +% monochromatic ([m,n,1]) or be RGB(A) ([m,n,3-4]). Images can be loaded in a +% few different ways. If you don't intend for the underlying image to +% change you can pass in a path to the image: +srcImg = which('cell.tif'); % Path to image +img = vis.image(t, srcImg); +% The source image may be a MAT file or an image file (tiff, png, etc.) +% If an alpha layer is present it will used. This can be overridden by +% providing an alpha layer as a positional argument: +img = vis.image(t, srcImg, 1); % alpha may be scalar or array the size of img. +% If creating more than one visual element (e.g. you have two images you +% want to show at the same time) and are providing a source path, the names +% of the image files must be unique. This is because the file name is used +% as the texture ID, which is ID used by Signals to distinguish textures. + +% The source image may be loaded separately and passed in the same way: +images = load('imdemos.mat'); +img = vis.image(t, images.circles); + +% Finally the input may be a Signal whose value is the image array. When +% the source image is a Signal it is loaded as a dynamic texture (the +% layer's textureId field starts with a '~'). This allows the source image +% to change throughout the experiment, however if you don't intend for your +% source image to change, consider pre-loading it like the above examples +% as it is more efficient. + +% You can optionally add a Gaussian window over the image: +img.window = 'gauss'; +img.sigma = [10 10]; + +% The image position and size may be set as expected: +img.dims = [40 20]; +img.orientation = 180; % upside-down +img.azimuth = 0; % centred in x +img.altitude = 10; % slightly elevated + +% The image may also be tiled across the screen by setting the repeat flag: +img.repeat = true; % cover the whole screen with image tiles + +%%% Checker / sparse noise + +%%% Gabor patch & gratings + +%%% Shapes + +%% Dynamic textures + +%% vis.rgba & vis.rgbaFromUint8 +%VIS.GRATING Returns a Signals grating stimulus defining a grating texture +% Produces a visual element for parameterizing the presentation of a +% grating. Produces a grating that can be either sinusoidal or +% square-wave, and may be windowed by a Gaussian stencil, producing a +% Gabor patch. +% +% Inputs: +% 't' - The "time" signal. Used to obtain the Signals network ID. +% (Could be any signal within the network - 't' is chosen by +% convention). +% 'grating' - A char array defining the nature of the grating. Options +% are 'sinusoid' (default) or 'squarewave'. +% 'window' - A char array defining the type of windowing applied. +% Options are 'gaussian' (default) or 'none'. +% +% Outputs: +% 'elem' - a subscriptable signal containing fields which parametrize +% the stimulus, and a field containing the processed texture layer. +% Any of the fields may be a signal. +% +% Stimulus parameters (fields belonging to 'elem'): +% 'grating' - see above +% 'window' - see above +% 'azimuth' - the azimuth of the image (position of the centre pixel in +% visual degrees). Default 0 +% 'altitude' - the altitude of the image (position of the centre pixel +% in visual degrees). Default 0 +% 'sigma' - if window is Gaussian, the size of the window in visual +% degrees. Must be an array of the form [width height]. +% Default [10 10] +% 'phase' - the phase of the grating in visual degrees. Default 0 +% 'spatialFreq' - the spatial frequency of the grating in cycles per +% visual degree. Default 1/15 +% 'orientation' - the orientation of the grating in degrees. Default 0 +% 'colour' - an array defining the intensity of the red, green and blue +% channels respectively. Values must be between 0 and 1. +% Default [1 1 1] +% 'contrast' - the normalized contrast of the grating (between 0 and 1). +% Default 1 +% 'show' - a logical indicating whether or not the stimulus is visible. +% Default false +% +% See Also VIS.EMPTYLAYER, VIS.PATCH, VIS.IMAGE, VIS.CHECKER6, VIS.GRID + + +% Map the visual element signal through the below function 'makeLayers' and +% assign it to the 'layers' field. When any of the above parameters takes +% a new value, 'makeLayer' is called, returning the texture layer. +% 'flattenStruct' returns the same texture layer but with all fields +% containing signals replaced by their current value. The 'layers' field +% is loaded by VIS.DRAW + +%% Notes +% # Like MATLAB OpenGl uses column-major order +% # Camera space may also be referred to as view space +% # In the unit cube, 1 means the object is at the far clipping plane +% (right up against the back-drop as it were) and -1, the near clipping +% plane (right up against the screen). All points visible to the camera +% have a negative z-component. +% # In OpenGL (GLUT more precisely), the FOV corresponds to the vertical +% angle +% # + +%% Etc. +% Author: Miles Wells +% +% v0.0.1 +%#ok<*NASGU,*NOPTS> \ No newline at end of file diff --git a/docs/scripts/using_wheel.m b/docs/scripts/using_wheel.m new file mode 100644 index 00000000..1866de1b --- /dev/null +++ b/docs/scripts/using_wheel.m @@ -0,0 +1,135 @@ +%% Working with wheel data +% In the Burgess wheel task a visual stimulus is yoked to LEGO wheel via +% a rotary encoder. Below are some things to consider when designing or +% modifying a wheel task. For information on setting up the rotary +% encoder, see <./hardware_config.html#29 Hardware Configuration: DAQ +% rotary encoder>. For information on wiring a rotary encoder for the +% Burgess steering wheel task, see the . + +%% The wheel input in Signals +% There are currently three wheel-related inputs used by the Signals +% Experiment class. These can be accessed via a subscripted reference(1) +% to the 'inputs' argument of an <./glossary.html experiment definition +% function (expDef)> : +% +% # wheel - the raw value of the rotary encoder, polled on every iteration +% of the main experiment loop. Each time the rotary encoder moves +% suffeciently it sends out a pulse. These are integrated by a counter +% channel and the output is seen in the wheel signal. This Signal is +% zero'd at the beginning of the experiment. +% # wheelMM - the wheel movement in units of centimetres linear +% displacement. That is the distance the wheel would have rolled along a +% flat surface. This Signal is zero'd at the beginning of the experiment. +% # wheelDeg - the wheel movement in degrees. This Signal is zero'd at the +% beginning of the experiment. +% +% The |wheelMM| and |wheelDeg| signals simply map the values of |wheel| +% through a function based on information found in the hardware file's +% mouseInput object, namely the 'WheelDiameter' and 'EncoderResolution' +% properties. + +%% Load information about the wheel from the hardware file +% For a given experiment you may wish to load the hardware used, and to +% view the settings for the rotary encoder. Each experiment, a JSON copy +% of the hardware file is saved to the <./glossary.html main repository>. +% This preserves the settings as they were at the time the experiment ran. +% The below code searches for this JSON file and tries to load it. If it +% doesn't exist, the current hardware file is loaded instead. Some +% information about the rotary encoder settings are the printed. +expRef = '2019-03-28_1_default'; % Example experiment +jsonPath = dat.expFilePath(expRef, 'hw-info', 'master', 'json'); +if exist(jsonPath, 'file') % Check is hardware JSON exists + % If the JSON file exists load that as the wheel may have sinced changed + rig = jsondecode(fileread(jsonPath)); +else + % Otherwise load the existing harware file + rigName = 'exampleRig'; + rig = hw.devices(rigName, false); +end + +% Print some info: +D = rig.mouseInput.WheelDiameter; +res = rig.mouseInput.EncoderResolution; +a = rig.mouseInput.MillimetresFactor; +fprintf(['Details for experiment %s:\n'... + 'Wheel diameter (mm): %.1f, '... + 'encoder resolution: %d, '... + 'calculated millimetres factor: %.4f\n'], expRef, D, res, a) + +%% Load the wheel data +% If availiable, load the auto-extracted ALF file as the data is quicker to +% load, in centimeters linear displacment units and resampled evenly at +% 1000Hz. +expPath = dat.expPath(expRef, 'main', 'master'); +files = dir(expPath); +Fs = 1000; % Frequency to resample at +if any(endsWith({files.name}, 'wheel.position.npy')) + fullFileFn = @(nm) readNPY(fullfile(expPath, endsWith({files.name}, nm))); + pos = fullFileFn('wheel.position.npy'); % in cm + rawT = fullFileFn('wheel.timestamps.npy'); % in sec + vel = fullFileFn('wheel.velocity.npy'); % in cm/sec + t = (rawT(1,2):1/Fs:rawT(2,2))'; +else % Otherwise load from block file and preprocess + data = dat.loadBlock(expRef); + pos = data.inputs.wheelValues; % in samples + tRaw = data.inputs.wheelTimes; % in sec + % Resample values + t = 0:1/Fs:tRaw(end); + pos = interp1(tRaw, pos, t); + % Correct for over-/underflow + pos = wheel.correctCounterDiscont(pos); +end + +%% Convert to linear displacement (cm) +% If the units are in samples (i.e. loaded from inputs.wheel or +% inputSensorPos), convert to units of centimetres linear displacement. +% That is the distance the wheel would have rolled along a flat surface. +posCM = (rig.mouseInput.MillimetresFactor/10) .* pos; %#ok<*NASGU> +% or alternatively +res = rig.mouseInput.EncoderResolution*4; % Resolution * 4 for '4X' encoders +D = rig.mouseInput.WheelDiameter/10; % Converted to cm from mm +posCM = pos./res * pi * D; + +% The velocity is the derivative of this, so it's the tangential velocity +% in cm/sec +smoothSize = 0.03; % Gaussian smoothing window +[vel, acc] = wheel.computeVelocity2(pos, smoothSize, Fs); + +%% Convert to angular displacement (rad) +% For angular displacement / velocity, just divide by the wheel radius +posRad = posCM / 0.5*D; % in radians +velAng = vel / 0.5*D; % in rad/sec + +%% Convert to angular displacement (RPM) +% Convert this to the more intuitive revolutions per minute: +RPM = velAng*60 / 2*pi; + +%% Convert to angular displacement (deg) +% For displacement in degrees: +posDeg = rad2deg(posRad); +velDeg = rad2deg(velAng); +% or... +posDeg = pos / res*360; + +%% Convert to azimuth (visual degrees) +% If you know the response threshold in visual degrees, you can convert +% this to visual degrees. +thresh = 35; % visual degrees azimuth +% Position relative to interactive on +pos = pos - pos(1); +% Distance moved in whatever units +dist = diff([pos(1) pos(end)]); +% Convert to visual degrees moved, assuming correct is an element of [-1 0 +% 1] +posAzi = (pos/abs(dist) * thresh) - (sign(dist) * sign(correct) * thresh); +velAzi = (vel/abs(dist) * thresh) - (sign(dist) * sign(correct) * thresh); + +%% Notes +% (1) e.g. 'inputs.foo'. This is know as dot notation. More info +% . + +%% Etc. +% Author: Miles Wells +% +% v1.0.0 diff --git a/docs/setup/websocket_config.m b/docs/scripts/websocket_config.m similarity index 93% rename from docs/setup/websocket_config.m rename to docs/scripts/websocket_config.m index bc67ba07..f0f56b5c 100644 --- a/docs/setup/websocket_config.m +++ b/docs/scripts/websocket_config.m @@ -12,7 +12,10 @@ % %% Configuring WebSockets -% In order for the two computers to communicate... +% This section demonstrates how to configure WebSockets so that MC can +% connect to the Stimulus computer. See <./using_single_rig.html#3 this +% guide> if you wish to configure things for running |mc| and +% |srv.expServer| on the same computer (not recommended). % The stimulus controllers are loaded from a MAT file with the name % 'remote' in the globalConfig directory, defined in dat.paths: @@ -43,6 +46,22 @@ stimulusControllers(rig2).DefaultPort % *2014 stimulusControllers(rig2).Uri % 'ws://192.168.0.1:5000' +%% +% The port set in the URI of a rig's StrimulusControl object must be the +% same as the port used by that rig's |srv.expServer|. When expServer is +% started it listens on the default port (normally |2014|). If you wish to +% set a port that is different to the default port, you must save a +% Communicator object into the rig's hardware file and set it there. Below +% is some code for setting the default port to |3000| on a Stimulus +% Computer: + +% Create a communicator object (var name must be 'communicator') +communicator = io.WSJCommunicator.server(3000); + +% Save into the hardware file +hardware = fullfile(getOr(dat.paths, 'rigConfig'), 'hardware.mat'); +save(hardware, 'communicator', '-append') % append to the hardware file + %%% Experiment delays % Setting default delays is sometimes useful. These can also be changed in % the 'rig options' dialog in MC. The ExpPreDelay property is the time in @@ -326,6 +345,6 @@ %% Etc. % Author: Miles Wells % -% v1.0.0 +% v1.0.1 %#ok<*NOPTS,*ASGLU,*NASGU,*CLJAVA,*CLALL> \ No newline at end of file diff --git a/docs/setup/README.md b/docs/setup/README.md deleted file mode 100644 index 00355003..00000000 --- a/docs/setup/README.md +++ /dev/null @@ -1,6 +0,0 @@ -After installing Rigbox, we recommend reading the files below in the given order for setting up and customizing Rigbox on a new rig. - -- `paths_config.m` - configure the paths that Rigbox will use. -- `hardware_config.m` - configure hardware on SC. -- `websocket_config.m` - set up communication between MC and SC. -- `Burgess_setup.m` - (optional) configure reasonable defaults for running the [Burgess Steering Wheel Task](https://www.ncbi.nlm.nih.gov/pubmed/28877482). \ No newline at end of file diff --git a/docs/usage/README.md b/docs/usage/README.md deleted file mode 100644 index 8d0204be..00000000 --- a/docs/usage/README.md +++ /dev/null @@ -1,10 +0,0 @@ -After installing and setting up Rigbox (see `docs\setup`), we recommend reading the files below in the given order for learning how to use certain Rigbox features. - -- `using_dat_package.m` - set configuration files, set paths for saving and loading behavioral data, and query data locations. -- `running_experiments.m` - use the MC GUI to run experiments. -- `../../signals/docs` - use Signals for designing behavioral tasks. -- `using_parameters.m` - create and edit behavioral task parameters. -- `using_timeline.m` - (optional) use Timeline for time-aligning datastreams from multiple sources. -- `../../alyx-matlab/docs/AlyxMatlabPrimer.m` - (optional) interact with an [Alyx](https://alyx.readthedocs.io/en/latest) database. -- `using_services.m` - (optional) use auxiliary services for logging/triggering events between computers via UDP messages. -- `using_ExpPanel.m` - (optional) create a custom Experiment Panel which displays real-time psychometric data when running a Signals experiment. \ No newline at end of file diff --git a/docs/usage/running_experiments.m b/docs/usage/running_experiments.m deleted file mode 100644 index 4956a524..00000000 --- a/docs/usage/running_experiments.m +++ /dev/null @@ -1,29 +0,0 @@ -% This guide covers the basics of running experiments via the MC GUI. -% -% In order to start an experiment, you must first run `srv.expServer` on -% the SC. `srv.expServer` initializes the rig hardware and creates a window -% on the SC screen(s) on which visual stimuli are presented. -% -% After launching `srv.expServer`, the `mc` command should be run on the -% MC. This launches a GUI in which you will select an experiment subject, -% task (which we refer to as an “expdef”, which is short for “experiment -% definition”), and rig (i.e. the SC on which you just launched -% `srv.expServer`) on which to run an experiment. These can all be selected -% via the appropriate dropdowns in the top left of the MC GUI. For -% launching a test experiment, select the `test` subject, and one of the -% expdefs in `/signals/docs/examples/expdefs/`. Additionally, if you have -% set up a remote Alyx database, you can log into Alyx in the top -% right-hand corner of the MC GUI. -% -% Expdef parameters and rig options can be edited directly in the MC GUI -% before starting the experiment. Changes can be made to expdef parameters -% by editing their fields directly in the MC GUI. To set rig specific -% options, press the `Options` push-button. To start the experiment, press -% the `Start` push-button. After starting the experiment, the MC GUI should -% switch from the `New` tab to the `Current` tab. In the `Current` tab, -% live updates of all currently running experiments will be shown. -% Additionally, if you’ve created an ExpPanel for the running expdef, -% you can view real-time psychometric performance plots for this expdef. -% For more information on creating an ExpPanel, see `using_ExpPanel`. -% -% @todo add pictures diff --git a/signals b/signals index 4e05d253..55817070 160000 --- a/signals +++ b/signals @@ -1 +1 @@ -Subproject commit 4e05d2530083c271b65bbc23e5627f71c217a9b2 +Subproject commit 558170702aa2e6962c58f8b2a7b603a96b2c6b1a