I am trying to implement the following code in Matlab:
v0=eps;
t0=0; tf=10;
[t,v]=ode45(#const_pow, [t0 tf], v0);
And the const_pow function is:
function f=const_pow(t,v)
f=(P/v-F0-c*v^2)/m;
end
While I am running the program, the following error shows up:
Error using ==> odearguments at 103
CONST_POW returns a vector of length 0, but the length of initial
conditions vector is 1. The vector returned by CONST_POW and the
initial conditions vector must have the same number of elements.
Any suggestions on where the error might be?
From your comments, you're defining some variables globally. In order to access them inside const_pow, you need to tell that function to use the global variables, e.g.:
function f=const_pow(t,v)
global P F0 c m
f=(P/v-F0-c*v^2)/m;
end
Without doing this, the function will not touch the global variables (this is to stop you accidentally changing their values). For example:
function f=const_pow(t,v)
global P F0 c
m = 23.7; % this does not change the global value of m
f=(P/v-F0-c*v^2)/m;
end
An alternative to passing a number of variables without using globals is to define a structure with your required data:
data.P = % initial values
data.F0 =
data.c =
data.m =
This also gives you a little more flexibility if there is more than one set of options. Or, you could pass the variables in directly. To do this with ode45, you would need to parameterize the function using an anonymous function:
function f=const_pow(t,v,P,F0,c,m)
% and so on
end
With P,F0,c,m pre-defined:
odefun = #(t,v) const_pow(t,v,P,F0,c,m); % anonymous function
Then:
[t,v]=ode45(odefun, [t0 tf], v0);
Related
I have defined a bunch of constants. I want to use these in local functions.
The function can't access these values and I get the error
Undefined function or variable 'g'.
I have tried shifting the position of the functions
Also tried to make the constants global so every local function knows them
**% Define constants**
K=0.5; % minor loss coefficient (square edged)
g=9.8; % gravity in m/s2
**%call function**
f1= 2 (value obtained from external function)
v1=velocity1(f1);
**% define function**
function v1=velocity1(f)
v1= sqrt((2*g*h)/(1+(f*(L./D))+K));
end
>> LvsQ_plot
Undefined function or variable 'g'.
Error in LvsQ_plot>velocity1 (line 48)
v1= sqrt((2*g*h)/(1+(f*(L./D))+K));
Error in LvsQ_plot (line 31)
v1=velocity1(f1);
There are multiple approaches passing constants to MATLAB functions
Defining variables as global is a simple solution.
Using global makes the variable "visible" to all functions and scripts. The downside of using global, is that it's not extendable, and prevents code reuse.
From academic software engineering perspective, you shouldn't use global variables at all. Assuming your code is used for solving a specific problem and not going to be extended or reused, using global is permitted.
Using global:
Declare the constants as global before initialization:
global K g
K=0.5; % minor loss coefficient (square edged)
g=9.8; % gravity in m/s2
Declare the variables as global in any function that uses them:
function v1=velocity1(f)
global K g
v1= sqrt((2*g*h)/(1+(f*(L./D))+K));
end
Using nested functions:
Instead of using global, you can use "nested functions" approach - an inner function can access the variables of an outer function.
Define your main script as a function, and velocity1 as an inner function:
function main()
%main is the outer function, and velocity1 is an inner function
K=0.5; % minor loss coefficient (square edged)
g=9.8; % gravity in m/s2
h=1;L=3;D=4;
f1= 2; %(value obtained from external function)
v1=velocity1(f1);
%Inner function:
function v1=velocity1(f)
v1= sqrt((2*g*h)/(1+(f*(L./D))+K));
end
end
Passing a struct of parameters to the function:
A common solution is MATLAB is passing a struct with constant parameters to all functions that uses them:
param.K=0.5; % minor loss coefficient (square edged)
param.g=9.8; % gravity in m/s2
param.h=1;param.L=3;param.D=4;
f1= 2; %(value obtained from external function)
v1=velocity1(f1, param);
function v1=velocity1(f, par)
K = par.K;
g = par.g;
h=par.h;L=par.L;D=par.D;
v1= sqrt((2*g*h)/(1+(f*(L./D))+K));
end
There are other approaches, but I can't list them all...
I have a use case as follows:
Inside F.m I have a function F that takes as its argument a 2 x 1 matrix x. F needs to matrix multiply the matrix kmat by x. kmat is a variable that is generated by a script.
So, what I did was set kmat to be global in the script:
global kmat;
kmat = rand(2);
In F.m:
function result = F(x)
global kmat;
result = kmat*x;
end
Then finally, in the script I have (x_0 has already been defined as an appropriate 2 x 1 matrix, and tstart and tend are positive integers):
xs = ode45(F, [tstart, tend], x_0);
However, this is causing the error:
Error using F (line 3)
Not enough input arguments.
Error in script (line 12)
xs = ode45(F, [tstart, tend], x_0);
What is going on here, and what can I do to fix it? Alternatively, what is the right way to pass kmat to F?
Firstly, the proper way to handle kmat is to make it an input argument to F.m
function result = F(x,kmat)
result = kmat*x;
end
Secondly, the input function to ode45 must be a function with inputs t and x (possibly vectors, t is the dependent variable and x is the dependent). Since your F function doesn't have t as an input argument, and you have an extra parameter kmat, you have to make a small anonymous function when you call ode45
ode45(#(t,x) F(x,kmat),[tstart tend],x_0)
If your derivative function was function result=derivative(t,x), then you simply do ode45(#derivative,[tstart tend],x_0) as Erik said.
I believe F in ode45(F,...) should be a function handle, i.e. #F. Also, you can have a look at this page of the MATLAB documentation for different methods to pass extra parameters to functions.
My Question: Given a function handle, does matlab parse the string each time it needs to evaluate it, or just once and then it caches it?
Example
Consider the ingenious function
function [] = foo(func)
for j=1:1e4
func(j);
end
and the script
func1 = #(x) 5*abs(x)^2
function foo(func1);
At run-time, Matlab needs to interpret #(x) 5*abs(x)^2 as a function. In this example, does it do it once, or a thousand times?
First of all #(x)cos(x) is not a string, it is an anonymous function declaration. When you create an anonymous function, MATLAB essentially creates a function object which contains all of the information it needs to run. This anonymous function can then be passed around to various functions or even saved to a file. As such, it is only constructed once and evaluated many times.
When evaluated, MATLAB does not do any caching, so calling the same anonymous function with the same inputs many times causes the contents of the anonymous function to be evaluated each time.
If you want to get more information about your anonymous function, including the local workspace of the function, you can use the functions function
f = #(x)cos(x);
functions(f)
% function: '#(x)cos(x)'
% type: 'anonymous'
% file: ''
% workspace: {[1x1 struct]}
% within_file_path: '__base_function'
That being said, in your example, it could really be reduced to a function handle rather than an anonymous function since you pass all input arguments directly to cos without modifying them. As you can see, this has a different internal representation and from some preliminary benchmarks, it seems to be marginally faster.
f = #cos
functions(f)
% function: 'cos'
% type: 'simple'
% file: ''
And a quick benchmark
function benchit
fprintf('Anonymous function: %0.4f\n', timeit(#option1));
fprintf('Function handle: %0.4f\n', timeit(#option2));
end
function option2()
f = #(x)cos(x);
for k = 1:10000
f(k);
end
end
function option1()
f = #cos;
for k = 1:10000
f(k);
end
end
And the results (not really a huge difference)
Anonymous function: 0.0056
Function handle: 0.0049
A few more things
When creating the anonymous function, the anonymous function declaration must still adhere to all of MATLAB's standard syntax rules otherwise it won't be created. For example, the following would throw an error during anonymous function creation since it is invalid syntax
func = #(x)thing]
Error: Unbalanced or unexpected parenthesis or bracket.
When you evaluate an anonymous function (after it's successful creation), it's just like evaluating any other function in that the anonymous function can throw an error and the error depends upon the input.
func = #(x) x + [1 2];
func([3 4])
% 4 6
% Now we're going to pass an array that isn't 1 x 2
func([5 6 7])
Matrix dimensions must agree.
Error in #(x)x+[1,2]
I begin with a symbolic function of one variable, calculate the symbolic derivatives of orders 1 through N, and then convert those symbolic functions into function handles and store the function handles in a cell array. I then evaluate each function handle at the same input value using a loop. The problem I have is that it is possible for one of the derivatives to be a constant (with higher order derivatives being zero, of course). As I was trying to give each function handle an input, I face the "Too many input arguments" error. I would like to be able to check, in advance, whether the function handle is a constant so I can avoid the error, but I can't figure out how to do that.
In case a small working example is helpful, I provide the following
symVar = sym('symVar');
startFunc = symVar^4 + symVar^3 + symVar^2;
derivesCell = cell(5);
for J=1:5
derivesCell(J) = {matlabFunction(diff(startFunc,symVar,J))};
end
cumSum = 0;
evalPoint = 2;
for J=1:5
cumSum = cumSum + derivesCell{J}(evalPoint);
end
Execution produces "Error using symengine>#()2.4e1
Too many input arguments."
tl;dr: You can do this with nargin:
>> nargin(derivesCell{5})
ans =
0
>> nargin(derivesCell{3})
ans =
1
Explanation:
Most people are familiar with the use of nargin as a "special variable" inside the function, but it can be used outside the context of a function definition, as a function that takes a function_handle argument, returning the number of input arguments that function handle takes. From the documentation:
NARGIN(FUN) returns the number of declared inputs for the
M-file function FUN. The number of arguments is negative if the
function has a variable number of input arguments. FUN can be
a function handle that maps to a specific function, or a string
containing the name of that function.
I want to minimize this function:
function [GCV2]=GCV(y,x,k)
[n, p]=size(x);
A=(x'*x+k*eye(p));
A=A\x';
A=x*A;
I_mat=eye(n);
num2=(I_mat-A);
num2=num2*y;
num2=norm(num2);
num2=num2^2;
num2=num2/n;
%(norm((I_mat-A)*y)^2)/n;
den2=(I_mat-A);
den2=trace(den2);
den2=den2/n;
den2=den2^2;
GCV2=num2/den2;
end
The x and y values are 13-by-4) and 13-by-1 arrays, respectively, and these values are already defined in the Matlab workspace. I want to optimize on the k value so that the function value GCV is minimized.
The parameter being optimized as well as the output are scalar so fminsearch should be appropriate.
But I can't get it to run?
I've tried several methods, the latest being:
k_min = fminsearch(#GCV,(x;y;0));
??? k_min = fminsearch(#GCV,(x;y;0));
|
Error: Unbalanced or unexpected parenthesis or bracket.
What am I doing wrong?
Looks like you're learning about anonymous functions. fminsearch minimizes a single variable (which may be a vector). Your objective function must therefore have only one input. You have a function, GCV, that takes three inputs. Two are static and are defined in the workspace outside of the minimization, while k is the one to be minimized. To create a function with one input from GCV, you can use any anonymous function, taking care to specify which variables are parameters:
x = ...
y = ...
k0 = 0;
k_min = fminsearch(#(k)GCV(y,x,k),k0);
The second input to fminsearch is the starting parameter (i.e. k0), so specify a starting value of k. Then you can define an anonymous helper function and optimize on that:
>> % define x,y
>> GCVk = #(k) GCV(y,x,k);
>> k0 = 0;
>> k_min = fminsearch(GCVk,k0)
There is probably another way to do this, but this is one of the listed ways of passing additional parameters for the optimizer.
And since there are no bonus points for being first, how about humor. Let's have an example:
>> x=1; y=1;
>> GCVk = #(k) x+y+k; k0=0;
>> k_min = fminsearch(GCVk,k0)
Exiting: Maximum number of function evaluations has been exceeded
- increase MaxFunEvals option.
Current function value: -316912650057057490000000000.000000
k_min =
-3.1691e+26
Found it - the lowest number (minus 2) in the world! Profit?