Suppressing a specific key press in PsychToolBox - matlab

We are preparing a Likert type scale. Subjects must be allowed to just press the numbers of 1-9. We know ListenChar but it suppresses the whole keyboard. How can we suppress non-number keys?
while(1)
ch = GetChar;
if ch == 10 %return is 10 or 13
%terminate
break
else
response=[response ch];
end
end

If you only want to accept keypresses 1-9:
while(1)
ch = GetChar;
if ch == 10 %return is 10 or 13
%terminate
break
elseif (ch>48) & (ch<58) %check if the char is a number 1-9
response=[response ch];
pause(0.1) %delay 100ms to debounce and ensure that we don't count the same character multiple times
end
end
I also added a debounce, so that you don't accidentally log a single input many times.

Psychtoolbox includes functionality, via RestrictKeysForKbCheck, to restrict listening to specific keys.
The following code restricts possible inputs from 1-9, plus the esc key:
KbName('UnifyKeyNames'); % use internal naming to support multiple platforms
nums = '123456789';
keynames = mat2cell(nums, 1, ones(length(nums), 1));
keynames(end + 1) = {'ESCAPE'};
RestrictKeysForKbCheck(KbName(keynames));
Below is a trivial example of a block:
response = repmat('x', 1, 10); % pre-allocate response, similar to OP example
for ii = 1:10
[~, keycode] = KbWait(); % wait until specific key press
keycode = KbName(keycode); % convert from key code to char
disp(keycode);
if strcmp(keycode, 'ESCAPE')
break;
else
response(ii) = KbName(keycode);
end
WaitSecs(0.2); % debounce
end
RestrictKeysForKbCheck([]); % re-enable all keys

Related

How do I adjust this code so that I can enter how many runs I want and it will store each run in a matrix?

I have created this code to generate a 1 set of lottery numbers, but I am trying to make it so that the user can enter how many sets they want (input n), and it will print out as one long matrix of size nX6? I was messing around with a few options from online suggestions, but to no avail. I put the initial for i=1:1:n at the beginning, but I do not know how to store each run into a growing matrix. Right now it still generates just 1 set.
function lottery(n)
for i=1:1:n
xlow=1;
xhigh=69;
m=5;
i=1;
while (i<=m)
lottonum(i)=floor(xlow+rand*(xhigh-xlow+1));
flag=0;
for j=1:i-1
if (lottonum(i)==lottonum(j))
flag=1;
end
end
if flag==0
i=i+1;
end
end
ylow=1;
yhigh=26;
m=1;
lottonum1=floor(ylow+rand*(yhigh-ylow+1));
z = horzcat(lottonum, lottonum1);
end
disp('The lotto numbers picked are')
fprintf('%g ',z)
disp (' ')
The problem is that you are not storing or displaying the newly generated numbers, only the last set. To solve this, initialize z with NaNs or zeros, and later index z to store each set in a row of z, by using z(i,:) = lottonum.
However, you are using i as iterator in the while loop already, so you should use another variable, e.g. k.
You can also set z as an output of the function, so you can use this matrix in some other part of a program.
function z = lottery(n)
% init z
z = NaN(n,6);
for k = 1:n
xlow=1;
xhigh=69;
m=5;
i=1;
while (i<=m)
lottonum(i)=floor(xlow+rand*(xhigh-xlow+1));
flag=0;
for j=1:i-1
if (lottonum(i)==lottonum(j))
flag=1;
end
end
if flag==0
i=i+1;
end
end
ylow=1;
yhigh=26;
lottonum1 = floor(ylow+rand*(yhigh-ylow+1));
z(k,:) = horzcat(lottonum, lottonum1); % put the numbers in a row of z
end
disp('The lotto numbers picked are')
disp(z) % prettier display than fprintf in this case.
disp (' ')
end
The nice answer from rinkert corrected your basic mistakes (like trying to modify your loop iterator i from within the loop => does not work), and answered your question on how to store all your results.
This left you with a working code, however, I'd like to propose to you a different way to look at it.
The porposed architecture is to divide the tasks into separate functions:
One function draw_numbers which can draw N numbers randomly (and does only that)
One function draw_lottery which call the previous function as many times as it needs (your n), collect the results and display them.
draw_lottery
This architecture has the benefit to greatly simplify your main function. It can now be as simple as:
function Draws = draw_lottery(n)
% define your draw parameters
xmin = 1 ; % minimum number drawn
xmax = 69 ; % maximum number drawn
nballs = 5 ; % number of number to draw
% pre allocate results
Draws = zeros( n , nballs) ;
for iDraw=1:1:n
% draw "nballs" numbers
thisDraw = draw_numbers(xmin,xmax,nballs) ;
% add them to the result matrix
Draws(iDraw,:) = thisDraw ;
end
disp('The lotto numbers picked are:')
disp (Draws)
disp (' ')
end
draw_numbers
Instead of using a intricated set of if conditions and several iterators (i/m/k) to branch the program flow, I made the function recursive. It means the function may have to call itself a number of time until a condition is satisfied. In our case the condition is to have a set of nballs unique numbers.
The function:
(1) draws N integer numbers randomly, using randi.
(2) remove duplicate numbers (if any). Using unique.
(3) count how many unique numbers are left Nu
(4a) if Nu = N => exit function
(4b) if Nu < N => Call itself again, sending the existing Nu numbers and asking to draw an additional N-Nu numbers to add to the collection. Then back to step (2).
in code, it looks like that:
function draw = draw_numbers(xmin,xmax,nballs,drawn_set)
% check if we received a partial set
if nargin == 4
% if yes, adjust the number of balls to draw
n2draw = nballs - numel(drawn_set) ;
else
% if not, make a full draw
drawn_set = [] ;
n2draw = nballs ;
end
% draw "nballs" numbers between "xmin" and "xmax"
% and concatenate these new numbers with the partial set
d = [drawn_set , randi([xmin xmax],1,n2draw)] ;
% Remove duplicate
drawn_set = unique(d) ;
% check if we have some more balls to draw
if numel(drawn_set) < nballs
% draw some more balls
draw = draw_numbers(xmin,xmax,nballs,drawn_set) ;
else
% we're good to go, assign output and exit funtion
draw = drawn_set ;
end
end
You can have both functions into the same file if you want.
I encourage you to look at the documentation of a couple of Matlab built-in functions used:
randi
unique

