## How can I find the maximum absolute value between two zeros ?

on 23 Jul 2013

### dpb (view profile)

Hello everyone

My goal is to find the maximums/minimums between two zeros and when it occurs for some velocity data that are in the form of a column vector.

I tried to find where are zeros upward, find where are zeros downward, and then to find the maximum/minimum in between.

The problem is that my code does not work and I do not understand why. I'm pretty sure I must not be far for the good answer.

How can I find the maximum of U between an upward going and a downward going zero and the minimum of U between a downward going and an upward going zero ?

My code is:

indx=find(U(1:end-1,1).*U(2:end,1) < 0);

new_U=zeros(length(indx),1);

for k=1:length(indx)

new_U(k,1)=max(U(indx(k))):U(indx(k+1));

end

But then I have a message error : ??? Subscripted assignment dimension mismatch.

Azzi Abdelmalek

### Azzi Abdelmalek (view profile)

on 23 Jul 2013

Give a short example

dpb

### dpb (view profile)

on 23 Jul 2013
for k=1:length(indx)
new_U(k,1)=max(U(indx(k))):U(indx(k+1));
end

error : ??? Subscripted assignment dimension mismatch.

Yes, there's no guarantee the number of elements from one set of indices is the same length as the next. If you want to save these subvectors then you'll have to use a cell array to handle the varying lengths.

Another way to find zero crossings is to look at

d=[0 diff(sign(U))];
find(d==2)                % +ive crossings
find(d==-2)               % -ive crossings

There are also a number of peak-finding routines on the FEX or findpeaks() in the Signal Processing Toolbox (altho iirc it doesn't isolate on the zero crossing intervals)

on 23 Jul 2013
Edited by dpb

### dpb (view profile)

on 24 Jul 2013

OK, I can't seem to find a utility I had that does basically what you were/are looking for that I thought was around but here's a straightahead implementation using the above idea of diff()==2...

function pks = peaksbetween(x)
% peaks from column vector x between zero crossings
ix=find(abs([0; diff(sign(x))])==2);  % zero crossing loc's
pks=zeros(length(ix)-1);              % one less peak than x'ings
for i=1:length(ix)-1
sx=x(ix(i):ix(i+1)-1);              % subvector between x'ings
[~,ipk]=max(abs(sx));               % peak location in subvector
pks(i)=sx(ipk);                     % and signed max/min value
end

To return the locations in the original vector means unwrapping the local location to the global--I left as "exercise for the student"... :)

If I can find the vectorized version I'll post it--I know it's around but this is a new install and it must not have gotten over from the utilities on the previous release or I put it somewhere other than I recall--altho which didn't find it so it's not on path... :(

Valentin

### Valentin (view profile)

on 24 Jul 2013

Thank you very much for your answer, it works really well. I knew little about diff()==2 before and I'm going to investigate this more. Regarding the vectorized version, I should be able to extract the first column of the matrix to turn it into a vector if you can't find it. I'll sort out how to return locations. Thank you again

dpb

### dpb (view profile)

on 24 Jul 2013

I knew little about diff()==2 before...

You have to think about ways to find out what it is you're looking for to come up w/ such--in this case it's starts w/ realizing that you don't need the magnitude only the sign to determine the zero-crossing point and that then when the time vector is turned into simply the sign of the result that only when it changes is there any difference between adjacent values. The ==2 is simply owing to that being the difference between 1 and -1. To keep the index into the original vector at the same point one then just prepends a 0 to the difference vector.

For the routine to handle arrays you have to add the logic to handle the second dimension--it's doable but takes some pre-work to check on sizes and then the addressing and didn't figure worth confusing the logic of the algorithm w/ the details...I've forgotten exactly how I did implement it originally; it's been a number of years and I've not done much signal processing in last almost 15 yr since returned to family farm... :)

### dpb (view profile)

on 27 Jul 2013

Updated version that also returns locations in original vector. I did for simplicity restrict the input to a column vector; just add logic to ensure correct orientation of the pieces internally if want to handle either...or just brute-force a row vector to a column vector internally and then return the same orientation as the input--that's actually probably the better idea but will leave as "exercise for the student" to choose/implement if wish.

function [pks, ipks] = peaksbetween(x)
% peaks and locations from vector x between zero crossings and location
if size(x,1)==1,       error('X must be a column vector'), end
if numel(x)~=length(x),error('X must be a column vector'), end
ix=find(abs(diff(sign(x)))==2)+1;     % zero crossing loc's
L=length(ix)-1;                       % one less peak than x'ings
ipk=zeros(L,1);
for i=1:length(ix)-1
sx=x(ix(i):ix(i+1)-1);              % subvector between x'ings
[~,ipk(i)]=max(abs(sx));            % peak location in subvector
end
ipks=ix(1:end-1)+ipk-1;               % max loc in original vector
pks=x(ipks);                          % and signed max/min value
end

dpb

### dpb (view profile)

on 27 Jul 2013

One more variant...I'm still learning about accumarray and friends... :)

Using a local function to return the indices from max() then accumarray to remove the explicit loop. Too bad there's no syntax for returning alternate return values only.

function [pks, ipks] = peaksbetween(x)
% peaks and locations from vector x between zero crossings and location
if size(x,1)==1,       error('X must be a column vector'), end
if numel(x)~=length(x),error('X must be a column vector'), end
ix=find(abs(diff(sign(x)))==2)+1;     % zero crossing loc's
L=length(ix)-1;                       % one less peak than x'ings
ipk=accumarray([1:L]',[1:L]',[], @(i) imax(abs(x(ix(i):ix(i+1)-1))) );
ipks=ix(1:L)+ipk-1;                   % max loc in original vector
pks=x(ipks);                          % and signed max/min value
end
function idx=imax(x)
%  Return max() indices as first argument
[~,idx]=max(x);
end