How can I pass data to the MATLAB oncleanup function? - matlab

I have a compiled matlab program that automatically tunes machine parameters. At the end of a tuning cycle I need to reistate some original settings. Sometime unexpected errors occur and sometimes the user can see that tuning algorithm is not working properly so should be terminated (with control-C).
If a predictable error occurs, I can reinstate parameters with a try catch block. However, if an unexpected error occurs or the user invokes control-C, the program exits without passing though the catch clause and the machine is left in an undefined state.
I know I can register a cleanup function that will run as my working functions finish, either normally, via an predictable or unpredictable error, or control-C event. Ideally, the the clean up function would do nothing and pass control to the top level to clean up if a predictable error occurs. If a control-C event or an unpredictable error occurs, clean up function should warn the user that the program failed so they clean up manually.
To do this, I need to make the fact of a predicted or not-predicted termination (i.e. control-C) known to the clean up function at run time. I know that the cleanup function takes a copy of parameter values when it is registered, and that these cannot be changed at run time, so passing in a parameter cannot work. What I believe should work is nesting the cleanup function within my working function so local variables in the enclosing function are available to the clean up function. This however does not work.
My question is: can anyone see a way to make just a single boolean available to a clean function so it can select between normal and abnormal clean up?
Here is some contrived example code that I believe should work.
function do_tuning
% Set this false to cause a warning messages for control-C or MATLAB coding errors.
normalTermination = false;
oc = onCleanup(#() my_clean_up());
tuningError = tuning_function()
if tuningError
% Set this true to suppress the warning message if a predictable error occurs.
normalTermination = true;
error('tuningError')
end
% Set this true to suppress the warning message if the function runs to completion.
normalTermination = true;
function my_clean_up
if ~normalTermination
disp('Warning: clean up failed. Please clean up manually');
end
end
end
Running real code following this pattern causes the error:
Undefined function or variable "normalTermination".

The onCleanup object calls the function from outside the workspace of the do_tuning function so using a nested function will not help...
Infact the documetation states:
Your cleanup routine should never rely on variables that are defined outside of that routine
[edit - based on comments] A better solution would be to change the problem and have all cleaning up done within the my_clean_up function, which may require it to determine if what needs doing (or to have generic behaviour which can always be applied)
If we disregard this warning and solve the question...
Passing varables between workspaces is easiest with global variables so for the example code above.
Firstly define the variable as global before initially setting it to false (otherwise the variable may be overwritten)
function do_tuning
%# snip
global normalTermination
normalTermination = false;
%# snip
Secondly define the variable as global in the my_clean_up callback function before using it to retrieve the value
function my_clean_up
global normalTermination
if ~normalTermination
%# snip
Warning as ever with global variables this is susceptible to the value of the global variable being edited elsewhere at the wrong time.

Here is a modification of my example that behaves as I want, using the global suggested by #RTL.
function do_tuning
global normalTermination;
% Set this false to cause a warning messages for control-C or MATLAB coding errors.
normalTermination = false;
oc = onCleanup(#() my_clean_up());
tuningError = tuning_function()
if tuningError
% Set this true to suppress the warning message if a predictable error occurs.
normalTermination = true;
error('tuningError')
end
% Set this true to suppress the warning message if the function runs to completion.
normalTermination = true;
function my_clean_up
if ~normalTermination
disp('Warning: clean up failed. Please clean up manually');
else
disp('Normal termination, you can relax.');
end
end
end

A more elegant solution can be achieved by modifying the onCleanup code. You could easily add a property or method to cancel the normal behaviour. Example:
classdef onCleanupCancel < handle
properties
active = true;
end
properties(SetAccess = 'private', GetAccess = 'public', Transient)
task = #nop;
end
methods
function h = onCleanupCancel(functionHandle)
h.task = functionHandle;
end
function delete(h)
if h.active
h.task();
end
end
end
end
function nop
end
At the last line of your function set the active of the onCleanupCancel object to false...

Related

set initial conditions in matlab function block (simulink)

I'm currently trying to learn some basis for a bigger project that will make a massive use of simulink.
Right now, I would like to code my own simulink block whith a feedback. It means that one of the inputs is also the output (with a 'memory' block between them to ensure everything goes right!).
My code looks like
function out = func(cmd,in)
if in == 0 && cmd == 1
out = 1;
elseif in == 1 && cmd == 0
out = 0;
else
disp('error')
end
As I said, 'in' is linked to 'out'. Unfortunatly, it is required to set an initial value for out otherwise I get some errors. Of course I can't do it in the code like that :
out = 0;
In that case, the value 'out' is set to 0 at each time step.
Have you any advice to do it ? I've read that S-functions and flag could be used, but I have no idea how it works.
Your function gets called during model initialization (t=0), and the value of out will be calculated based on the value of cmd and in value at t=0.
Hence you need to make sure cmd and in are initialized correctly you shouldn't be setting a value explicitly for out.
If you really need to (which you won't) then the simplest thing to do is use an Initial Condition block after this block.
Note that the above is only applicable to a block that has no states, as with your example. For your bigger project, you may have custom written blocks with states, in which case the approach to setting initial conditions for the states is different depending on whether you are using a MATLAB Function block or an S-Function.
Finally, note that if you want an error to be thrown then throw an error in the usual MATLAB way. Using disp as you are doing doesn't stop the simulation, but you haven't set a value for out, which is bad coding.
Well, I think that I've solve that issue. I put it here, I could help someone else
by adding a clock and initialize out with an if statement if time <=0 out = ...
However, it requires to add an extra input, which is not very convinient. Maybe someone could tell me how to solve that.
do the if properly and terminate it by else out = in;
I belive that was the main problem here. I've also placed my matlab-function block in a subsystem with a mask that initializes in and cmd.
Thanks again for your help, it helped a lot.
However, my problem is still unsolved since the statement if t<0 doesn't work for some reason.

matlab using try-catch all throughout program (global) to report errors

My matlab program is a multiple window programmatic GUI. I have implemented a reporting system so when an error is encountered, it calls a function I wrote, generateReport.m, which sends an e-mail with some log and state info and then continues execution.
To accomplish this I have put a try-catch block in EVERY single function. That means even creating a wrapper for my main function. Does anybody know of a way to avoid this? I.e. being able to but a global try-catch. The reason I need multiple try-catch blocks right now is because try-catch will catch errors in functions within the block, but not sub-functions of those
Example psuedo-code:
try:
segmentImage
catch:
generateReport
end
^-- This way an error in segment-image calls generateReport, however an error in a subfunction of segment-image won't. Optimally I would only need one try-catch (or some other statement/structure I'm not aware of) in each file.
Most of the files code one GUI window each. Some are just utility.
I wrote a similar question before: matlab can't catch error in subfunction
That question asked how to use the try-catch or some function-wrapper in a callback, to implement the reporting system I have now. Before I just wanted to know why I couldn't catch errors in subfunctions. I put try-catches in every subfunction to solve that.
This question is different as I'm asking is if there's another way to do this instead of putting a try-catch in every function and subfunction which is really inconvenient and doesn't look that great. Maybe a technique I don't know about to do this or a more efficient way of structuring my code to accomplish this is needed?
Example of multiple try-catches:
First the main function I run, which just wraps CSTMainWindow
function CeleST
try
% Global try-catch on CeleST
CSTMainWindow()
catch exception
generateReport(exception)
end
Within CSTMainWindow: I have to put try-catch blocks on it's subfunctions. In this example given CSTProcessVideos and CSTCheckResults are programmatic GUI files
function processVideo(hObject,eventdata) %#ok<INUSD>
try
set(mainFigure,'Visible','off');
CSTProcessVideos
set(mainFigure,'Visible','on');
flagConsistentButton = false;
checkSequences
populateFilters
catch exception
generateReport(exception)
end
end
function checkResults(hObject,eventdata) %#ok<INUSD>
try
set(mainFigure,'Visible','off');
CSTCheckResults
set(mainFigure,'Visible','on');
flagConsistentButton = false;
checkSequences
populateFilters
catch exception
generateReport(exception)
end
end
I would like to know if there's something I could do to avoid putting a try-catch on everything (I also put the try-catch blocks on subfunctions that don't contain code written in other files)
I hope my question was clear. Thanks in advance for the help
Preliminaries. Since your application is event-driven (i.e. performs actions by callbacks) you have at least two potential sources of errors: 1) the function that builds your GUI, and then exits, 2) every callback assigned to the active UI elements.
The GUI builder. Errors in building the GUI should exit the application. Which means that your function should look like
function main(arg1, arg2, ...)
try
% test your arguments
% create the main window
% add ui elements
% register the callbacks
% create backup for application state
catch ME
generateReport(ME);
end;
end
without putting a try/catch in every helper function that is called. Since the GUI creation is faulty, the catch block should not attempt to restore the application to a (safe) default state, because there is no such default state to begin with.
The callbacks. Errors in callbacks are most likely due to wrong user input, so there is a way to rollback the application to the last known safe state:
function ui1_cbk(h, varargin)
try
% test your arguments
% perform required action
% update the backup state with the actual state
catch ME
generateReport(ME);
% restore state from last good backup
% let the user know something went wrong
end;
end
function ui2_cbk(h, varargin)
try
% ...
catch ME
% ...
end;
end;
Please note that, for UI elements that have a single callback registered to them, there is one easy way to handle all actions in a single function, thus having a single try/catch block:
function ui_general_cbk(h, varargin)
try
switch get(h, 'Tag')
case 'Tag_ui1'
% test your arguments
% perform required action
case 'Tag_ui2'
% test your arguments
% perform required action
% ...
otherwise
% ignore request
end;
% update the backup state with the actual state
catch ME
generateReport(ME);
% restore state from last good backup
% let the user know something went wrong
end;
end
Of course, for this to work, your GUI builder should assign unique (and maybe suggestive) tags to all your active UI elements.
How to generate error reports. The try/catch block could be only at the top level of the main function and the callback; to see what exactly caused the exception, one can always inspect the .stack struct array of the ME object, and—for fancy exception handling—eventually the .cause field (which would be another MException object if not empty). Like this one avoids polluting all the functions with exception handling on every level.

