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

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.

Related

How to make for loops run faster - Psychtoolbox in matlab

I created a MATLAB code using Psychtoolbox to make an experiment.
Everything works as I intended but it seems the initial loading of the experiment takes too long. The task is a simple yes/no response task whether the target word('probe') appeared in the previous set of word stimuli.
I put basic intro text as an image and then wait for any keypress to start the experiment but it will take about 40 seconds to actually begin the first trial after any keystroke. I want to make it work without any delay. It should start its first trial immediately after any keystroke.
I checked the timestops with GetSecs() on numerous positions in the code and it was not anything to do with loading stimuli or initial setting of the experiment before the for loop I attached below.
To make things look simpler, I changed some of the variables into actual numbers I used. I can gurantee that it is not due to large stimuli size since it is only 1500 words. Once the for loop starts, it goes smoothly but it takes 40 seconds to actually start the first trial so I think it is something to do with a specific function in the for loop or the way I built it.
Please let me know if anything is too vague or unclear. I will do my best to make things read better.
Edit: I minimalized the code leaving only the function names used in Psychtoolbox. I left the functions I used in between loops to let you know if they could cause any delay. It will not be possible to run this without Psychtoolbox installed so I guess you can briefly examine the structure of the code.
for trial = 1:250
for i = 1:6
DrawFormattedText();
Screen();
WaitSecs(0.5);
end
DrawFormattedText();
flipTime = Screen();
WaitSecs(0.5);
DrawFormattedText();
flipTime = Screen();
rt = 0;
resp = 0;
while GetSecs - flipTime < 3
clear keyCode;
RestrictKeysForKbCheck();
[keyIsDown,secs,keyCode] = KbCheck;
respTime = GetSecs;
pressedKeys = find(keyCode);
% ESC key quits the experiment
if keyCode(KbName('ESCAPE')) == 1
clear all
close all
sca
return
end
% Check for response keys
if ~isempty(pressedKeys)
for i = 1:2
if KbName(i) == pressedKeys(1)
resp = i;
rt = respTime - flipTime;
end
end
end
% Exit loop once a response is recorded
if rt > 0
break;
end
end
if rt == 0 || rt > 3 % 3 second limit for subjects to react to the probe stimuli
DrawFormattedText();
Screen();
WaitSecs(1);
end
Screen();
vbl = Screen();
WaitSecs(1);
% Record the trial data into output data matrix
respMat{1, trial} = trial;
respMat{2, trial} = resp;
respMat{3, trial} = rt;
end

MATLAB: Check for while loop divergence

I have piece of code with a while loop. This loop will diverge in certain conditions and thus will yield a infinite loop.
I want to check whether the loop is diverging and break the loop in an elegant and efficient procedure.
A solution to this is to check every output of the loop, save it, and compare it to the previously calculated loop output.
This is the code:
ai = 0;
ai_old = 100;
iteration = 0;
CDeff = 0;
while abs(ai - ai_old)>2*10^-1 % Get induced angle of attack
iteration = iteration +1;
ai_old = ai;
Cleff = (Clp * cosd(ai)^2 + CDeff * sind(ai) )/cosd(ai);
Veff = Vp/cosd(ai);
Re_eff = Reinf * Veff/Vinf * cp/c;
Meff = Mp/cosd(ai);
if iteration ==1
AFdata(:,2) = AFdata(:,2)/cosd(SweepQC);
end
[~,a_eff,CDeff] = obj.ConstantVortex(AFdata,[],Cleff,Meff);
ai = -a_eff + (AOA + Twists(zz))/cosd(SweepQC);
end
Here, ai is calculated with the function obj.ConstantVortex and compared with the previous calculated ai. The while loop is terminated when the difference is small enough.
However, it can occur that the difference between the initial ai and calculated ai is increasing with every iteration.
How can I check this? and break the loop accordingly?
Thank you
A typical solution for this situation is to store more previous values, and monitor the behaviour over time. So instead of ai_old, you would use:
ai = 0;
num_prev = 5; % how many previous results to check
ai_prev = zeros(1,num_prev);
iteration = 0;
while abs(ai - ai_prev(end))>2*10^-1
iteration = iteration+1;
% your loop code goes here
% now update the array of previous values
ai_prev = circshift(ai_prev,[0 -1]);
ai_prev(end) = ai;
if iteration > num_prev && all(sign(diff(ai_prev)))
% the slope of the previous five results is positive, so exit
break
end
end
You can change the number of previous results and use whatever function is appropriate to check for a break condition on the data in ai_prev for your computation. For example you might want to do some averaging on the previous results, or use a different function than diff().
One solution is to keep last differences or min differences and compare the current difference with that. For example you can have variable ai_older and use it. You can add
ai_older = 1000;
before your while loop and then have
ai_older = ai_old;
ai_old = ai;
and change while condition to
while abs(ai - ai_old)>2*10^-1 && abs(ai - ai_old) < abs(ai_old - ai_older)
Now you can avoid divergence. However, I'm not completely aware of your problem and not sure using abs is required or not.
As I previously mentioned, depending to your problem you may want to keep minimum difference till now and compare current one against that.

How to get out a value outside of objective function of multistart (MS) of Matlab

