MATLAB: Cannot properly evaluate function using input vector - matlab

I am trying to pass a vector into a function, and evaluate the vector over a piecewise function. When I run the code below, I am only returned a single number rather than a vector. Any ideas?
Thanks!
t[-5:1:50]
velocity(t)
function [v] = velocity( t )
%This function takes vector 't' and evaluates a velocity over a given
%piecewise function
if t>=0 & t<=8
v=10*t^2-5*t;
elseif t>=8 & t<=16
v=624-5*t;
elseif t>=16 & t<=26
v= 36*t+12*(t-16)^2;
elseif t>26
v=2136*exp(-0.1*(t-26));
else t<0
end

When you elevate a vector to the square, you are performing a scalar product with itself.
Replace t^2 with t.^2 for element-wise operators.
Do the same for (t-16).^2.
All the other operators should fall automatically into the element wise case but you can add points before them to be sure.
And, furthermore, the conditions as you have wrote them apply to a t as a scalar value. You can get the researched effect by doing the following:
Instead of
if cond1:
v = something
elif cond2:
v = something_else
Do
indices1 = (cond1) % where cond1 is t < 10 for example
indices2 = (cond2) % and cond2 is t >= 10
v[indices1] = something
v[indices2] = something_else
I hope you get the gist.

Related

How do I splice two vectors in MATLAB?

