Take user input while running in Matlab - matlab

I have a function that I would like to take input for but only when the user wants to. For example if i have this code:
figure
amplitude = 10;
tic
i = 1;
while(1)
time = toc;
values(i) = amplitude*sin(time);
times(i) = time;
plot(times, values)
drawnow
i = i+1;
end
You will get a continually plotting sine wave (like a lame movie). What I want to do is allow the user to change the amplitude of the wave at any time. That is the program will continue to run but if the user types in 20 and Enter then the amplitude variable can be changed and the sine wave will change amplitude in the movie. Any pointers on how to achieve this?

You won't be able to do this by typing numbers into the console, but you can do it with a simple GUI. Do a google search for Matlab callbacks to find examples. When a GUI event occurs, it triggers a function that you can use to modify the variables in your loop.

It is probably best to do it with a GUI as mentioned, but if you just want something in the console here is what I can offer:
A script that periodically asks the user to input an amplitude and then continues the 'movie' with this amplitude. It can easily be expanded to allow the user to decide when he will be asked to input the next amplitude change.
clear
amplitude = 10;
i=1;
while(1)
time = i/1000;
values(i) = amplitude*sin(time);
times(i) = time;
plot(times, values)
drawnow
i = i+1;
if mod(i,3141) == 0
keyboard
end
end
Now this will run for a while and then ask you to input the next amplitude. Note that you can actually give multiple commands at once.
amplitude = 20; return
amplitude = 1; return
This will let the next amplitude be 20 and the one after that 1. Note that the upward arrow key is your friend here.

Related

Matlab: Criteria for displaying screens to subjects