I have a multi-start fmincon code. One variable needs to be determined: u0. Inside ObjectiveFunc there is a variable, Parameter I need to output when running multi-start, so I am trying to output a parameter that changes inside an objective function. I wrote a simple example below.
How can I output the value of the Parameter inside Func(u0) below when running run(ms,Prob,big start)?
ObjectiveFunc = #(u0) Func(u0);
gs = GlobalSearch; ms = MultiStart(gs); opts = optimoptions(#fmincon);
Prob = createOptimProblem('fmincon','x0',1,'objective',ObjectiveFunc,'options',opts);
u0_ini_range = 0.1:1:20;
[u0_iniGrid] = ndgrid(u0_ini_range);
W = u0_iniGrid(:);
bigstart = CustomStartPointSet(W);
[u0_OptVal Delta_u0] = run(ms,Prob,bigstart);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function Delta_u0 = Func(u0)
Parameter = randn(1);
Delta_u0 = u0+Parameter;
There are a variety of ways to solve this issue. None of them are pretty. The problem is confounded due to the use of MultiStart, which runs multiple instances simultaneously, only one of which returns the global optimum. This means that the last evaluation of your objective function (and it's call to randn) isn't necessarily the relevant one.
Here's one way to accomplish this with persistent variables. First, you objective function need to look something like this (here Delta is your Parameter):
function [z,Delta_u0_Opt]=HBM1_SlipSolution02hbm3Fcn(u0)
persistent Delta idx;
if isempty(idx)
idx = 0; % Initialize persistent index
end
if nargout > 1
% Output Delta history
Delta_u0_Opt = Delta;
z = (u0-Delta).^2;
else
% Normal operation
idx = idx+1;
Delta(idx) = randn; % Save Delta history
z = (u0-Delta(idx)).^2;
end
Then run your setup code as before:
ObjectiveFunc = #(u0)HBM1_SlipSolution02hbm3Fcn(u0);
u0_ini0 = 0;
gs = GlobalSearch;
ms = MultiStart(gs);
opts = optimoptions(#fmincon);
Lowbound = 0.1;
Xst_rig = 1;
Upbound = 20*Xst_rig;
Prob = createOptimProblem('fmincon','x0',u0_ini0,'objective',ObjectiveFunc,...
'lb',Lowbound,'options',opts);
u0_ini_range = 0.1:1:Upbound;
[u0_iniGrid] = ndgrid(u0_ini_range);
W = u0_iniGrid(:);
bigstart = CustomStartPointSet(W);
[u0_OptVal,fval1] = run(ms,Prob,big start);
Then extract your Delta value:
[fval2,Delta_u0_Opt] = HBM1_SlipSolution02hbm3Fcn(u0_OptVal)
Delta_u0_Opt = Delta_u0_Opt(fval1==fval2)
The main problem with this solution is that the entire history of Delta must be retained via constantly appending to a vector. And it requires that the function value of the solution, fval1, uniquely match only one of fval2. The solution could probably be optimized a bit and the last issue resolved by saving more state history and clever use of an output function. I have no idea how or if this would work if you decide to turn on UseParallel. As you can see, this optimization scheme is not at all designed for what you're trying to get it to do.
Finally, are you sure that it's a good idea to use random values in the way that you are for this kind of optimization scheme? At minimum, be sure to specify a seed so results can be replicated. You might consider creating your own global optimization method based on fmincon if you want something more straightforward and efficient.

MATLAB: Saving While loop data

I'm running a while loop and I am running in to some problems.
I have the following piece of code:
Angle_int = 0.5; % Initial interpolation angle of attack
Clmax2d(1,1:length(Yle_wing)) = 3; % Dummy value
diff = 0; % Dummy value
while sum(diff < 0) > fix(tol*length(Yle_wing))
Angle_int = Angle_int + 0.5; % Interpolation angle increases with 0.5 with every iteration
for j = 1:length(Yle_wing)
CL3d = interp1(Angle,[cl_matrix(1,j) cl_matrix(2,j) cl_matrix(3,j)],Angle_int,'linear');
CL_3DD(:,j) = CL3d;
end
diff = (Clmax2d - CL_3DD); % Difference between Cl2d and Cl3d
Angle_stall = Angle_int;
CL_3D = CL_3DD;
end
For some reason, CL_3D = CL_3DD; and Angle_stall = Angle_int; seem to disappear when the while loop finishes. Hence, I cannot use their converged values ahead of the while loop since these variables are not recognized. I get the following error:
Undefined function or variable "CL_3D".
Hence, does someone knows what I am doing wrong? or any tips would be welcome as well.
Thanks in advance,
cheers
The error message:
Undefined function or variable "CL_3D".
is always because you're trying to use a variable or function that you haven't initialized yet. Often this happens in loops where you want to increment a counter, or compare values etc.
A common error is doing something like this without writing ii = 0 in front of the loop:
while ii < some_num
ii = ii + 1;
some_function();
end
With your dummy variables, you never enter the loop (unless tol < 0, which seems like an odd choice). You probably want to initialize diff = Inf or something like that. However, using diff as a variable name is not a good idea, since it's a builtin function.
You probably try to use CL_3D, when it's not yet initialized (somewhere else in your code, not in the part you posted). MATLAB tells you which line the error appears in, you should try using it!
Maybe initializing it like zeros(size(Clmax2d)); could work (it will definitely remove your error, but it might not give the desired behavior).
PS!
Using i and j as variables are not recommended as they represent the imaginary unit in MATLAB.

Variable persisting between function calls

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.