Signals often contain peaks that you aren't interested in. This guide will show you how to filter peaks you don't want.
How to filter peaks by peak spacing
Real data typically has noise that can create lots of closely spaced, unwanted peaks.
T = 1/25
t = 0:T:23
multisin(t) = 3sinpi(0.1t) + 2sinpi(0.2t) + sinpi(0.6t)
y = multisin.(t) .+ 0.1rand(length(t))
pks = findmaxima(y)
plotpeaks(t, y; peaks=pks.indices)
The simplest way to remove those peaks (assuming the signal is already filtered) is by setting the window w
argument in findmaxima
and friends:
pks = findmaxima(y, 15)
f = plotpeaks(t, y; peaks=pks.indices)
If only the peaks circled in blue are wanted, then setting the window w
too wide won't work, since there are larger peaks that would become dominant.
How to filter peaks by peak characteristics
Every peak-characteristic finding function can optionally filter the newly calculated characteristics using the keyword arguments min
and max
.
Plotting all the peak characteristics and/or looking at the characteristic values can help show which characteristics should be filtered to remove all the unwanted peaks.
plotpeaks!(f, t, y; peaks=pks.indices, prominences=true, widths=true)
DataFrame(pks[Not(:data)])
Row | indices | heights | proms | widths | edges |
---|---|---|---|---|---|
Int64 | Float64 | Float64 | Float64 | Tuple… | |
1 | 37 | 3.3983 | 0.349768 | 19.0733 | (28.6219, 47.6952) |
2 | 102 | 5.06883 | 5.0532 | 111.484 | (18.3513, 129.835) |
3 | 180 | 1.26454 | 0.60992 | 24.5815 | (169.131, 193.712) |
4 | 273 | 1.3268 | 2.5423 | 44.1711 | (251.305, 295.477) |
5 | 347 | -0.559051 | 0.627436 | 23.1592 | (332.166, 355.326) |
6 | 446 | -2.94121 | 0.340754 | 20.0388 | (436.069, 456.108) |
7 | 534 | 3.38041 | 0.331916 | 16.6846 | (528.124, 544.809) |
Looking at the figure and the characteristic values, we can list the usefulness of each characteristic for filtering:
- Peak height?
- There are other peaks around the same height as the peaks we want, so applying a
min
ormax
height filter would remove peaks we want, or allow peaks we don't want.
- There are other peaks around the same height as the peaks we want, so applying a
- Peak prominence?
- All the peaks we want have similarly small prominences (<1) and the other peaks have much larger prominences (>2). This would be a good filtering option, using
peakproms(pks; max=1)
.
- All the peaks we want have similarly small prominences (<1) and the other peaks have much larger prominences (>2). This would be a good filtering option, using
- Peak width?
- The peaks we want have fairly similar widths (~15-25 elements wide), and the other peaks have larger widths (>40 elements wide). This would be a good filter, using
peakwidths(pks; max=30)
.
- The peaks we want have fairly similar widths (~15-25 elements wide), and the other peaks have larger widths (>40 elements wide). This would be a good filter, using
In this case, filtering by peak prominence would be the better choice, because calculating peak widths depends on prominences, so filtering by peak prominence would do the job while avoiding unnecessary work.
In many cases, the desired peaks aren't very different from many other peaks in any one peak characteristic. In these situations, it may be necessary to filter multiple times based on different peak characteristics or different min
/max
thresholds. There is also a filterpeaks!
function which allows you to give a filter predicate and filter by multiple characteristics at once.