I need to splice two vectors based on a condition that also takes a vector as an argument. Example:
vec_cond = -5:5; % The exact values are calculated differently
vec1 = 0:10;
vec2 = 5:15;
I need a resulting vector to be comprised from values out of both vectors based on a condition from the third vector. Let's assume this is the condition: vec_cond >= 0
Then if this is true, I want vec_result to have values from vec1 on appropriate indexes, and if not, take values from vec2 on appropriate indexes:
vec_result = vec1 if (vec_cond >=0) else vec2
This is portion of my MATLAB script (original comments were Czech) where I would need to use that:
%% Draw output current and voltage characteristics
R = 100:5:2*10^3; % Load rezistor [ohm]
U_2 = R .* (I * 10^(-3)); % Load voltage [V]
U_1stab = U_LM + U_x + U_2; % Min. required input voltage
% for stabilization [V]
U_delta = U_1 - U_1stab; % Difference between actual and
% min. req. input voltage [V]
U_2norm = U_1 - U_LM - U_x % Calculating output load
% voltage based on params [V]
I_z = U_2norm ./ R .* 10^3; % Load current param based[mA]
I_r1 = I * I_z.^0; % Stabilizator current [mA]
So the condition would be U_delta >= 0.
I tried to use a ternary operator, which I found here:
I_graph = (U_delta >= 0) : (#() I) : (#() I_z); % Current splice [mA]
U_graph = (U_delta >= 0) : (#() U_2) : (#() U_2norm); % Voltage splice [V]
That means that for I_graph, if the condition is met, take a constant value I and vectorize it, otherwise take values from I_z vector. For U_graph, if the condition is met, take values from U_2 vector, otherwise take constant value of U_2norm and vectorize it.
But it didn't work, this is what it tells me:
Operator ':' is not supported for operands of type 'function_handle'.
Error in vypocet1 (line 52)
I_graph = (U_delta >= 0) : (#() I) : (#() I_z); % Current splice [mA]
I guess that I might want to use for loop, but I'm not sure how it will help me and how can I actually construct the necessary vector using a for loop.
Given:
vec_cond = -5:5;
vec1 = 0:10;
vec2 = 5:15;
You can set:
out = vec2;
I = vec_cond >= 0;
out(I) = vec1(I);
This uses logical indexing, which is indexing with a logical array.
By the way, the ternary operator you found is an exercise to overload the : operator for a specific class to do something that it normally doesn’t do. Note how you use the colon when creating vec_cond. This is what the colon operator does normally.

Write a function that takes as input `n` and returns the matrix C, Cij= 0 if i/j<2 , Cij =ij^2 otherwise in MATLAB

Consider the nxn matrix C with elements
Cij = 0 if i/j < 2
Cij = ij^2 otherwise
with 1 <= i,j <= n
Write a Matlab function matSetup that takes as input n and returns the matrix C. Use your function to create C for n = 6. function [Cij]= matSetup(n)
I have written this but it seems not to be correct
function Cij=matSetup(n)
for n=1:n
% whatever you write here is done with i=1, then i=2, then i=3, etc.
Cij(3,j)=i+7;
if (i/j)<2
Cij=0
else
Cij=i*(j)^2
end
end
end
Unfortunately, you can't just write something math-like and have a computer understand it. Things like 1<=i<=n have to be written instead with something like an explicit loop. For Matlab, here's one way to write a loop:
for i=1:n
% whatever you write here is done with i=1, then i=2, then i=3, etc.
end
To assign a value to an element of an array in Matlab, do something like this:
Cij(3,j)=i+7;
To test for a condition in Matlab, do this:
if i+3>2*j
% What you write here is done if the condition is true
else
% What you write here is done if the condition is false
end
If you put all of those things together correctly, you should be able to write your desired function.
Like the other answer, you should first learn to use loops to write a naive program to achieve your goal. When you are comfortable enough, you can try vectorizing your program with functions like meshgrid. Below is an example:
n = 20;
eps = 1/(n+1);
[x, y] = meshgrid(1:n, 1:n);
r = y./x;
z = heaviside(r - 2 + eps) .* y .* x.^2;

Calling if else output to other script

I have written a function called "tension.m" in which I have used if else condition as shown below.
function [T,T_earlyvalues,T_latervalues] = tension(u,sigma,G,N,K)
%the values of sigma,G,N,K can be taken arbitrary.
sigma=2; G=3;N=8;K=1; v=1;
w=2.2;
if u<w
T =v*sqrt(sigma+G^2/(N-K));
T_earlyvalues=T;
else
T=(2*v)*sqrt(sigma+G^2/(N+K));
T_latervalues=T;
end
Now in another script "myvalues.m" I need to call T_earlyvalues and T_latervalues separately.
%have some coding before this part
sigma0=2400; lambda=1.3; v=2; sigma=2; G=3;N=8;K=1;
u=0:0.01:5;
T=tension(u,sigma,G,N,K);
T_earlyvalues=tension(u,sigma,G,N,K);
T_latervalues=tension(u,sigma,G,N,K);
deltaA=T_earlyvalues*sigma0*pi;
deltaB=T_latervalue*lambda*pi/2;
%have some coding after this part
How could I call the said values which are under if-else statement from tension.m function to myvalues.m script?
You have defined the tension function such that it returns three outputs.
If you call that function by requiring only one output, the function returns the first value, in your case, T
This implies that
T=tension(u,sigma,G,N,K);
shoud work since T is the first output parameter
T_earlyvalues=tension(u,sigma,G,N,K);
T_latervalues=tension(u,sigma,G,N,K);
are not working, since, actually tension returns the first value (T, whjikle you are expecting the second and the third respectively.)
You can cahnge the two above calls this way:
[~,T_earlyvalues,~]=tension(u,sigma,G,N,K);
[~,~,T_latervalues]=tension(u,sigma,G,N,K);
The ~ allows to avoid the function return the output paraemter.
You can find additional information here
Notice that in your function T_earlyvalue is not set in the else block, same for T_latervalue in the if block.
This will generate an error such as
Output argument T_earlyvalue (and maybe others) not assigned during call to tension
or
Output argument T_latervalues (and maybe others) not assigned during call to tension
You can initialize the output values to default values, at the beginning of the function, for example:
T=NaN
T_earlyvalue=NaN
T_latervalues=NaN
You can then use these special values (or any other you want to use) to trace, for example, if the if block has been executed or the else.
There seem to be a number of issues here, not the least of which is some confusion about how output argument lists work when defining or calling functions. I suggest starting with this documentation to better understand how to create and call functions. However, this issue is somewhat moot because the larger problem is how you are using your conditional statement...
You are trying to pass a vector u to your function tension, and from what I can tell you want to return a vector T, where the values of T for u < w are computed with a different formula than the values of T for u >= w. Your conditional statement will not accomplish this for you. Instead, you will want to use logical indexing to write your function like so:
function [T, index] = tension(u, sigma, G, N, K)
T = zeros(size(u)); % Initialize T to a vector of zeroes
w = 2.2;
index = (u < w); % A logical vector, with true where u < w, false where u >= w
T(index) = u(index)*v*sqrt(sigma+G^2/(N-K)); % Formula for u < w
T(~index) = 2*(u(~index)-v)*sqrt(sigma+G^2/(N+K)); % Formula for u >= w
end
Now you can call this function, capturing the second output argument to use for identifying "early" versus "late" values:
sigma0 = 2400; lambda = 1.3; v = 2; sigma = 2; G = 3; N = 8; K = 1;
u = 0:0.01:5;
[T, earlyIndex] = tension(u, sigma, G, N, K); % Call function
T_earlyvalues = T(earlyIndex); % Use logical index to get early T values
T_latervalues = T(~earlyIndex); % Use negated logical index to get later T values
And you can then use the subvectors T_earlyvalues and T_latervalues however you like.

How to vectorize a piecewise periodic function in MATLAB?

I've noticed that matlab builtin functions can handle either scalar or vector parameters. Example:
sin(pi/2)
ans =
1
sin([0:pi/5:pi])
ans =
0 0.5878 0.9511 0.9511 0.5878 0.0000
If I write my own function, for example, a piecewise periodic function:
function v = foo(t)
t = mod( t, 2 ) ;
if ( t < 0.1 )
v = 0 ;
elseif ( t < 0.2 )
v = 10 * t - 1 ;
else
v = 1 ;
end
I can call this on individual values:
[foo(0.1) foo(0.15) foo(0.2)]
ans =
0 0.5000 1.0000
however, if the input for the function is a vector, it is not auto-vectorized like the builtin function:
foo([0.1:0.05:0.2])
ans =
1
Is there a syntax that can be used in the definition of the function that indicates that if a vector is provided, a vector should be produced? Or do builtin functions like sin, cos, ... check for the types of their input, and if the input is a vector produce the same result?
You need to change your syntax slightly to be able to handle data of any size. I typically use logical filters to vectorise if-statements, as you're trying to do:
function v = foo(t)
v = zeros(size(t));
t = mod( t, 2 ) ;
filt1 = t<0.1;
filt2 = ~filt1 & t<0.2;
filt3 = ~filt1 & ~filt2;
v(filt1) = 0;
v(filt2) = 10*t(filt2)-1;
v(filt3) = 1;
In this code, we've got three logical filters. The first picks out all elements such that t<0.1. The second picks out all of the elements such that t<0.2 that weren't in the first filter. The final filter gets everything else.
We then use this to set the vector v. We set every element of v that matches the first filter to 0. We set everything in v which matches the second filter to 10*t-1. We set every element of v which matches the third filter to 1.
For a more comprehensive coverage of vectorisation, check the MATLAB help page on it.
A simple approach that minimizes the number of operations is:
function v = foo(t)
t = mod(t, 2);
v = ones(size(t)) .* (t > 0.1);
v(t < 0.2) = 10*t(t < 0.2) - 1;
end
If the vectors are large, it might be faster to do ind = t < 0.2, and use that in the last line. That way you only search through the array once. Also, the multiplication might be substituted by an extra line with logical indices.
I repeatedly hit the same problem, thus I was looking for a more generic solution and came up with this:
%your function definition
c={#(t)(mod(t,2))<0.1,0,...
#(t)(mod(t,2))<0.2,#(t)(10 * t - 1),...
true,1};
%call pw which returns the function
foo=pw(c{:});
%example evaluation
foo([0.1:0.05:0.2])
Now the code for pw
function f=pw(varargin)
for ip=1:numel(varargin)
switch class(varargin{ip})
case {'double','logical'}
varargin{ip}=#(x)(repmat(varargin{ip},size(x)));
case 'function_handle'
%do nothing
otherwise
error('wrong input class')
end
end
c=struct('cnd',varargin(1:2:end),'fcn',varargin(2:2:end));
f=#(x)pweval(x,c);
end
function y=pweval(x,p)
todo=true(size(x));
y=x.*0;
for segment=1:numel(p)
mask=todo;
mask(mask)=logical(p(segment).cnd(x(mask)));
y(mask)=p(segment).fcn(x(mask));
todo(mask)=false;
end
assert(~any(todo));
end

Is there a Matlab conditional IF operator that can be placed INLINE like VBA's IIF

In VBA I can do the following:
A = B + IIF(C>0, C, 0)
so that if C>0 I get A=B+C and C<=0 I get A=B
Is there an operator or function that will let me do these conditionals inline in MATLAB code?
How about simply using the fact that MATLAB automatically converts variable types when required by the operation? E.g., logical to double.
If your variables are scalar double, your code, I believe, can be replaced by
a = b + (c > 0) * c;
In this case, the operator (c > 0) values 1 (logical type) whenever c > 0 and values to 0 otherwise.
There is no ternary operator in Matlab. You can, of course, write a function that would do it. For example, the following function works as iif with n-d input for the condition, and with numbers and cells for the outcomes a and b:
function out = iif(cond,a,b)
%IIF implements a ternary operator
% pre-assign out
out = repmat(b,size(cond));
out(cond) = a;
For a more advanced solution, there's a way to create an inline function that can even do elseif, as outlined in this blog post about anonymous function shenanigans:
iif = #(varargin) varargin{2*find([varargin{1:2:end}], 1, 'first')}();
You use this function as
iif(condition_1,value_1,...,true,value_final)
where you replace the dots with any number of additional condition/value pairs.
The way this works is that it picks among the values the first one whose condition is true. 2*find(),1,'first') provides the index into the value arguments.
There is no built-in solution for this, but you can write an IIF yourself.
function result=iif(cond, t, f)
%IIF - Conditional function that returns T or F, depending of condition COND
%
% Detailed
% Conditional matrix or scalar double function that returns a matrix
% of same size than COND, with T or F depending of COND boolean evaluation
% if T or/and F has the same dimensions than COND, it uses the corresponding
% element in the assignment
% if COND is scalar, returns T or F in according with COND evaluation,
% even if T or F is matrices like char array.
%
% Syntax
% Result = iif(COND, T, F)
% COND - Matrix or scalar condition
% T - expression if COND is true
% F - expression if COND is false
% Result - Matrix or scalar of same dimensions than COND, containing
% T if COND element is true or F if COND element is false.
%
if isscalar(cond)
if cond
result = t;
else
result = f;
end
else
result = (cond).*t + (~cond).*f;
end
end
Others have said already that there is no ternary ?: operator in Matlab. As a solution I suggest this function, which takes three functions instead of values. Therefore the amount of unnecessary calculations is minimized and you can check conditions before starting calculations, e.g. if a value is really numeric, or finite, or nonzero:
function [ out ] = iif( condition, thenF, elseF, in, out)
%iif Implements the ternary ?: operator
% out = iif (#condition, #thenF, #elseF, in[, out])
%
% The result is equivalent to:
% condition(x) ? thenF(x) : elseF(x)
%
% The optional argument out serves as a template, if the output type is
% different from the input type, e.g. for mapping arrays to cells and
% vice versa.
%
% This code is in the public domain.
mask = condition(in);
if nargin <= 4
out = in;
end
if sum(mask)
out(mask) = thenF(in(mask));
end
if sum(~mask)
out(~mask) = elseF(in(~mask));
end
end
Use it like this:
f = #(y)(iif(#(x)(x > 3), #(x)(x.^2), #(x)(x/2), y))
f(linspace(0,6,10))
Inspired by Jonas' answer the function below also works for mixed type input and chars, for which his function isn't stable.
function out = iif(cond, a, b)
%IIF implements a ternary operator
% Use cell output for either char or mixed type input
if ischar(a) || ischar(b) || ~strcmp(class(a), class(b))
out = cell(size(cond));
[out{cond}] = deal(a);
[out{~cond}] = deal(b);
else
% Use array output and logical indexing
out = repmat(b, size(cond));
out(cond) = a;
end
end
Edit: weeded out the extra conditional options in the cell branch, which were apparently remnants of a previous mistake, this is probably faster, and definitely cleaner.
What you refer to is a ternary operator, in C-like notation, ?:. The expression
tern = bool ? T : F
returns T if bool evaluates to true, F otherwise. MATLAB has no ternary operator, however it can be implemented in different ways as an inline expression.
Arrays
% cell array version (any type)
tern = {F,T}{bool+1} % only Octave
tern = subsref({F,T}, struct('type', '{}', 'subs', {{bool+1}}))
% vector array version (numeric types only)
tern = [F,T](bool+1) % only Octave
tern = subsref([F,T], struct('type', '()', 'subs', {{bool+1}}))
Note that T and F have been swapped, and that different brackets are used. The vector array version is a specialization for numeric types. MATLAB does not allow direct indexation of fresh arrays, hence the use of subsref.
Pros: Works for any type and any value. Can be used inline.
Cons: Before returning the result to tern, both T and F
are evaluated.
Logical operators and eval
( bool && eval('tern=T') ) || eval('tern=F')
Note that the logical operators are short-circuited.
Pros: Works for any type and any value. Only one, T or F, is evaluated.
Cons: Works only in Octave. Can't be used inline, but through the variable tern. eval is not efficient but required.
Basic arithmetic
tern = bool*T + !bool*F
Pros: Can be used inline.
Cons: Works only for numeric types, and might fail when T or F are NaN or Inf. Both, T and F, are evaluated.
Maximum
tern = max(T,F) % bool = T>F
Note that this solution fits the particular requirements of the initial question with max(C,0).
Pros: Can be used inline.
Cons: Works only for numeric types, and might fail when T or F are NaN. Both, T and F, are evaluated. Use is strongly limited.
There is now a tern function on the MathWorks file exchange:
http://www.mathworks.com/matlabcentral/fileexchange/39735-functional-programming-constructs/content/tern.m
The code is reproduced here:
function varargout = tern(condition, true_action, false_action)
% out = tern(condition, true_action, false_action)
%
% Ternary operator. If the first input is true, it returns the second
% input. Otherwise, it returns the third input. This is useful for writing
% compact functions and especially anonymous functions. Note that, like
% many other languages, if the condition is true, not only is the false
% condition not returned, it isn't even executed. Likewise, if the
% condition is false, the true action is never executed. The second and
% third arguments can therefore be function handles or values.
%
% Example:
%
% >> tern(rand < 0.5, #() fprintf('hi\n'), pi)
% ans =
% 3.1416
% >> tern(rand < 0.5, #() fprintf('hi\n'), pi)
% hi
%
% It works with multiple outputs as well.
%
% >> [min_or_max, index] = tern(rand < 0.5, ...
% #() min([4 3 5]), ...
% #() max([4 3 5]))
% min_or_max =
% 5
% index =
% 3
%
% Tucker McClure
% Copyright 2013 The MathWorks, Inc.
if condition() % Works for either a value or function handle.
[varargout{1:nargout}] = true_action();
else
[varargout{1:nargout}] = false_action();
end
end
This is more of an addenum to Alex's answer.
Alex's method doesn't work when you want to return inf
In these cases you often end up getting a 0*inf figure, which MATLAB will evaluate to NaN. Problematic... We can avoid this multiplication using a lookup instead.
As an example, a useful barrier function in convex optimization is something that behaves like log everywhere positive, and -inf elsewhere. Here is how you might create such a function using a lookup:
INF_CONDITION = [0, inf];
fn_logbr = #(x) (x>0)*log(x) - INF_CONDITION( 1+(x<=0) )
Inline conditionals are a hack, and you lose lazy evaluation. You have to be careful. However, having semantic code is really nice, and its easier to share your code when you can't guarantee everyone's environments are the same.
If you're looking for an option that doesn't force you to build a function and can take care fairly simple expressions, you can take advantage of anonymous functions. The anonymous function returns a logical, which can be a numeral 1 or 0. Because of this, they can be used to multiply with other numbers to determine if they still hold a value after the expression, or lose their value.
For your case (including if A, B, and C are vectors or not): A = B .+ (#() C>0)()
Using:
eval('input;', 'input = 1;');
is very helpful where 'input' might not exist in the first place.