Visual Vibration Tracking 0.2
Загрузка...
Поиск...
Не найдено
peak_finder.cpp
1#include "VVT-V2\peak_finder.h"
2
3#include <iostream>
4#include <vector>
5#include <algorithm>
6#include <cmath>
7
8void diff(std::vector<float> in, std::vector<float>& out)
9{
10 out = std::vector<float>(in.size()-1);
11
12 for(int i=1; i<in.size(); ++i)
13 out[i-1] = in[i] - in[i-1];
14}
15
16void vectorElementsProduct(std::vector<float> a, std::vector<float> b, std::vector<float>& out)
17{
18 out = std::vector<float>(a.size());
19
20 for(int i=0; i<a.size(); ++i)
21 out[i] = a[i] * b[i];
22}
23
24void findIndicesLessThan(std::vector<float> in, float threshold, std::vector<int>& indices)
25{
26 for(int i=0; i<in.size(); ++i)
27 if(in[i]<threshold)
28 indices.push_back(i+1);
29}
30
31void selectElementsFromIndices(std::vector<float> in, std::vector<int> indices, std::vector<float>& out)
32{
33 for(int i=0; i<indices.size(); ++i)
34 out.push_back(in[indices[i]]);
35}
36
37void selectElementsFromIndices(std::vector<int> in, std::vector<int> indices, std::vector<int>& out)
38{
39 for(int i=0; i<indices.size(); ++i)
40 out.push_back(in[indices[i]]);
41}
42
43void signVector(std::vector<float> in, std::vector<int>& out)
44{
45 out = std::vector<int>(in.size());
46
47 for(int i=0; i<in.size(); ++i)
48 {
49 if(in[i]>0)
50 out[i]=1;
51 else if(in[i]<0)
52 out[i]=-1;
53 else
54 out[i]=0;
55 }
56}
57
58void scalarProduct(float scalar, std::vector<float> in, std::vector<float>& out)
59{
60 out = std::vector<float>(in.size());
61
62 for(int i=0; i<in.size(); ++i)
63 out[i] = scalar * in[i];
64}
65
66void PeakFinder::findPeaks(std::vector<float> x0, std::vector<int>& peakInds, bool includeEndpoints, float extrema)
67{
68 int minIdx = distance(x0.begin(), min_element(x0.begin(), x0.end()));
69 int maxIdx = distance(x0.begin(), max_element(x0.begin(), x0.end()));
70
71 float sel = (x0[maxIdx]-x0[minIdx])/4.0;
72 int len0 = x0.size();
73
74 scalarProduct(extrema, x0, x0);
75
76 std::vector<float> dx;
77 diff(x0, dx);
78 replace(dx.begin(), dx.end(), 0.0f, -PeakFinder::EPS);
79 std::vector<float> dx0(dx.begin(), dx.end()-1);
80 std::vector<float> dx0_1(dx.begin()+1, dx.end());
81 std::vector<float> dx0_2;
82
83 vectorElementsProduct(dx0, dx0_1, dx0_2);
84
85 std::vector<int> ind;
86 findIndicesLessThan(dx0_2, 0, ind); // Find where the derivative changes sign
87 std::vector<float> x;
88 float leftMin;
89 int minMagIdx;
90 float minMag;
91
92 if(includeEndpoints)
93 {
94 //x = [x0(1);x0(ind);x0(end)];
95 selectElementsFromIndices(x0, ind, x);
96 x.insert(x.begin(), x0[0]);
97 x.insert(x.end(), x0[x0.size()-1]);
98 //ind = [1;ind;len0];
99 ind.insert(ind.begin(), 1);
100 ind.insert(ind.end(), len0);
101 minMagIdx = distance(x.begin(), std::min_element(x.begin(), x.end()));
102 minMag = x[minMagIdx];
103 //std::cout<<"Hola"<<std::endl;
104 leftMin = minMag;
105 }
106 else
107 {
108 selectElementsFromIndices(x0, ind, x);
109 if(x.size()>2)
110 {
111 minMagIdx = distance(x.begin(), std::min_element(x.begin(), x.end()));
112 minMag = x[minMagIdx];
113 leftMin = x[0]<x0[0]?x[0]:x0[0];
114 }
115 }
116
117 int len = x.size();
118
119 if(len>2)
120 {
121 float tempMag = minMag;
122 bool foundPeak = false;
123 int ii;
124
125 if(includeEndpoints)
126 {
127 // Deal with first point a little differently since tacked it on
128 // Calculate the sign of the derivative since we tacked the first
129 // point on it does not neccessarily alternate like the rest.
130 std::vector<float> xSub0(x.begin(), x.begin()+3);//tener cuidado subvector
131 std::vector<float> xDiff;//tener cuidado subvector
132 diff(xSub0, xDiff);
133
134 std::vector<int> signDx;
135 signVector(xDiff, signDx);
136
137 if (signDx[0] <= 0) // The first point is larger or equal to the second
138 {
139 if (signDx[0] == signDx[1]) // Want alternating signs
140 {
141 x.erase(x.begin()+1);
142 ind.erase(ind.begin()+1);
143 len = len-1;
144 }
145 }
146 else // First point is smaller than the second
147 {
148 if (signDx[0] == signDx[1]) // Want alternating signs
149 {
150 x.erase(x.begin());
151 ind.erase(ind.begin());
152 len = len-1;
153 }
154 }
155 }
156
157 //Skip the first point if it is smaller so we always start on maxima
158 if ( x[0] >= x[1] )
159 ii = 0;
160 else
161 ii = 1;
162
163 //Preallocate max number of maxima
164 float maxPeaks = ceil((float)len/2.0);
165 std::vector<int> peakLoc(maxPeaks,0);
166 std::vector<float> peakMag(maxPeaks,0.0);
167 int cInd = 1;
168 int tempLoc = 0;
169
170 while(ii < len)
171 {
172 ii = ii+1;//This is a peak
173 //Reset peak finding if we had a peak and the next peak is bigger
174 //than the last or the left min was small enough to reset.
175 if(foundPeak)
176 {
177 tempMag = minMag;
178 foundPeak = false;
179 }
180
181 //Found new peak that was lager than temp mag and selectivity larger
182 //than the minimum to its left.
183
184 if( x[ii-1] > tempMag && x[ii-1] > leftMin + sel )
185 {
186 tempLoc = ii-1;
187 tempMag = x[ii-1];
188 }
189
190 //Make sure we don't iterate past the length of our vector
191 if(ii == len)
192 break; //We assign the last point differently out of the loop
193
194 ii = ii+1; // Move onto the valley
195
196 //Come down at least sel from peak
197 if(!foundPeak && tempMag > sel + x[ii-1])
198 {
199 foundPeak = true; //We have found a peak
200 leftMin = x[ii-1];
201 peakLoc[cInd-1] = tempLoc; // Add peak to index
202 peakMag[cInd-1] = tempMag;
203 cInd = cInd+1;
204 }
205 else if(x[ii-1] < leftMin) // New left minima
206 leftMin = x[ii-1];
207
208 }
209
210 // Check end point
211 if(includeEndpoints)
212 {
213 if ( x[x.size()-1] > tempMag && x[x.size()-1] > leftMin + sel )
214 {
215 peakLoc[cInd-1] = len-1;
216 peakMag[cInd-1] = x[x.size()-1];
217 cInd = cInd + 1;
218 }
219 else if( !foundPeak && tempMag > minMag )// Check if we still need to add the last point
220 {
221 peakLoc[cInd-1] = tempLoc;
222 peakMag[cInd-1] = tempMag;
223 cInd = cInd + 1;
224 }
225 }
226 else if(!foundPeak)
227 {
228 float minAux = x0[x0.size()-1]<x[x.size()-1]?x0[x0.size()-1]:x[x.size()-1];
229 if ( x[x.size()-1] > tempMag && x[x.size()-1] > leftMin + sel )
230 {
231 peakLoc[cInd-1] = len-1;
232 peakMag[cInd-1] = x[x.size()-1];
233 cInd = cInd + 1;
234 }
235 else if( !tempMag > minAux + sel)// Check if we still need to add the last point
236 {
237 peakLoc[cInd-1] = tempLoc;
238 peakMag[cInd-1] = tempMag;
239 cInd = cInd + 1;
240 }
241 }
242
243 //Create output
244 if( cInd > 0 )
245 {
246 std::vector<int> peakLocTmp(peakLoc.begin(), peakLoc.begin()+cInd-1);
247 selectElementsFromIndices(ind, peakLocTmp, peakInds);
248 }
249
250 }
251 //else
252 //{
253 //input signal length <= 2
254 //}
255}
void findPeaks(std::vector< float > x0, std::vector< int > &peakInds, bool includeEndpoints=true, float extrema=1)
Definition: peak_finder.cpp:66