Storing Maximum values from each row

Hi I am trying to find the minimum peak force and so I am trying to find the maximum value in each row, store that and then later choose the minimum from the matrix of maximums. I would then also need the corresponding variable values which give this minimum force. As you can see in my code, I am trying to do this using (i,:) to look at a specific row and all the possible 'j' (column) values. However, I think that it is only storing the maximum value from the last iteration/row rather than from every iteration/row. For the problem we were instructed to store the maximum value if it is larger than the last, hence the if F(i,:)>F_max bit. Any help much appreciated! Thank you in advance. This is my code...
m=4000; %kg
g=9.81;
L=4; %m
r_min=1.2; %m
r_max=2.2; %m
r=linspace(1.2,2.2,37); %m
theta_min=-20; %degrees
theta_max=80; %degrees
theta=linspace(-20,80,37); %degrees
phi=linspace(0,180,37); %degrees
gamma=phi+20; %degrees
%-----------------------------------
F_max=0;
for i=1:37
c_2(i)=((r_max^2)-(r_min^2))./(cosd(gamma(i)+theta_min)-cosd(gamma(i)+theta_max));
c_1(i)=(r_max^2)+c_2(i).*cosd(gamma(i)+theta_max);
a(i)=real(0.5*(((c_1(i)+c_2(i)).^(1/2))+((c_1(i)-c_2(i)).^(1/2))));
b(i)=real(c_2(i)/(2*a(i)));
for j=1:37
r(i,j)=sqrt((a(i)^2)+(b(i)^2)-(2*a(i)*b(i)*cosd(gamma(i)+theta(j))));
F(i,j)=(r(i,j)*m*g*L*cosd(theta(j)))/(b(i)*a(i)*sind(gamma(i)+theta(j)));
end
k=1;
if F(i,:)>F_max & F(i,:)~=Inf & F(i,:)~=-Inf
F_new(k)=F(i,:);
k=1+k;
end
F_max=max(k);
F_min=min(k);
theta_opt=theta(:);
a_opt=a(:);
b_opt=b(:);
r_opt=r(:);
phi_opt=gamma(:)-20;
end
Currently when run this code is giving the error:
In an assignment A(I) = B, the number of elements in B and I must be the same.
Error in MatLab_Code_main_3 (line 56)
F_new(k)=F(i,:);

 Accepted Answer

Adam
Adam on 28 Oct 2014
Edited: Adam on 28 Oct 2014
At a glance...
F_max(k) = F_new;
looks to be what you need, but with simply
F_new = F(i,:);
inside your if statement. You will get warnings about an array growing inside a loop, but that doesn't really matter for now. Just get your code right first, then see if you can improve on warnings if they matter (unless it is causing unacceptable speed then it doesn't matter in this case).
Your F_min I am a bit confused about as you should presumably have an if statement for checking the min against current min too if you want that.
If that is meant to be getting the minimum of all your maximums then it should be right at the bottom outside the loop as:
F_min = min( F_max );
Your code appears to be taking the maximum of your k's which is just an index not your values of interest. Also unless I am missing something you only need to keep a single F_new value (though you could simply use F(i,:) itself in your F_max line.

9 Comments

