-
Notifications
You must be signed in to change notification settings - Fork 0
/
peak.h
103 lines (82 loc) · 2.05 KB
/
peak.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/**
* Z-Score Peak Detection Algorithm, adapted from:
*
* https://stackoverflow.com/questions/22583391/peak-signal-
* detection-in-realtime-timeseries-data/22640362#22640362
*
* ---------------------------------------------------------
*
* Some performance tests:
*
* Single-sample time, measured by averaging
* running time of 10^6 sample operations:
*
* No peak detection: 1.7 us
* No peak detection, O2: 1.4 us
*
* Original peak detection: 2.8 us
* Original peak detection, O2: 2.2 us
*
* Inlined peak detection, with pointer(s): 2.4 us
* Inlined peak detection, no pointer(s): 1.96 us
*
* Inline peak detection, no pointer(s), O2: 1.68 us
*
* Os -> O2, size increased from ~9kB to ~10kB
*
* ADC settings for these tests:
* RCC_CFGR_ADCPRE_PCLK2_DIV2
* ADC_SMPR_SMP_1DOT5CYC
*
*/
#ifndef PEAK_H
#define PEAK_H
#include <stdint.h>
#include <core/usb_vcp.h>
typedef unsigned int uint;
typedef unsigned long ulong;
typedef struct {
uint threshold;
uint influence;
uint lag;
uint elements;
uint oldest;
uint16_t *samples;
ulong sample_sum;
} peak_stat_t;
inline void peak_stat_init(peak_stat_t &s, uint threshold,
uint influence, uint lag, uint16_t *samples) {
s = {
.threshold = threshold,
.influence = influence,
.lag = lag,
.elements = 0,
.oldest = 0,
.samples = samples,
.sample_sum = 0
};
}
inline void peak_stat_reset(peak_stat_t &s) {
s.elements = 0;
s.oldest = 0;
s.sample_sum = 0;
}
inline bool peak_detect(peak_stat_t &s, uint16_t value) {
uint16_t new_value = value;
bool has_peak = false;
if(s.elements == s.lag) {
uint16_t average = s.sample_sum / s.elements;
if(value > average && (uint)(value - average) > s.threshold) {
uint16_t previous = s.samples[(s.oldest + s.lag - 1) % s.lag];
new_value = s.influence * value + (1 - s.influence) * previous;
has_peak = true;
}
s.sample_sum -= s.samples[s.oldest];
} else
s.elements++;
s.sample_sum += new_value;
s.samples[s.oldest] = new_value;
s.oldest = (s.oldest + 1) % s.lag;
return has_peak;
}
#endif