1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "peak_finder.h"
17
18 #include <algorithm>
19 #include <cmath>
20 #include <iterator>
21
22 #include "sensor_log.h"
23 #include "sensors_errors.h"
24 #include "utils.h"
25
26 #undef LOG_TAG
27 #define LOG_TAG "PeakFinder"
28
29 namespace OHOS {
30 namespace Sensors {
31 namespace {
32 constexpr size_t MAX_N { 32 };
33 constexpr int32_t PEAKS_MIN_SAMPLE_COUNT { 512 };
34 constexpr double REMOVE_RATIO { 0.1 };
35 constexpr double PEAKMAX_THRESHOLD_HIGH { 0.6 };
36 constexpr double PEAKMAX_THRESHIOLD_MID { 0.4 };
37 constexpr double PEAK_LOWDELTA_RATIO_HIGH { 0.3 };
38 constexpr double PEAK_LOWDELTA_RATIO_MID { 0.2 };
39 constexpr double PEAK_LOWDELTA_RATIO_LOW { 0.1 };
40 constexpr int32_t LOOP_TIMES_MAX { 1000000 };
41 constexpr size_t GRADIENT_SIZE_MIN { 3 };
42 // The smaller the value, the faster the descent speed
43 constexpr double DOWN_TREND_MAX { 0.3 };
44 constexpr size_t DESCENT_WNDLEN { 128 };
45 constexpr int32_t HUNDRED_POINT_DESCENT_HEIGHT { 100 };
46 constexpr double DROP_HIGHT { 1.0 };
47 constexpr int32_t AMPLITUDE_ENVELOPE_HOP_LENGTH { 256 };
48 constexpr double DROP_HIGHT_THRESHOLD { 0.3 }; // 30%
49 } // namespace
50
ExtractValues(const std::vector<double> & envelope,const std::vector<int32_t> & idxs)51 std::vector<double> PeakFinder::ExtractValues(const std::vector<double> &envelope, const std::vector<int32_t> &idxs)
52 {
53 size_t envelopSize = envelope.size();
54 size_t idxsSize = idxs.size();
55 std::vector<double> values;
56 for (size_t i = 0; i < idxsSize; i++) {
57 if (idxs[i] >= envelopSize) {
58 break;
59 }
60 values.push_back(envelope[idxs[i]]);
61 }
62 return values;
63 }
64
65 // In order to reduce the impact of voiceless and noise on the frequency of voiced sounds, the threshold is increased.
GetVoiceFlag(const std::vector<double> & data,const std::vector<int32_t> & peaks,double lowerAmp)66 std::vector<bool> PeakFinder::GetVoiceFlag(const std::vector<double> &data, const std::vector<int32_t> &peaks,
67 double lowerAmp)
68 {
69 if (data.empty()) {
70 SEN_HILOGE("data is empty");
71 return {};
72 }
73 std::vector<int32_t> peakAmp;
74 for (size_t i = 0; i < peaks.size(); i++) {
75 if (peaks[i] > data.size()) {
76 break;
77 }
78 peakAmp.push_back(fabs(data[peaks[i]]));
79 }
80 lowerAmp = *max_element(peakAmp.begin(), peakAmp.end()) * INTERSITY_BOUNDARY_POINT;
81 if (peakAmp.size() > 2) {
82 lowerAmp = peakAmp[static_cast<int32_t>(peakAmp.size() * INTERSITY_NUMBER_BOUNDARY_POINT)];
83 }
84 std::vector<double> triangularEnvelope(data.size(), 0.0);
85 for (size_t i = 0; i < data.size(); i++) {
86 triangularEnvelope[i] = fabs(data[i]);
87 }
88 double threshold = lowerAmp;
89 for (size_t i = 0; i < triangularEnvelope.size(); i++) {
90 if (triangularEnvelope[i] < threshold) {
91 triangularEnvelope[i] = 0;
92 }
93 }
94 size_t envelopeLength = triangularEnvelope.size();
95 auto it = triangularEnvelope.begin();
96 for (size_t i = 0; i < envelopeLength; i++) {
97 if ((i + MAX_N) >= envelopeLength) {
98 break;
99 }
100 triangularEnvelope[i] = *max_element(it + i, it + i + MAX_N);
101 }
102 MountainPosition mountainPosition;
103 // Obtain the independent envelope of each peak point
104 GetEachIndependentEnvelope(triangularEnvelope, peaks, lowerAmp, mountainPosition);
105 // Obtain sound and silent envelopes
106 return SplitVoiceSlienceRange(envelopeLength, mountainPosition.firstPos, mountainPosition.lastPos);
107 }
108
GetVoiceSegmentFlag() const109 std::vector<bool> PeakFinder::GetVoiceSegmentFlag() const
110 {
111 return voiceSegmentFlag_;
112 }
113
114 // Obtain soundand silent envelopes.
SplitVoiceSlienceRange(int32_t dataSize,const std::vector<int32_t> & envelopeStart,const std::vector<int32_t> & envelopeLast)115 std::vector<bool> PeakFinder::SplitVoiceSlienceRange(int32_t dataSize, const std::vector<int32_t> &envelopeStart,
116 const std::vector<int32_t> &envelopeLast)
117 {
118 if (dataSize < 0 || hopLength_ == 0) {
119 SEN_HILOGE("Invalid parameter");
120 return {};
121 }
122 std::vector<bool> vioceFlag(dataSize, false);
123 std::vector<bool> segmentFlag(ceil(static_cast<double>(dataSize) / hopLength_), false);
124 for (size_t i = 0; i < envelopeStart.size(); ++i) {
125 for (int32_t boundary = envelopeStart[i]; boundary <= envelopeLast[i]; ++boundary) {
126 if (boundary > vioceFlag.size()) {
127 break;
128 }
129 vioceFlag[boundary] = true;
130 }
131 }
132 for (int32_t i = 0; i < dataSize;) {
133 if (vioceFlag[i]) {
134 int32_t j = i / hopLength_;
135 segmentFlag[j] = true;
136 i = (j + 1) * hopLength_;
137 } else {
138 ++i;
139 }
140 }
141 return segmentFlag;
142 }
143
144 // Obtain the independent envelope of each peak point.
GetEachIndependentEnvelope(const std::vector<double> & data,const std::vector<int32_t> & peaks,double lowerAmp,MountainPosition & mountainPosition)145 void PeakFinder::GetEachIndependentEnvelope(const std::vector<double> &data, const std::vector<int32_t> &peaks,
146 double lowerAmp, MountainPosition &mountainPosition)
147 {
148 int32_t lastLeftPos = -1;
149 int32_t lastRightPos = -1;
150 bool findBoundary = false;
151 BothSidesOfPeak bothSides;
152 for (size_t i = 0; i < peaks.size(); i++) {
153 int32_t index = peaks[i];
154 // Peak points in the same envelope.
155 if ((index >= lastLeftPos) && (index < lastRightPos)) {
156 mountainPosition.firstPos.push_back(bothSides.leftPos);
157 mountainPosition.peakPos.push_back(index);
158 mountainPosition.lastPos.push_back(bothSides.rightPos);
159 continue;
160 }
161 // Find boundary point from peak to both sides.
162 findBoundary = FindPeakBoundary(data, index, lowerAmp, bothSides);
163 if (findBoundary) {
164 lastLeftPos = bothSides.leftPos;
165 lastRightPos = bothSides.rightPos;
166 mountainPosition.firstPos.push_back(bothSides.leftPos);
167 mountainPosition.peakPos.push_back(index);
168 mountainPosition.lastPos.push_back(bothSides.rightPos);
169 }
170 }
171 }
172
173 // Find boundary point from peak to both sides.
FindPeakBoundary(const std::vector<double> & data,int32_t peakPlace,double threshold,BothSidesOfPeak & bothSides)174 bool PeakFinder::FindPeakBoundary(const std::vector<double> &data, int32_t peakPlace, double threshold,
175 BothSidesOfPeak &bothSides)
176 {
177 if (data.empty() || (peakPlace > data.size())) {
178 SEN_HILOGE("data is empty or peakPlace greater than data");
179 return false;
180 }
181 bool findLeft = false;
182 int32_t i = 0;
183 for (i = peakPlace; i >= 0; i--) {
184 if (data[i] < threshold) {
185 findLeft = true;
186 bothSides.leftPos = i;
187 break;
188 }
189 }
190 // Zero hour high opening
191 if (!findLeft && (i == -1)) {
192 bothSides.leftPos = 0;
193 findLeft = true;
194 }
195 size_t dataSize = data.size();
196 bool findRight = false;
197 size_t j = 0;
198 // Find Right
199 for (j = peakPlace; j < dataSize; j++) {
200 if (data[j] < threshold) {
201 findRight = true;
202 bothSides.rightPos = j;
203 break;
204 }
205 }
206 if (!findRight && (j == dataSize)) {
207 bothSides.rightPos = dataSize - 1;
208 findRight = true;
209 }
210 return (findLeft && findRight);
211 }
212
213 // Based on the time difference between peak points, retain a larger value and filter the peak points.
PeakFilterMinRange(const std::vector<double> & data,std::vector<int32_t> & peaks,int32_t minSampleCount)214 std::vector<int32_t> PeakFinder::PeakFilterMinRange(const std::vector<double> &data, std::vector<int32_t> &peaks,
215 int32_t minSampleCount)
216 {
217 if (peaks.empty() || peaks.size() <= 1) {
218 return peaks;
219 }
220 for (size_t i = 0; i < (peaks.size() - 1); i++) {
221 if (fabs(peaks[i] - peaks[i + 1]) < minSampleCount) {
222 if (peaks[i + 1] > data.size()) {
223 SEN_HILOGW("peaks value greater than data size");
224 return peaks;
225 }
226 if (data[peaks[i]] >= data[peaks[i + 1]]) {
227 auto it = (peaks.begin() + i + 1);
228 peaks.erase(it);
229 } else {
230 auto it = (peaks.begin() + i);
231 peaks.erase(it);
232 }
233 --i;
234 }
235 }
236 return peaks;
237 }
238
239 // As a short event peak, directly remove peaks smaller than 0.1 * max().
FilterLowPeak(const std::vector<double> & envelope,const std::vector<int32_t> & peaks,double removeRatio)240 std::vector<int32_t> PeakFinder::FilterLowPeak(const std::vector<double> &envelope, const std::vector<int32_t> &peaks,
241 double removeRatio)
242 {
243 std::vector<int32_t> peakPoint = peaks;
244 size_t peaksSize = peakPoint.size();
245 if (peaksSize == 0) {
246 return peakPoint;
247 }
248 std::vector<double> peakValue;
249
250 for (size_t i = 0; i < peaksSize; i++) {
251 peakValue.push_back(envelope[peakPoint[i]]);
252 }
253 double threshold = *max_element(peakValue.begin(), peakValue.end()) * removeRatio;
254 for (int32_t i = (peaksSize - 1); i >= 0; i--) {
255 if (peakValue[i] < threshold) {
256 peakPoint.erase(peakPoint.begin() + i);
257 }
258 }
259 return peakPoint;
260 }
261
262 // Filter secondary peak points.
263 // Like heartbeat.wav, mp5.wav and clavels.wav process here.
FilterSecondaryPeak(const std::vector<double> & envelope,const std::vector<int32_t> & peaks,double lowerAmp)264 std::vector<int32_t> PeakFinder::FilterSecondaryPeak(const std::vector<double> &envelope,
265 const std::vector<int32_t> &peaks, double lowerAmp)
266 {
267 MountainPosition wholeEnvelop;
268 // Obtain the independent envelope of each peak point
269 GetEachIndependentEnvelope(envelope, peaks, lowerAmp, wholeEnvelop);
270 if (wholeEnvelop.firstPos.empty()) {
271 SEN_HILOGE("firstPos is empty");
272 return {};
273 }
274 int32_t lastFirstPos = wholeEnvelop.firstPos[0];
275 int32_t lastEndPos = wholeEnvelop.lastPos[0];
276 size_t frontIndex = 0;
277 int32_t n = 0;
278 int32_t times = 0;
279 size_t i = 1;
280 while (i < wholeEnvelop.peakPos.size()) {
281 ++times;
282 if ((wholeEnvelop.firstPos[i] == lastFirstPos) && (wholeEnvelop.lastPos[i] == lastEndPos)) {
283 ++n;
284 if (i != (wholeEnvelop.peakPos.size() - 1)) {
285 ++i;
286 continue;
287 }
288 }
289 if (n == 0) {
290 lastFirstPos = wholeEnvelop.firstPos[i];
291 lastEndPos = wholeEnvelop.lastPos[i];
292 frontIndex = i;
293 ++i;
294 continue;
295 }
296 if (frontIndex == (wholeEnvelop.peakPos.size() - 1)) {
297 break;
298 }
299 int32_t toIndex = frontIndex + n;
300 // The peak points are enveloped together, and the drop of the secondary peak is less than 30 %.
301 // Delete this peak point
302 int32_t index = 0;
303 if (DeletePeaks(envelope, frontIndex, toIndex, wholeEnvelop, index) != Sensors::SUCCESS) {
304 SEN_HILOGE("DeletePeaks failed");
305 return {};
306 }
307 if (times > LOOP_TIMES_MAX) {
308 SEN_HILOGW("times should not be greater than LOOP_TIMES_MAX, times:%{public}d", times);
309 break;
310 }
311 frontIndex = index;
312 i = index;
313 n = 0;
314 }
315 return wholeEnvelop.peakPos;
316 }
317
318 // The peak points are enveloped together, and the drop of the secondary peak is less than 30 %. Delete this peak point
DeletePeaks(const std::vector<double> & envelope,int32_t startPos,int32_t endPos,MountainPosition & mountainPosition,int32_t & endIndex)319 int32_t PeakFinder::DeletePeaks(const std::vector<double> &envelope, int32_t startPos, int32_t endPos,
320 MountainPosition &mountainPosition, int32_t &endIndex)
321 {
322 bool delFlag = true;
323 while (delFlag) {
324 ValleyPoint valleyPoint;
325 // The valley in both peaks detection.
326 if (DetectValley(envelope, startPos, endPos, mountainPosition, valleyPoint) != Sensors::SUCCESS) {
327 SEN_HILOGE("DetectValley failed");
328 return Sensors::ERROR;
329 }
330 std::vector<double> valleysValue = valleyPoint.values;
331 // Filter out secondary peak points
332 delFlag = false;
333 int32_t valleyIndex = 0;
334 for (int32_t peakIndex = startPos; peakIndex < (endPos + 1); peakIndex++) {
335 delFlag = GetDeleteFlagOfPeak(envelope, peakIndex, valleyIndex, valleysValue, mountainPosition);
336 if (delFlag && (peakIndex < static_cast<int32_t>(mountainPosition.firstPos.size()))) {
337 mountainPosition.firstPos.erase(mountainPosition.firstPos.begin() + peakIndex);
338 mountainPosition.peakPos.erase(mountainPosition.peakPos.begin() + peakIndex);
339 mountainPosition.lastPos.erase(mountainPosition.lastPos.begin() + peakIndex);
340 --endPos;
341 break;
342 }
343 ++valleyIndex;
344 }
345 if (endPos <= startPos) {
346 break;
347 }
348 }
349 endIndex = endPos;
350 return Sensors::SUCCESS;
351 }
352
GetDeleteFlagOfPeak(const std::vector<double> & envelope,int32_t peakIndex,int32_t valleyIndex,const std::vector<double> & valleysValue,const MountainPosition & mountainPosition)353 bool PeakFinder::GetDeleteFlagOfPeak(const std::vector<double> &envelope, int32_t peakIndex, int32_t valleyIndex,
354 const std::vector<double> &valleysValue, const MountainPosition &mountainPosition)
355 {
356 if (valleyIndex >= valleysValue.size() || peakIndex >= mountainPosition.peakPos.size()) {
357 SEN_HILOGW("invalid parameter");
358 return false;
359 }
360 double peakValue = envelope[mountainPosition.peakPos[peakIndex]];
361 double hightThreshold = DROP_HIGHT_THRESHOLD * peakValue;
362 bool delFlag = false;
363 if (((peakValue - valleysValue[valleyIndex]) < hightThreshold) &&
364 ((peakValue - valleysValue[valleyIndex + 1]) < hightThreshold)) {
365 delFlag = true;
366 } else if (((peakValue - valleysValue[valleyIndex]) > hightThreshold) &&
367 ((peakValue - valleysValue[valleyIndex + 1]) < hightThreshold)) {
368 if (peakValue < envelope[mountainPosition.peakPos[peakIndex+1]]) {
369 delFlag = true;
370 }
371 } else if (((peakValue - valleysValue[valleyIndex]) < hightThreshold) &&
372 ((peakValue - valleysValue[valleyIndex + 1]) > hightThreshold)) {
373 if (peakValue < envelope[mountainPosition.peakPos[peakIndex-1]]) {
374 delFlag = true;
375 }
376 }
377 return delFlag;
378 }
379
380 // The valley in both peaks detection.
DetectValley(const std::vector<double> & envelope,int32_t startPos,int32_t endPos,const MountainPosition & mountainPosition,ValleyPoint & valleyPoint)381 int32_t PeakFinder::DetectValley(const std::vector<double> &envelope, int32_t startPos, int32_t endPos,
382 const MountainPosition &mountainPosition, ValleyPoint &valleyPoint)
383 {
384 if (mountainPosition.peakPos.empty()) {
385 SEN_HILOGE("peakPos is empty");
386 return Sensors::ERROR;
387 }
388 if (startPos < 0 || endPos < 0) {
389 SEN_HILOGE("startPos or endPos is wrong");
390 return Sensors::ERROR;
391 }
392 valleyPoint.values.resize(mountainPosition.peakPos.size() + 1);
393 valleyPoint.pos.resize(mountainPosition.peakPos.size() + 1);
394
395 if ((startPos >= mountainPosition.firstPos.size()) || (endPos >= mountainPosition.lastPos.size())) {
396 SEN_HILOGE("The parameter is invalid or out of bounds");
397 return Sensors::ERROR;
398 }
399 int32_t valleyPos = mountainPosition.firstPos[startPos];
400 if (startPos > 0) {
401 int32_t startIndex = mountainPosition.peakPos[startPos - 1];
402 int32_t endindex = mountainPosition.peakPos[startPos];
403 auto iter = std::min_element((envelope.begin() + startIndex), (envelope.begin() + endindex));
404 valleyPos = iter - envelope.begin();
405 }
406 int32_t indexCount = 0;
407 valleyPoint.values[indexCount] = envelope[valleyPos];
408 valleyPoint.pos[indexCount] = valleyPos;
409 ++indexCount;
410 for (int32_t i = startPos; i < endPos; i++) {
411 int32_t startIndex = mountainPosition.peakPos[i];
412 int32_t endindex = mountainPosition.peakPos[i + 1];
413 auto iter = std::min_element((envelope.begin() + startIndex), (envelope.begin() + endindex));
414 valleyPos = iter - envelope.begin();
415 valleyPoint.values[indexCount] = envelope[valleyPos];
416 valleyPoint.pos[indexCount] = valleyPos;
417 ++indexCount;
418 }
419 valleyPos = mountainPosition.lastPos[endPos];
420 valleyPoint.values[indexCount] = envelope[valleyPos];
421 valleyPoint.pos[indexCount] = valleyPos;
422 return Sensors::SUCCESS;
423 }
424
425 // Calculate peak value by difference, method: low+high+low
426 // 1. When equal to 0, all peak points are selected
427 // 2. In situations such as OnCarpet.wav and CoinDrop.wav with zero hour high opening,
428 // having more than 2 segments is the true high
429 // 3. Like heartbeat. wav, the secondary peak point is not from the lowest point and must be removed
DetectPeak(const std::vector<double> & envelope,double peakThreshold)430 std::vector<int32_t> PeakFinder::DetectPeak(const std::vector<double> &envelope, double peakThreshold)
431 {
432 CALL_LOG_ENTER;
433 if (envelope.empty() || envelope.size() <= 1) {
434 SEN_HILOGE("envelope is empty or envelope is less than or equal to one");
435 return {};
436 }
437 std::vector<double> gradientEnvelope;
438 for (size_t i = 0; i < (envelope.size() - 1); i++) {
439 gradientEnvelope.push_back(envelope[i+1] - envelope[i]);
440 }
441 if (gradientEnvelope.empty()) {
442 SEN_HILOGE("gradientEnvelope is empty");
443 return {};
444 }
445 std::vector<double> gradient;
446 for (size_t i = 0; i < (gradientEnvelope.size() - 1); i++) {
447 if ((gradientEnvelope[i] > 0) && (gradientEnvelope[i+1] < 0)) {
448 gradient.push_back((gradientEnvelope[i] + fabs(gradientEnvelope[i+1])) / 2);
449 }
450 }
451 // At begining, no rising edge, directly at the maximum point
452 std::vector<int32_t> peaks;
453 if ((gradientEnvelope[0] < 0) && (gradientEnvelope[1] < 0)) {
454 peaks.push_back(0);
455 }
456 if (peakThreshold < EPS_MIN) {
457 for (size_t j = 0; j < (gradientEnvelope.size() - 1); j++) {
458 if((gradientEnvelope[j] > 0) && (gradientEnvelope[j+1] < 0)) {
459 peaks.push_back(j+1);
460 }
461 }
462 return peaks;
463 }
464 double thresholdGradient = *max_element(gradient.begin(), gradient.end()) / 2;
465 if (gradient.size() > GRADIENT_SIZE_MIN) {
466 gradient.erase(max_element(gradient.begin(), gradient.end()));
467 gradient.erase(max_element(gradient.begin(), gradient.end()));
468 thresholdGradient = *max_element(gradient.begin(), gradient.end()) * peakThreshold;
469 }
470 for (size_t k = 0; k < (gradientEnvelope.size() - 1); k++) {
471 if ((gradientEnvelope[k] > 0) && (gradientEnvelope[k+1] < 0)) {
472 if ((gradientEnvelope[k] + fabs(gradientEnvelope[k+1])) / 2 > thresholdGradient) {
473 peaks.push_back(k+1);
474 }
475 }
476 }
477 return peaks;
478 }
479
480 // Starting from the peak, find the first lowest point on both sides
481 // The minimum amplitude obtained through this method is small
482 // Envelope: multi point maximum envelope
GetLowestPeakValue(const std::vector<double> & envelope,const std::vector<int32_t> & peaks)483 double PeakFinder::GetLowestPeakValue(const std::vector<double> &envelope, const std::vector<int32_t> &peaks)
484 {
485 if (peaks.empty()) {
486 SEN_HILOGE("peaks is empty");
487 return Sensors::ERROR;
488 }
489 std::vector<double> peakValues;
490 for (size_t i = 0; i < peaks.size(); i++) {
491 peakValues.push_back(envelope[peaks[i]]);
492 }
493 double maxPeak = *max_element(peakValues.begin(), peakValues.end());
494 double minPeak = *min_element(peakValues.begin(), peakValues.end());
495 if (maxPeak > PEAKMAX_THRESHOLD_HIGH) {
496 minPeak *= PEAK_LOWDELTA_RATIO_HIGH;
497 } else if (maxPeak > PEAKMAX_THRESHIOLD_MID) {
498 minPeak *= PEAK_LOWDELTA_RATIO_MID;
499 } else {
500 minPeak *= PEAK_LOWDELTA_RATIO_LOW;
501 }
502 return minPeak;
503 }
504
505 // Determine the peak position and parameters of short events through amplitude values.
GetPeakEnvelope(const std::vector<double> & data,int32_t samplingRate,int32_t hopLength,PeaksInfo & peakDetection)506 int32_t PeakFinder::GetPeakEnvelope(const std::vector<double> &data, int32_t samplingRate, int32_t hopLength,
507 PeaksInfo &peakDetection)
508 {
509 CALL_LOG_ENTER;
510 if ((data.empty()) || (samplingRate == 0) || (hopLength == 0)) {
511 SEN_HILOGE("Invalid parameter");
512 return Sensors::PARAMETER_ERROR;
513 }
514 std::vector<double> absData;
515 for (size_t i = 0; i < data.size(); i++) {
516 absData.push_back(fabs(data[i]));
517 }
518 size_t maxN = static_cast<size_t>(hopLength);
519 std::vector<double> peakEnvelope;
520 std::vector<int32_t> peakEnvelopeIdx;
521 size_t i = 0;
522 while ((i + maxN) <= absData.size()) {
523 auto it = std::max_element(absData.begin() + i, absData.begin() + i + maxN);
524 int32_t maxIndex = it - absData.begin();
525 peakEnvelopeIdx.push_back(maxIndex);
526 peakEnvelope.push_back(*it);
527 i += maxN;
528 }
529 // Peak detection
530 std::vector<int32_t> peakAllIdx = DetectPeak(peakEnvelope, REMOVE_RATIO);
531
532 // Filter low peak
533 peakAllIdx = FilterLowPeak(peakEnvelope, peakAllIdx, REMOVE_RATIO);
534 std::vector<double> extractValues = ExtractValues(peakEnvelope, peakAllIdx);
535 double lowerAmp = *std::min_element(extractValues.begin(), extractValues.end()) * PEAK_LOWDELTA_RATIO_LOW;
536
537 // Filter secondary peak points
538 std::vector<int32_t> ampPeakBigIdx = FilterSecondaryPeak(peakEnvelope, peakAllIdx, lowerAmp);
539 if (ampPeakBigIdx.empty()) {
540 SEN_HILOGE("ampPeakBigIdx is empty");
541 return Sensors::ERROR;
542 }
543 peakDetection.ampPeakEnvelope = peakEnvelope;
544 peakDetection.ampPeakAllIdx = peakAllIdx;
545
546 std::vector<int32_t> ampPeakAct;
547 for (i = 0; i < ampPeakBigIdx.size(); i++) {
548 if (ampPeakBigIdx[i] >= peakEnvelopeIdx.size()) {
549 break;
550 }
551 ampPeakAct.push_back(peakEnvelopeIdx[ampPeakBigIdx[i]]);
552 }
553 // Based on the time difference between peak points, retain a larger value and filter the peak points
554 peakDetection.ampPeakIdxs = PeakFilterMinRange(absData, ampPeakAct, PEAKS_MIN_SAMPLE_COUNT);
555 double coef = 1.0 / samplingRate;
556 for (i = 0; i < peakDetection.ampPeakIdxs.size(); i++) {
557 peakDetection.ampPeakTimes.push_back(peakDetection.ampPeakIdxs[i] * coef);
558 }
559 return Sensors::SUCCESS;
560 }
561
562 // Estimating the downward trend of isolated short events.
563 // A descent height of less than 0.03 at 100 points indicates a slow descent.
EstimateDownwardTrend(const std::vector<double> & data,const std::vector<int32_t> & peaksPoint,const std::vector<int32_t> & lastPeaksPoint,std::vector<DownwardTrendInfo> & downwardTrends)564 int32_t PeakFinder::EstimateDownwardTrend(const std::vector<double> &data, const std::vector<int32_t> &peaksPoint,
565 const std::vector<int32_t> &lastPeaksPoint, std::vector<DownwardTrendInfo> &downwardTrends)
566 {
567 if (peaksPoint.empty() || lastPeaksPoint.size() < peaksPoint.size()) {
568 SEN_HILOGE("Invalid parameter");
569 return Sensors::ERROR;
570 }
571 bool isRapidlyDecay = false;
572 std::vector<double> partEnvelope;
573 for (size_t i = 0; i < peaksPoint.size(); i++) {
574 for (int32_t j = peaksPoint[i]; j < lastPeaksPoint[i]; j++) {
575 if (data[j] > data.size()) {
576 SEN_HILOGE("parameter is error");
577 break;
578 }
579 partEnvelope.push_back(data[j]);
580 }
581 double dropHeight = 0.0;
582 double ducyCycle = 0.0;
583 if (EstimateDesentEnergy(partEnvelope, dropHeight, ducyCycle) != Sensors::SUCCESS) {
584 SEN_HILOGD("EstimateDesentEnergy failed");
585 continue;
586 }
587 dropHeight *= HUNDRED_POINT_DESCENT_HEIGHT ;
588 if (IsLessNotEqual(ducyCycle, DOWN_TREND_MAX) && IsGreatNotEqual(dropHeight, DROP_HIGHT)) {
589 isRapidlyDecay = true;
590 } else {
591 isRapidlyDecay = false;
592 }
593 downwardTrends.push_back(DownwardTrendInfo(isRapidlyDecay, dropHeight, ducyCycle));
594 }
595 return Sensors::SUCCESS;
596 }
597
598 // Merge continuous long envelopes and continuous pure instantaneous event intervals to avoid low energy
599 // long event outputs.
600 // between two short events, such as CoinDrop.wav.
601 // Pre processing before peak point co envelope refinement
602 // a0[0],a2[0],a0[1],a2[1]... May be discontinuous
603 // Output list_ I is continuous
SplitLongShortEnvelope(int32_t dataSize,const std::vector<int32_t> & firstPos,const std::vector<int32_t> & lastPos,EnvelopeSegmentInfo & envelopeList)604 void PeakFinder::SplitLongShortEnvelope(int32_t dataSize, const std::vector<int32_t> &firstPos,
605 const std::vector<int32_t> &lastPos, EnvelopeSegmentInfo &envelopeList)
606 {
607 int32_t leastCount = 2 * hopLength_;
608 std::vector<int32_t> countAssemble;
609 for (size_t i = 0; i < firstPos.size(); i++) {
610 countAssemble.push_back(lastPos[i] - firstPos[i]);
611 }
612 int32_t longestSampleCount = *max_element(countAssemble.begin(), countAssemble.end());
613 if (longestSampleCount <= leastCount) {
614 SEN_HILOGE("longestSampleCount must be less than or equal to leastCount");
615 return;
616 }
617 bool preFlag = false;
618 int32_t preIndex = 0;
619 size_t countAssembleLen = countAssemble.size();
620 if (countAssembleLen == 0) {
621 SEN_HILOGE("countAssembleLen should not be 0");
622 return;
623 }
624 for (size_t j = 0; j < countAssembleLen; j++) {
625 bool flag = true;
626 if (countAssemble[j] < hopLength_) {
627 flag = false;
628 }
629 int32_t toIndex = lastPos[j];
630 if (j == 0) {
631 envelopeList.continuousEventFlag.push_back(flag);
632 envelopeList.demarcPos.push_back(0);
633 envelopeList.demarcPos.push_back(toIndex);
634 preFlag = flag;
635 } else if (j == (countAssembleLen - 1)) {
636 if (flag != preFlag) {
637 envelopeList.continuousEventFlag.push_back(flag);
638 envelopeList.demarcPos.push_back(preIndex);
639 preFlag = flag;
640 }
641 envelopeList.demarcPos[envelopeList.demarcPos.size() - 1] = dataSize;
642 } else {
643 if (flag == preFlag) {
644 envelopeList.demarcPos[envelopeList.demarcPos.size() - 1] = toIndex;
645 } else {
646 envelopeList.continuousEventFlag.push_back(flag);
647 envelopeList.demarcPos.push_back(preIndex);
648 envelopeList.demarcPos.push_back(toIndex);
649 preFlag = flag;
650 }
651 }
652 preIndex = toIndex;
653 }
654 }
655
656 // Calculate the starting and ending envelopes of isolated pure short events, searching from peak to both sides
657 // Do not merge common envelope peaks
658 // Missing trackback function similar to note when co enveloping
GetIsolatedEnvelope(const std::vector<double> & data,const std::vector<int32_t> & peaks,double lowerAmp,IsolatedEnvelopeInfo & isolatedEnvelopeInfo)659 int32_t PeakFinder::GetIsolatedEnvelope(const std::vector<double> &data, const std::vector<int32_t> &peaks,
660 double lowerAmp, IsolatedEnvelopeInfo &isolatedEnvelopeInfo)
661 {
662 std::vector<double> triangularEnvelope(data.size(), 0.0);
663 for (size_t i = 0; i < data.size(); i++) {
664 triangularEnvelope[i] = fabs(data[i]);
665 if (triangularEnvelope[i] < lowerAmp) {
666 triangularEnvelope[i] = 0;
667 }
668 }
669 size_t envelopeSize = triangularEnvelope.size();
670 size_t j = 0;
671 while ((j + MAX_N) <= envelopeSize) {
672 double maxValue = *std::max_element(triangularEnvelope.begin() + j, triangularEnvelope.begin() + j + MAX_N);
673 triangularEnvelope[j] = maxValue;
674 ++j;
675 }
676 int32_t leastCount = 2 * hopLength_;
677 MountainPosition mountainPosition;
678 // Obtain the independent envelope of each peak point
679 GetEachIndependentEnvelope(triangularEnvelope, peaks, lowerAmp, mountainPosition);
680 if (mountainPosition.peakPos.empty()) {
681 SEN_HILOGE("peakPos is empty");
682 return Sensors::ERROR;
683 }
684 EnvelopeSegmentInfo envelopeList;
685 // Merge continuous long envelopes and continuous pure instantaneous event intervals
686 SplitLongShortEnvelope(envelopeSize, mountainPosition.firstPos, mountainPosition.lastPos, envelopeList);
687 ValleyPoint valleyPoint;
688 size_t envPeakLen = mountainPosition.peakPos.size() - 1;
689 // The valleyes in both peaks to detection
690 if (DetectValley(triangularEnvelope, 0, envPeakLen, mountainPosition, valleyPoint) != Sensors::SUCCESS) {
691 SEN_HILOGE("DetectValley failed");
692 return Sensors::ERROR;
693 }
694 std::vector<int32_t> countAssemble;
695 for (size_t i = 0; i < mountainPosition.lastPos.size(); i++) {
696 countAssemble.push_back(mountainPosition.lastPos[i] - mountainPosition.firstPos[i]);
697 }
698 isolatedEnvelopeInfo.isHaveContinuousEvent = false;
699 isolatedEnvelopeInfo.mountainPosition = mountainPosition;
700 isolatedEnvelopeInfo.longestSampleCount = *max_element(countAssemble.begin(), countAssemble.end());
701 if (isolatedEnvelopeInfo.longestSampleCount > leastCount) {
702 isolatedEnvelopeInfo.isHaveContinuousEvent = true;
703 }
704 for (size_t i = 0; i < countAssemble.size(); i++) {
705 bool flag = false;
706 if (countAssemble[i] < hopLength_) {
707 flag = true;
708 }
709 isolatedEnvelopeInfo.transientEventFlags.push_back(flag);
710 }
711 return Sensors::SUCCESS;
712 }
713
714 // Find all isolated short events through the original amplitude
ObtainTransientByAmplitude(const std::vector<double> & data,IsolatedEnvelopeInfo & isolatedEnvelopeInfo)715 int32_t PeakFinder::ObtainTransientByAmplitude(const std::vector<double> &data,
716 IsolatedEnvelopeInfo &isolatedEnvelopeInfo)
717 {
718 if (data.empty()) {
719 SEN_HILOGE("data is empty");
720 return Sensors::ERROR;
721 }
722 PeaksInfo peakDetection;
723 // Determine the peak position and parameters of short events through amplitude values
724 GetPeakEnvelope(data, SAMPLE_RATE, AMPLITUDE_ENVELOPE_HOP_LENGTH, peakDetection);
725
726 // Starting from the peak, find the first lowest point on both sides
727 double ampLowerDalta = GetLowestPeakValue(peakDetection.ampPeakEnvelope, peakDetection.ampPeakAllIdx);
728
729 // Calculate the starting and ending envelopes of isolated pure short events, searching from peak to both sides
730 if (GetIsolatedEnvelope(data, peakDetection.ampPeakIdxs,
731 ampLowerDalta, isolatedEnvelopeInfo) != Sensors::SUCCESS) {
732 SEN_HILOGE("GetIsolatedEnvelope failed");
733 return Sensors::ERROR;
734 }
735 // In order to reduce the impact of voiceless and noise on the frequency of voiced sounds,
736 // the threshold is increased
737 voiceSegmentFlag_ = GetVoiceFlag(data, peakDetection.ampPeakIdxs, ampLowerDalta);
738 std::vector<DownwardTrendInfo> downwardTrends;
739 // Estimating the downward trend of isolated short events
740 int32_t ret = EstimateDownwardTrend(data, isolatedEnvelopeInfo.mountainPosition.peakPos,
741 isolatedEnvelopeInfo.mountainPosition.lastPos, downwardTrends);
742 if (downwardTrends.size() > 0) {
743 SEN_HILOGD("isRapidlyDecay:%{public}d,dropHeight:%{public}lf,ducyCycle:%{public}lf",
744 downwardTrends[0].isRapidlyDecay, downwardTrends[0].dropHeight, downwardTrends[0].ducyCycle);
745 }
746 return ret;
747 }
748
EstimateDesentEnergy(const std::vector<double> & data,double & dropHeight,double & dutyCycle)749 int32_t PeakFinder::EstimateDesentEnergy(const std::vector<double> &data, double &dropHeight, double &dutyCycle)
750 {
751 if (data.empty()) {
752 SEN_HILOGE("data is empty");
753 return Sensors::ERROR;
754 }
755 std::vector<double> blockSum = ObtainAmplitudeEnvelop(data, DESCENT_WNDLEN, DESCENT_WNDLEN);
756 if (blockSum.empty()) {
757 SEN_HILOGE("blockSum is empty");
758 return Sensors::ERROR;
759 }
760 // Number of consecutive drops.
761 size_t n = 1;
762 for (size_t i = 0; i < (blockSum.size() - 1); i++) {
763 if (blockSum[i] < blockSum[i + 1]) {
764 break;
765 }
766 ++n;
767 }
768 size_t dataSize = data.size();
769 dropHeight = 0;
770 if (n == 1) {
771 dropHeight = blockSum[0] / dataSize;
772 } else {
773 dropHeight = (blockSum[0] - blockSum[1]) / DESCENT_WNDLEN;
774 }
775
776 // Estimating within 1024 sampling points (0.046ms).
777 int32_t miniFrmN = ENERGY_HOP_LEN / DESCENT_WNDLEN;
778 if (n > miniFrmN) {
779 n = miniFrmN;
780 }
781 double totalEnergy = 0.0;
782 for (size_t i = 0; i < n; i++) {
783 totalEnergy += blockSum[i];
784 }
785 double virtualWholeEnergy = miniFrmN * blockSum[0];
786 if (virtualWholeEnergy < EPS_MIN) {
787 dutyCycle = 0.0;
788 SEN_HILOGW("The virtualWholeEnergy value is too low");
789 }
790 dutyCycle = totalEnergy / virtualWholeEnergy;
791 return Sensors::SUCCESS;
792 }
793 } // namespace Sensors
794 } // namespace OHOS
795