Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

Thread Subject:
Locate two rising values followed by two falling values

Subject: Locate two rising values followed by two falling values

From: Jeff

Date: 9 Feb, 2011 19:24:04

Message: 1 of 4

I want to look at a vector (actually, an array, but I'm treating each column as a vector) and pick out two successive rising values followed by two successive dropping values (e.g., 1,2,3,2,1, a peak) and vice versa (a valley). What is the best way to do that, without writing anti-Mathlab loops and nested-loops and if..thens, and so forth? Here's the best I could come up with, but it still requires a test:

I start by shifting and subtracting the vector and taking its sign. That tells me if each is rising or falling compared to the previous.
>signdiffx=sign(x(1:end-1)-x(2:end));

Next, I shift and multiply. Multiplying tells me if there is a sign change, which indicates a change in the direction:
>signchg=signdiffx(1:end-1).*signdiffx(2:end);

In signchg, a positive value indicates two consecutive changes in x in the same direction; a negative value mans the next change is in the opposite direction from the previous; finally, a positive value means the next change is in the same direction as the middle step (where it changed direction). So, a positive followed by a negative followed by a positive (i.e., +,-,+) indicates a peak or valley (are you following this?).

How do I extract that info from signchg?

If I add each entry in signchg to the one before and after it:
>peak=signchg(1:end-2)+signchg(2:end-1)+signchg(3:end);

the pattern I'm looking for (+,-,+) will add up to 1. But so would any other pattern with two positives and a negative (e.g., +,+,- and -,+,+).

Among those three patterns, only the desired one has a negative in the middle. So I can try multiplying the result by the middle term and see which one becomes negative:
>peak=(signchg(1:end-2)+signchg(2:end-1)+signchg(3:end)).*signchg(2:end-1)

But now it seems that -,+,- also returns a negative one.

Anyone know how I can find the locations of two rising values followed by two falling values (and vice versa)? Am I at least on the right track?

Thanks,
Jeff

Subject: Locate two rising values followed by two falling values

From: someone

Date: 9 Feb, 2011 19:34:04

Message: 2 of 4

"Jeff" wrote in message <iiupkk$ove$1@fred.mathworks.com>...
> I want to look at a vector (actually, an array, but I'm treating each column as a vector) and pick out two successive rising values followed by two successive dropping values (e.g., 1,2,3,2,1, a peak) and vice versa (a valley). What is the best way to do that, without writing anti-Mathlab loops and nested-loops and if..thens, and so forth? Here's the best I could come up with, but it still requires a test:
>
> I start by shifting and subtracting the vector and taking its sign. That tells me if each is rising or falling compared to the previous.
> >signdiffx=sign(x(1:end-1)-x(2:end));
>
> Next, I shift and multiply. Multiplying tells me if there is a sign change, which indicates a change in the direction:
> >signchg=signdiffx(1:end-1).*signdiffx(2:end);
>
> In signchg, a positive value indicates two consecutive changes in x in the same direction; a negative value mans the next change is in the opposite direction from the previous; finally, a positive value means the next change is in the same direction as the middle step (where it changed direction). So, a positive followed by a negative followed by a positive (i.e., +,-,+) indicates a peak or valley (are you following this?).
>
> How do I extract that info from signchg?
>
> If I add each entry in signchg to the one before and after it:
> >peak=signchg(1:end-2)+signchg(2:end-1)+signchg(3:end);
>
> the pattern I'm looking for (+,-,+) will add up to 1. But so would any other pattern with two positives and a negative (e.g., +,+,- and -,+,+).
>
> Among those three patterns, only the desired one has a negative in the middle. So I can try multiplying the result by the middle term and see which one becomes negative:
> >peak=(signchg(1:end-2)+signchg(2:end-1)+signchg(3:end)).*signchg(2:end-1)
>
> But now it seems that -,+,- also returns a negative one.
>
> Anyone know how I can find the locations of two rising values followed by two falling values (and vice versa)? Am I at least on the right track?
>
> Thanks,
> Jeff

You might take a look at extrema from the MATLAB FEX at:

http://www.mathworks.com/matlabcentral/fileexchange/12275-extrema-m-extrema2-m

to see how he did it. Also typing extrema in the search box at:

http://www.mathworks.com/matlabcentral/fileexchange/

will point you to a lot of other peak picker MATLAB files.

Subject: Locate two rising values followed by two falling values

From: Jeff

Date: 10 Feb, 2011 00:04:03

Message: 3 of 4

"someone" wrote in message <iiuq7c$3vj$1@fred.mathworks.com>...
 
> You might take a look at extrema from the MATLAB FEX at:
>
> http://www.mathworks.com/matlabcentral/fileexchange/12275-extrema-m-extrema2-m
>
> to see how he did it. Also typing extrema in the search box at:
>
> http://www.mathworks.com/matlabcentral/fileexchange/
>
> will point you to a lot of other peak picker MATLAB files.

Thanks, someone (good, anonymous, name, btw).

I will look in the library. But first I created some code which actually works pretty well. But I don't know how to use it.

The code extracts a list of index locations where the peaks and valleys occur without using any time-consuming loops. So, is there a way to extract the data from the index points (and surrounding points) without resorting to loops?

Here's my code:
signdiffx=sign(M(1:end-1,:)-M(2:end,:));
signchg=signdiffx(1:end-1,:).*signdiffx(2:end,:);
sumsignchg=[zeros(1,nFreqs);...
    signchg(1:end-2,:)+signchg(2:end-1,:)+signchg(3:end,:)==1;...
    zeros(1,nFreqs)];
xtm=[zeros(1,nFreqs); signchg.*sumsignchg==-1];
[idxXtrms(:,1) idxXtrms(:,2)]=find(xtm);

And a sample of the output:

And here's a sample of the output (idxXtrms) I get:
21 1
32 1
42 1
...
8 8
11 8
17 8

How do I use that to get the values at *and near* position M(21,1), M(32,1), M(42,1)...M(8,8), M(11,8), M(17,8)... without looping?

Thanks for someone (or anyone) who can help.

Subject: Locate two rising values followed by two falling values

From: Jos (10584)

Date: 10 Feb, 2011 11:34:03

Message: 4 of 4

"Jeff" wrote in message <iiupkk$ove$1@fred.mathworks.com>...
> I want to look at a vector (actually, an array, but I'm treating each column as a vector) and pick out two successive rising values followed by two successive dropping values (e.g., 1,2,3,2,1, a peak) and vice versa (a valley). What is the best way to do that, without writing anti-Mathlab loops and nested-loops and if..thens, and so forth? Here's the best I could come up with, but it still requires a test:
>
> I start by shifting and subtracting the vector and taking its sign. That tells me if each is rising or falling compared to the previous.
> >signdiffx=sign(x(1:end-1)-x(2:end));
>
> Next, I shift and multiply. Multiplying tells me if there is a sign change, which indicates a change in the direction:
> >signchg=signdiffx(1:end-1).*signdiffx(2:end);
>
> In signchg, a positive value indicates two consecutive changes in x in the same direction; a negative value mans the next change is in the opposite direction from the previous; finally, a positive value means the next change is in the same direction as the middle step (where it changed direction). So, a positive followed by a negative followed by a positive (i.e., +,-,+) indicates a peak or valley (are you following this?).
>
> How do I extract that info from signchg?
>
> If I add each entry in signchg to the one before and after it:
> >peak=signchg(1:end-2)+signchg(2:end-1)+signchg(3:end);
>
> the pattern I'm looking for (+,-,+) will add up to 1. But so would any other pattern with two positives and a negative (e.g., +,+,- and -,+,+).
>
> Among those three patterns, only the desired one has a negative in the middle. So I can try multiplying the result by the middle term and see which one becomes negative:
> >peak=(signchg(1:end-2)+signchg(2:end-1)+signchg(3:end)).*signchg(2:end-1)
>
> But now it seems that -,+,- also returns a negative one.
>
> Anyone know how I can find the locations of two rising values followed by two falling values (and vice versa)? Am I at least on the right track?

Here is a fairly simple approach:

% data
V = [4 2 3 4 2 1 7 3 5 6 4 3]
vi = 1:numel(d)-4 ;

d = sign(diff(V)) ; % direction of slope
TF = d(vi) > 0 & d(vi+1) > 0 & d(vi+2)<0 & d(vi+3) < 0 ;
TFidx = find(TF) % start of sequence 2 up followed by 2 down

% result
plot(1:numel(V),V,'bs-',TFidx+2,V(TFidx+2),'rs') ;

hth
Jos

Tags for this Thread

No tags are associated with this thread.

What are tags?

A tag is like a keyword or category label associated with each thread. Tags make it easier for you to find threads of interest.

Anyone can tag a thread. Tags are public and visible to everyone.

Contact us