How can I rewrite this to get peak locations?

I have this
amps = arrayfun(@(h2) max((findpeaks(udata(h2, :), x) < 0.99)...
.* findpeaks(udata(h2, :), x)), 1:size(udata, 1));
And I want to rewrite it to get peak locations. When I call x(amps) it gives a logic error...

Answers (2)

The locations are the second output from findpeaks, so I doubt that arrayfun will do what you want.
I would do something like this —
udata = randn(10); % Create 'udata' Array
for h2 = 1:size(udata,2)
[pks,locs] = findpeaks(udata(h2, :));
pksc{h2,:} = pks; % Cell Array Of Peak Values
locsc{h2,:} = locs; % Cell Array Of Location Values
end
Lv = cellfun(@(x)x<0.99, pksc, 'Unif',0) % Cell Array Of Logical Vectors
Lv = 10×1 cell array
{[ 1 1 1]} {[ 0 1 1]} {[ 1 1 0]} {[0 1 1 1]} {[ 0 1]} {[ 1 1 1]} {[ 1 1 1]} {[ 1 1 1]} {[ 0 1]} {[ 0 1 1]}
pksm = cellfun(@(x,y)x(y), pksc, Lv, 'Unif',0) % Peak Values Result
pksm = 10×1 cell array
{[ 0.8875 0.9108 0.2496]} {[ -0.3314 -0.1289]} {[ 0.3672 0.2208]} {[ 0.6036 0.8317 0.5501]} {[ 0.0153]} {[-0.1968 -0.5469 0.4821]} {[ 0.5430 0.8575 0.9401]} {[ 0.5961 0.3895 -0.1598]} {[ 0.9421]} {[ 0.5154 0.5672]}
locsm = cellfun(@(x,y)x(y), locsc, Lv, 'Unif',0) % Location Values Result
locsm = 10×1 cell array
{[3 5 8]} {[ 7 9]} {[ 4 6]} {[5 7 9]} {[ 4]} {[4 6 8]} {[2 4 8]} {[4 6 8]} {[ 7]} {[ 7 9]}
This will store the ‘pks’ and ‘locs’ vectors in their respective cell arrays. Process them appropriately later.
The ‘Lv’ (logical vector cell array) can have more than one condition, so that you can use a range of values such as:
@(x)(x<0.99) & (x>0.5)
if that is what you want to do. The rest of the code is unchanged.
EDIT — Corrected typographical errors.
.

6 Comments

ok, how can I extend this so it looks for peaks greater than 1 but less than 2?
Try this —
Lv = cellfun(@(x) (x>1) & (x<2), pksc, 'Unif',0) % Cell Array Of Logical Vectors
Testing it with a random matrix —
udata = rand(500,15)*3; % Create 'udata' Array
for h2 = 1:size(udata,2)
[pks,locs] = findpeaks(udata(h2, :));
pksc{h2,:} = pks; % Cell Array Of Peak Values
locsc{h2,:} = locs; % Cell Array Of Location Values
end
Lv = cellfun(@(x)(x>1) & (x<2), pksc, 'Unif',0) % Cell Array Of Logical Vectors
Lv = 15×1 cell array
{[0 0 0 0 0]} {[0 0 0 0 0]} {[ 1 0 0 0]} {[ 0 0 1 0]} {[0 1 1 1 0]} {[0 0 1 0 1]} {[ 1 0 0 0]} {[ 0 0 0 1]} {[ 0 1 0]} {[1 0 0 0 0]} {[ 1 1 0 0]} {[ 0 1 0 0]} {[ 0 0 0 0]} {[ 0 0 0]} {[ 0 0 1 0]}
pksm = cellfun(@(x,y)x(y), pksc, Lv, 'Unif',0) % Peak Values Result
pksm = 15×1 cell array
{1×0 double } {1×0 double } {[ 1.3583]} {[ 1.4681]} {[1.6804 1.5822 1.5507]} {[ 1.6386 1.5791]} {[ 1.8833]} {[ 1.5120]} {[ 1.9282]} {[ 1.8557]} {[ 1.7491 1.1003]} {[ 1.5079]} {1×0 double } {1×0 double } {[ 1.8701]}
locsm = cellfun(@(x,y)x(y), locsc, Lv, 'Unif',0) % Location Values Result
locsm = 15×1 cell array
{1×0 double} {1×0 double} {[ 4]} {[ 9]} {[ 5 7 11]} {[ 9 14]} {[ 4]} {[ 14]} {[ 9]} {[ 2]} {[ 3 6]} {[ 4]} {1×0 double} {1×0 double} {[ 11]}
x = linspace(0, (size(udata,1)-1)/100, size(udata,1)); % Create Indepdent Variable Vector
for k = 1:numel(locsm)
if any(locsm{k})
xv{k,:} = x(locsm{k});
else
xv{k,:} = NaN;
end
end
xv
xv = 15×1 cell array
{[ NaN]} {[ NaN]} {[ 0.0300]} {[ 0.0800]} {[0.0400 0.0600 0.1000]} {[ 0.0800 0.1300]} {[ 0.0300]} {[ 0.1300]} {[ 0.0800]} {[ 0.0100]} {[ 0.0200 0.0500]} {[ 0.0300]} {[ NaN]} {[ NaN]} {[ 0.1000]}
There are peaks in every vector, however only some of them meet the criteria (the ‘1’ values in ‘Lv’). The corresponding peak values are returned in ‘pksm’ and their location indices in the peak array are returned in ‘locsm’.
These results will need to be processed as individual cells (not as matrices), since it is unlikely that there will be the same number of columns in every cell.
Get the actual values of the independent variable vector (here ‘x’) at the peak locations as illustrated in the last loop (added here to my original code to demonstrate that). It includes a test to be certain that only ‘locsm’ cells with valid indices are addressed, returning NaN for the others. You can use that approach for other processing steps, as well.
.
thank you, so if the max of my array was say 1.96 and the min was 0.75, how might I do that? I tried with
Lv = cellfun(@(x)(x>0.96) & (x<1.96), pksc, 'Unif',0) ; % Cell Array Of Logical Vectors
And after a cutoff all my values just jump up to 1?
My pleasure!
I do not understand what you want to do.
The ‘Lv’ assignment here will return true for peaks between 0.96 and 1.96. Peaks outside that range (including peaks equalling 0.75) will return false. In a logical vector, true values are denoted by 1 and false by 0. (The logical values are not inherently numerical values, although they become numerical values if you use them in calculations.)
Yes so sorry for not being very clear there. What I'd like to do is find peaks between 0.96 and 1.96 but when I do that it just returns an array of zeros for locsm :(
That means that there are no peaks in that column that meet the criteria. You can verify that by looking at the ‘pksc’ cell for that particular column:
pksv = pksc{column_number}
You can see that also occurs in my demonstration in my previous Comment. There may not be any peaks in a particular column that meet the criteria, and in that instance, my code assigns the cell as NaN (all detected peaks are false).

Sign in to comment.

Perhaps the islocalmax function with the dim input argument will meet your needs.

Products

Release

R2022b

Asked:

on 10 Feb 2023

Commented:

on 14 Feb 2023

Community Treasure Hunt

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

Start Hunting!