v2.0.0
Loading...
Searching...
No Matches
peak_finder.cpp
Go to the documentation of this file.
1//=============================================================================================================
12
13//=============================================================================================================
14// INCLUDES
15//=============================================================================================================
16
17#include "peak_finder.h"
18
19//=============================================================================================================
20// STL INCLUDES
21//=============================================================================================================
22
23#include <algorithm>
24#include <cmath>
25
26//=============================================================================================================
27// USED NAMESPACES
28//=============================================================================================================
29
30using namespace UTILSLIB;
31using namespace Eigen;
32
33//=============================================================================================================
34// DEFINE FUNCTIONS
35//=============================================================================================================
36
37VectorXd UTILSLIB::peakProminences(const VectorXd& data, const QList<int>& peakIndices)
38{
39 const int n = static_cast<int>(data.size());
40 VectorXd proms(peakIndices.size());
41
42 for (int p = 0; p < peakIndices.size(); ++p) {
43 int idx = peakIndices[p];
44 double peakVal = data(idx);
45
46 // Search left for highest valley before a higher peak
47 double leftMin = peakVal;
48 for (int i = idx - 1; i >= 0; --i) {
49 if (data(i) > peakVal) break;
50 leftMin = std::min(leftMin, data(i));
51 }
52
53 // Search right for highest valley before a higher peak
54 double rightMin = peakVal;
55 for (int i = idx + 1; i < n; ++i) {
56 if (data(i) > peakVal) break;
57 rightMin = std::min(rightMin, data(i));
58 }
59
60 // Prominence = peak height minus highest of the two valleys
61 double highestValley = std::max(leftMin, rightMin);
62 proms(p) = peakVal - highestValley;
63 }
64
65 return proms;
66}
67
68//=============================================================================================================
69
70QList<QPair<int,double>> UTILSLIB::peakFinder(const VectorXd& data,
71 const PeakFinderParams& params)
72{
73 const int n = static_cast<int>(data.size());
74 QList<QPair<int,double>> peaks;
75
76 if (n < 3) {
77 return peaks;
78 }
79
80 // Step 1: Find all local maxima (strictly greater than both neighbours)
81 QList<int> peakIdx;
82 for (int i = 1; i < n - 1; ++i) {
83 if (data(i) > data(i - 1) && data(i) > data(i + 1)) {
84 if (data(i) >= params.dMinHeight) {
85 peakIdx.append(i);
86 }
87 }
88 }
89
90 // Step 2: Filter by prominence
91 if (params.dProminence > 0.0 && !peakIdx.isEmpty()) {
92 VectorXd proms = peakProminences(data, peakIdx);
93 QList<int> filtered;
94 for (int i = 0; i < peakIdx.size(); ++i) {
95 if (proms(i) >= params.dProminence) {
96 filtered.append(peakIdx[i]);
97 }
98 }
99 peakIdx = filtered;
100 }
101
102 // Step 3: Filter by minimum distance (keep highest peaks)
103 if (params.iMinDistance > 1 && !peakIdx.isEmpty()) {
104 // Sort peaks by height descending
105 std::vector<int> sortedIdx(peakIdx.begin(), peakIdx.end());
106 std::sort(sortedIdx.begin(), sortedIdx.end(),
107 [&data](int a, int b) { return data(a) > data(b); });
108
109 QList<int> kept;
110 std::vector<bool> suppressed(static_cast<size_t>(n), false);
111
112 for (int idx : sortedIdx) {
113 if (suppressed[static_cast<size_t>(idx)]) continue;
114 kept.append(idx);
115
116 // Suppress nearby peaks
117 int lo = std::max(0, idx - params.iMinDistance);
118 int hi = std::min(n - 1, idx + params.iMinDistance);
119 for (int s = lo; s <= hi; ++s) {
120 if (s != idx) {
121 suppressed[static_cast<size_t>(s)] = true;
122 }
123 }
124 }
125
126 // Re-sort by index
127 std::sort(kept.begin(), kept.end());
128 peakIdx = kept;
129 }
130
131 // Build output
132 for (int idx : peakIdx) {
133 peaks.append(qMakePair(idx, data(idx)));
134 }
135
136 return peaks;
137}
Local-maxima peak detection in 1-D signals with prominence filtering.
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
DSPSHARED_EXPORT QList< QPair< int, double > > peakFinder(const Eigen::VectorXd &data, const PeakFinderParams &params=PeakFinderParams())
Find peaks in a 1D signal.
DSPSHARED_EXPORT Eigen::VectorXd peakProminences(const Eigen::VectorXd &data, const QList< int > &peakIndices)
Compute prominence of each peak.