I am delivering a psychology experiment in Matlab, where screens with questions will be presented to subject. The screen will also collect and display the subjects' responses. For example: Screen displays '2+3' and also displays what participant types (say, 99999), until they press enter.
GOAL: get it to stop displaying the question after 16 seconds if the participant has not yet pressed enter. (That is, stop displaying the screen if time=16sec OR if subject presses Enter.)
The problem revolves around the following code:
While CurrentTime<TimeOut
respond=GetChar() <-(Waits till user press enter)
end
So whatever the statements we add before/after capturing respond statements is not executed.
Any help on how to work around this issue would be greatly appreciated! Thanks.
Here is an example, I presented an oval as an example, you can obviously replace that with whatever your stimuli are. Enter and Return are separate keys, I wasn't sure which you're looking for, so in the example the loop looks for either.
%% include at top of experiment / block
waitForResponseSeconds = 16; % number of second to wait for a response
enterKey = KbName('enter'); % numeric code for enter key
returnKeys = KbName('return'); % numeric code for return key(s)
responseKeys = [enterKey returnKeys];
wPtr = Screen('OpenWindow', 0, 0, [0 0 400 400]);
%% within the trial loop:
hasResponded = 0;
% present the stimulus (here the window pointer is called wPtr, you may
% need to adjust this depending on what you named the window pointer.
Screen('FillOval', wPtr, [100 0 100], [0 0 400 400]);
[~, Onset] = Screen('Flip', wPtr);
while ~hasResponded && ((GetSecs - Onset) <= waitForResponseSeconds)
[keyIsDown, secs, keyCode] = KbCheck;
if any(keyCode(responseKeys))
rt = 1000.*(secs-Onset); % get response time
hasResponded = 1;
end
% Wait 1 ms before checking again to prevent
% overload of the machine at elevated priority
WaitSecs(0.001);
end
%% end of exp
sca;

How can I check mouse events as a background process in Matlab?

I am using Matlab to develop an application which performs several mathematical operations, whose parameters can be changed when the mouse is clicked, as in the example below.
while time<endtime
calculate_manythings;
if ~mod(time,checkmouse)
mouseinput_timeout(timemouse, gca);
change_calculation_parameters;
end
time=time+1;
end
At the moment, I am pausing the operations periodically to check for mouse events, but this is slow and unpractical. How can I monitor these continually and run the code at the same time? Could I make the mouse event checks a background process using parfeval, for example?
Many thanks,
Marta
you can use callback functions. here I used 'ButtonDownFcn':
timeinterval = 1; % seconds between mouse clicks
% generate axes with callback function
h = plot(rand(1,2),'LineWidth',6);
set(gca,'ButtonDownFcn',#callback);
% reset Tag and time
h.Tag = '';
tic;
while true
drawnow;
if strcmp(h.Tag,'Pressed') % if pressed
t = toc; % check time passed
if t >= timeinterval
% change parameters
disp('Pressed');
h.Color = rand(1,3);
% reset timer
tic;
end
% reset Tag
h.Tag = '';
end
end
and the callback function is:
function callback(src,~)
src.Children(1).Tag = 'Pressed';
end

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

Matlab parallel computing - Simultaneous play and record

I want to play a pure tone and record from the default microphone simultaneously using Matlab.
%% Main code
frequency = 500;
time = 5;
tic
parfor ii = 1:2
if ii==1
recording = test_record(time);
elseif ii==2
test_play(frequency,time);
end
end
toc
size(recording)
This all works fine except that recording variable is not available after the parfor loop ends and I need it for further analysis. I'd appreciate suggestions of how to make the recorded sample available after the parforloop or even better - I'll be happy to learn if a better design is preferable.
Thanks!
Here are the two additional functions used for running the above code :
%% Play the given frequency
function test_play(frequency,recording_time)
fs = 8000; % Samples per second
t = 0:(1/fs):recording_time;
y = sin(2*pi*frequency*t);
sound(y, fs);
end
%% Record from the microphone for given number of seconds
function recording = test_record(recording_time)
recObj = audiorecorder;
recordblocking(recObj, recording_time);
recording = getaudiodata(recObj);
end
Note - A related question's answer redirect to some program (Sox) that seem to do what I search for, however I want to write the Matlab code myself.
In your case, recording is a local variable which remains on the worker. This code creates a sliced cell array which should fix it:
%% Main code
frequency = 500;
time = 5;
recording=cell(2,1)
parfor ii = 1:2
if ii==1
recording{ii} = test_record(time);
elseif ii==2
test_play(frequency,time);
end
end
Obviously, your data is recording{1}

Matlab: Print progress from parfor loop

I run a lot of long simulations in Matlab, typically taking from a couple of minutes to a couple of hours, so to speed things up I decided to run the simulations simultaneously using a parfor loop.
arglist = [arg1, arg2, arg3, arg4];
parfor ii = 1:size(arglist, 2)
myfun(arglist(ii));
end
Everything worked just fine, except for one thing: the progress printing. Since each simulation takes a lot of time, I usually print progress using something like
prevlength = 0;
for ii = 1:tot_iter
% Some calculations here
msg = sprintf('Working on %d of %d, %.2f percent done', ii, tot_iter, ii/tot_iter);
fprintf(repmat('\b', 1, prevlength))
fprintf(msg);
prevlength = numel(msg);
end
but, as could be expected, when doing this inside a parfor loop, you get chaos.
I have googled a lot in search of a solution and have found a bunch of "parfor progress printers" like this one. However, all of them print the progress of the entire parfor loop instead of showing how far each of the individual iterations have come. Since I only have about 4-8 iterations in the parfor loop, but each iteration takes about an hour, this approach isn't very helpful to me.
The ideal solution for me would be something that looks like this
Working on 127 of 10000, 1.27 percent done
Working on 259 of 10000, 2.59 percent done
Working on 3895 of 10000, 38.95 percent done
Working on 1347 of 10000, 13.47 percent done
that is, each simulation gets one line showing how far it has run. I'm not sure though if this is possible at all, I can at least not imagine any way to do this.
Another way would be to do something like this
Sim 1: 1.27% Sim 2: 2.59% Sim 3: 38.95% Sim 4: 13.47%
that is, show all the progresses on the same line. To do this, you would need to keep track of what position on the line each simulation is to write on and write there, without erasing the other progresses. I can't figure out how this would be done, is this possible to do?
If there is some other solution to my problem (showing the progress of each individual iteration) that I haven't thought of, I'd be happy to hear about it.
Since this is the first time I ask a question here on SO it is quite possible that there is something that I have missed; if so, please feel free to comment below.
Edit
After receiving this answer, I thought that I should share how I used it to solve my problem since I didn't use it exactly as in the answer, in case someone else encounters the same problem.
Here is a small test program with basically the same structure as my program, making use of the progress bar (parfor_progress) mentioned in the answer:
function parfor_progress_test()
cpus = feature('numCores');
matlabpool('open', cpus);
cleaner = onCleanup(#mycleaner);
args = [1000, 1000, 1000, 1000];
m = sum(args);
parfor_progress(m);
parfor ii = 1:size(args,2)
my_fun(args(ii));
end
parfor_progress(0);
end
function my_fun(N)
for ii = 1:N
pause(rand*0.01);
parfor_progress;
end
end
function mycleaner
matlabpool close;
fclose all;
end
Simple Progress Bar
Something like a progress bar could be done similar to this...
Before the parfor loop :
fprintf('Progress:\n');
fprintf(['\n' repmat('.',1,m) '\n\n']);
And during the loop:
fprintf('\b|\n');
Here we have m is the total number of iterations, the . shows the total number of iterations and | shows the number of iterations completed. The \n makes sure the characters are printed in the parfor loop.
Progress Bar and Percentage Completion
Otherwise you could try this: http://www.mathworks.com/matlabcentral/fileexchange/32101-progress-monitor--progress-bar--that-works-with-parfor
It will display a progress bar and percentage completion but can be easily modified to just include the percentage completion or progress bar.
This function amends a character to a file on every iteration and then reads the number of characters written to that file which indicates the number of iterations completed. This file accessing method is allowed in parfor's.
Assuming you correctly add the above to your MATLAB path somehow, you can then use the following:
arglist = [arg1, arg2, arg3, arg4];
parfor_progress(size(arglist, 2)); % Set the total number of iterations
parfor ii = 1:size(arglist, 2)
myfun(arglist(ii));
parfor_progress; % Increment the progress counter
end
parfor_progress(0); % Reset the progress counter
Time to Completion and Percentage Completion
There is also a function called showTimeToCompletion() which is available from: https://www.soundzones.com/software/sound-zone-tools/
and works alongside parfor_progress. This function allows you to print a detailed summary of the progress of a parfor loop (or any loop for that matter) which contains the start time, length of time running, estimated finish time and percentage completion. It makes smart use of the \b (backspace) character so that the command window isn't flooded with text. Although not strictly a progress 'bar' it is perhaps more informative.
The third example in the header of the function file,
fprintf('\t Completion: ');
showTimeToCompletion; startTime=tic;
len=1e2;
p = parfor_progress( len );
parfor i = 1:len
pause(1);
p = parfor_progress;
showTimeToCompletion( p/100, [], [], startTime );
end
outputs the following to the command window:
Completion: 31.00%
Remaining: 00:00:23
Total: 00:00:33
Expected Finish: 3:30:07PM 14-Nov-2017
Useful for estimating the completion of a running simulation, especially one that may take hours or days.
Starting in R2013b, you can use PARFEVAL to evaluate your function asynchronously and have the client display progress updates. (Obviously this approach is not quite as simple as adding stuff to your PARFOR loop). There's an example here.
The Diary property of the Future returned by PARFEVAL is updated continuously while processing, so that might also be useful if you have a small number of large tasks.
Starting in R2017a, you can use parallel.pool.DataQueue and afterEach to implement a waitbar for parfor, like so:
if isempty(gcp('nocreate'))
parpool('local', 3);
end
dq = parallel.pool.DataQueue;
N = 10;
wb = waitbar(0, 'Please wait...');
% Use the waitbar's UserData to track progress
wb.UserData = [0 N];
afterEach(dq, #(varargin) iIncrementWaitbar(wb));
afterEach(dq, #(idx) fprintf('Completed iteration: %d\n', idx));
parfor idx = 1:N
pause(rand());
send(dq, idx);
end
close(wb);
function iIncrementWaitbar(wb)
ud = wb.UserData;
ud(1) = ud(1) + 1;
waitbar(ud(1) / ud(2), wb);
wb.UserData = ud;
end
after exploring #Edric answer I found that there is an example in the Matlab documentation that exactly implements a waitbar for a pareval loop. Check help FetchNext
N = 100;
for idx = N:-1:1
% Compute the rank of N magic squares
F(idx) = parfeval(#rank, 1, magic(idx));
end
% Build a waitbar to track progress
h = waitbar(0, 'Waiting for FevalFutures to complete...');
results = zeros(1, N);
for idx = 1:N
[completedIdx, thisResult] = fetchNext(F);
% store the result
results(completedIdx) = thisResult;
% update waitbar
waitbar(idx/N, h, sprintf('Latest result: %d', thisResult));
end
% Clean up
delete(h)