I just started with MATLAB and I'm seeking advice for how to make a function work with more arguments.
I've built this formula:
I = real((U0.*exp(i.*vw.*vt))./(L.*(-vw.^2+ (R/L).*i.*vw + (1/L.*C)))) + ...
exp((-R.*vt)./(2.*L).*( alpha.*cos( sD.*vt)+ beta.*sin( sD.*vt)));
Therefore I needed the values for U0, vw, vt, L, R
If I put this in the command window:
D = (1/L*C)-((R^.2)/(4*L^.2));
sD = sqrt(D);
vt = linspace(tmin,tmax,200);
vw = omega;
[vw,vt] = meshgrid(vw,vt);
I = real((U0.*exp(i.*vw.*vt))./(L.*(-vw.^2+ (R/L).*i.*vw + (1/L.*C)))) + exp((-R.*vt)./(2.*L).*( alpha.*cos( sD.*vt)+ beta.*sin( sD.*vt)));
surf(vw,vt,I)
It works fine.
So, now I want to create a function which reads the values and calculates all the stuff above and returns a surf plot.
My try:
function [u] = test(L,C,R,tmin,tmax,omega,U0)
D = (1/L*C)-((R^.2)/(4*L^.2));
sD = sqrt(D);
vt = linspace(tmin,tmax,200);
vw = omega;
[vw,vt] = meshgrid(vw,vt);
I = real((U0.*exp(i.*vw.*vt))./(L.*(-vw.^2+ (R/L).*i.*vw + (1/L.*C))))+exp((-R.*vt)./(2.*L).*( alpha.*cos( sD.*vt)+ beta.*sin( sD.*vt)));
surf(vw,vt,I)
end
This error occurs:
Error using alphaToo many output arguments.
Do you have an idea how to make this function work?
What is alpha? It's likely that it exists in your workspace, so when you call those lines from your workspace everything is fine. However, within the test function MATLAB has no visibility of the "base" workspace, and alpha doesn't exist! Pass it as an argument or define it like your other values. Ditto with beta.
Also you have defined the output argument u in your function
% Ouput vvv
function [u] = test(L,C,R,tmin,tmax,omega,U0)
But you never assigned anything to the variable u during the function". If you want to return the surf figure object, assign that to u when it is called.
% Square brackets not needed as only returning one variable
function u = test(L,C,R,tmin,tmax,omega,U0)
% ... stuff
u = surf(vw,vt,I)
end
Related
I've written the following piece of subcode (with parameters commented) for an Euler policy iteration algorithm. When I try to run the body of the function (everything below global) for say, a1 = 1, it works, and returns a scalar. However, when I call the function as euler_diff_test(1), I get an error. (Pasted below)
function diff = euler_diff_test(a1)
%the following comments are example parameters. They are in the global line originally.
% r = 0.2, a = 0.5, y = 1.1, a_grid = linspace(0.5,7,100)
%policy_guess = zeros(2,N);
%policy_guess(1,:) = 0.3*a_grid;
%policy_guess(2,:) = 0.3*a_grid;
% M = zeros(2,2); %M for markov transition kernel
% M(1,1) = p;
% M(2,2) = p;
% M(2,1) = 1-p;
% M(1,2) = 1-p;
% j = 1
global r a y a_grid policy_guess M j;
c = (1+r)*a + y - a1; %consumption formula
if c<=1e-02 %don't care about consumption being negative
diff = 888888888888888888888;
else
policy_func = interp1(a_grid', policy_guess', a1, 'linear');
diff = 1/c - beta*(1+r)*(1 ./ policy_func)*M(j,:)';
end
end
Error Reads:
Any help is much appreciated!
The problem is that you dont understand globals nor how they work!
You seem to be doing something like:
N=100; p=0.1;
r = 0.2, a = 0.5, y = 1.1, a_grid = linspace(0.5,7,100)
policy_guess = zeros(2,N);
policy_guess(1,:) = 0.3*a_grid;
policy_guess(2,:) = 0.3*a_grid;
M = zeros(2,2); %M for markov transition kernel
M(1,1) = p;
M(2,2) = p;
M(2,1) = 1-p;
M(1,2) = 1-p;
euler_diff_test(1)
And this is causing the error you show. Of course it is!
First, you need to learn what a global is and what worskpaces are. Each fucntion has its own worskpace or "scope". That means that only variables defined within the workspace are visible by the function itself.
A global variable is one that exist for all workspaces, and everyone can modify it. You seem to want all those variables defined outside the function, inside your function. But realise! when the variables are defined, they are not global. The function starts, and in its first line, it does only know about the existence of a1. Then, later, you define a bunch of variables as global, that the function did not know about. So what does the function do? just create them empty, for you.
If you want your the variables that you create in the main script scope to be global, you need to declare them as global then, not inside the function. So cut your line global ... from the fucntion, and put it on top of the script where you declare all your variables, i.e. on top of
% here!
N=100; p=0.1;
...
in my example.
Now, the important stuff: Global variables are bad. When you have globals, you don't know who modifies, and its super easy to lost track of what is happening to them, because every function that uses a variable a will modify the global a, so its a pain to debug. Almost no one uses globals because of this. The best way is to pass them to the function as input, i.e. define your function as:
function diff = euler_diff_test(a1,r, a, y, a_grid, policy_guess, M, j)
clear all;
close all
clc
e = .25;
%fun = #find_root;
z = fzero(fun,1)
yy = z+.5^2*z/e-z^3/e
%=================================
function y = find_root(x)
y1 = x+0.5^2*x/e-x^3/e;
y = -e*x + e*y1 +.5^2*y1-y1^3
end
It can work if I separate two parts in different .m file of the above code. However, when I
combine them together, Matlab shows:
Error: File: find_root.m Line: 11 Column: 14
Function with duplicate name "find_root" cannot be defined.
Since I want to set e from 0 to 1 in for loop and I cannot add parameter in the following way
z = fzero(fun(x,e),1)
that is why I have to combine both parts in ONE .m file.
How to fix it?
Okay, so there is a few things wrong here. Firstly with your error:
Error: File: find_root.m Line: 11 Column: 14 Function with duplicate name "find_root" cannot be defined.
This is caused when you give your file the same name as a function contained in the script. I suggest you change it to something else (e.g. calc_yy.m). Other than that you should define your function as a function handle with your desired input (fun = #(x)find_root(x,e); is a function handle with input x). Something else to watch out for is including e as a parameter for your function. If you do not include e as a function parameter in the definition function y = find_root(x,e) and the function handle fun = #(x)find_root(x,e);, then the e you defined earlier will be out of scope within the function. The following code worked just fine for me (saved as test.m):
%% Script
clear all
close all
clc
e = .25;
fun = #(x)find_root(x,e);
z = fzero(fun,1);
yy = z+.5^2*z/e-z^3/e;
%% Functions
function y = find_root(x,e)
y1 = x+0.5^2*x/e-x^3/e;
y = -e*x + e*y1 +.5^2*y1-y1^3;
end
Good luck with your future MATLAB endeavours and don't ever feel silly for mistakes like this, we have all made them at some point!
and I am pretty new at it. I wrote the simple function below, which gets a pair and returns the polar form
function [r,a] = rect2polar(x,y)
r = sqrt(x^2 + y^2);
a = atan(y/x);
[r,a]
end
and when I try for example rect2polar(3,5) it gives me the next output:
ans =
5.8310 1.0304
ans =
5.8310
It returns the desired output, plus the output 5.8310, in other words it returns the variable r in the function for the second time. How can I fix this? Writing
rect2polar(3,5);
helped (the difference is that I wrote ; at the end), but it doesn't feel right. Any help is appreciated, thanks!
The first displayed part,
ans =
5.8310 1.0304
is produced by this line in your function
[r,a]
Since it is missing a ;, Matlab displays the result.
The second part,
ans =
5.8310
is produced because when you call the function as rect2polar(3,5) you are indicating that you want only one output, namely the first, which is displayed after the function returns.
So, the solution would be:
Remove the line [r, a] in your function, which is doing nothing but display what the function will output;
Call your function as [out1, out2] = rect2polar(3,5).
Or, if you want the function to return a vector:
function out = rect2polar(x,y)
r = sqrt(x^2 + y^2);
a = atan(y/x);
out = [r,a];
end
I have a function that gets a matrix and do some operations on it.
but I do not know how to declare function's parameter .
this is my function Code:
function D=Shirinkage(a)
D(1,:)=a(1,:);%this is X1
for i=2:4
D(i,4)=0;
for j=1:3
D(i,j)=1/2*(a(1,j)+a(i,j));
D(i,4)=D(i,j)^2 + D(i,4); %object function
end
end
end
I tried a(4,4) instead of a (parameter of the function),but the error does not appear.
Error:
??? Input argument "a" is undefined.
Error in ==> Shirinkage at 3
D(1,:)=a(1,:);%this is X1
also I want to declare D correctly.
appreciating any help.
Edited:
i call my function from a script file , in this way:
I have a 2-dimention array(matrix) its size is : 4*4 and its name is A.
i want my function gets this matrix and do the operation on it and the result can be saved again in it.
A=Shirinkage(A)
e.x. A has this values:
A=[1,2,3,4;2,3,4,5;5,6,7,8;1,2,3,4]
The function you created is working fine. The only recommendation I have to pre-allocate the size of D as it varies in each iteration in your current code.
function D = Shirinkage(a)
D = zeros(size(a));
D(1,:) = a(1,:); %this is X1
for i = 2:4
D(i,4) = 0;
for j = 1:3
D(i,j) = 0.5*(a(1,j) + a(i,j));
D(i,4) = D(i,4) + D(i,j)^2; %object function
end
end
end
The function was called from command window by using the same matrix you have used and it gave the following output.
The error you have posted says that the function hasn't received the argument a. If your script and the function are in the same MATLAB path, this should work perfectly.
I'm trying to use arrayfun() to map a function over a cell array. The following is happening:
>> arrayfun(solveFunc, equArray)
Error using arrayfun
First input must be a function handle.
Error in solve>genGuess (line 33)
funcVals = abs(arrayfun(inFunc, xValues));
Error in solve (line 8)
x = genGuess(inFunc, varargin{1}, varargin{2});
Error in makeSolveFunc>#(func)solve(func,start,stop) (line 3)
sFunc = #(func) solve(func, start, stop);
But, the first input IS a function handle. Also... if I manually apply the function to each element of the provided cell array, everything works fine:
>> solveFunc(equArray{1})
ans =
4.7335
>> solveFunc(equArray{2})
ans =
4.7356
Does anyone know why this would be happening? I assumed that if I could manually apply the function to each element of my array, and the return type of the function was consistent and one of the allowed types (you can't for example have arrayfun return an array of function handles... I already tried doing that), it should work. Perhaps that is not the only requirement.
Here is some code that generates this error:
solve.m
function solution = solve(inFunc, start, stop)
%SOLVE solve an equation using Newton's Method
x = genGuess(inFunc, start, stop);
for i = 1:100
m = getSlope(inFunc, x);
x = (m*x - inFunc(x))/m;
end
solution = x;
end
function slope = getSlope(inFunc, x)
%SLOPE calculate the slope at a given point
inc = 1e-5;
if x ~= 0
inc = inc * x;
end
slope = (inFunc(x + inc) - inFunc(x - inc))/(2*inc);
end
function guess = genGuess(inFunc, start, stop)
%GENGUESS get an initial guess to the solution
xValues = linspace(start, stop, 101);
funcVals = abs(arrayfun(inFunc, xValues));
[~, minIndex] = min(funcVals);
guess = xValues(minIndex);
end
charEqu.m
function equ = charEqu(a)
%CHAREQU create a KP model characteristic equation with provided p
equ = #(x) x + a;
end
makeSolveFunc.m
function sFunc = makeSolveFunc(start, stop)
%MAKESOLVEFUNC return a function that solves an equation
sFunc = #(func) solve(func, start, stop);
end
test.m
pArray = 1:5;
equArray = cell(1,arrayLen);
for i = 1:5
equArray{i} = charEqu(pArray(i));
end
solveFunc = makeSolveFunc(1.1*pi, 2*pi);
alphaAArray = arrayfun(solveFunc, equArray);
I have narrowed down the error to something in genGuess(). For some reason, in the line funcVals = abs(arrayfun(inFunc, xValues)); the variable inFunc is a 1x1 cell array containing a function handle. I have no idea why that would be the case. I traced this back to the anonymous function call #(func) solve(func, start, stop); in the makeSolveFunc() function. There it is still a 1x1 cell array containing a function handle. I'm not really sure where that cell array is coming from as that function is getting called from arrayfun().
Background information on what I'm trying to do in case someone wants to suggest a better way:
I'm trying to solve equations using Newton's method. I have written a function that can solve an equation given an initial guess range. This function is the solve() function you can see in the first error message. It takes a function, and the guess range and returns a function that I'm calling solveFunc(). solveFunc() takes a function and solves it using the initial guess range previously provided.
Maybe I'm just too used to functional programming and should just use a loop.
If the arguments passed to the function handle are contents of elements of a cell array, you need to use cellfun instead of arrayfun:
cellfun(solveFunc, equArray)
This is equivalent to
for i=1:length(equArray)
out(i) = solveFunc(equArray{i});
end
since solveFunc is already a function handle.
Check where the error comes from. This line causes the error:
funcVals = abs(arrayfun(inFunc, xValues));
The first input argument is a 1x1 cell containing one function handle. This is caused because equArray is a cell, thus use cellfun as Jonas already mentioned:
pArray = 1:5;
equArray = cell(1,arrayLen);
for i = 1:5
equArray{i} = charEqu(pArray(i));
end
solveFunc = makeSolveFunc(1.1*pi, 2*pi);
alphaAArray = cellfun(solveFunc, equArray);