In the workspace I make a matrix .
Now I can access the variable in script. Like doing Variable(2) will return 4.
But inside a function like
function y= getvariable(x)
y=Variable(x)
end
I get error
y=getvariable(2)
??? Undefined function or method 'Variable' for input
arguments of type 'double'.
Error in ==> getvariable at 3
y=Variable(x)
So how to make the Variable matrix global so that I can access it through any function?
Although you could use globals
>> global Variable = rand(50,12);
...
function y = getvariable(x)
% Always needed
global Variable;
% Here ya go
y = Variable;
end
the MUCH better alternative is to use
function x = getvariable(x)
% no body needed
end
which you call as
>> y = getvariable(Variable);
(Of course, for this contrived example, this would just be equal to
>> y = Variable;
)
Although there are some legitimate use cases for global variables, in general they tend to spaghettify your code and make it far more bug-prone and much harder to debug. Have a read on the subject.
As #rody suggested, pass the matrix and the x inside the function
I am just giving an example to make things clear.
Like you want to access the 10th element of Variable matrix, so make the function as
function y= getvariable(matrixname,no)
y=matrixname(no)
end
If you want to access 3rd element of Variable, so you type
y=getvariable(Variable,3)
you will get 3rd element
call global Variable before you define it in your workspace
call global Variable before you use it in your function
However I suggest you think of other ways to pass variables to your function, as globals might cause difficulties during debugging.
Related
I'm trying to use the MATLAB function fzero properly but my program keeps returning an error message. This is my code (made up of two m-files):
friction_zero.m
function fric_zero = friction_zero(reynolds)
fric_zero = 0.25*power(log10(5.74/(power(reynolds,0.9))),-2);
flow.m
function f = flow(fric)
f = 1/(sqrt(fric))-1.873*log10(reynolds*sqrt(fric))-233/((reynolds*sqrt(fric))^0.9)-0.2361;
f_initial = friction_zero(power(10,4));
z = fzero(#flow,f_initial)
The goal is to return z as the root for the equation specified by f when flow.m is run.
I believe I have the correct syntax as I have spent a couple of hours online looking at examples. What happens is that it returns the following error message:
"Undefined function or variable 'fric'."
(Of course it's undefined, it's the variable I'm trying to solve!)
Can someone point out to me what I've done wrong? Thanks
EDIT
Thanks to all who helped! You have assisted me to eventually figure out my problem.
I had to add another file. Here is a full summary of the completed code with output.
friction_zero.m
function fric_zero = friction_zero(re)
fric_zero = 0.25*power(log10(5.74/(power(re,0.9))),-2); %starting value for fric
flow.m
function z = flow(fric)
re = power(10,4);
z = 1/(sqrt(fric))-1.873*log10(re*sqrt(fric))-233/((re*sqrt(fric))^0.9)-0.2361;
flow2.m
f_initial = friction_zero(re); %arbitrary starting value (Reynolds)
x = #flow;
fric_root = fzero(x,f_initial)
This returns an output of:
fric_root = 0.0235
Which seems to be the correct answer (phew!)
I realised that (1) I didn't define reynolds (which is now just re) in the right place, and (2) I was trying to do too much and thus skipped out on the line x = #flow;, for some reason when I added the extra line in, MATLAB stopped complaining. Not sure why it wouldn't have just taken #flow straight into fzero().
Once again, thanks :)
You need to make sure that f is a function in your code. This is simply an expression with reynolds being a constant when it isn't defined. As such, wrap this as an anonymous function with fric as the input variable. Also, you need to make sure the output variable from your function is z, not f. Since you're solving for fric, you don't need to specify this as the input variable into flow. Also, you need to specify f as the input into fzero, not flow. flow is the name of your main function. In addition, reynolds in flow is not defined, so I'm going to assume that it's the same as what you specified to friction_zero. With these edits, try doing this:
function z = flow()
reynolds = power(10,4);
f = #(fric) 1/(sqrt(fric))-1.873*log10(reynolds*sqrt(fric))-233/((reynolds*sqrt(fric))^0.9)-0.2361;
f_initial = friction_zero(reynolds);
z = fzero(#f, f_initial); %// You're solving for `f`, not flow. flow is your function name
The reason that you have a problem is because flow is called without argument I think. You should read a little more about matlab functions. By the way, reynolds is not defined either.
I am afraid I cannot help you completely since I have not been doing fluid mechanics. However, I can tell you about functions.
A matlab function definition looks something like this:
function x0 = f(xGuess)
a = 2;
fcn =#(t) a*t.^3+t; % t must not be an input to f.
disp(fcn);
a = 3;
disp(fcn);
x0 = fsolve(fcn1,xGuess); % x0 is calculated here
The function can then ne called as myX0 = f(myGuess). When you define a matlab function with arguments and return values, you must tell matlab what to do with them. Matlab cannot guess that. In this function you tell matlab to use xGuess as an initial guess to fsolve, when solving the anonymous function fcn. Notice also that matlab does not assume that an undefined variable is an independent variable. You need to tell matlab that now I want to create an anonymous function fcn which have an independent variable t.
Observation 1: I use .^. This is since the function will take an argument an evaluate it and this argument can also be a vector. In this particulat case I want pointwise evaluation. This is not really necessary when using fsolve but it is good practice if f is not a matrix equation, since "vectorization" is often used in matlab.
Observation 2: notice that even if a changes its value the function does not change. This is since matlab passes the value of a variable when defining a function and not the variable itself. A c programmer would say that a variable is passed by its value and not by a pointer. This means that fcn is really defined as fcn = #(x) 2*t.^3+t;. Using the variable a is just a conveniance (constants can may also be complicated to find, but when found they are just a value).
Armed with this knowledge, you should be able to tackle the problem in front of you. Also, the recursive call to flow in your function will eventuallt cause a crash. When you write a function that calls itself like this you must have a stopping criterium, something to tell the program when to stop. As it is now, flow will call ifself in the last row, like z = fzero(#flow,f_initial) for 500 times and then crash. Alos it is possible as well to define functions with zero inputs:
function plancksConstant = h()
plancksConstant = 6.62606957e−34;
Where the call h or h() will return Plancks constant.
Good luck!
I have a MATLAB function to solve a Inertia Tensor , and I have a nested function in my program . All the variables in it are symbolics but it told me
“Error using assignin: Attempt to add ”x“ to a static workspace”
and I don't understand why this happens . Here is my test.m code:
function test
syms x y z
f=x
f1=f+1
f2=f1^2
function r=test2
r=f2^3;
end
f3=test2
end
After searching this web-forum I have found some answers . But at the same time I just don't understand it
Andrew Janke explianed it like this : While syms A may look like a static variable declaration, it isn't. It's just a regular function call. It's using Matlab's "command" invocation style to look like syntax, but it's really equivalent to syms('a', 'b', 'c').
on this page : Matlab: "Error using assignin: Attempt to add "c" to a static workspace"
what does static variable mean ?
I also search the HELP doc and it said :In functions and scripts, do not use syms to create symbolic variables with the same names as MATLAB® functions. For these names MATLAB does not create symbolic variables, but keeps the names assigned to the functions.
I only know syms x to create a symbolic variable in the workspace but why does the documentation say MATLAB does not create ?
'Static' means fixed, 'workspace' is what Matlab calls the places where all of its variables are stored. For non-nested functions the workspace starts off as empty when Matlab is at the beginning of the function; as Matlab continues through function's lines of code it continuously add more variables to the workspace.
For functions with a nested function, Matlab first parses the function to see what variable will be created (it specifically looks for x = type lines), then it creates all of these variables (with value as 'unassigned'), and then only does it start to run through the code; but while running through the code, it can never create a new variable.
This is why the code
function TestNestedFunction
syms x;
function Nested()
end
end
generates an error, there is no x = to tell it to pre-create the unassigned variable x at the start of the code. It fails at syms x;, as that line tries to create a new variable x, which fails as it may not.
This is also why the following code runs
function TestNestedFunction
syms x;
x = x;
function Nested()
end
end
it sees the x = and then pre-creates x. (This is why your example of adding [x, y, z] = deal([]); also works).
You can test this with a break point at the beginning of simple non-nested function and a simple nested function. Just run it step by step.
This code works:
function test
x=sym('x')
y=sym('y')
z=sym('z')
f=x
f1=f+1
f2=f1^2
function r=test2
r=f2^3;
end
f3=test2
end
I think the pages you found are quite clear.
You need to declare the variables one by one and use:
x = sym('x')
Otherwise syms will try to assign the values into a workspace where this is not allowed.
I operate on global variable the way below in code. I want to save every time to global variable and keep its content so that it expands. If I declare function with output being this variable, in case of huge structures it may significantly slow down I assume. How to do it?
function test()
global n1;
n1 = [1 2 3];
for x=1:10
% [n1] = global_up(n1,x); % no need for output parameter, as n1 is global right?
f_up(n1,x);
end
end
function f_up(arg1,arg2) %function [arg1] = f_up(arg1,arg2) is wrong?
global n1; % need to write it in every function ?
arg1 = [arg1 arg2];
end
I don't really understand what you are trying to do, but global variables are almost definitely not the way to go. just pass the variable as a parameter:
function test()
n1 = [1 2 3];
for x=1:10
n1 = f_up(n1,x);
end
end
function arg3 = f_up(arg1,arg2)
arg3 = [arg1 arg2];
end
But if you explain the point of this code you might get a much better solution. as it stand f_up really doesn't do anything (i.e. it encapsulates syntax that is already very concise with no benefit)
EDIT: Consider this question for a discussion of your actual problem: How to modify an array in function?
I think what you want to do is call by reference, the usage of a global variable is unnecessary.
You have a variable x, you want to give that variable to a function and you want the function to do manipulations on x directly, so that these manipulations will be visible on the xoutside your function.
This is called call by reference. Matlab doesn't support it for simple variables.
You can however use an object that inhertis from the handle - class. This will give you the desired behaviour.
If you don't want to use objects, you will have to use a return argument in your function. Don't use global variables, they will make your code unreadable and almost certainly lead to mistakes.
when I am doing a function in Matlab. Sometimes I have equations and every one of these have constants. Then, I have to declare these constants inside my function. I wonder if there is a way to call the values of that constants from outside of the function, if I have their values on the workspace.
I don't want to write this values as inputs of my function in the function declaration.
In addition to the solutions provided by Iterator, which are all great, I think you have some other options.
First of all, I would like to warn you about global variables (as Iterator also did): these introduce hidden dependencies and make it much more cumbersome to reuse and debug your code. If your only concern is ease of use when calling the functions, I would suggest you pass along a struct containing those constants. That has the advantage that you can easily save those constants together. Unless you know what you're doing, do yourself a favor and stay away from global variables (and functions such as eval, evalin and assignin).
Next to global, evalin and passing structs, there is another mechanism for global state: preferences. These are to be used when it concerns a nearly immutable setting of your code. These are unfit for passing around actual raw data.
If all you want is a more or less clean syntax for calling a certain function, this can be achieved in a few different ways:
You could use a variable number of parameters. This is the best option when your constants have a default value. I will explain by means of an example, e.g. a regular sine wave y = A*sin(2*pi*t/T) (A is the amplitude, T the period). In MATLAB one would implement this as:
function y = sinewave(t,A,T)
y = A*sin(2*pi*t/T);
When calling this function, we need to provide all parameters. If we extend this function to something like the following, we can omit the A and T parameters:
function y = sinewave(t,A,T)
if nargin < 3
T = 1; % default period is 1
if nargin < 2
A = 1; % default amplitude 1
end
end
y = A*sin(2*pi*t/T);
This uses the construct nargin, if you want to know more, it is worthwhile to consult the MATLAB help for nargin, varargin, varargout and nargout. However, do note that you have to provide a value for A when you want to provide the value of T. There is a more convenient way to get even better behavior:
function y = sinewave(t,A,T)
if ~exists('T','var') || isempty(T)
T = 1; % default period is 1
end
if ~exists('A','var') || isempty(A)
A = 1; % default amplitude 1
end
y = A*sin(2*pi*t/T);
This has the benefits that it is more clear what is happening and you could omit A but still specify T (the same can be done for the previous example, but that gets complicated quite easily when you have a lot of parameters). You can do such things by calling sinewave(1:10,[],4) where A will retain it's default value. If an empty input should be valid, you should use another invalid input (e.g. NaN, inf or a negative value for a parameter that is known to be positive, ...).
Using the function above, all the following calls are equivalent:
t = rand(1,10);
y1 = sinewave(t,1,1);
y2 = sinewave(t,1);
y3 = sinewave(t);
If the parameters don't have default values, you could wrap the function into a function handle which fills in those parameters. This is something you might need to do when you are using some toolboxes that impose constraints onto the functions that are to be used. This is the case in the Optimization Toolbox.
I will consider the sinewave function again, but this time I use the first definition (i.e. without a variable number of parameters). Then you could work with a function handle:
f = #(x)(sinewave(x,1,1));
You can work with f as you would with an other function:
e.g. f(10) will evaluate sinewave(10,1,1).
That way you can write a general function (i.e. sinewave that is as general and simple as possible) but you create a function (handle) on the fly with the constants substituted. This allows you to work with that function, but also prevents global storage of data.
You can of course combine different solutions: e.g. create function handle to a function with a variable number of parameters that sets a certain global variable.
The easiest way to address this is via global variable:
http://www.mathworks.com/help/techdoc/ref/global.html
You can also get the values in other workspaces, including the base or parent workspace, but this is ill-advised, as you do not necessarily know what wraps a given function.
If you want to go that route, take a look at the evalin function:
http://www.mathworks.com/help/techdoc/ref/evalin.html
Still, the standard method is to pass all of the variables you need. You can put these into a struct, if you wish, and only pass the one struct.
Is there a way to declare global variables in MATLAB?
Please don't respond with:
global x y z;
Because I can also read the help files.
I've declared a global variable, x, and then done something like this:
function[x] = test()
global x;
test1();
end
Where the function test1() is defined as:
function test1()
x = 5;
end
When I run test(), my output is x = []. Is there a way I can make it output the x=5, or whatever I define x to be in a separate function? In C, this would be an external variable, and I thought making it a global variable should accomplish just that.
You need to declare x as a global variable in every scope (i.e. function/workspace) that you want it to be shared across. So, you need to write test1 as:
function test1()
global x;
x = 5;
end
Referring to your comment towards gnovice using a global variable can be an approach to solve your issue, but it's not a commonly used.
First of all make sure that your .m files are functions and not scripts. Scripts share a common workspace, making it easy to unwillingly overwrite your variables. In contrast, functions have their own scope.
Use xUnit in order to generate repeatable unit test for your functions. By testing each function involved in your program you will track down the error source. Having your unit test in place, further code modifications, can be easily verified.
A possible way to get around the global mess is to assign the variable as appdata. You can use the functions setappdata and getappdata to assign and retrieve appdata from a MATLAB window. As long as a MATLAB session is active there exists a window denoted by 0.
>> setappdata(0,'x',10) % 0 indicates the root MATLAB window
Now the variable x is not visible to any script or function but can be accessed wherever needed by using getappdata.
function test
globalX = getappdata(0,'x');
disp(globalX);
end
x =
10
The good news is that you can assign any valid MATLAB object to appdata, just be cautious with the names, using unique names for appdata fields like ModelOptimizerOptions instead of a generic x,y would help. This works on compiled executables and code deployed on the MATLAB production server as well.