KeyPressFcn not working on specific occasions - matlab

I have a KeyPressFcn that seems to work whenever I'm obtaining new data and plotting it. When I'm not obtaining new data, the KeyPressFcn seems to no longer work. But if I do press the corresponding key, once I get back into data range and begin taking data again, it closes the figure.
I'm really confused why this is happening. My data collection happens only if a certain condition is met, but changing the KeyPressFcn and exitflag is inside my while loop and should be happening every time a loop occurs, thus I don't see why it wouldn't immediately exit my figure. Here is the code,
disp('DICOM Slice Viewer');
disp('" ": exit on space key');
global kpressed;
kpressed = 0;
%init figure on screen
global Fig;
Fig=DICOM_SliceViewer_createFigure(1,DICOMparam);
set(Fig.fig,'KeyPressFcn','global kpressed; global Fig; kpressed = get(Fig.fig,''CurrentChar'');');
exitflag = 0;
while (exitflag == 0)
Naviparam=Navi_acquire(Naviparam);
Naviparam=Navi_calc_data(Naviparam);
%calibration calculation !TO BE CHECKED!
DICOMPos = DICOMparam.calib.navi2dicom*[Naviparam.data.Endo_RefOffsetPosVec;1];
ixR=round(min(max(DICOMPos(1),1),DICOMparam.Sx));
iyR=round(min(max(DICOMPos(2),1),DICOMparam.Sy));
izR=round(min(max(DICOMPos(3),1),DICOMparam.Sz));
if kpressed ~= 0
switch kpressed
case ' '
exitflag = 1;
disp('**** Exit DICOM Slice Viewer ****')
end
kpressed = 0;
end
if Naviparam.datastr(5:11)~='MISSING'
%refresh plot with 3 standard cuts
set(Fig.sub1im, 'cdata', reshape(DICOMparam.Vd(ixR,:,:),[DICOMparam.Sy DICOMparam.Sz]));
set(Fig.sub2im, 'cdata', reshape(DICOMparam.Vd(:,iyR,:),[DICOMparam.Sx DICOMparam.Sz]));
set(Fig.sub3im, 'cdata', reshape(DICOMparam.Vd(:,:,izR),[DICOMparam.Sx DICOMparam.Sy]));
drawnow;
end
end
close(Fig.fig);
clear global;

Solved my own problem!
All I did was move the "drawnow" out of the if statement. This allowed me to draw my new data if it was taken, but also allowed some internal parameters to be updated in the figure I believe.

Related

How to plot data dynamically in MATLAB

I am having trouble plot the data dynamically,my goal is to plot data after checking a certain test of 14 days if I entered that condition loop I would like to execute a rectangle between the 1st day and the 14th day.
when I enter that last if loop I already have a xfist,xlast,y first y last. so I can draw a rectangle between them. And then when I pass the 14 days test again I would like to add to the existing plot another rectangle.
Here is my code so far.
The plot lines don't plot anything.
j=1;
while(j<72)
boom=true;
if a13(j)~= b8(j)|| a13(j)>1.1*(b8(j))&& a13(j)<0.9*(b8(j))
elseif a13(j)~=c5(j)|| a13(j)<0.9*(c5(j))&&a13(j)<0.9*(c5(j))
boom=false;
end
Xfirst=[];
Yfirst=[];
Xlast=[];
Ylast=[];
Yfirst=a13(j);
Xfirst=datetime(Date(j));
for i=j+1 :j+14
if a13(i)~= b8(i)|| a13(i)>1.1*(b8(i))&& a13(i)<0.9*(b8(i))
elseif a13(i)~= c5(i) || a13(i)<0.9*(c5(i)) && a13(i)>1.1*(c5(j))
j=i;
boom=false;
break;
end
end
if(boom==true)
Ylast=a13(j+14);
Xlast=New_Date(j+14);
figure (1)
plot(Xfirst,Yfirst)
hold on
plot(Xlast,Ylast)
end
j=j+1;
end
use drawnow inside the loop:
j=1;
while(j<72)
boom=true;
if a13(j)~= b8(j)|| a13(j)>1.1*(b8(j))&& a13(j)<0.9*(b8(j))
elseif a13(j)~=c5(j)|| a13(j)<0.9*(c5(j))&&a13(j)<0.9*(c5(j))
boom=false;
end
Xfirst=[];
Yfirst=[];
Xlast=[];
Ylast=[];
Yfirst=a13(j);
Xfirst=datetime(Date(j));
for i=j+1 :j+14
if a13(i)~= b8(i)|| a13(i)>1.1*(b8(i))&& a13(i)<0.9*(b8(i))
elseif a13(i)~= c5(i) || a13(i)<0.9*(c5(i)) && a13(i)>1.1*(c5(j))
j=i;
boom=false;
break;
end
end
if(boom==true)
Ylast=a13(j+14);
Xlast=New_Date(j+14);
figure (1)
plot(Xfirst,Yfirst)
hold on
plot(Xlast,Ylast)
drawnow; % To force figure to update
pause(0.2); % to allow time for it to render
end
j=j+1;
end
drawnow updates figures and processes any pending callbacks. Use this command if you modify graphics objects and want to see the updates on the screen immediately.

