Matlab batch not passing arguments to function - matlab

Thank you in advance for any help you can give. I am relatively new to Matlab and am stuck with the use of the batch command for passing arguments to the function. I have tried to simplify the example as much as possible.
Following the documentation, I can get it to work with a built-in function:
>>
>> j = batch(#zeros,1,{10,1});
>> a=fetchOutputs(j)
a =
1×1 cell array
{10×1 double}
>> a{1}
ans =
0
0
0
0
0
0
0
0
0
0
I then created a simple stand-along function runTest.m:
function result = runTest(n1,n2)
result = zeros(n1,n2);
end
It works with a direct call:
>> a=runTest(5,1)
a =
0
0
0
0
0
But, it doesn't work using batch:
>> j = batch(runTest,1,{5,1});
Not enough input arguments.
Error in runTest (line 2)
result = zeros(n1,n2);
Any suggestions? Thank you.

When you do
j = batch(runTest,1,{5,1});
then the part of that statement that reads runTest tries to call the function runTest with no input arguments. This is where the error happens. It never gets to call batch.
Like in just about every other programming language, the arguments to a function call are evaluated before the function is called, evaluating runTest is the same as evaluating runTest(), MATLAB makes no distinction between the two.
What you intended to write was
j = batch(#runTest,1,{5,1});

Related

Plotting a function in another .m file

i started programming Matlab the last week and i`ve been trying to plot a function file with no success.
This is my function file (impuls.m). It basicaly should set y = 0 for 0<=x<5 and x>10. y = 5 for 5<=x<=10).
function y = impuls(x)
if ((x>=0 && x<5) || x>10)
y=0;
else if (x>=5 && x<=10)
y=5;
end
end
end
I guess i did it right, because when i test it on my main file (fourierreihe.m) using impuls(1) i get a "0" and when using impuls(7) i get a 5. The problem is when i try to get all resuts for the interval [0 13] and plot them as a rectangular impuls.
I tried using:
impuls([0 13])
But i keep getting the error:
fouhierreihen
Operands to the || and && operators must be convertible to logical scalar values.
Error in impuls (line 3)
if ((x>=0 && x<5) || x>10)
Error in fouhierreihen (line 1)
impuls([0 13])
Shouldnt i be getting something as "ans = 0 0 0 0 0 5 5 5 5 5 5 0 0 0" this as an answer?
So guys, what am i doing wrong? I`ve searched for videos and posts and i cant find the mistake there. How could i possibly plot it for the interval?
Thank you in advance,
Pedro.
As the error message and documentation explain, inputs to the short-circuit logical operators must be scalars. It doesn't really make sense fundamentally trying to robustly short circuit with two arrays of truth values.
You can use logical indexing to accomplish the same task in a vectorized manner. For example:
function y = impuls(x)
y = zeros(size(x)); % Initialize the output array
y(x>=5 & x<=10) = 5; % Condition one
Which returns:
impuls(1) =
0
impuls(7) =
5
impuls([0 13]) =
0 0
impuls(0:13) =
0 0 0 0 0 5 5 5 5 5 5 0 0 0
That your original function works with fplot is a concession from MATLAB's developers. The function documentation repeatedly states that the function being plotted must accept vector inputs (though they don't actually enforce it, apparently):
The function must accept a vector input argument and return a vector
output argument of the same size
Your function doesn't do this, because && and || are scalar operations. However, fplot will revert to calculating function outputs element-by-element (a loop) in the event that the array input fails, throwing the following warning:
Warning: Function fails on array inputs. Use element-wise operators to increase speed.
> In matlab.graphics.function.FunctionLine>getFunction
In matlab.graphics.function.FunctionLine/updateFunction
In matlab.graphics.function.FunctionLine/set.Function_I
In matlab.graphics.function.FunctionLine/set.Function
In matlab.graphics.function.FunctionLine
In fplot>singleFplot (line 223)
In fplot>#(f)singleFplot(cax,{f},limits,extraOpts,args) (line 182)
In fplot>vectorizeFplot (line 182)
In fplot (line 153)
In trialcode (line 1)
My Friend....
Try this:
function y = impulse(t)
if 0
%% Example
t=(0:100)';
y=impulse(t)
plot(t,y);
end
for i=1:length(t)
if ((t(i)>=0 && t(i)<5) || t(i)>10)
y(i,1)=0;
else if (t(i)>=5 && t(i)<=10)
y(i,1)=5;
end
end
end
Note:
the for loop is critical in these cases,
the function impulse could exist anywhere, but your local version prevail,
the y(i,1) retain your vector as columns,
run the section inside the void loop (if 0)
the time is normally used here as variable :)....
hyp.

