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
Related
So I am currently working with different datasets. Some are monthly, some daily, but I want quarterly. This is why I wrote the following function:
function y = average2(data, frequency)
% Monthly/Daily data to quarterly data by taking average
% INPUT data Nx2 monthly/daily data
% OUTPUT y Mx2 quarterly data
% USAGE average2(data)
if frequency == 'monthly';
K = 1:3:(length(data)-3);
quarterly = (data(K, 2)+data(K+1, 2)+data(K+2, 2))/3;
timevector = data(K, 1);
y = [timevector quarterly];
elseif frequency == 'daily';
y = data*data; %just as an example, not correct calculation
else frequency ~= 'daily' || 'monthly';
error('Requested frequency not available');
end
(the calculation of daily is not the problem). So my Problem is the following: If I use the monthly option, everything works fine. But everytime I use something different than 'monthly' as frequency in my function, I get the error message:
Matrix dimensions must agree.
Error in average2 (line 8)
if frequency == 'monthly';
Therefore activating the elseif clause and processing the input I get in frequency doesn't work. Does anyone know where I have a mistake? Thanks in advance
To compare strings, use the strcmp (case sensitive) or the strcmpi (case insensitive) functions.
if(strcmp(frequency,'monthly'))
K = 1:3:(length(data)-3);
quarterly = (data(K, 2)+data(K+1, 2)+data(K+2, 2))/3;
timevector = data(K, 1);
y = [timevector quarterly];
elseif(strcmp(frequency,'monthly'))
y = data*data; %just as an example, not correct calculation
else % frequency ~= 'daily' || 'monthly' % don't have to do this comparison and is not correctly coded
error('Requested frequency not available');
end
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
I have a small piecewise function that profiling reveals is taking 60% of the runtime of the program. It is called very often because it goes within some integrals that I perform quite a lot in my code.
According to profiling, it is called 213560 times, taking 47.786 s in total, corresponding to ~220 microseconds per call.
I want to pass it an array, and it should return an array, operating element wise.
I know that using loops in Matlab is very slow and should be avoided, but I'm not sure how to vectorise this sort of function.
function bottleradius = aux_bottle_radius(z_array)
%AUXBOTTLERADIUS Radius of aux bottle
% This returns the radius of the aux bottle as a function of z. It works for all
% heights of aux bottle, just remember to integrate over the right height
% range
bottleradius = zeros(size(z_array));
for i = 1 : max(size(z_array))
if z_array(i)<-30e-3
%door cavity
bottleradius(i) = 34e-3;
elseif z_array(i)>=-30e-3 && z_array(i)<-20e-3
%radiussing door cavity
bottleradius(i) = 34e-3 + 10e-3 - sqrt((10e-3).^2 - (z_array(i)+30e-3).^2);
elseif z_array(i)>=-20e-3 && z_array(i)<-10e-3
%aluminium plate
bottleradius(i) = 46e-3;
elseif z_array(i)>=-10e-3 && z_array(i)<0e-3
%radiussing aluminium plate to main bottle
bottleradius(i) = 46e-3 + 10e-3 - sqrt((10e-3).^2 - (z_array(i)+10e-3).^2);
elseif z_array(i)>=0e-3
%top of Al plate, bottom of main bottle
bottleradius(i) = 185e-3;
else
bottleradius(i) = 0;
end
end
end
You can do that completely vectorized with logical operators. You can essentially replace that code with:
function bottleradius = aux_bottle_radius(z_array)
%// Declare initial output array of all zeroes
bottleradius = zeros(size(z_array));
%// Condition #1 - Check for all values < -30e-3 and set accordingly
bottleradius(z_array < -30e-3) = 34e-3;
%// Condition #2 - Check for all values >= -30e-3 and < -20e-3 and set accordingly
ind = z_array >= -30e-3 & z_array < -20e-3;
bottleradius(ind) = 34e-3 + 10e-3 - sqrt((10e-3).^2 - (z_array(ind)+30e-3).^2);
%// Condition #3 - Check for all values >= -20e-3 and < -10e-3 and set accordingly
bottleradius(z_array >=-20e-3 & z_array < -10e-3) = 46e-3;
%// Condition #4 - Check for all values >= -10e-3 and < 0 and set accordingly
ind = z_array >=-10e-3 & z_array < 0;
bottleradius(ind) = 46e-3 + 10e-3 - sqrt((10e-3).^2 - (z_array(ind)+10e-3).^2);
%// Condition #5 - Check for all values >= 0 and set accordingly
bottleradius(z_array >= 0) = 185e-3;
end
Minor comments
0e-3 doesn't make any sense precision wise. This is essentially the same as 0 and I've changed that in your code.
Note that for conditions #2 and #4, I precompute a logical array that indicates where we would need to access the corresponding values in z_array to make things easier and set those same locations in bottleradius to be the desired computed outputs. I don't do this for the other conditions because you're just setting them to a single constant.
Thankfully, you use element-wise operators for conditions #2 and #4 so there wasn't a need to change the expressions for those conditions.
I am working on a scilab program to average a 3d matrix in cubes.This is mostly done, but I want to set the size to a given sum,(the voxels all add up to a set amount in each cube)and I keep breaking the program every time I try to add this feature.
function totSAR = comptS(Material, SAR, a, b, c, a1, b1, c1, grams)
si=size(SAR);
radius=0;
OK=0;
totwei=0;
totSAR=0;
totpx=0;
while (totwei<=grams*1e-3 && OK==0)
totwei2=totwei;
totSAR2=totSAR;
totpx2=totpx;
totwei=0;
totpx=0;
totSAR1=0;
totSAR=0;
radius=radius+1;
for o=-radius:radius
rado=floor(sqrt(radius^2-o^2));
for m=-rado:rado
radm=floor(sqrt(rado^2-m^2));
for n=-radm:radm
if (a+m >= 1 && a+m <= si(1) && b+n >=1 && b+n <=si(2) && c+o >= 1 && c+o <si(3))
if totwei<=10e-3
totwei=totwei+a1*b1*c1*Material(a+m, b+n, c+o);
if SAR(a+m, b+n, c+o)>0
totpx=totpx+1;
totSAR=totSAR+SAR(a+m, b+n, c+o);
end
end
end
end
end
end
if totSAR==totSAR1
OK=1;
end
end
coefw = (grams*1e-3 - totwei2)/(totwei-totwei2);
totpxs = coefw*(totpx-totpx2);
totSARs = coefw*(totSAR-totSAR2);
totpx;
if totpx>0
totSAR=(totSAR2+totSARs)/(totpx2+totpxs);
end
end
Sorry that I am a bit of a newbie, and thanks for the help!
Your only problem is that you aren't updating the totwei variable when you create a voxel.You will need to subtract the value of the voxel from the remaining desired weight, and add it to the total weight.
totwei = totwei + voxel
valleft = valleft - voxel
I'm trying to find an as efficient as possible way to store and call my matlab shape-functions. I have an interval x=linspace(0,20) and a position-vector
count = 10;
for i=1:count
pos(i)=rand()*length(x);
end
And now, I want to put on every position pos(j) shape functions like Gauss-kernels with compact support or hat-functions or something similar (it should be possible to change the prototype function easily). The support of the function is controlled by a so-called smoothing length h.
So I constructed a function in a .m-file like (e.g. a cubic spline)
function y = W_shape(x,pos,h)
l=length(x);
y=zeros(1,l);
if (h>0)
for i=1:l
if (-h <= x(i)-pos && x(i)-pos < -h/2)
y(i) = (x(i)-pos+h)^2;
elseif (-h/2 <= x(i)-pos && x(i)-pos <= h/2)
y(i) = -(x(i)-pos)^2 + h^2/2;
elseif (h/2 < x(i)-pos && x(i)-pos <=h)
y(i) = (x(i)-pos-h)^2;
end
end
else
error('h must be positive')
end
And then construct my functions on the interval x like
w = zeros(count,length(x));
for j=1:count
w(j,:)=W_shape(x,pos(j),h);
end
So far so good, but when I make x=linspace(0,20,10000) and count=1000, it takes my computer (Intel Core-i7) several minutes to calculate the whole stuff.
Since it should be some kind of PDE-Solver, this procedure has to be done in every time-step (under particular circumstances).
I think my problem is, that I use x as an argument for my function-call and store every function instead of store just one and shift it, but my matlab-knowledge is not that good, so any advices? Fyi: I need the integral of the areas, where two or more function-supports intersect...and when I'm done with this in 1D, I wanna do it for 2D-functions, so it has to be efficient anyways
One initial vectorization would be to remove the for loop in the W_shape function:
for i=1:l
if (-h <= x(i)-pos && x(i)-pos < -h/2)
y(i) = (x(i)-pos+h)^2;
elseif (-h/2 <= x(i)-pos && x(i)-pos <= h/2)
y(i) = -(x(i)-pos)^2 + h^2/2;
elseif (h/2 < x(i)-pos && x(i)-pos <=h)
y(i) = (x(i)-pos-h)^2;
end
end
Could become
xmpos=x-pos; % compute once and store instead of computing numerous times
inds1=(-h <= xmpos) & (xmpos < -h/2);
y(inds1) = (xmpos(inds1)+h).^2;
inds2=(-h/2 < xmpos) & (xmpos <= h/2);
y(inds2) = -(xmpos(inds2).^2 + h^2/2;
inds3=(h/2 < xmpos) & (xmpos <=h);
y(inds3) = (xmpos(inds3)-h).^2;
There is probably better optimisations than this.
EDIT:
I forgot to mention, you should use the profiler to find out what is actually slow!
profile on
run_code
profile viewer