Matlab stop function's execution

I have an array. I am processing elements of this array in a for loop inside a function.
function results = processArray(array)
for ii = 1:length(array)
%some stuff here
results(ii) = %getting the results for this particular element
end
end
There might be a lot of elements and computations might take a lot of time. I want to be able to finish execution of the for loop at any arbitrary time when a user wants to do that so that the results for already processed elements would be available.
I was trying to make a figure with a button which would change a boolean flag. Inside the for loop I was checking the value of that boolean. If the boolean changed then the for loop should break.
function results = processArray(array)
fig = figure;
fig.UserData.continue = 1;
uicontrol('Parent', fig', 'Style', 'pushbutton', 'String', 'stop', 'callback', #interrupt)
for ii = 1:length(array)
if(fig.UserData.continue == 0)
break;
end
%some stuff here
results(ii) = %getting the results for this particular element
end
end
function interrupt(obj, ~)
fig = obj.Parent;
fig.UserData.continue = 0;
end
well, that does not work. The figure shows up only after all the computations are done already. If I draw the figure first using something like waitforbuttonpress and proceed to the for loop pressing the button does not stop the execution. I think the callback function is being executed only after the for loop is finished. Is there any way to solve this?
You will need to drawnow after you create the button, so it will show up. You also need to drawnow within the loop to update the button state. Then you should achieve what you want.
drawnow force figure update, so it will slow down your computation a little.

Matlab gui with pause function

I am using the GUIDE for matlab gui.
The gui built in order to communicate with keithley current measurement device through GPIB.
When using a toggle button for Current measurement while loop, i am using a pause() function inside the while loop for each iteration and a ytranspose on the y array reading results.
function Measure_Callback(hObject, eventdata, handles)
global GPIB1
global filename
global timeStep
disp('Measurement in progress \n stopwatch starts!');
tic
x=0;
n=0;
while get(hObject,'Value')
fprintf(GPIB1, 'printnumber(smua.measure.i(smua.nvbuffer1))');
fprintf(GPIB1, 'printbuffer(1,1,nvbuffer1)');
A = fscanf(GPIB1);
if length(A)<20
x = x+1;
n = n+1;
t(n) = toc ;
y(x) = str2double(A);
plot(t,y,'-bo',...
'LineWidth',2,...
'MarkerEdgeColor','k',...
'MarkerFaceColor',[.49 1 .63],...
'MarkerSize',10);
grid on
hold on
end
title('Current vs Time','FontSize', 15)
xlabel('Time [s]','FontSize', 15)
ylabel('Current [A]','FontSize', 15)
a = timeStep;
pause(a)
end
disp('Measurement terminated');
disp('Elapsed time: ');
elapsedtime = toc;
elapsedtime_string = num2str(elapsedtime);
disp(elapsedtime_string);
ytrans = transpose(y);
csvwrite(filename,ytrans);
fprintf(GPIB1, 'smua.source.output = smua.OUTPUT_OFF');
For the pause function i'm geting error:
?? Error using ==> pause Error while evaluating uicontrol Callback
For the transpose(y) function i'm also getting a error:
its undefined y.
Cant understand why are those errors and could use some help.
Thank you!
First off, as people say, post the errors and the code. Do you know if length(A) is smaller than 20 in the first time you run the loop? Because if not, A is not defined and you can't transpose something that is not there. Initialize A before the loop to something and see if the error persists (or print out length(A) to make sure the loop gets entered the first run).
As for the pause error, make sure pause is an int or double, not a string. If you get your global timeStep from the GUI field, it is probably a string and you need to covert it to double first.

Saving a specific simulation time

I have a two-track model implemented in simulink. To control the velocity I use a PID-controller, so that the the output of the velocity looks like this:
now I want to implement a MATLAB function or simulink block that tracks the time when the velocity reaches a steady-state-behaviour and puts it into some kind of storage. I tried to implement something like this via the following MATLAB function with MATLAB-function-block:
function y = fcn(t,v,dv,tv)
%#codegen
if (v==tv+0.01) & (dv<0)
y=t
end
t is the clock-signal, v the velocity, dv the first derivation of the velocity and tv is the targetvelocity. The problem about this function is that there "y is not defined on some execution paths". do you have any ideas how to make this work?
I solved the problem without a MATLAB function using the simulink blocks data store memory and its read & write blocks. The signal that is coming in from bottom right side is the momentary velocity. The if statement is
(u1 >= 22.2) & (u1<=22.3) & (u2<0)
Since simulink is using time steps and the momentary velocity will never be exactly 22.2, you can not use u1==22.2
In SimuLink add a second output and a fifth input to your function. Then use that new output as a feedback to the function.
function [y, output] = fcn(t,v,dv,tv,input)
y = 0;
output = input;
if (v == tv + 0.01) && (dv < 0)
y = t;
if (input == -1)
output = t;
end
end
Attach the output to an IC block where you set the input initial value to -1 or whatever value you want to use. Then attach the IC block to the input of the function. output will be feedback constantly through the function. Once it's set it will reatin it's value forever.
function y = fcn(t,v,dv,tv)
%#codegen
y = zeros(length(t),1); % Initialise the array
for ii = 1:length(t)
if (v==tv+0.01) & (dv<0)
y(ii)=t;
else
y(ii)=0;
end
end
y(y==0)=[];
end
Two changes: added a semicolon after y=t to force it to not print it every time it is set. Second, your question, else y=[];, which means that y will be an empty matrix if you do not adhere to your if statement.
It now stores a 0 each time you do not adhere to the if statement. The line y(y==0)=[]; deletes all zeros, comment this line if you want your y to be the same length as the input variables.
function y = fcn(t,v,dv,tv)
%#codegen
y = zeros(length(t),1); % Initialise the array
ii=1;
while exist(t)
if (v==tv+0.01) & (dv<0)
y(ii)=t;
else
y(ii)=0;
end
ii = ii+1;
end
y(y==0)=[];
end

Repeating trials in MatLab

i'm am very new to Matlab but really want improve. For my experiment i want to show a picture which the participant response yes/no to, using two different keys (f&g) and then the next picture is presented and it repeats so onward.
Presenting the picture, using the keys works for far, but i can't get it to repeat the trial. Thus my question is how can i get the program to repeat/loop my trial?
Is there something wrong in my code so far or is there additional coding i should use?
this is my code so far
function try1_6()
cleanupObj= onCleanup(#() myCleanupFxn);
% PRETEST
% Initialize screen with black background
winID = Screen('openWindow',0, [0 0 0]);
%Parameter
backcol=255;
textcol=0;
% Load image file(s)
structimages= [];
TheImagesdir = dir('theImagesdir/*.jpg');
for i=1: length(TheImagesdir);
TheImages = imread(['theImagesdir/' TheImagesdir(i).name], 'JPEG');
% Get width and height
imageX = size(TheImages,2);
imageY = size(TheImages,1);
% Convert to texture
myTexture = Screen('MakeTexture', winID, TheImages);
% Set destination rectangle
destRect = [50 100 50+imageX 100+imageY];
%save to structure
structimages(end+1).filename=TheImagesdir(i).name;
structimages(end).destRect= destRect;
structimages(end).texture= myTexture;
end
%Make triallist
numberOfItems= [5]; %list of all possible items
Nrepeats=4;
Response=0;
TrialList=HH_mkTrialList({numberOfItems Response},Nrepeats);
%PRESENTATION
for trialnum=1:size(TrialList,1)
nitems = TrialList(trialnum,1);
Screen('FillRect', winID,backcol); % makes the screen blank
%displays text
DrawFormattedText(winID,'dkjfghaslkdfglksdjgfh','center','center',textcol);
Screen('Flip', winID)
HH_waitForKeyPress({'space'}); % waits for spacebar to be pressed
Screen('FillRect',winID,backcol);
Screen('Flip',winID);
WaitSecs(1);
%display picture
whichTheImages= randi(length(TheImagesdir)); % randomly selects image for directory
Screen('FillRect',winID,backcol);
Screen('DrawTexture', winID, myTexture, [], destRect);
Screen('Flip', winID);
HH_waitForKeyPress({'f','j'},5)
if resp==-1
break
end
TrialList(trialnum,4)= response; %records response
end
end
function myCleanupFxn()
Screen('CloseAll')
end
There are a number of problems with you code that you need to address. First of all, TrialList is used before it is declared/initialized. The Make triallist block of code seems out of place in the body of the for loop, and should probably be placed before you loop TrialList.
Your second problem is the inner for loop that loads images. Right now, it loads every image found in the directory, on every trial! There is no reason for you to be doing this, and you should be placing this for loop outside the trial loop as well. Furthermore, your original code never worked as intended, because you never save the loaded texture anywhere; myTexture is overwritten by the last image in your folder and that's the only texture you're ever gonna get. So in addition to pre-loading the images before the loop, you need to save them in a data structure so that you can use them later in your trial loop. A simple struct will work nicely here:
structImages = [];
TheImagesdir = dir('theImagesdir/*.jpg');
for i = 1:length(TheImagesdir);
TheImages = imread(['theImagesdir/' TheImagesdir(i).name], 'JPEG');
% Get width and height
imageX = size(TheImages,2);
imageY = size(TheImages,1);
% Convert to texture
myTexture = Screen('MakeTexture', winID, TheImages);
% Set destination rectangle
destRect = [50 100 50+imageX 100+imageY];
%save to structure
structImages(end+1).filename = TheImagesdir(i).name;
structImages(end).destRect = destRect;
structImages(end).texture = myTexture;
end
There are other inconsistencies in your code:
whichTheIamges is defined but not used
resp is used in the comparison if resp==-1 but is not defined
response is saved into TrialList before it is defined
Finally, the biggest problem is Screen('CloseAll', winID); is inside the trial loop, so you tear down your whole presentation platform after the first trial.
FYI, as noted in my comment wrapping your entire script in a try block is really poor practice. I suspect you do this because you want to be able to Ctrl+C mid-task, but there's a better way to do this. If you make your entire script a function then you can use the onCleanup method to execute code whenever your function exits (whether normally, by error, or by interruption). The method goes like this:
function myScript()
%//make your script a function. There is an additional advantages to doing this:
%//function performance is better than script performance.
%//blah-blah-blah
%//setup the cleanup object before opening screen
cleanupObj = onCleanup(#() myCleanupFxn);
%//open the screen
winID = Screen('openWindow',0, [0 0 0]);
%//blah-blah-blah
end
function myCleanupFxn()
%//local function, not visible outside of this file
Screen('CloseAll');
end