How to clear persistent variables in sub-functions

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

Matlab: What is the best way to keep trying and catching error such that the optimization process restart every time an error is seen?

I need run an optimization process using fminunc for 1000 times, which means I am essentially using a for-loop to loop the optimization process 1000 times. Sometimes, I will get an error like the following:
Error using fminusub (line 16)
Objective function is undefined at initial point. Fminunc cannot continue.
or another error:
Error using chol
Matrix must be positive definite.
Now, it is obvious that these are two different type of errors and when either one of them occurs, the function will exit the for loop , which is painful for me to restart the entire process again. I am wondering whether it is possible to run a statement that try and catch all the errors and restart that single optimization process again until it runs smoothly without encountering any errors.
I just picked up matlab today and I have no idea how to do this ? Is this even possible ?
So far, this is what I have got in my mind:
try
% optimization process
fminunc(.....)
% if it fails
catch err
% regenerate a new initial values then restart optimization process
initial_para = randn(1)
fminunc(...., initial_para)
% PROBLEM is: what if it fails again in the catch statement , how can I try and catch that
end
What is particular with this code is that the only difference between the try and the catch block is that you generate new initial parameters. So what you need to do in the catch is to solve the problem. And the problem is really that you have bad initial parameters, given the code in the question. This is what you have to solve. The way you solve this is really to use a while loop that goes on until it works. So instead of creating new initial parameters and repeat the same process as in try, you should use the code you have. Else you would be forced using recursion (I really would not use a recursion of try-catch! The debugging would be really painful). Ok, but what you do: Fix the problem in catch (which means set a new initial value) and repeat the process until it works.
success = false;
while (~success)
try
% optimization process
fminunc(.....);
success = true;
catch err
% regenerate a new initial values then restart optimization process
initial_para = randn(1);
end
end
So, the code will only reach success=true if the code in the try block works. Else it will go directly to the catch block.