how to set for-loop times limit and break the for-loop?

I would type the number 1~22. (because the number of figure is 22.)
( ex) when i type 1 then figure(1) is shown up. )
now i want to set times limit of this loop to 22.
because even i type all of them, they can't over 22.
and also i want to know the way end this loop without typing all number (less than 22).
i will show the code that i writed, please give me the advice.
for TNP=1:23
**% for-loop's end condition -->1. when i type all 22 number.
->2. when i type 23 to end the for-loop without typing more number.**
FN = input('Which figure do you want: ') **% here i would type the number of figure.**
if FN==1
F1=meshc(z(:,111:268))
grid on
hold on
elseif FN==2
F2=meshc(z(:,269:419))
grid on
hold on
elseif FN==3
F3=meshc(z(:,431:586))
grid on
hold on
.
.
.
else FN=23
close;
end
end
**% but even i add the 'break' for-loop doesn't end. what is the reason??**
You cannot use a loop here.
A loop is used when you want to repeat some code an specific number of times, which is not the case here (if I understood correctly).
What you want is to accept inputs from 1 to 22 to show the corresponding figures. I assume the figures don't have to be in order (otherwise you won't need a manual input)
You have to first define a number that will finish the loop (for example -1) and then use a while.
FN = input('Which figure do you want (1 to 22, or -1 to exit)?: ')
while FN ~= -1
if FN < 1 | FN > 22
disp (['Incorrect option: ' num2str(FN)]);
else
% your code to handle correct cases here
end
% now ask again
FN = input('Which figure do you want (1 to 22, or -1 to exit)?: ')
end
I agree with SembeiNorimaki -- your chosen design is a bit strange. I would go for something similar to what s/he wrote:
function myfcn()
% (define Z here)
% User input loop
while true
% Get the number
FN = input('Which figure do you want: ');
% Don't ever trust the user, even if
% the only user is you
if ~isnumeric(FN) || ...
~isscalar(FN) || ....
~isfinite(FN) || ...
~isreal(FN) || ...
FN > 23 || ...
FN < 0
warning([mfilename ':invalid_input'],...
'Invalid input; please insert a figure number 1-23, or 0 to exit.');
continue;
end
% It's always good to have an explicit exit condition
if FN == 0
break; end
% Apparently, you want this to be a special case
% (Note that this will only close the last figure drawn)
if FN == 23
close; end
% Call a handler to do all the heavy lifting
h = myGraphicsHandler(z, round(FN));
% ...Do whatever you want with this handle
end
end
function h = myGraphicsHandler(z, FN)
% These are the only things that seem to be
% different between each case
rangesTable = {111:268
269:419
431:586 % ... and so on
};
% create the figure
h = figure;
hold on
meshc(z(:, rangesTable{FN}));
grid on
% ... other operations / figure decorations here
end

Matlab: Can't handle data

