I have a GUI callback that includes a for loop but compared to running the same code in a script, the data/variable being retrieved within the loop after the loop ends is not being recognized and instead MATLAB says that the variable is undefined. The script runs fine with the same inputs. I am well aware that scripts and functions have different workspaces, but does this mean that the recent data in a function after ending a loop is forgotten?
The callback belongs to a push button while the data I am handling in that callback is symbolic.
I would like to know what is causing this problem
There is difference between functions and scripts.
functions have their local variables. These variables are defined within the scope of that function only. Inside of a function is isolated from the caller scope. The only way to exchange data is input and output parameters of the function.
When the flow of program reaches to a function, all variables are stored in stack, and the execution of function starts without any variables except the input parameter. On the exit from function, all local variable defined in the function are deleted, and the stored variable on the stack will be returned back to the scope.
To circumvent this mechanism, you can use
global variables
assignin and evalin functions
But this is not considered as a procedural programming.
Related
I have a script that calls a function, which is written in separate file and contains sub-functions that are inner to main function only. In one of my sub-functions, I have persistent variable that I would like to clear every time I run the main script. How can I do so? In addition, I have breakpoints through my code, and I would prefer to keep them while I clear the persistent variable - how that can be done?
MainScript.m script:
clear variables;
for iterNum=1:5
dataOut = MyMainFunction(iterNum);
end
disp(dataOut);
MyMainFunction code:
function dataOut = MyMainFunction(iterNum)
if (iterNum==1)
clear MySubFunction;
end
dataOut = MySubFunction();
end
function dataOut = MySubFunction()
persistent idx;
if isempty(idx)
idx=1;
end
dataOut=idx;
idx=idx+1;
end
I would like to clear "idx" persistent variable every time that I run MainScript.m, but of course to keep that variable as long as the script is running.
Thanks, John
The easiest way I see is to call clear followed the function name:
clear MySubFunction
instead of
clear variables;
This should clear all the persistent variables in that particular function. This will probably have the side effect of removing the stored JIT'd copy of it, causing it to be reparsed the next time it is invoked.
You can use munlock if you previously mlock'ed your function.
OR
You can define a special set of parameters in your function that are designed to solely clear the persistent variable, and you call the function with this syntax at the beginning of your main file.
Unfortunately, the other answer is partially incorrect - it is NOT possible to clear persistent variables in a sub-function using clear MySubFunction.
To quote an answer by a MathWorks staff member,
Only top level or main functions (with the same name as the file) may be cleared. To clear any local or nested function the main function must be cleared and that can't be done while the main function (or any other function in the file) is running.
and
Only whole m files can be cleared from memory. The entire file is managed as a unit so sub functions can't be cleared without clearing the main function.
As such, your options are to
separate the sub-function into its own m-file, or
clear the entire MyMainFunction from within MainScript.m, or
follow Ratbert's second suggestion, i.e. instead of using clear, give MySubFunction an additional argument that tells it to reset the persistent variables by itself
I have to work with a lot of data and run the same MATLAB program more than once, and every time the program is run it will store the data in the same preset variables. The problem is, every time the program is run the values are overwritten and replaced, most likely because all the variables are type double and are not a matrix. I know how to make a variable that can store multiple values in a program, but only when the program is run once.
This is the code I am able to provide:
volED = reconstructVolume(maskAlignedED1,maskAlignedED2,maskAlignedED3,res)
volMean = (volED1+volED2+volES3)/3
strokeVol = volED-volES
EF = strokeVol/volED*100
The program I am running depends on a ton more MATLAB files that I cannot provide at this moment, however I believe the double variables strokeVol and EF are created at this instant. How do I create a variable that will store multiple values and keep adding the values every time the program is run?
The reason your variables are "overwritten" with each run is that every function (or standalone program) has its own workspace where the local variables are located, and these local variables cease to exist when the function (or standalone program) returns/terminates. In order to preserve the value of a variable, you have to return it from your function. Since MATLAB passes its variables by value (rather than reference), you have to explicitly provide a vector (or more generally, an array) as input and output from your function if you want to have a cumulative set of data in your calling workspace. But it all depends on whether you have a function or a deployed program.
Assuming your program is a function
If your function is now declared as something like
function strokefraction(inputvars)
you can change its definition to
function [EFvec]=strokefraction(inputvars,EFvec)
%... code here ...
%volES initialized somewhere
volED = reconstructVolume(maskAlignedED1,maskAlignedED2,maskAlignedED3,res);
volMean = (volED1+volED2+volES3)/3;
strokeVol = volED-volES;
EF = strokeVol/volED*100;
EFvec = [EFvec; EF]; %add EF to output (column) vector
Note that it's legal to have the same name for an input and an output variable. Now, when you call your function (from MATLAB or from another function) each time, you add the vector to its call, like this:
EFvec=[]; %initialize with empty vector
for k=1:ndata %simulate several calls
inputvar=inputvarvector(k); %meaning that the input changes
EFvec=strokefraction(inputvar,EFvec);
end
and you will see that the size of EFvec grows from call to call, saving the output from each run. If you want to save several variables or arrays, do the same (for arrays, you can always introduce an input/output array with one more dimension for this purpose, but you probably have to use explicit indexing instead of just shoving the next EF value to the bottom of your vector).
Note that if your input/output array eventually grows large, then it will cost you a lot of time to keep allocating the necessary memory by small chunks. You could then choose to allocate the EFvec (or equivalent) array instead of initializing it to [], and introduce a counter variable telling you where to overwrite the next data points.
Disclaimer: what I said about the workspace of functions is only true for local variables. You could also define a global EFvec in your function and on your workspace, and then you don't have to pass it in and out of the function. As I haven't yet seen a problem which actually needed the use of global variables, I would avoid this option. Then you also have persistent variables, which are basically globals with their scope limited to their own workspace (run help global and help persistent in MATLAB if you'd like to know more, these help pages are surprisingly informative compared to usual help entries).
Assuming your program is a standalone (deployed) program
While I don't have any experience with standalone MATLAB programs, it seems to me that it would be hard to do what you want for that. A MathWorks Support answer suggests that you can pass variables to standalone programs, but only as you would pass to a shell script. By this I mean that you have to pass filenames or explicit numbers (but this makes sense, as there is no MATLAB workspace in the first place). This implies that in order to keep a cumulative set of output from your program you would probably have to store those in a file. This might not be so painful: opening a file to append the next set of data is straightforward (I don't know about issues such as efficiency, and anyway this all depends on how much data and how many runs of your function we're talking about).
I came accross this sentence in MATLAB doc:
The body of a parfor-loop cannot make reference to a nested function. However, it can call a nested function by means of a function handle.
Can someone please explain what this means?
A parfor loop is different from a normal loop, in that the body of the loop has its independent workspace for every iteration. In fact, when you are running the parfor loop on a parallel pool, the variables that need to be transmitted to the loop body are saved and reloaded (that's, by the way, the reason for the "variable x cannot be sliced which may lead to communication overhead" warning: Having to save and reload huge variables may add quite a bit to your processing time).
Consequently, calls to nested functions won't work - the nested function in the parent function no longer shares its workspace with the loop body. Furthermore, nested function calls may alter workspace variables across iterations of a loop, which won't mesh with parallel execution.
In contrast, passing a function handle, or calling a separate function, works fine. The function defined in the function handle, as well as the separate function, have their own workspaces, nothing gets shared across iterations of the parfor body, and thus the iterations can run completely independently.
/aside: Creating a function handle to a nested function may still be able to cause you problems: a live function (as opposed to a function handle stored as string which you "activate" with str2func) handle can carry quite a bit of the existing workspace, including handle objects. Both the size of the workspace and the not-being-passed-by-reference (because of save&reload) may lead to unhappiness.
I have a function in MATLAB, say [o1, o2]=MyFunction(i1,i2), and I have a main which is also in a function called main. Is this even make sense?
I did it in MATLAB as follow:
function main
i1=1;
i2=2;
[o1, o2]=MyFunction(i1, i2);
end
function [o1, o2]=MyFunction(i1, i2)
%Code goes here.
end
I cannot run this script anyway. Please any suggestions?
There is no "main" function in MATLAB. You should move its contents to a separate script, like the following:
Script 1:
i1=1;
i2=2;
[o1, o2]=MyFunction(i1, i2);
Script 2 (called "MyFunction.m"):
function [o1, o2]=MyFunction(i1, i2)
%Code goes here.
end
Then run Script 1.
as it has been commented above it works fine... also if all you want the function to do is define simple variables and call another function #ClydeW's answer is a sensible way to do that. For more complicated variables mat-files created with save or matfile and recoverd with load or matfile are available.
In Matlab terminology what you have there is a local function
Local Functions are extra functions defined within a function m-file, appearing after the end of the "main" function. Local functions have a separate workspace i.e. to use variables from the main function they will need to be inputs to the local function
Other alternatives for having "sub-functions" which are stored in the same m-file and used by the "main" function within Matlab are Nested Functions and anonymous functions
Nested functions are similar to a local function but appear within the "main" function definition i.e. before the end. The major difference being that a nested function has acces to the main functions workspace i.e. can use & modify variables from the main function without having them explicity as inputs or outputs
Anonymous functions are quite different in that they need defining with different syntax again within the "main" function, but prior to use (appearing earlier in file than the call to them). The inputs to an anonymous function come from the main function however other values used within an anonymous function use values from the main function at the time the anonymous function was defined.
I have a virtual subsystem with a bunch of parameters. I would like to use those parameters to calculate other properties of the block. This needs to be done before the simulation starts, but after the block has been initialized.
I created a script that would do the calculations, and tried to get it to run from the StartFcn block callback. But the script cannot access the parameters (which are input by the user through the mask) in the callback. I'm guessing this is because those parameters aren't available in the Matlab workspace, only within the block.
Is there any way to access those parameters through StartFcn? Failing that, is there another way, instead of the StartFcn, through which I can perform some calculations BEFORE simulation starts?
To clarify, I cannot use the Initialization tab in the block's mask because the script requires data from other blocks too (which are available in the workspace at the start of the simulation).
Your guess is correct, block callbacks are evaluated in the base workspace, but mask parameters are part of the mask's private workspace. To access them use get_param and gcb within your callback function.
value = get_param(gcb, 'my_param_name');