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
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.
I'm working on this function which gets axis handler and data, and is supposed to plot it correctly in the axis. The function is called in for loop. It's supposed to draw the multiple data in one figure. My resulted figure is shown below.
There are only two correctly plotted graphs (those with four colors). Others miss areas plotted before the final area (red area is the last plotted area in each graph). But the script is same for every axis. So where can be the mistake? The whole function is written below.
function [] = powerSpectrumSmooth(axis,signal,fs)
N= length(signal);
samplesPer1Hz = N/fs;
delta = int16(3.5*samplesPer1Hz); %last sample of delta frequncies
theta = int16(7.5*samplesPer1Hz); %last sample of theta frequncies
alpha = int16(13*samplesPer1Hz); %last sample of alpha frequncies
beta = int16(30*samplesPer1Hz); %last sample of beta frequncies
x=fft(double(signal));
powerSpectrum = 20*log10(abs(real(x)));
smoothPS=smooth(powerSpectrum,51);
PSmin=min(powerSpectrum(1:beta));
y1=[(smoothPS(1:delta)); zeros(beta-delta,1)+PSmin];
y2=[zeros(delta-1,1)+PSmin; (smoothPS(delta:theta)); zeros(beta-theta,1)+PSmin];
y3=[zeros(theta-1,1)+PSmin; (smoothPS(theta:alpha)); zeros(beta-alpha,1)+PSmin];
y4=[zeros(alpha-1,1)+PSmin; (smoothPS(alpha:beta))];
a1=area(axis,1:beta,y1);
set(a1,'FaceColor','yellow')
hold on
a2=area(axis,1:beta,y2);
set(a2,'FaceColor','blue')
a3=area(axis,1:beta,y3);
set(a3,'FaceColor','green')
a4=area(axis,1:beta,y4);
set(a4,'FaceColor','red')
ADDED
And here is the function which calls the function above.
function [] = drawPowerSpectrum(axesContainer,dataContainer,fs)
size = length(axesContainer);
for l=1:size
powerSpectrumSmooth(axesContainer{l},dataContainer{l},fs)
set(axesContainer{l},'XTickLabel','')
set(axesContainer{l},'YTickLabel','')
uistack(axesContainer{l}, 'top');
end
ADDED 29th July
Here is a script which reproduces the error, so you can run it in your computer. Before running it again you might need to clear variables.
len = 9;
axesContainer = cell(len,1);
x = [0.1,0.4,0.7,0.1,0.4,0.7,0.1,0.4,0.7];
y = [0.1,0.1,0.1,0.4,0.4,0.4,0.7,0.7,0.7];
figure(1)
for i=1:len
axesContainer{i} = axes('Position',[x(i),y(i),0.2,0.2]);
end
dataContainer = cell(len,1);
N = 1500;
for i=1:len
dataContainer{i} = rand(1,N)*100;
end
for l=1:len
y1=[(dataContainer{l}(1:N/4)) zeros(1,3*N/4)];
y2=[zeros(1,N/4) (dataContainer{l}(N/4+1:(2*N/4))) zeros(1,2*N/4)];
y3=[zeros(1,2*N/4) (dataContainer{l}(2*N/4+1:3*N/4)) zeros(1,N/4)];
y4=[zeros(1,3*N/4) (dataContainer{l}(3*N/4+1:N))];
axes=axesContainer{l};
a1=area(axes,1:N,y1);
set(a1,'FaceColor','yellow')
hold on
a2=area(axes,1:N,y2);
set(a2,'FaceColor','blue')
hold on
a3=area(axes,1:N,y3);
set(a3,'FaceColor','green')
hold on
a4=area(axes,1:N,y4);
set(a4,'FaceColor','red')
set(axes,'XTickLabel','')
set(axes,'YTickLabel','')
end
My result of this script is plotted below:
Again only one picture contains all areas.
It looks like that every call to plot(axes,data) deletes whatever was written in axes.
Important note: Do not use a variable name the same as a function. Do not call something sin ,plot or axes!! I changed it to axs.
To solve the problem I just used the classic subplot instead of creating the axes as you did:
len = 9;
axesContainer = cell(len,1);
x = [0.1,0.4,0.7,0.1,0.4,0.7,0.1,0.4,0.7];
y = [0.1,0.1,0.1,0.4,0.4,0.4,0.7,0.7,0.7];
figure(1)
dataContainer = cell(len,1);
N = 1500;
for i=1:len
dataContainer{i} = rand(1,N)*100;
end
for l=1:len
y1=[(dataContainer{l}(1:N/4)) zeros(1,3*N/4)];
y2=[zeros(1,N/4) (dataContainer{l}(N/4+1:(2*N/4))) zeros(1,2*N/4)];
y3=[zeros(1,2*N/4) (dataContainer{l}(2*N/4+1:3*N/4)) zeros(1,N/4)];
y4=[zeros(1,3*N/4) (dataContainer{l}(3*N/4+1:N))];
axs=subplot(3,3,l);
a1=area(axs,1:N,y1);
set(a1,'FaceColor','yellow')
hold on
a2=area(axs,1:N,y2);
set(a2,'FaceColor','blue')
hold on
a3=area(axs,1:N,y3);
set(a3,'FaceColor','green')
hold on
a4=area(axs,1:N,y4);
set(a4,'FaceColor','red')
set(axs,'XTickLabel','')
set(axs,'YTickLabel','')
axis tight % this is to beautify it.
end
As far as I know, you can still save the axs variable in an axescontainer and then modify the properties you want (like location).
I found out how to do what I needed.
len = 8;
axesContainer = cell(len,1);
x = [0.1,0.4,0.7,0.1,0.4,0.7,0.1,0.4];
y = [0.1,0.1,0.1,0.4,0.4,0.4,0.7,0.7];
figure(1)
for i=1:len
axesContainer{i} = axes('Position',[x(i),y(i),0.2,0.2]);
end
dataContainer = cell(len,1);
N = 1500;
for i=1:len
dataContainer{i} = rand(1,N)*100;
end
for l=1:len
y1=[(dataContainer{l}(1:N/4)) zeros(1,3*N/4)];
y2=[zeros(1,N/4) (dataContainer{l}(N/4+1:(2*N/4))) zeros(1,2*N/4)];
y3=[zeros(1,2*N/4) (dataContainer{l}(2*N/4+1:3*N/4)) zeros(1,N/4)];
y4=[zeros(1,3*N/4) (dataContainer{l}(3*N/4+1:N))];
axes=axesContainer{l};
Y=[y1',y2',y3',y4'];
a=area(axes,Y);
set(axes,'XTickLabel','')
set(axes,'YTickLabel','')
end
The area is supposed to work with matrices like this. The tricky part is, that the signal in every next column is not plotted absolutely, but relatively to the data in previous column. That means, if at time 1 the data in first column has value 1 and data in second column has value 4, the second column data is ploted at value 5. Source: http://www.mathworks.com/help/matlab/ref/area.html
I want to calculate if a real-time signal pass some thresholds in the first step. In the first step, I want to detect if the real signal pass under those thresholds (in order to detect a peak in the signal). My Matlab code:
k=1;
t = 1;
l=1;
for i =1:length(sm) //sm my signal.
if (sm(i) > 0.25)
first(k) = i;
k = k+1;
if (sm(i) > 0.5)
second(t) = i;
t =t +1;
if (sm(i) > 0.75)
third(l) = i;
l = l+1;
end
end
end
end
Example:
![enter image description here][1]
I want to calculate the times that the signal pass over and under the three thresholds 0.25, 0.5, 0.75 and to return those windows. Basically the three main peaks that I have in my example.
Basically what am I trying to do is to use fastsmooth function and findpeaks.
signalSmoothed = fastsmooth(sm,50); plot(signalSmoothed)
[max_pk1 max_pk2] = findpeaks(signalSmoothed);
find(max_pk1 >0.5)
inversex = 1.01*max(signalSmoothed) - signalSmoothed;
[min_pk1 min_pk2] = findpeaks(inversex);
find(min_pk1 >0.5)
Which are the heuristics in order to take only the desired peaks? Moreover the depticted image is an offline example. Generally I want to perform the technique online.
EDIT: I wrongfully defined as peak my desired curve result which is the whole wave not just the max value.
Here is a solution to get the points where the signal sm passes the thresholds 0.25, 0.50 and 0.75. The points can be converted into windows inside the data-range and get stored in W. Finally we can plot them easily in the same figure. Note that we need to do some checks in the local function getwindows to handle special cases, for example when the window starts outside the data-range. The detection of windows inside another window is done in the getwindowsspecial-function.
Here is the code:
function peakwindow
% generate sample data
rng(7);
sm = 2*rand(1,25)-0.5;
sm = interp1(1:length(sm),sm,1:0.01:100*length(sm));
% get points
firstup = find(diff(sm > 0.25)==1);
secondup = find(diff(sm > 0.50)==1);
thirdup = find(diff(sm > 0.75)==1);
firstdown = find(diff(sm < 0.25)==1);
seconddown = find(diff(sm < 0.50)==1);
thirddown = find(diff(sm < 0.75)==1);
% plot the result
figure; hold on;
plot(sm,'k')
plot(firstup,sm(firstup),'*')
plot(firstdown,sm(firstdown),'*')
plot(secondup,sm(secondup),'*')
plot(seconddown,sm(seconddown),'*')
plot(thirdup,sm(thirdup),'*')
plot(thirddown,sm(thirddown),'*')
% get windows
W1 = getwindows(firstup,firstdown);
W2 = getwindows(secondup,seconddown);
W3 = getwindows(thirdup,thirddown);
% get special window
WS = getwindowsspecial(W1,W3);
% plot windows
plotwindow(W1,0.25,'r');
plotwindow(W2,0.50,'r');
plotwindow(W3,0.75,'r');
plotwindow(WS,0,'b-');
function W = getwindows(up,down)
if length(up)>1 && length(down)>1 && up(1)>down(1)
down(1)=[]; % handle case when window begins out of bounds left
end
if length(up)<1 || length(down)<1;
W = []; % handle if no complete window present
else
% concatenate and handle case when a window ends out of bounds right
W = [up(1:length(down));down]';
end
function plotwindow(W,y,lspec)
for i = 1:size(W,1)
plot(W(i,:),[y,y],lspec)
end
% get windows of U where there is a window of H inside
function W = getwindowsspecial(U,H)
W = []; % empty matrix to begin with
for i = 1:size(U,1) % for all windows in U
if any(H(:,1)>=U(i,1) & H(:,1)<=U(i,2))
W = [W;U(i,:)]; % add window
end
end
This is the result:
To see that the handling works properly, we can plot the result when initialized with rng(3):
Note that the window of 0.25 and 0.50 would start out of bounds left and therefore is not present in the plotted windows.
I am attempting to write a function that, if called before any animation, will handle the close events without extra code in the animation file.
function matlabStopFunction(varargin)
persistent runs
if runs==2
runs = [];
end
if isempty(runs)
evalin('base','figure(''DeleteFcn'',#matlabStopFunction);');
runs = 1;
else
assignin('base','play',false);
pause(1);
runs = 2;
end
end
Here's a sample animation code that I've been using:
function sampleAnimation
matlabStopFunction;
r = 5;
th = 0;
play = true;
while play
x = r * cosd(th);
y = r * -sind(th);
plot(x,y,'r*');
axis([-10 10 -10 10]);
th = th + 45;
pause(0.25);
end
end
The stop function works fine creating the figure, and when I close the figure, it calls the same function as expected (including the assignin on line 10). However, when stepping through, when I first get back to the base function (sampleAnimation), play is false as would be expected:
But when I step one more line, play is reset to true
Am I incorrectly assigning the value of play to false in the stop function, and if so, how could I correct this so that the animation stops when the figure is closed while keeping the code inside the animation to a minimum? I am trying to replicate the method on this blog except with all the code contained in a separate file.
I am running Matlab 2014b on Windows 8.1.
To answer your question - you are modifying the value play in the base workspace - where as the loop is in the workspace of the sampleAnimation function -> so you are not changing the required value to stop the animation. To verify this clear your variables in the base workspace clear before you run your code and you will see that the variable play is created and set to false.
By the way there is a much simpler way to do this, you animation can create a figure and then you can stop when it is deleted:
function sampleAnimation
h = figure;
r = 5;
th = 0;
while ishandle ( h )
x = r * cosd(th);
y = r * -sind(th);
plot(x,y,'r*');
axis([-10 10 -10 10]);
th = th + 45;
pause(0.25);
end
end