matlab cant divide using / - matlab

I have some simple function that takes in a value
This value is the checked off a number of if or elseif statements to calculate another value.
The problem is it seems to find an error when trying to run which says
Error using /
Matrix dimensions must agree.
Error in abc (line 9)
a = 5000 / g;
the code is as follows
function abc(g)
if (g == 100)
a = 1;
elseif (g <= 99 & g >= 50)
a = 200 -2*g;
elseif (g <= 50 & g >= 1)
a = 5000 / g;
else
warning('Invalid value passed, a defaults to 1');
a =1;
end
end
So, im passing in abc 100 and i expect a to be 1 but instead it runs through each if / elseif and throws an error on a = 5000/g
I should also mention that i initially tried using && in the elseifs but this also gave an error which said
Operands to the || and && operators must be convertible to logical scalar values.
Error in abc (line 6)
elseif (g <= 99 && g >= 50)
Anybody any idea whats going on here ?
Thanks

You are probably passing a matrix to your function, e.g. when you call
abc(yourdata)
yourdata is actually not one number, but a matrix. If you called directly
abc(100)
you should not see your problem (or do you?).
In other words, your main problem is not inside your function, but when you call it!
Given your description, it seems that you set yourdata(1) to the value 100 that you want to test, but some other element of the matrix has a different value, which is why the if construct branches into the else case. There, you need ./ instead of / if you want to do element-wise division instead of matrix division.
But really you probably just need to make sure that yourdata is scalar when you call your function.

Related

Finding the machine value of epsilon in Matlab

The following Matlab code is meant to find the machine value of epsilon.
e = 1;
while (1+e>1)
if e+1 <= 1
e = 2*e;
else e = e/2;
end
end
e = 2*e
While the value of epsilon is correctly approximated, modifying the code leads to unexpected results. For example, if the while loop condition is modified, as shown below, to e>0 the program either crashes or outputs 0 rather than an approximation for epsilon even though adding a constant doesn't change the inequality. Could someone explain why this is happening?
e = 1;
while (e>0)
if e+1 <= 1
e = 2*e;
else e = e/2;
end
end
e=2*e
The concept of “epsilon” is that there is a minimal value that must be added to 1 to obtain a different value. If e is smaller than epsilon, then 1+e==1. Floating-point numbers cannot represent values in between 1 and 1 + epsilon.
So replacing the condition in the while loop, 1+e>1, with e>0, though mathematically equivalent, breaks the concept we are trying to define: epsilon as the smallest value to add to 1 to get a value larger from 1. Note that you can represent values very close to 0, such as 10-300, but you cannot represent values that close to 1. Epsilon is about 10-16. This means that the two inequalities are not the same when working with floating-point numbers.
Note that the statement if e+1 <= 1 is only reached when 1+e>1, and so will always be false. You can simplify the code by removing this if statement and keeping only the code in the else clause:
e = 1;
while 1+e > 1
e = e/2;
end
e = 2*e

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.

Basic structure of a for loop

