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