I am writing a program in Matlab that reads in a Matrix coming from a sensor (microcontroller is an Arduino Leonardo). You can choose how fast the matrices are being recorded (e.g. 60 frames per min would be one matrix every second).
All that works great, but I had to create a default file that records all the matrices that would not be recorded (let’s say it’s fast enough to record 8 matrices per sec and you only want one per sec, then the default file would record the other seven). Otherwise I’d get kicked out of here:
%Get data
%Data is read as string (CSV)
data = str2double(strsplit(fgetl(serialPort), ','));
if and(get(hObject,'Value') == 1, correctPort == 1)
%try for right ports
try
%Reshape data (1D -> 2D array) and display in matrix
k = 1;
for i = 1:nrow
for j = 1:ncol
% Reading in tag names
tagNames{k} = ['tag_matrix_' num2str(k)];
% Creating matrix
data2d(row_index(i), col_index(j)) = data(k);
% Display in matrix
set(handles.(tagNames{k}),'String',data2d(i,j));
set(handles.(tagNames{k}),'visible','on');
k = k + 1;
end
end
catch
set(handles.tag_txt3,'String','This is not the correct port. Please look up the correct port in your Device Manager. Set up the right port and start again');
set(handles.tag_OnOff,'Value',0);
set(handles.tag_log,'Value',0);
set(handles.tag_log,'Enable','off')
correctPort = 0;
end
end
It goes through the loop a couple of time (a different number of times every time) but eventually I’ll get send to “catch”. This happens if i started recording or not. Doesn't matter.
If I have it display the matrices in the Command Window (data2d(row_index(i), col_index(j)) = data(k) without ;) it works.
Here is how I record the data:
% Open for writing
% Preparation
if and(startLog == 1, correctPort == 1)
set(handles.tag_txt3,'String','Program running and recording data');
end
% Set interval = recTime after logging (don't worry about that)
if and(startLog == 1, counter == 0)
interval = recTime;
counter = 1;
end
% Making sure you have to restart after stop logging
if and(startLog == 0, counter == 1)
set(handles.tag_OnOff,'Value',0)
end
% Record data when the time has come
if and(startLog == 1,time > interval)
fprintf(fid, '#');
fprintf(fid, '%u', matrixNumber);
fprintf(fid, '\n');
for i=1:size(data2d,1)
fprintf(fid, '%g\t', data2d(i,:));
fprintf(fid,'\n');
end
interval = recTime + interval;
matrixNumber = matrixNumber + 1;
%Making sure you have choosen a unit and send out error
elseif and(startLog == 1,recTime == 0)
set(handles.tag_txt3,'String','Choose a unit and start again');
set(handles.tag_OnOff,'Value',0)
set(handles.tag_log,'Value',0)
counter = 0;
else
%This is where the default file would be recording all the other matrices
end
Hope someone can help me. I didn't wanna put in the entire code because it's already ten pages. Please let me know if you have further questions.
Thank you so much in advance
Mike

Matlab symbols used to terminate the loop

I am new to matlab and I have couple of questions about it. First one, "Your function should terminate the sequence when either the value of ... or..." I use || in the code but it does not work as expected while && gives me the correct answer. Second question, how could the code be to display only the final answer?
Problem: calculate X which is represented by the sequence below
X = 1 - 1/2^2 + 1/3^2 - 1/4^2 +....
Requirement: Your function should terminate the sequence when either the value of 1/k^2 is less than 0.0001 or k is equal to k_max.
input k
Initialize x = 0
for loop i from 1 to k
if 1/i^2<0.0001 && i >= 100
break
end
Calculate X = (-1)^(i+1)./i^2 + X
end
You can use the break function as follows, where END_CONDITION is the condition you want to end your loop in.
if END_CONDITION
disp(X);
break;
end
To display the final answer, you can use the disp function. Eg. if your variable you want to print is called A then you use the following code.
disp(A)
Collectively this is your code. Since k_max terminates at the end of the for loop, we don't have to add any conditions to break out of the loop.
X = 0;
for i = 1:k
if 1/i^2<0.0001 || i==100
break;
end
X = (-1)^(i+1)./i^2 + X;
end
disp(X);

Identifying a flag set and printing a message in Matlab

Hi all I am working on checking for certain cases in a large loop, with in this large loop is this statement:
%Center Dialouge
timers_c = [start_dpc_sh_hi_timer_c, start_dpc_sh_lo_timer_c, start_ffm_sh_act_hi_timer_c,...
start_ffm_sh_act_lo_timer_c, start_hpot_eff_loss_timer_c, start_lfpt_dpsh_timer_c,...
start_pc_sh_time_c, start_post_tl_nl_c, start_pre_tl_nl_c, start_elec_lu_timer_c];
if perf_case_c ~= -1
for k = 1:10
if iscellstr(timers_c(k)) == 1
perf_case_timer_c = timers_c{k};
timer_set_c = 1;
end
end
end
To I identify the start time and the case type to be output in a dialogue message:
if timer_set_c == 1
pcase_c = msgbox([sprintf('%s'),perf_case_c,sprintf('\nMET:%s\n'),perf_case_timer_c],'PERFORMANCE CASE');
end
I can't get the if statement that determines which case has been determined to work. I am trying to use the change from -1 to a string somehow, but it doesn't quite work.
A minimal example would be
%Assume all timers initialized as zero
%Assume case ~= -1 (is a char array, string
timers_c = [timer1, timer2, timer3 ]
if case ~= -1
for k = 1:3
if iscellstr(timer_c(k)) ==1
case_time = timers(c{k});
time_set_flag = 1
end
end
end
...
and then outside of the loop would be the above msgbox