I am trying to write a MATLAB function that accepts non-integer, n, and then returns the factorial of it, n!. I am supposed to use a for loop. I tried with
"for n >= 0"
but this did not work. Is there a way how I can fix this?
I wrote this code over here but this doesn't give me the correct answer..
function fact = fac(n);
for fact = n
if n >=0
factorial(n)
disp(n)
elseif n < 0
disp('Cannot take negative integers')
break
end
end
Any kind of help will be highly appreciated.
You need to read the docs and I would highly recommend doing a basic tutorial. The docs state
for index = values
statements
end
So your first idea of for n >= 0 is completely wrong because a for doesn't allow for the >. That would be the way you would write a while loop.
Your next idea of for fact = n does fit the pattern of for index = values, however, your values is a single number, n, and so this loop will only have one single iteration which is obviously not what you want.
If you wanted to loop from 1 to n you need to create a vector, (i.e. the values from the docs) that contains all the numbers from 1 to n. In MATLAB you can do this easily like this: values = 1:n. Now you can call for fact = values and you will iterate all the way from 1 to n. However, it is very strange practice to use this intermediary variable values, I was just using it to illustrate what the docs are talking about. The correct standard syntax is
for fact = 1:n
Now, for a factorial (although technically you'll get the same thing), it is clearer to actually loop from n down to 1. So we can do that by declaring a step size of -1:
for fact = n:-1:1
So now we can find the factorial like so:
function output = fac(n)
output = n;
for iter = n-1:-1:2 %// note there is really no need to go to 1 since multiplying by 1 doesn't change the value. Also start at n-1 since we initialized output to be n already
output = output*iter;
end
end
Calling the builtin factorial function inside your own function really defeats the purpose of this exercise. Lastly I see that you have added a little error check to make sure you don't get negative numbers, that is good however the check should not be inside the loop!
function output = fac(n)
if n < 0
error('Input n must be greater than zero'); %// I use error rather than disp here as it gives clearer feedback to the user
else if n == 0
output = 1; %// by definition
else
output = n;
for iter = n-1:-1:2
output = output*iter;
end
end
end
I don't get the point, what you are trying to do with "for". What I think, what you want to do is:
function fact = fac(n);
if n >= 0
n = floor(n);
fact = factorial(n);
disp(fact)
elseif n < 0
disp('Cannot take negative integers')
return
end
end
Depending on your preferences you can replace floor(round towards minus infinity) by round(round towards nearest integer) or ceil(round towards plus infinity). Any round operation is necessary to ensure n is an integer.

Matlab simple matrix manip

I'm new to Matlab and I want to achieve a very simple operation : I have a 792 x 1046 uint8 matrix called mg and want to convert its cells values (from 0 to 255) to values between 1 and 4 (1,2,3,4) in a new matrix called mgc accordingly to simple conditions.
Strangely, the new matrix is filled with only 1s and 2s but not any 3s or 4s...
Here is my code :
[x,y]=size(mg);
mgc = zeros(x,y);
for i=1:x
for j=1:y
if (mg(i,j)<=100)
mgc(i,j)=1;
elseif (100<mg(i,j)<=110)
mgc(i,j)=2;
elseif (110<mg(i,j)<=120)
mgc(i,j)=3;
else
mgc(i,j)=4;
end
end
end
If anyone could help me solve this stupid issue, it would be great !
THX
You shouldn't use expressions such as 100<mg(i,j)<=110 in MATLAB. Instead, use something like 100<mg(i,j) && mg(i,j)<=110.
At the moment, MATLAB is evaluating the expression 100<mg(i,j)<=110 as (100<mg(i,j))<=110. (100<mg(i,j)) is going to be either one or zero (true or false), and therefore will always be <=110. So it never gets past the second else, and your array is all either 1 or 2.
Edit: although this answer explains the specific issue you're having, you should probably instead be using logical indexing, which would be much more efficient than a double for loop (and more idiomatic in MATLAB). See the answers from #excaza or #Benoit_11 for examples of that).
As stated in the comments you need to use logical operators in your elseif statements. Just so you know, you can vectorize this whole for loop with those same logical operators as follows:
Let's define mgc2 as you did for mgc:
mgc2 = zeros(x,y);
Then you can fill mgc2 like this:
mgc2(mg<=100) =1;
mgc2(mg>100 & mg<=110) =2;
mgc2(mg>110 & mg <=120) =3;
mgc2(mg>120) =4;
You need to use and operators:
% Dummy data
mg = [10 115; 125 140];
[x,y]=size(mg);
mgc = zeros(x,y);
for i=1:x
for j=1:y
if (mg(i,j)<=100)
mgc(i,j)=1;
elseif (100 < mg(i,j) && mg(i,j) <= 110)
mgc(i,j)=2;
elseif (110 < mg(i,j) && mg(i,j) <= 120)
mgc(i,j)=3;
else
mgc(i,j)=4;
end
end
end
Returns:
mgc =
1 3
4 4
You also don't need to use a loop here, and can leverage MATLAB's logical indexing instead:
% Dummy data
mg = [10 115; 125 140];
mgc = zeros(size(mg));
mgc(mg <= 100) = 1;
mgc((mg > 100 & mg <= 110)) = 2;
mgc((mg > 110 & mg <= 120)) = 3;
mgc(mg > 120) = 4;
Which returns the same matrix.
This is because any value greater than 100 will return true for the first elseif statement.
100 < my(i,j) returns 1.
When you want to do a double condition, you must use the & operator otherwise you may have false statements
>> x = 4
>> res = 2<x<=3
res =
1
%%Using the `&` operator instead
>> res = 2<x && x<=3
res =
0

Problems with Plotting Matlab Function

I am Beginner in Matlab, i would like to plot system concentration vs time plot at a certain time interval following is the code that i have written
%Input function of 9 samples with activity and time calibrated with Well
%counter value approx : 1.856 from all 9 input values of 3 patients
function c_o = Sample_function(td,t_max,A,B)
t =(0 : 100 :5000); % time of the sample post injection in mins
c =(0 : 2275.3 :113765);
A_max= max(c); %Max value of Concentration (Peak of the curve)
if (t >=0 && t <= td)
c_o(t)=0;
else if(td <=t && t<=t_max)
c_o(t)= A_max*(t-td);
else if(t >= t_max)
c_o(t)=(A(1)*exp(-B(1)*(t-t_max)))+(A(2)*exp(-B(2)*(t- t_max)))+...
(A(3)*exp(-B(3)*(t-t_max)));
end
fprintf('plotting Data ...\n');
hold on;
figure;
plot(c_o);
xlabel('Activity of the sample Ba/ml ');
ylabel('time of the sample in minutes');
title (' Input function: Activity sample VS time ');
pause;
end
I am getting following error
Operands to the || and && operators must be convertible to logical scalar values.
Error in Sample_function (line 18)
if (t >=0 && t <= td)
Kindly .Let me know if my logic is incorrect
Your t is not a single value to compare with 0 so it cannot evaluate to true or false.
You want to do this with logical indexing
c_o = zeros(size(t));
c_o(t>=0 & t<=td) = 0; % this line is actually redundant and unnecessary since we initialized the vector to zeros
c_o(t>td & t<=t_max) = A_max*(t(t>td & t<=t_max)-td);
c_o(t>t_max) = (A(1)*exp(-B(1)*(t(t>t_max)-t_max)))+(A(2)*exp(-B(2)*(t(t>t_max)- t_max)))...
+ (A(3)*exp(-B(3)*(t(t>t_max)-t_max)));
You could also make this a little prettier (and easier to read) by assigning the logical indexes to variables:
reg1 = (t>=0 & t<=td);
reg2 = (t>td & t<=t_max);
reg3 = (t>t_max);
Then, for instance, the second assignment becomes the much more readable:
c_o(reg2) = A_max*(t(reg2)-td);
t is written as a array of numbers. So, it can't be compared with a scalar value ex. 0.
Try it in a for loop
for i=1:length(t)
if (t(i) >=0 && t(i) <= td)
c_o(t(i))=0;
else if(td <=t(i) && t(i)<=t_max)
c_o(t(i)))= A_max*(t(i)-td);
else if(t(i) >= t_max)
c_o(t)=(A(1)*exp(-B(1)*(t(i)-t_max)))+(A(2)*exp(-B(2)*(t(i)- t_max)))...
+ (A(3)*exp(-B(3)*(t(i)-t_max)));
end
end