Variable persisting between function calls - matlab

Suppose I want to call a function twice, but I need the function to remember variables it initialized the first time it is called so execution can be changed in subsequent calls.
For example if I have a piece of code like this:
function random
if exist('a','var') == 0
fprintf('hello\n');
a = 1;
else
disp('goodbye\n');
end
end
How could I get MATLAB to remember that a equals 1 when when I call the code again? Specifically, I'm hoping to use this for a push button callback function in a program I'm writing.

MATLAB supports the keyword persistent, which you would use as follows:
function toggleval_persist
% Set up the persistent variable and initialize it.
persistent a;
if isempty(a)
a = 0;
end
if ( a == 0 )
disp('hello');
a = 1;
else
a = 0;
disp('goodbye');
end
end
Also, I wouldn't recommend using a persistent variable for toggling a button state. The button's state is usually available in the object structure for the GUI if you're using MATLAB's UI system.

What you could do (in the optics of using this code in a GUI) is set up a flag telling whether a has been initialized or not and pass it as an argument to the function random. Storing the flag (let's call it a_flag) in the handles structure of the GUI, for instance, would allow you to keep track of its value (actually stored in handles.a_flag) for example.
So in other words,you could set the flag to 0 during the creation of the GUI (or in its Opening_Fcn if you are using GUIDE) as follows:
handles.a_flag = false;
and then in the function called random, which you could call with: random(handles.a_flag):
function random(a_flag)
if ~a_flag
%// Update the flag
a_flag = true;
fprintf('hello\n');
a = 1;
else
fprintf('goodbye\n');
end
end
Even simpler would be to use global variables...but I like that idea better :)
EDIT
The point of my code is to demonstrate that we can use the handles structure of a GUI (as asked by the OP) to store the value of the flag. Since the structure is accessible from every callback pressing the pushbutton will update it the same way a persistent variable would.
Please try this code to see what I mean:
function TestGUI
clear
clc
hFigure = figure('Position',[200 200 200 150]);
handles.Disp_a_title = uicontrol('Style','text','String','a','Position',[20 100 60 20]);
handles.Disp_aflag = uicontrol('Style','text','String','0','Position',[100 100 60 20]);
handles.Button = uicontrol('Style','Push','Position',[50 50 60 20],'String','Update a','Callback',#(s,e) PushCb);
a = 0;
handles.a_flag = false;
guidata(hFigure,handles)
function PushCb(~,~)
handles = guidata(hFigure);
fprintf('Flag is %i\n',handles.a_flag)
if handles.a_flag == false;
disp('hello\n');
a = 1;
handles.a_flag = true;
else
disp('goodbye\n');
end
guidata(hFigure,handles)
end
end
Pressing the button twice results in the following output in the Command Window:
Flag is 0
hello\n
Flag is 1
goodbye\n
Which from what I understood is the expected behaviour the OP is looking for.

Related

Matlab-GUI warning when using parfeval(): "Unable to save App Designer app object."

I am trying to call parallel functions within my Matlab-GUI by pushing a startbutton.
For the beginning I tried to call one single function ("ReadTwinCAT") but I'm always getting the following error-message:
"Warning: Unable to save App Designer app object. Save not supported
for matlab.apps.AppBase objects."
As I thought I already used parallel functions like this within a GUI, I don't know what I am doing wrong...
Matlab-App-Designer Code:
properties (Access = private)
running_state = 0; % Description
tcClient;
db_conn;
end
methods (Access = private)
function ReadTwinCAT(app)
while app.running_state == 1
disp('running')
pause(0.1)
end
disp('stopped')
end
end
% Callbacks that handle component events
methods (Access = private)
function StartButtonPushed(app, event)
app.running_state = 1;
pool = gcp(); %Initialize pool of workers
parfeval(pool, #ReadTwinCAT, 0, app); %Call parallel function
end
end
Ok, I think I found an answer from Mathworks staff:
https://www.mathworks.com/matlabcentral/answers/366576-will-there-be-a-support-of-the-parallel-toolbox-in-matlab-app-designer#comment_720548
Note the limitation of accessing the app object inside the parfor loop or any other functions called though Parallel Computing Toolbox.
If you need to access properties of your app pass them down as values directly, e.g. instead of
b = [0,0];
parfor i=1:2
b(i) = app.myprop*2
end
use
tmp = app.myprop;
b = [0,0];
parfor i=1:2
b(i) = tmp*2
end
So it seems that you can't access (or it would seem set) the properties of the app object within a parallelized function. If you want to get data out, you'll probably have to set up a communication system using parallel.pool.DataQueue. Your example is tough to parallelize. A better option would probably be to add a listener to your running_state property, and/or use a timer function.
The major downside of this is that the function you call from the timer is not actually parallelized - it runs in the same thread, so if you have a lot of computation in ReadTwinCAT, I think it will cause lag/unresponsiveness in the GUI.
I've modified your code to use a timer instead of parfeval:
properties (Access = private)
running_state = 0; % Description
runningTimer;
tcClient;
db_conn;
end
methods (Access = private)
function ReadTwinCAT(app, varargin)
if app.running_state == 1
disp('running')
else
stop(app.runningTimer);
disp('stopped')
end
end
end
% Callbacks that handle component events
methods (Access = private)
function StartButtonPushed(app, event)
app.running_state = 1;
app.runningTimer = timer;
app.runningTimer.Period = 0.1;
app.runningTimer.ExecutionMode = 'fixedRate';
app.runningTimer.TimerFcn = #app.ReadTwinCAT;
start(app.runningTimer)
end
end
I'll share my half-baked solution here for parfor and app. If you get your function outside of App Designer you can do the following
function ExternalFunction(app)
dataQueueUpdateUI = parallel.pool.DataQueue;
afterEach(dataQueuePorthole, #UpdateUI);
parfor i = 1 : 4
CalculatingFunction(arg1, dataQueueUpdateUI)
send(dataQueueUpdateUI, 'whatever')
end
end
UpdateUI can take only one argument (cell, array, struct etc.), but based on type, you can trigger different actiens in app. The function is evaluated on client, therefore it can find app handles. You can also have multiple DataQueue objects, but I can't really tell how does it affect the lag. Speaking of it, there might be some, anything from 0-5 seconds, at least in my case.
Example for UpdateUI function, I run it every 0.5 s while I have few instances of other programs working in background. Within UpdateUI, you can do whatever you want to with the app.
function UpdateUI(arg)
% Initialising app
persistent app
if isempty(app)
app = get(findall(0, 'type', 'figure'), 'RunningAppInstance'); % if you only have one figure on
end
pause(0.1)
drawnow limitrate;
end

Accessing the value of other sliders from within a ValueChangingFcn

I have multiple sliders inside a figure, and I would like to publish their values (using the robotics toolbox) when one of them changes. I'm unable to access the value of more than one slider - an attempt to access the slider values gives me the following error in the sliderMoving function:
Undefined variable "event1" or class "event1.Value".
The code is as follows:
function sliderchanging
%rosinit('129.78.214.177');
first_val = 0;
euler_v = rossubscriber('/Euler_values');
slider_v = rospublisher('/Slider_values', 'std_msgs/Float64MultiArray');
slidermsg = rosmessage(slider_v);
eulermsg = rostopic('echo', '/Euler_values');
ypr = eulermsg.Data;
y = ypr(1);
p = ypr(2);
r = ypr(3);
fig = uifigure;
sld = uislider(fig,'Position',[20 50 260 20],'ValueChangingFcn',#(sld,event) sliderMoving(event, slidermsg, slider_v, y, p, r));
sld1 = uislider(fig,'Position',[20 80 260 20],'ValueChangingFcn',#(sld1,event1) sliderMoving(event1, slidermsg, slider_v, y, p, r));
if first_val == 0
send(slider_v, eulermsg);
end
sld.Limits = [y-2 y+2];
sld.Value = y;
sld.Position = [20 50 260 20];
sld1.Limits = [p-2 p+2];
sld1.Value = p;
sld1.Position = [20 80 260 20];
end
function sliderMoving(event, slidermsg, slider_v, y, p, r)
first_val = 1;
disp(event.Value)
disp(event1.Value)
slidermsg.Data = [event.Value, p, r];
send(slider_v, slidermsg)
end
What is wrong with this code? How can I access the values of all available sliders from within the sliderMoving callback?
Your problem is because the sliderMoving function does not know the name of the variable in the calling workspace. In other words,
function out = func(in)
% do something with in
end
won't behave differently if we call it like func(in1) or func(in2).
In your case, the event will always be known inside the callback as event.
If you want different behavior based on which slider was used, you should decide based on the first two inputs to the callback (commonly: src and eventData), or via some additional input parameter (as you already do). If you need to access the value of the other slider, you can do this using event.Source.Parent.otherSld.
You should also note that the statement first_val = 1; that is found inside the callback has no effect on the value outside the callback. You should read about nested functions.
I think this is what you meant to do:
function sliderchanging
...
fig = uifigure;
...
function sliderMoving(...)
end
end
As the error message says event1 is not a variable or class. You can't copy the slider code and put a 1 after every entry.
I suggest you look at the MATLAB documentation on events. You will have to use event
in both slider definitions and either use a different callback for each slider or if you use the same call back then you will need to find someway of identifying which slider triggered the callback.

How to initialize a variable in a user defined MATLAB function(simulink)

I am trying to make a user defined function is simulink which looks something like this
function [minTR,maxTR,out] = Temperature(u)
[minTR] = min(u);
[maxTR] = max(u);
if((maxTR - minTR > 1.5))
out = 1;
else
out = 0;
end
end
Where u is a 1200x1 array for every sampling time , now the problem is I want is if this condition if((maxTR - minTR > 1.5)) holds true I want the out to remain 1 until the difference between maximum and minimum become less than lets say 0.7 , my plan was to set a flag which i would set in the condition to become 1 so my else code will look something like
else if((maxTR - minTR < 1.5) && flag == 0)
out = 0;
end
but the problem is initialization , I have to initialize this flag once but simulink run this whole function for every sampling time and the flag would be reinitialized again and again , does anyone know what can i do to achieve that ?
As percusse mentioned in the comments, you should look into already existing blocks (comparison + hysteresis) in the Simulink library.
In general, initialization of variables in Matlab/Simulink could be solved with persistent variables.
persistent flag
% If first run. Initialize flag.
if isempty(flag)
flag = false;
end
An alternative is to take in an output signal from previous sample period by using the delay block which can be initialized with a value.

Call a function within a function matlab

I have defined a function called CARE_SAV which contains a recursive process, the code is
function [miu_tau_c,miu_tau] = CARE_SAV(beta,Yt,t,miu_1)
global miu_tau
global t
global miu_1
if t > 1
miu_tau_c = beta(1)+beta(2) * ...
[CARE_SAV(beta, Yt, t-1, miu_1)]+beta(3)*abs(Yt(t-1));
miu_tau = [miu_tau;miu_tau_c];
else
miu_tau_c = miu_1;
miu_tau = [miu_tau;miu_tau_c];
end
The function itself runs perfectly. However, when I define another function (ALS) and call this CARE_SAV, the error keeps popping out saying the local variable may have been changed to match local variable value. And hence there is error on ALS line 6. The ALS code is shown below
function sum = ALS(tau,Yt,beta,miu_1,CARE_SAV)
s = 0; % set the initial value for the ALS sum
global t
global miu_1
t = size(Yt,1); % indicate the length of the simulated data
[~,miu_tau]=CARE_SAV(beta,Yt,t,miu_1); % call the CARE_SAV function to get miu_tau value
for i = 1:size(Yt,1) % conduct the ALS summation process for each t
if Yt(i) < miu_tau(i) % set the indicator function
s = s+abs(tau-1)*(Yt(i) - miu_tau(i))^2;
else
s = s+abs(tau-0)*(Yt(i) - miu_tau(i))^2;
end
end
sum = s;
Can someone explain to me what I happening here? Much appreciated.
In CARE_SAV, you have this:
miu_tau_c = miu_1; - being miu_1 a global variable.
Then, in the other function, you have as input miu_1 AGAIN and you call global miu_1 AGAIN. This is the issue.
Try to remove miu_1 from input in the second function. It might work, but using globals in functions like this it's not recommended.

How to update a uitable after creation from other functions?

I created a matfile in which I store data that are constantly overwritten by user behavior. This occurs in a function "test()".
n=1
while n < 5
myVal = double(Test704(1, 780, -1)) %Returns the user's behavior
if myVal == 1
n = n + 1 %"n" is the overwritten variable in the matfile
end
save('testSave1.mat') %The matfile
m = matfile('testSave1.mat')
end
Then, I want to display these data in another function (it is essential to have two separated functions) called "storageTest()". More particularly, storageTest() is a GUI function where I developped an uitable "t". So, I first call the function "test()" and give its output values as data of "t". Here is the code of the interesting part of "storageTest":
m = test()
d = [m.n]
t = uitable('Data',d, ...
'ColumnWidth',{50}, ...
'Position',[100 100 461 146]);
t.Position(3) = t.Extent(3);
t.Position(4) = t.Extent(4);
drawnow
This code executes only when "m = test()" running is over and displays me a tab in which I can see the final value of "n". However, I want my table to be displayed before and to see my value incrementing according to user's behavior.
I have searched on the web to solve my issue, but I cannot find any answer, is it possible to do such a thing?
Assuming I'm interpreting the question correctly, it should be fairly trivial to accomplish this if you initialize your table prior to calling test and then pass the handle to your table for test to update in the while loop:
For example:
function testGUI
% Initialize table
t = uitable('ColumnWidth',{50}, 'Position',[100 100 461 146]);
test(t)
function test(t)
n = 1;
while n < 5
n = n + 1;
t.Data = n;
pause(0.25); % Since we're just incrementing a number, a slight so we can actually see the change
end
When you run the above, you'll notice the data in your table iterating as expected.
excaza was a little faster in writing basically the same answer like me. As it looks a slightly different, I'll post it anyway.
function storagetest()
close all
f = figure;
data = [1];
t = uitable(f,'Data',data,'ColumnWidth',{50});
test()
end
function test()
% handle uitable
t = evalin('caller','t')
n = 1;
while n < 5
newVal = input('Enter a number:');
data = get(t,'Data');
set(t,'Data', [data; newVal]);
n = n + 1;
end
end
The "user behaviour" I imitated with the input function. The basic idea is to update your table from within test(). evalin you can use, if you don't want to pass parameters to test(), though passing the handle of the uitable directly is certainly the better option.
If you are working on a serious GUI project I highly recommend you reading this answer.