Simulink difference between load_system and open_system

I have a Simulink model that calls a script in the InitFcn of the Model callbacks. This script initializes a bunch of variables in the base workspace so that they can be used by the Simulink model. When using Classes, I found that using the load_system function will make Matlab crash and the open_system function will work just fine.
Here the Class:
classdef simulinkModel
properties
model = '';
end
methods
function obj = simulinkModel(modelName)
obj.model = modelName;
end
function openModel(obj)
% Make sure any previously open model are closed, and open the model.
if bdIsLoaded(obj.model)
obj.closeModel()
end
%load_system(obj.model) % Matlab crash
open_system(obj.model) % Matlab run the model correctly
end
function closeModel(obj)
close_system(obj.model, 0)
end
function runModel(obj)
sim(obj.model)
end
end
end
And in the command window:
objModel = simulinkModel('test');
objModel.openModel
objModel.runModel
So how comes it crashs with the load_system vs the open_system? Is there something that the open_system function do with the base workspace that the load_system function doesn't do?
EDIT
I decided to try running simple commands outside of the class to see if the problem is elsewhere. So typing in the command window:
load_system('test')
sim('test')
When executing this in the command window, Matlab will also crash. So I'm starting to wonder if the model callbacks are not executed when the load_system function is called.
I can confirm there is indeed very different behaviour between load_system and open_system. I am currently debugging a weird problem under 2015b to be, and I just realized the LoadFcn callback of my simulink models is not called when I use load_system, but is is called properly when I use open_system. I don't know that this is documented anywhere. I find this callback name misleading if it is not called when you "load" the system !!! If I find more info, I will post back on this thread.