The PERSISTENT declaration must precede any use of the variable - matlab

While working on my matlab homework, I came across a very strange bug. Here's my code:
function [z,times] = Divide(x,y)
persistent times;
if (y == 0)
if (isempty(times))
times = 1;
else
times = times + 1;
end
end
z = x/y;
end
When run, this gives me the error:
Error: File: Divide.m Line: 3 Column: 16
The PERSISTENT declaration must precede any use of the variable times.
This is strange, because it is telling me that I need to declare the variable as persistent before I declare it as persistent (!?). I have no idea what I'm doing wrong here, so if there's some strange workaround that I should be using, please tell me.

The error message means : you've used the 'times' before you declare it as persistent variable. As you used 'times' in return variables.
One of the solution might be keep two different variables for 'times', one for persistent, and another one for return variable.
Paste my change here for your reference. Good luck!
function [z,times] = Divide(x,y)
persistent p_times;
if (y == 0)
if (isempty(p_times))
p_times = 1;
else
p_times = p_times + 1;
end
end
times = p_times;
z = x/y;
end

Related

octave: No function and no method found error

I get the following error trying to solve a non linear system in Octave:
error: #Jfun: no function and no method found
error: called from
voc at line 4 column 13
I'm using 4 scripts and I couldn't find the source of the error. The ffun, jfun and newtonsys files have been tested before and I am almost sure the issue is not there (I don't know if it could be an issue with the naming of variables though), but I have included them all below just in case.
file voc.m
x0=[9;8;0.5];
tol=10^-3;
nmax=1000;
[z,res,niter]=newtonsys(#Ffun,#Jfun,x0,tol,nmax)
File Ffun.m
q=1.602E-19;
k=1.381E-23;
Ncs=12;
Tc=329.25;
gamma=1.35;
Isc=9.14;
Rsh=94.5;
Vmp=37.8;
Imp=8.74;
function F=Ffun(x)
F(1,1)=Isc+x(2)*[exp((q*Isc*x(3))/(gamma*k*Tc*Ncs))-1]-(Isc*x(3))/Rsh-x(1);
F(2,1)=x(2)*[exp(q*(Voc)/(gamma*k*Tc*Ncs))-1]+(Voc/Rsh)-x(1);
F(3,1)=Imp+x(2)*[exp(q*(Vmp+Imp*x(3))/(gamma*k*Tc*Ncs))-1]+(Vmp+(Imp*x(3)))/Rsh-x(1);
endfunction
File JFun.m
q=1.602E-19;
k=1.381E-23;
Ncs=12;
Tc=329.25;
gamma=1.35;
Isc=9.14;
Rsh=94.5;
Vmp=37.8;
Imp=8.74;
function J=Jfun(x)
J(1,1)=-1;
J(1,2)=exp((q*Isc*x(3))/(gamma*k*Tc*Ncs))-1;
J(1,3)=x(2)*[exp((q*Isc*x(3))/(gamma*k*Tc*Ncs))]*(q*Isc/(gamma*k*Tc*Ncs))-(Isc/Rsh);
J(2,1)=-1;
J(2,2)=exp(q*(Voc)/(gamma*k*Tc*Ncs))-1;
J(2,3)=0;
J(3,1)=-1;
J(3,2)=exp(q*(Vmp+Imp*x(3))/(gamma*k*Tc*Ncs))-1;
J(3,3)=x(2)*[exp(q*(Vmp+Imp*x(3))/(gamma*k*Tc*Ncs))]*(q*Imp/(gamma*k*Tc*Ncs))+(Imp/Rsh);
endfunction
file newtonsys.m
function [x,res,niter] = newtonsys(Ffun,Jfun,x0,tol,...
nmax, varargin)
niter = 0;
err = tol + 1;
x = x0;
while err >= tol & niter < nmax
J = Jfun(x,varargin{:});
F = Ffun(x,varargin{:});
delta = - J\F;
x = x + delta;
err = norm(delta);
niter = niter + 1;
end
res = norm(Ffun(x,varargin{:}));
if (niter==nmax & err> tol)
fprintf(['Il metodo non converge nel massimo ',...
'numero di iterazioni. L''ultima iterata\n',...
'calcolata ha residuo relativo pari a %e\n'],F);
else
fprintf(['Il metodo converge in %i iterazioni',...
' con un residuo pari a %e\n'],niter,F);
end
return
The problem is your JFun.m file is NOT a function file, it is a script file which happens to define an 'on-the-spot' function JFun within it. If the voc.m script happens to call that function before it has been defined (i.e. before the JFun.m script has had a chance to be run and therefore end up defining that function in the current environment) then it will complain it's not there.
The solution in your case is to move all those variable definitions inside the function block, making it a proper 'function file', which will then be accessible from voc (as long as it's on the same directory / in the octave path).
Alternatively, if you still prefer JFun.m to be a script, (e.g. maybe you do want all those variables to end up being defined at global scope), then simply make sure you run it as a script first, such that it first defines the function you need; however, in that case, it is a good idea to change the name of your script to something else, so that its name doesn't conflict with the on-the-spot function defined inside it.
Have a quick look at the respective section in the manual, and in particular this part.

Call a script with definitions in a function

We have a script that defines values to names similar to #define in c. For example:
script.m:
ERR_NOERROR = 0;
ERR_FATAL = 1;
This script already exists and is used for value replacement when reading data from files.
Now we have a function (or more) that does some analysis and we would like to use the same definition in this function to avoid magic numbers. But when the script is called from the function we get an error.
Attempt to add "ERR_NOERROR" to a static workspace.
See MATLAB Programming, Restrictions on Assigning to Variables for details.
And this does not help much in the understanding of the problem.
The question is how can we make these definitions visible/usable in the functions with having to copying it every time.
Example:
function foo = bar(a)
run(script.m) %also tried running it without the run command
if a == ERR_NOERROR
foo = 5;
else
foo = 6;
end
end
edit:
There was a nested function,below in the function which I was not aware of. This explains the problem.
This kind of scoping error happens when you use nested or anonymous function within a function. The solution is well documented.
To your case, you can avoid nested function, or "Convert the script to a function and pass the variable using arguments", as the documentation suggests.
EDIT: I should have made it clear that the error occurs even if the script is not called within the nested function. Similar scenario is that, in debug mode (by setting up a break point), it will be an error if one tries to create a temporal variable to test something.
This is not a direct answer, rather a recommendation to switch to another method, which will not be mixing scope and workspace.
Instead of defining your constant in a script, you could make a class containing only constant properties. ex: code for error_codes.m:
classdef error_codes
% ---------------------------------------------------------------------
% Constant error code definition
% ---------------------------------------------------------------------
properties (Constant = true)
noerror = 0 ;
fatal = 1 ;
errorlvl2 = 2 ;
errorlvl3 = 3 ;
warning = -1 ;
% etc ...
end
end
I use this style for many different type of constants. For tidiness, I groups them all in a Matlab package directory (The directories which starts with a + character.
The added benefit of using constant class properties is the safety that the values cannot be changed in the middle of the code (your variables defined in a script could easily be overwritten by a careless user).
So assuming my file error_codes.m is placed in a folder:
\...somepath...\+Constants\error_codes.m
and of course the folder +Constants is on the MATLAB path, then to use it as in your example, instead of calling the script, just initialise an instance of the class, then use the constant values when you need them:
function foo = bar(a)
ERR = Constants.error_codes ;
if a == ERR.noerror
foo = 5;
else
foo = 6;
end
or it can works in switch statement too:
switch a
case ERR.noerror
foo = 5 ;
case ERR.warning
foo = 42 ;
case ERR.fatal
foo = [] ;
end

Use of if statement in for loop in this code

What does the statement for if=ilow:ihigh mean in this program?
function [d]=for_taup(m,dt,h,q,N,flow,fhigh);
nt= max(size(m));
nh = max(size(h));
M = fft(m,[],1);
D = zeros(nt,nh);
i = sqrt(-1);
ilow = floor(flow*dt*nt)+1; if ilow<1; ilow=1;end;
ihigh = floor(fhigh*dt*nt)+1;
if ihigh>floor(nt/2)+1; ihigh=floor(nt/2)+1;end
for if=ilow:ihigh
f = 2.*pi*(if-1)/nt/dt;
L = exp(i*f*(h.^N)’*q);
x = M(if,:)’;
y = L * x;
D(if,:) = y’;
D(nt+2-if,:) = conj(y)’;
end
D(nt/2+1,:) = zeros(1,nh);
d = real(ifft(D,[],1));
return;
if is used as a variable name. I am surprised that this does not raise a syntax error: most languages would forbid the use of "reserved" keywords. Maybe it would be a good idea to replace if with a different name in order to clarify your code and avoid confusion.
As far as MATLAB is concerned, this code doesn't really mean anything, because it's just a syntax error. if is reserved keyword, and you can't create a variable called if. As such, it just instantly errors and won't run.
You should probably replace all occurrences of the variable if (although not the keyword if in lines 8 and 10) with some other variable name. Avoid i, since you're using that as the imaginary unit.

1-line try/catch equivalent in MATLAB

I have a situation in MATLAB where I want to try to assign a struct field into a new variable, like this:
swimming = fish.carp;
BUT the field carp may or may not be defined. Is there a way to specify a default value in case carp is not a valid field? For example, in Perl I would write
my $swimming = $fish{carp} or my $swimming = 0;
where 0 is the default value and or specifies the action to be performed if the assignment fails. Seems like something similar should exist in MATLAB, but I can't seem to find any documentation of it. For the sake of code readability I'd rather not use an if statement or a try/catch block, if I can help it.
You can make your own function to handle this and keep the code rather clear. Something like:
swimming = get_struct(fish, 'carp', 0);
with
function v = get_struct(s, f, d)
if isfield(s, f)
v = s.(f); % Struct value
else
v = d; % Default value
end
Best,
From what I know, you can't do it in one line in MATLAB. MATLAB logical constructs require explicit if/else statements and can't do it in one line... like in Perl or Python.
What you can do is check to see if the fish structure contains the carp field. If it isn't, then you can set the default value to be 0.
Use isfield to help you do that. Therefore:
if isfield(fish, 'carp')
swimming = fish.carp;
else
swimming = 0;
end
Also, as what Ratbert said, you can put it into one line with commas... but again, you still need that if/else construct:
if isfield(fish,'carp'), swimming = fish.carp; else, swimming = 0;
Another possible workaround is to declare a custom function yourself that takes in a structure and a field, and allow it to return the value at the field, or 0.
function [out] = get_field(S, field)
if isfield(S, field)
out = S.(field);
else
out = 0;
end
Then, you can do this:
swimming = get_field(fish, 'carp');
swimming will either by 0, or fish.carp. This way, it doesn't sacrifice code readability, but you'll need to create a custom function to do what you want.
If you don't like to define a custom function in a separate function file - which is certainly a good option - you can define two anonymous functions at the beginning of your script instead.
helper = {#(s,f) 0, #(s,f) s.(f)}
getfieldOrDefault = #(s,f) helper{ isfield(s,f) + 1 }(s,f)
With the definition
fish.carp = 42
and the function calls
a = getfieldOrDefault(fish,'carp')
b = getfieldOrDefault(fish,'codfish')
you get for the first one
a = 42
and the previous defined default value for the second case
b = 0

Passing a variable out of local functions

I'm having some trouble with local functions within my code so I've pasted a simple example below:
function [avg,testvar] = test(x) %Warning
n = length(x);
avg = mymean(x,n);
end
function [a,testvar] = mymean(v,n)
a = sum(v)/n;
testvar=123;
end
One can probably see what I'm attempting; to pass testvar out of the local functions. However Matlab returns the warning:
"The function return value 'testvar' might be unset"
with respect to the line I've commented "%Warning".
What's the best way of getting around this?
You need to specify the value of the second output of test(). Otherwise how can MATLAB know what its value is supposed to be? It doesn't know the second output of mymean() should be routed to the second output of test(). Perhaps this will solve your problem.
function [avg,testvar] = test(x) %Warning
n = length(x);
[avg, testvar] = mymean(x,n);
end
function [a,testvar] = mymean(v,n)
a = sum(v)/n;
testvar=123;
end
The variables between brackets after function are the output variables.
In your first function, you did not assign any value to testvar hence the warning. If you add testvar = 123; in the first function, the warning goes away. Or you can remove testvar from the output variables, leaving:
function avg = test(x)