Skip to content

Commit e892f3a

Browse files
committed
Merge remote-tracking branch 'cpp-lln-lab/master'
2 parents 570c717 + 73580bb commit e892f3a

34 files changed

+767
-363
lines changed

README.md

Lines changed: 121 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -35,44 +35,74 @@ We use the [MISS_HIT linter](https://florianschanda.github.io/miss_hit/style_che
3535

3636
## How to install
3737

38-
### Use the matlab package manager
38+
### Download with git
39+
40+
``` bash
41+
cd fullpath_to_directory_where_to_install
42+
# use git to download the code
43+
git clone https://github.com/cpp-lln-lab/CPP_PTB.git
44+
# move into the folder you have just created
45+
cd CPP_PTB
46+
# add the src folder to the matlab path and save the path
47+
matlab -nojvm -nosplash -r "addpath(fullfile(pwd)); savepath ();"
48+
```
49+
50+
Then get the latest commit:
51+
```bash
52+
# from the directory where you downloaded the code
53+
git pull origin master
54+
```
3955

40-
This repository can be added as a dependencies by listing it in a [mpm-requirements.txt file](.mpm-requirements.txt)
41-
as follows:
56+
To work with a specific version, create a branch at a specific version tag number
57+
```bash
58+
# creating and checking out a branch that will be calle version1 at the version tag v0.0.1
59+
git checkout -b version1 v0.0.1
60+
```
4261

43-
CPP_PTB -u https://github.com/cpp-lln-lab/CPP_PTB.git
62+
### Add as a submodule
4463

45-
You can then use the [matlab package manager](https://github.com/mobeets/mpm), to simply download the appropriate version of those dependencies and add them to your path by running a `getDependencies` function like the one below where you just need to replace `YOUR_EXPERIMENT_NAME` by the name of your experiment.
64+
Add it as a submodule in the repo you are working on.
4665

47-
```matlab
48-
function getDependencies(action)
49-
% Will install on your computer the matlab dependencies specified in the mpm-requirements.txt
50-
% and add them to the matlab path. The path is never saved so you need to run getDependencies() when
51-
% you start matlab.
52-
%
53-
% getDependencies('update') will force the update and overwrite previous version of the dependencies.
54-
%
55-
% getDependencies() If you only already have the appropriate version but just want to add them to the matlab path.
56-
57-
experimentName = YOUR_EXPERIMENT_NAME;
58-
59-
if nargin<1
60-
action = '';
61-
end
62-
63-
switch action
64-
case 'update'
65-
% install dependencies
66-
mpm install -i mpm-requirements.txt -f -c YOUR_EXPERIMENT_NAME
67-
end
68-
69-
% adds them to the path
70-
mpm_folder = fileparts(which('mpm'));
71-
addpath(genpath(fullfile(mpm_folder, 'mpm-packages', 'mpm-collections', experimentName)));
72-
73-
end
66+
``` bash
67+
cd fullpath_to_directory_where_to_install
68+
# use git to download the code
69+
git submodule add https://github.com/cpp-lln-lab/CPP_PTB.git
70+
# move into the folder you have just created
71+
cd CPP_PTB
72+
# add the src folder to the matlab path and save the path
73+
matlab -nojvm -nosplash -r "addpath(fullfile(pwd))"
7474
```
7575

76+
To get the latest commit you then need to update the submodule with the information
77+
on its remote repository and then merge those locally.
78+
```bash
79+
git submodule update --remote --merge
80+
```
81+
82+
Remember that updates to submodules need to be commited as well.
83+
84+
**TO DO**
85+
<!-- Submodules
86+
pros: in principle, downloading the experiment you have the whole package plus the benefit to stay updated and use version control of this dependency. Can probably handle a use case in which one uses different version on different projects (e.g. older and newer projects).
87+
cons: for pro users and not super clear how to use it at the moment. -->
88+
89+
### Direct download
90+
91+
Download the code. Unzip. And add to the matlab path.
92+
93+
Pick a specific version:
94+
95+
https://github.com/cpp-lln-lab/CPP_PTB/releases
96+
97+
Or take the latest commit (NOT RECOMMENDED):
98+
99+
https://github.com/cpp-lln-lab/CPP_PTB/archive/master.zip
100+
101+
**TO DO**
102+
<!-- Download a specific version and c/p it in a subfun folder
103+
pros: the easiest solution to share the code and 'installing' it on the stimulation computer (usually not the one used to develop the code).
104+
cons: extreme solution useful only at the very latest stage (i.e. one minute before acquiring your data); prone to be customized/modified (is it what we want?) -->
105+
76106
## Setting up keyboards
77107

78108
To select a specific keyboard to be used by the experimenter or the participant, you need to know
@@ -98,9 +128,66 @@ press the keys necessary to start or abort the experiment.
98128

99129
Using empty vectors (ie `[]`) or a negative value for those means that you will let PTB find and use the default device.
100130

101-
## Structure and function details
131+
## Structure
132+
133+
```matlab
134+
135+
cfg.testingDevice = 'pc';
136+
137+
% cfg.color
138+
cfg.keyboard.keyboard = [];
139+
cfg.keyboard.responseBox = [];
140+
cfg.keyboard.responseKey = {};
141+
cfg.keyboard.escapeKey = 'ESCAPE';
142+
143+
% cfg.debug
144+
cfg.debug.do = true;
145+
cfg.debug.transpWin = true;
146+
cfg.debug.smallWin = true;
147+
148+
% cfg.text
149+
cfg.text.font
150+
cfg.text.size
151+
cfg.text.style
152+
153+
% cfg.color
154+
cfg.color.background
155+
156+
% cfg.screen
157+
cfg.screen.monitorWidth
158+
cfg.screen.monitorDistance
159+
cfg.screen.idx
160+
cfg.screen.win
161+
cfg.screen.winRect
162+
cfg.screen.winWidth
163+
cfg.screen.winHeight
164+
cfg.screen.center
165+
cfg.screen.FOV
166+
cfg.screen.ppd
167+
cfg.screen.ifi
168+
cfg.screen.monRefresh
169+
170+
% cfg.audio
171+
cfg.audio.do
172+
cfg.audio.pahandle
173+
cfg.audio.devIdx
174+
cfg.audio.playbackMode
175+
cfg.audio.requestedLatency
176+
cfg.audio.fs
177+
cfg.audio.channels
178+
cfg.audio.initVolume
179+
cfg.audio.pushSize
180+
cfg.audio.requestOffsetTime
181+
cfg.audio.reqsSampleOffset
182+
183+
% cfg.mri
184+
cfg.mri.repetitionTime
185+
cfg.mri.triggerNb
186+
cfg.mri.triggerKey
187+
```
188+
189+
## function details
102190

103-
<!-- ### setParameters -->
104191

105192
### initPTB
106193

apertureTexture.m

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
function cfg = apertureTexture(action, cfg, thisEvent)
2+
3+
transparent = [0 0 0 0];
4+
5+
switch action
6+
7+
case 'init'
8+
9+
% we take the screen height as maximum aperture width if not
10+
% specified.
11+
if ~isfield(cfg.aperture, 'width') || isempty(cfg.aperture.width)
12+
cfg.aperture.width = cfg.screen.winRect(4) / cfg.screen.ppd;
13+
end
14+
cfg.aperture = degToPix('width', cfg.aperture, cfg);
15+
16+
cfg.aperture.texture = Screen('MakeTexture', cfg.screen.win, ...
17+
cfg.color.background(1) * ones(cfg.screen.winRect([4 3])));
18+
19+
case 'make'
20+
21+
switch cfg.aperture.type
22+
23+
case 'none'
24+
25+
Screen('Fillrect', cfg.aperture.texture, transparent);
26+
27+
case 'circle'
28+
29+
diameter = cfg.aperture.widthPix;
30+
31+
xPos = cfg.screen.center(1);
32+
yPos = cfg.screen.center(2);
33+
if isfield(cfg.aperture, 'xPosPix')
34+
xPos = cfg.screen.center(1) + cfg.aperture.xPosPix;
35+
end
36+
if isfield(cfg.aperture, 'yPosPix')
37+
yPos = cfg.screen.center(2) + cfg.aperture.yPosPix;
38+
end
39+
40+
Screen('FillOval', cfg.aperture.texture, transparent, ...
41+
CenterRectOnPoint([0 0 repmat(diameter, 1, 2)], ...
42+
xPos, yPos));
43+
44+
end
45+
46+
case 'draw'
47+
48+
Screen('DrawTexture', cfg.screen.win, cfg.aperture.texture);
49+
50+
% Screen('DrawTexture', cfg.screen.win, apertureTexture, ...
51+
% cfg.screen.winRect, cfg.screen.winRect, current.apertureAngle - 90);
52+
53+
end
54+
55+
end

checkAbort.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
function checkAbort(cfg, deviceNumber)
2+
% checkAbort(cfg, deviceNumber)
3+
%
24
% Check for experiment abortion from operator
35
% When no deviceNumber is set then it will check the default device
46
% When an abort key s detected this will set a global variable and throw a

cleanUp.m

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
function cleanUp
1+
function cleanUp()
2+
% cleanUp()
3+
%
24
% A wrapper function to close all windows, ports, show mouse cursor, close keyboard queues
35
% and give access back to the keyboards.
46

collectAndSaveResponses.m

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
function responseEvents = collectAndSaveResponses(cfg, expParameters, logFile, experimentStart)
2-
1+
function responseEvents = collectAndSaveResponses(cfg, logFile, experimentStart)
2+
33
responseEvents = getResponse('check', cfg.keyboard.responseBox, cfg);
4-
4+
55
if isfield(responseEvents(1), 'onset') && ~isempty(responseEvents(1).onset)
6-
6+
77
for iResp = 1:size(responseEvents, 1)
88
responseEvents(iResp).onset = ...
99
responseEvents(iResp).onset - experimentStart;
1010
end
11-
11+
1212
responseEvents.fileID = logFile.fileID;
1313
responseEvents.extraColumns = logFile.extraColumns;
14-
saveEventsFile('save', expParameters, responseEvents);
15-
14+
saveEventsFile('save', cfg, responseEvents);
15+
1616
end
17-
end
17+
end

computeFOV.m

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
function FOV = computeFOV(cfg)
2+
% FOV = computeFOV(cfg)
3+
%
4+
% computes the number of degrees of visual angle in the whole field of view
5+
%
6+
% δ = 2 arctan ( d / 2D )
7+
%
8+
% δ is the angular diameter, and d is the actual diameter of the object,
9+
% and D is the distance to the object.
10+
% The result obtained is in radians.
11+
%
12+
13+
FOV = ...
14+
180 / pi * ...
15+
2 * atan(cfg.screen.monitorWidth / (2 * cfg.screen.monitorDistance));
16+
17+
end

decompMotion.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
function [horVector, vertVector] = decompMotion(angleMotion)
2+
% decompose angle of start motion into horizontal and vertical vector
3+
horVector = cos(pi * angleMotion / 180);
4+
vertVector = -sin(pi * angleMotion / 180);
5+
end

degToPix.m

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
function structure = degToPix(fieldName, structure, cfg)
2+
% structure = degToPix(fieldName, structure, cfg)
3+
%
24
% For a given field value in degrees of visual angle in the structure,
35
% this computes its value in pixel using the pixel per degree value of the cfg structure
46
% and returns a structure with an additional field with Pix suffix holding that new value.
57

68
deg = getfield(structure, fieldName); %#ok<GFLD>
79

810
structure = setfield(structure, [fieldName 'Pix'], ...
9-
floor(cfg.ppd * deg)) ; %#ok<SFLD>
11+
floor(deg * cfg.screen.ppd)) ; %#ok<SFLD>
1012

1113
end

demos/CPP_waitForTriggerDemo.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
cfg.testingDevice = 'mri';
44

5-
cfg.numTriggers = 4;
5+
cfg.mri.triggerNb = 4;
66

7-
cfg.triggerKey = 'space';
7+
cfg.mri.triggerKey = 'space';
88

99
KbName('UnifyKeyNames');
1010

0 commit comments

Comments
 (0)