Thank you very much. I could only keep a single F_new value, provided it is bigger than any other previous value. I will however also have to draw a graph showing how the peak value for F varies with theta so I thought it would be easier to store the values. The problem that I am now having is that, as I understand it, my F_new is saving a 1x37 matrix which suggests that it isn't moving through all the rows, and F_max is only showing the number "1" rather than a matrix which I would like to be showing effectively the max force in a box which tells me what the corresponding value of theta and phi is. k is also only showing "1" rather than "1 to 37". I have changed the code to this...
m=4000; %kg
g=9.81;
L=4; %m
r_min=1.2; %m
r_max=2.2; %m
r=linspace(1.2,2.2,37); %m
theta_min=-20; %degrees
theta_max=80; %degrees
theta=linspace(-20,80,37); %degrees
phi=linspace(0,180,37); %degrees
gamma=phi+20; %degrees
%-----------------------------------
for i=1:37
c_2(i)=((r_max^2)-(r_min^2))./(cosd(gamma(i)+theta_min)-cosd(gamma(i)+theta_max));
c_1(i)=(r_max^2)+c_2(i).*cosd(gamma(i)+theta_max);
a(i)=real(0.5*(((c_1(i)+c_2(i)).^(1/2))+((c_1(i)-c_2(i)).^(1/2))));
b(i)=real(c_2(i)/(2*a(i)));
for j=1:37
r(i,j)=sqrt((a(i)^2)+(b(i)^2)-(2*a(i)*b(i)*cosd(gamma(i)+theta(j))));
F(i,j)=(r(i,j)*m*g*L*cosd(theta(j)))/(b(i)*a(i)*sind(gamma(i)+theta(j)));
end
F_max=0;
k=1;
if F(i,:)>F_max & F(i,:)~=Inf & F(i,:)~=-Inf
F_new=F(i,:);
F_max(k)=max(F_new);
k=1+k;
end
end
F_min=min(F_max);
F_max=max(k);
theta_opt=theta(:);
a_opt=a(:);
b_opt=b(:);
r_opt=r(:);
phi_opt=gamma(:)-20;
This gives out...
Maximum Force possible on ram 1N
Minimum Force possible on ram 0N
Error using horzcat
Dimensions of matrices being concatenated are not consistent.
Error in MatLab_Code_main_3 (line 72)
disp(['Corresponding Boom Angle for Minimum force ' num2str(theta_opt) 'degrees' ])
Any my workspace looks like this, hopefully this will clarify my description!
I'm afraid I only have time to glance over this quickly inbetween my work so I may miss a few things.
The line:
F_max(k) = F_new;
should replace
F_max=max(k);
after the if statement in your original code, not where you put it in the above code.
Your F_min line also still needs to be right at the bottom, outside of the whole loop as it is the final operation.
There are other things that look wrong too though that I just don't have time to give corrections to at the moment I'm afraid, but to point in their direction:
You need to think about what you are wanting to compare with the line:
if F(i,:)>F_max & F(i,:)~=Inf & F(i,:)~=-Inf
F(i,:) will be an array of values so if you compare this against F_max you will get a logical array of the same length as F(i,:) out. To use this in an if statement reliably it needs to be a single logical value, e.g. all( F(i,:)>F_max ) or any( F(i,:)>F_max ).
Also since this is a logical statement I'm not quite sure what the Inf is doing in there.
Cat
Cat on 28 Oct 2014
Edited: Cat on 28 Oct 2014
Hi, I have tried to simplify this down a little bit as F_new was already storing values so I'm not sure if I need another vector? I think that it may still only be going through one row of my F rather than all 37. I also tried changing to
if any(F(:,:)>F_max) & F(:,:)~=Inf & F(:,:)~=-Inf
to see if that would make it go through all rows but it displayed an error.
This is the simplified code. I think that this problem really shouldn't be difficult but a lot of people in my class have made it complicated. My problem is that I don't understand why it's not doing it because I feel like I've put it in okay!
for i=1:37
c_2(i)=((r_max^2)-(r_min^2))./(cosd(gamma(i)+theta_min)-cosd(gamma(i)+theta_max));
c_1(i)=(r_max^2)+c_2(i).*cosd(gamma(i)+theta_max);
a(i)=real(0.5*(((c_1(i)+c_2(i)).^(1/2))+((c_1(i)-c_2(i)).^(1/2))));
b(i)=real(c_2(i)/(2*a(i)));
for j=1:37
r(i,j)=sqrt((a(i)^2)+(b(i)^2)-(2*a(i)*b(i)*cosd(gamma(i)+theta(j))));
F(i,j)=(r(i,j)*m*g*L*cosd(theta(j)))/(b(i)*a(i)*sind(gamma(i)+theta(j)));
end
F_max=0;
if any(F(i,:)>F_max) & F(i,:)~=Inf & F(i,:)~=-Inf
F_new=F(i,:);
end
end
F_min=min(F_new);
F_max=max(F_new);
The reason I have the stuff about Inf is because the F(i,j) matrix includes Inf and -Inf which causes these to be given as the max and min values which is obviously not practical so I was trying to eliminate them as answers.
Adam
Adam on 28 Oct 2014
Edited: Adam on 28 Oct 2014
Ok, so now that I look at it again I think this could be done more simply and I realise I misinterpreted part of the code earlier.
At the end of your nested loops your variable, F, is of size 37*37.
i.e. it contains all the F values that you are looking to find maxes of (unless I mistake this).
So, how about you just remove all the code testing for max and min inside the loop because you can do this after the loop instead.
To find the maximum value in each row of F (which is what the text of your question suggests you are trying to do) you can simply do:
[F_max, idx1] = max( F, [], 2 );
This will give you a 37*1 array containing the maximum value from each row of F.
Then if you want the min of these you can simply do:
[F_min, idx2] = min( F_max );
This will give you a single scalar value for F_min. idx1 will give you the column indices at which those maxima occured, then idx2 will give you the index into those for the minimum.
(Note: If it turns out what you actually wanted was the maximum value from each column of F you can replace the above simply with:
F_max = max( F );
and then take F_min in the same way).
Apologies if I have missed something important here that means you really do have to keep track of maxima or minima inside the loop itself.
Adam
Adam on 28 Oct 2014
Edited: Adam on 28 Oct 2014
So something more like this, lifting your code from the previous comment without checking whether any of the rest of it is correct, only the max calculation stuff:
for i=1:37
c_2(i)=((r_max^2)-(r_min^2))./(cosd(gamma(i)+theta_min)-cosd(gamma(i)+theta_max));
c_1(i)=(r_max^2)+c_2(i).*cosd(gamma(i)+theta_max);
a(i)=real(0.5*(((c_1(i)+c_2(i)).^(1/2))+((c_1(i)-c_2(i)).^(1/2))));
b(i)=real(c_2(i)/(2*a(i)));
for j=1:37
r(i,j)=sqrt((a(i)^2)+(b(i)^2)-(2*a(i)*b(i)*cosd(gamma(i)+theta(j))));
F(i,j)=(r(i,j)*m*g*L*cosd(theta(j)))/(b(i)*a(i)*sind(gamma(i)+theta(j)));
end
end
[F_max, idx1] = max( F, [], 2 );
[F_min, idx2] = min( F_max );
As an aside, blank lines are your friend when it comes to coding! They cost nothing and vastly improve readability by separating code out so make good use of them!!
Thank you so much!
Why is it in the F_max that you have a 2? (just for my understanding)
The above formula will give me the max for each row, considering all of the column values, even though it only gives out a 37*1 array?
I assume to find the maximum of the F_max array I can just put
F_max=max(F_max)
although maybe better to call it something new such as F_max_final.
The only problem when I do the above is that it give me the overall maximum value to be Inf so I tried writing {below} but it still gives out F_max as Inf.
F_max_array=max(F,[],2)
F_min=min(F_max_array)
F_max<Inf;
F_max=max(F_max_array)
Once I have my max and min, how can I find the corresponding values of my variables for these? I want to write something like {below} but so far that hasn't been working, I'm not sure if this is because it is now outside of the loop.
theta_opt=theta(i,j);
a_opt=a(i,j);
b_opt=b(i,j);
r_opt=r(i,j);
phi_opt=gamma(i,j)-20;
Adam
Adam on 28 Oct 2014
Edited: Adam on 28 Oct 2014
The 2 in the F_max calculation tells it to do the max calculation along dimension 2 of your 2d array rather than along dimension 1.
There are a number of ways you could deal with Inf values I guess.
One of the simplest though is simply to add in:
F( F == Inf ) = NaN;
before your max calculation and instead of using max use:
F_max = nanmax( F, [], 2 );
This will replace infinity with NaN and use a function (nanmax) which ignores NaNs in its calculation.
To get the corresponding variables use the 2nd output argument from nanmean and min which gives you the index at which the max or min occured (you may have read my earlier comment before I edited it to include these). Using these for both your nanmax and your later min you should be able to map these back onto your original variables as the indices output will be as if you had the i and j values from inside your loop.
Cat
Cat on 28 Oct 2014
Edited: Cat on 28 Oct 2014
I'm sorry I didn't see the edit in your last response as I happened to read it as you put it up! I have now put for my max/min section this, but unfortunately I am still getting the maximum value out as Inf at position 1.
[F_min, idx2] = min( F_max )
F ( F == Inf ) = NaN;
[F_max, idx2] = nanmax( F_max )
Can I input something like {below} to give out each of my I and j, rather than just one position (position 2 which is my column value)?
F ( F == Inf ) = NaN;
[F_max, idx1, idx2] = nanmax( F_max )
[F_min, idx1, idx2] = min( F_max )
I have tried this, but it isn't giving me the same min(or max) & the two positions, it is instead listing.
F ( F == Inf ) = NaN;
[F_max, idx1] = nanmax( F, [], 2 )
[F_max, idx2] = nanmax( F, [], 2 )
[F_min, idx1] = min( F, [], 2 )
[F_min, idx2] = min( F, [], 2 )
You shouldn't be passing F_max to nanmax, you should be passing F in.
nanmax (just like max) only returns indices in one direction, but it will return 1 index for each row - i.e. the index of the maximum value on each row.
[F_max, idx] = max( F, [], 2 );
[F_min, idxRow] = min( F_max );
idxCol = idx( idxRow );
That should give you the row index and the column index of the value you want in idxRow and idxCol.
Those values can then be used exactly as if they were i and j in your loop when it comes to retrieving the parameters for that particular value of F.

Sign in to comment.

More Answers (0)

Asked:

Cat
on 28 Oct 2014

Commented:

on 28 Oct 2014

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!