Help finding the first minimum value in an array and indexing the value in a new array!!!

Hi, I am trying to run code that calls in the function below, and I am having problems with the final for loop. Basically, I am trying to take an array (v), find the point at which the first minimum value occurs in the array, and assign that point or timelag to a new array called (x). However, my data doesn't always have a first minimum so I had to create another loop (else) that is supposed to find the first value within array (v) whose difference is less than or equal to 5% of the value before it. Once it finds that value, its supposed to take the point (i) where that value occurs and assign it to a new array (x).
function [tau,v_AMI]=AMI(data, L)
N=length(data);
bins=128; %number of bins used for histogram calculation
%bins=floor(1+log2(N-L)+0.5);
epsilon = eps;
data = data - min(data); % making all the data points positive
data = 1+ floor(data/(max(data)/(bins-epsilon))); %scaling the data
v=zeros(L,1); %create a zero vector
overlap=N+1-L;
increment= 1/overlap;
one = ones(overlap,1); %create a column vector with all elements being one
pA = sparse (data(1:overlap),one,increment);
for lag = 0: L -1
pB = sparse(one, data(1+lag:overlap+lag), increment);
pAB = sparse(data(1:overlap),data(1+lag:overlap+lag),increment);
[A, B, AB]=find(pAB);
v(lag+1)=sum(AB.*log2(AB./(pA(A).*pB(B)'))); %Average Mutual Information
end
v_AMI=v;
%Take time_lag when 1st min(I(time_lag))occurs for values of time_lag near
%this minimum, the coordinate system produced by time delay vector is
%esentially as good as that of the time_lag which is the actual 1st min(I(time_lag))
for i = 1:length(v)-1
if (find((v(i)<v(i+1)) && (v(i)<v(i-1))))==1 %(find(v==min(v),1,'first'))
x(i)=i;
else
myindexes=0.95*v(i);
(find(v(i+1)<=myindexes))==1;
x(i)=i;
end
end
A=sparse(x);
A=find(A);
tau=A(1);
I've tried writing the loop as the commented portion and that didn't seem to work. I've also tried writing the if statement as
if (find((v(i)<v(i+1)) && (v(i)<v(i-1)),1,'first'))
and that may have worked but the second loop didn't. I originally had the 2nd loop written as
if (find(v(i)<=0.95*v(i-1),1,'first')
but had to get creative because it kept giving me an error "must be real numbers or logicals". Which makes sense because you can't have decimals as indices (e.g. v(3.9154)). I also tried running it as
else
myindexes=0.95*v(i);
(find(v(i+1)<=myindexes,1,'first'));
x(i)=i;
end
which actually ran without giving me errors, but its not working appropriately because it calculated tau as 1 for all files.
The code used to call in the function is below:
directory_name = uigetdir(pwd,'Select data directory');
directory_name = ([directory_name '/']);
files = dir([directory_name,'*txt']);
if isempty(files)
msgbox('No raw files in this directory')
end
FileName=[];
for i=1:length(files)
filename=files(i).name;
data = load(filename,'-ascii');
filename=filename(1:end-4);
FileName=[FileName; cellstr(filename)];
L=32; % window size for average mutual information
[tau,v_AMI]=AMI(data, L); %Find the first minimum average mutual information
end
To give you an idea of the data array v, I included a graph of v for one of the files that doesn't have a first minimum value.
How might I fix the loops to run appropriately?

2 commentaires

Wasn't sure if the graph attached properly so here is a picture of it instead.

Connectez-vous pour commenter.

 Réponse acceptée

Part of the issue you're having is that your if statement doesn't have an actual condition in it.
if (find((v(i)<v(i+1)) && (v(i)<v(i-1))))==1 %(find(v==min(v),1,'first'))
All of these 'conditions' are going to return specific values, which may or may not make logical sense. Specifically, using the find() produces a non logical result. If you want to make this a proper logic check for the if then you need to adust your statement to be something more like:
if ~isempty(find(v==min(v),1,'first')) % Determines if the result exists
Also, there should always be a minimum value, assuming the array v is not empty or NaN. Even if all of the values are the same, the min() function should return that value.
Because you're only looking for a single value (the first minimum) I don't know that the loop is even necessary (unless v is not an array of doubles). Try something like this?
x = find(v==min(v),1,'first');

5 commentaires

Thank you. And yes I agree there will always be a minimum value, but in the case of the graph that I posted, the minimum value would be the final data point (v(~32)), which is not what I am trying to find.
I guess a better way of saying this is when I have data that looks like the curve below, I need to find the index (i) where its similar to like an inflection point (finding some value of v that satisfies the condition v less than a 5% difference from the value before it (v(i-1)).
That's why I needed the first loop to satisfy both conditions (the value v(i) had to be less than both the values before and after it....to prevent it from taking the final value, as in the case below, as the minimum). Essentially, the first loop should find a minimum value, but it needs to be a value that isn't the last data point (needs to have values to the left and right of it to compare to, to see if its a minimum).
So when its like the curve below, it shouldn't find a minimum and should automatically go to the else statement to satisfy the other condition (finding (i) when v(i) is less than or equal to 0.95*v(i-1)). The array (v) is a 32x1 array and has decimal values that are all positive numbers if thats helps.
Graph2.jpg
Ok, that's a different deal than just finding the minimum.
This returns back to the idea of how you are producing your logic for your if statement. The logic checks themselves should be correct, you really just need to remove the find function from it.
for i = 1:length(v)-1
if v(i)<v(i+1) & v(i)<v(i-1)
x=i;
break % You mentioned you want the first value, this should cut the loop at this i value
else
myindexes=0.95*v(i);
(find(v(i+1)<=myindexes))==1; % What are we doing with this?
% x(i)=i; % I'm not sure the point of this, but if you leave it on you will end up with x being all indices i
end
end
Thank you!! that makes a lot more sense for the first loop now. The second part
else
myindexes=0.95*v(i);
(find(v(i+1)<=myindexes))==1;
x(i)=i;
end
was to find x=i for a different condition (for when the first loop doesn't work / when there is no minimum value that satisfies those conditions).
I couldn't figure out the correct way to write what I was trying to get the code to do.
When the first loop isn't satisfied, and I get an array of values, that when plotted, looks like the curve previously posted.... I need to look at each value within array (v) and find the first point whose value is no more than a 5 percent difference than the value before it.
For example, if
v=[7.1
6.2
6.0
5.0
4.2
2.3]
it would need to see if v(i+1) is greater than or equal to 0.95*(v(i)) (to be no more than a 5% difference from the previous number)
(e.g. if v(2)=6.2 and v(3)=6.0
5 percent of v(i) or v(2)=6.2 in this case is (0.05 x 6.2) =0.31 but for comparison its easier to compare the number after it to 95% of v(i)
V(i+1) >= (0.95*v(i)) which in this case is true because 6.0 >=(0.95*6.2)
but the problem I am having with writing the statement is that it creates a nonlogical index when multiplied by 0.95.
so is there a way to fix this?
elseif v(i+1)>=0.95*v(i)
x=i+1;
end
or actually I think a better way to write it is
elseif v(i)-v(i+1)<=0.05*v(i)
x=i+1;
end
so back to the example, 6.2 - 6.0 <= (0.05*6.2) or 0.2<=0.31 so since v(i+1) is no more than a 5% difference from v(i)....I would want to make x=i+1
Both of those new statements create logical results, because the ultimate operator is the comparison >= or <=. If we break things down a bit you have three parts 1) v(i+1), 2) () >= (), and 3) 0.05*v(i). By order of operations the inequality is the last operation to happen, so your result must be logical in nature.
When we do something similar with the previous find setup, we have basically the same three portions, but there is a fourth, the find() function itself, that ends up being the final operator, and causes the lack of logical result that you were experiencing.
TL:DR either one of those new setups should work, although I would suggest naming x as a different variable. That way, if you encounter both situations in a loop you can capture both results.

Connectez-vous pour commenter.

Plus de réponses (0)

Catégories

En savoir plus sur Loops and Conditional Statements dans Centre d'aide et File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by