Matlab : Insert values from a 2-d matrix into a 3-d matrix on some condition

output is a 3d matrix with size(output) == [height width N] and input is a 2d matrix with size(input) == [height width] . I need to implement the following code in one line.
for k = 1:size(output,3)
f = output(:,:,k);
i_zero = (f==0);
f(is_zero) = input(is_zero);
output(:,:,k) = f;
end
bsxfun approach -
output = bsxfun(#times,output==0,input) + output
Alternative approach -
output = (output==0).*input(:,:,ones(1,N))+ output
I hope the "I need to implement" is not a homework.
Here goes a solution that should solve your problem although not in one line.
new_input=repmat(input,1,1,size(output,3));
output(output==0)=new_input(output==0);
All the answers solve the problem when there is a exact comparison to 0 (as OP required) but for the sake of generalization if you intend to change for another comparison be aware that not all methods work in the same way.
Example below:
CODE:
%Simulation
output=rand(10,10,3);
input=rand(10,10);
% output=randi(9,10,10,3);
% input=randi(9,10,10);
%OP code
output2=[]
for k = 1:size(output,3)
f = output(:,:,k);
i_zero = (f<0.5);
f(i_zero) = input(i_zero);
output2(:,:,k) = f;
end
%repmat code
output3=output;
new_input=repmat(input,1,1,size(output,3));
output3(output<0.5)=new_input(output<0.5);
any(output2(:)-output3(:))
%bsxfun code
output4 = bsxfun(#times,output<0.5,input) + output;
any(output2(:)-output4(:))
%other variation code
output5 = (output<0.5).*input(:,:,ones(1,size(output,3)))+ output;
any(output2(:)-output5(:))
% bultin code
output6=output;
output6(output<0.5)=builtin('_paren',repmat(input,[1,1,size(output,3)]),output<0.5);
any(output2(:)-output6(:))
'-----'
any(abs(output2(:)-output3(:))>eps)
any(abs(output2(:)-output4(:))>eps)
any(abs(output2(:)-output5(:))>eps)
any(abs(output2(:)-output6(:))>eps)
'-----'
sum(abs(output2(:)-output3(:)))
sum(abs(output2(:)-output4(:)))
sum(abs(output2(:)-output5(:)))
sum(abs(output2(:)-output6(:)))
OUTPUT:
ans =
0
ans =
1
ans =
1
ans =
0
-----
ans =
0
ans =
1
ans =
1
ans =
0
-----
ans =
0
ans =
150.5088
ans =
150.5088
ans =
0
If you insist on a single line solution, you can use the (:) operator along with the mod command:
output(output(:)==0) = input(mod(find(output(:)==0)-1,height*width)+1)
where the -1 and +1 are in order to avoid index 0
Here is in a one liner... but uses the undocumented builtin('_paren',... to subscript reference to the output of a function
output(output==0)=builtin('_paren',repmat(input,[1,1,N]),output==0)
without the the undocumented builtin this method gets messy if you want it in one line...
output=subsasgn(output,struct('type','()','subs',{{output==0}}),...
subsref(repmat(input,[1,1,N]),struct('type','()','subs',{{output==0}})))
...sadly I forgot using masks and adding two matrices together was an option...
You should have the 'cat' function:
http://www.mathworks.nl/help/matlab/ref/cat.html
cat(3,matrix1,matrix2,...) to concatenate along the 3rd dimension.

How to use the trapz function verses the integral function

I have my code working using the integral function but I'm looking to implement it using the trapz function instead.
fc = 5*10^6;
fb = 0.2*10^6;
F = [0:10000:10^7];
Tb = 1/fb;
Sequence = [0 1 0 1 1 0 1 1 1 0 0 0 1 0 1 ];
A = sqrt(9/Tb);
w = 2*pi*fc;
I = zeros(1,length(F));
for counter1 = 1:length(Sequence)
if Sequence ( 1, counter1) == 1
s_of_t = #(t) A*cos(w*t)*exp(-1i*2*pi*t*F);
else
s_of_t = #(t) -A*cos(w*t)*exp(-1i*2*pi*t*F);
end
S_of_f = integral(s_of_t,((counter1-1)*Tb),(counter1*Tb),'ArrayValued', true);
for counter2 = 1:length(S_of_f)
I( 1, counter2) = I(1,counter2)+S_of_f(1,counter2);
end
clear S_of_f s_of_t;
end
figure(1)
plot(F,abs(I));
What I want to do is use the trapz function instead of the integral function like this:
for n = 1 : length(F)
S_of_f(n) = trapz(F,s_of_t);
end
instead of:
S_of_f = integral(s_of_t,((counter1-1)*Tb),(counter1*Tb),'ArrayValued', true);
I am having trouble implementing my code using this function so if you have any advice I'd appreciate it.
Errors include:
Undefined function 'max' for input arguments of type 'function_handle'.
Error in trapz (line 43)
perm = [dim:max(ndims(y),dim) 1:dim-1];
I'm not sure which function handles I'm missing.
(Yes I'm taking the Fourier Transform however my attempts to utilize the FFT function took up way too much memory).
trapz expects a vector of function evaluations, not a function handle, which is what integral expects.
if Sequence ( 1, counter1) == 1
s_of_t = #(t,F) A*cos(w*t).*exp(-1i*2*pi*t*F);
else
s_of_t = #(t,F) -A*cos(w*t).*exp(-1i*2*pi*t*F);
end
for i=1:length(F)
r=linspace(((counter1-1)*Tb),(counter1*Tb),100);
S_of_f(i) = trapz(r,s_of_t(r,F(i)));
end
...
I arbitrarily chose 100 evaluation points for the integral using trapz; you will want to modify this to an appropriate value depending on how you are using this code.

How to store a function-wrapped solve call?

Bear with me please, I'm completely new to matlab. I am attempting to store the call to eigenvalue in another function, but it's giving me the error: Too many output arguments.
function eigenvalue(M)
syms l;
eq = det(M - l*[1 0; 0 1]);
solve(eq == 0)
end
I've tried storing it in many different ways, but nothing seems to work:
>> a = eigenvalue(M)
Error using eigenvalue
Too many output arguments.
>> [a, b] = eigen(M)
Error using eigenvalue
Too many output arguments.
The weird thing is that if I solve a normal polynomial equation I can do sol=solve(x^2==4) just fine and access sol(0)and sol(1)without any problems. I guess that I haven't picked up on a simple matlab concept and thanks to anyone who's willing to help!
Your problem is that you don't have any output arguments in your function.
function eigenvalue(M)
In MATLAB, you should* use the following syntax:
function output = func_name(input_1,input_2,...)
You have 2 alternatives:
You can skip the first line and save it as script, as this:
syms l;
eq = det(M - l*[1 0; 0 1]);
solve(eq == 0)
Or, you can save it as a function, but with output variable(s), like this:
function output = eigenvalue(M)
syms l;
eq = det(M - l*[1 0; 0 1]);
output = solve(eq == 0)
end
*You should use the syntax I described, but you can use the syntax you used as well. However, if you do, the function won't give you anything back except possibly printing the result to screen. You will not get to use any variables created inside the function.
If you want a function to provide an output argument then you have to declare it in the function definition. E.g.
function a = eigenvalue(M)
You then need to make sure you assign a value to each output variable in the function body.

Saving derivative values in ode45 in Matlab

I'm simulating equations of motion for a (somewhat odd) system with mass-springs and double pendulum, for which I have a mass matrix and function f(x), and call ode45 to solve
M*x' = f(x,t);
I have 5 state variables, q= [ QDot, phi, phiDot, r, rDot]'; (removed Q because nothing depends on it, QDot is current.)
Now, to calculate some forces, I would like to also save the calculated values of rDotDot, which ode45 calculates for each integration step, however ode45 doesn't give this back. I've searched around a bit, but the only two solutions I've found are to
a) turn this into a 3rd order problem and add phiDotDot and rDotDot to the state vector. I would like to avoid this as much as possible, as it's already non-linear and this really makes matters a lot worse and blows up computation time.
b) augment the state to directly calculate the function, as described here. However, in the example he says to make add a line of zeros in the mass matrix. It makes sense, since otherwise it will integrate the derivative and not just evaluate it at the one point, but on the other hand it makes the mass matrix singular. Doesn't seem to work for me...
This seems like such a basic thing (to want the derivative values of the state vector), is there something quite obvious that I'm not thinking of? (or something not so obvious would be ok too....)
Oh, and global variables are not so great because ode45 calls the f() function several time while refining it's step, so the sizes of the global variable and the returned state vector q don't match at all.
In case someone needs it, here's the code:
%(Initialization of parameters are above this line)
options = odeset('Mass',#massMatrix);
[T,q] = ode45(#f, tspan,q0,options);
function dqdt = f(t,q,p)
% q = [qDot phi phiDot r rDot]';
dqdt = zeros(size(q));
dqdt(1) = -R/L*q(1) - kb/L*q(3) +vs/L;
dqdt(2) = q(3);
dqdt(3) = kt*q(1) + mp*sin(q(2))*lp*g;
dqdt(4) = q(5);
dqdt(5) = mp*lp*cos(q(2))*q(3)^2 - ks*q(4) - (mb+mp)*g;
end
function M = massMatrix(~,q)
M = [
1 0 0 0 0;
0 1 0 0 0;
0 0 mp*lp^2 0 -mp*lp*sin(q(2));
0 0 0 1 0;
0 0 mp*lp*sin(q(2)) 0 (mb+mp)
];
end
The easiest solution is to just re-run your function on each of the values returned by ode45.
The hard solution is to try to log your DotDots to some other place (a pre-allocated matrix or even an external file). The problem is that you might end up with unwanted data points if ode45 secretly does evaluations in weird places.
Since you are using nested functions, you can use their scoping rules to mimic the behavior of global variables.
It's easiest to (ab)use an output function for this purpose:
function solveODE
% ....
%(Initialization of parameters are above this line)
% initialize "global" variable
rDotDot = [];
% Specify output function
options = odeset(...
'Mass', #massMatrix,...
'OutputFcn', #outputFcn);
% solve ODE
[T,q] = ode45(#f, tspan,q0,options);
% show the rDotDots
rDotDot
% derivative
function dqdt = f(~,q)
% q = [qDot phi phiDot r rDot]';
dqdt = [...
-R/L*q(1) - kb/L*q(3) + vs/L
q(3)
kt*q(1) + mp*sin(q(2))*lp*g
q(5)
mp*lp*cos(q(2))*q(3)^2 - ks*q(4) - (mb+mp)*g
];
end % q-dot function
% mass matrix
function M = massMatrix(~,q)
M = [
1 0 0 0 0;
0 1 0 0 0;
0 0 mp*lp^2 0 -mp*lp*sin(q(2));
0 0 0 1 0;
0 0 mp*lp*sin(q(2)) 0 (mb+mp)
];
end % mass matrix function
% the output function collects values for rDotDot at the initial step
% and each sucessful step
function status = outputFcn(t,q,flag)
status = 0;
% at initialization, and after each succesful step
if isempty(flag) || strcmp(flag, 'init')
deriv = f(t,q);
rDotDot(end+1) = deriv(end);
end
end % output function
end
The output function only computes the derivatives at the initial and all successful steps, so it's basically doing the same as what Adrian Ratnapala suggested; re-run the derivative at each of the outputs of ode45; I think that would even be more elegant (+1 for Adrian).
The output function approach has the advantage that you can plot the rDotDot values while the integration is being run (don't forget a drawnow!), which can be very useful for long-running integrations.